{"id":25345749,"url":"https://github.com/jibstack64/field","last_synced_at":"2026-02-26T15:38:48.605Z","repository":{"id":64611351,"uuid":"576795602","full_name":"jibstack64/field","owner":"jibstack64","description":"A subcommand-based argument parsing library.","archived":false,"fork":false,"pushed_at":"2022-12-12T16:09:35.000Z","size":35,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-08T16:31:19.410Z","etag":null,"topics":["args","argument-parsing","cpp"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jibstack64.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-12-11T02:02:27.000Z","updated_at":"2024-02-08T20:02:41.000Z","dependencies_parsed_at":"2022-12-14T18:46:28.883Z","dependency_job_id":null,"html_url":"https://github.com/jibstack64/field","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/jibstack64/field","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jibstack64%2Ffield","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jibstack64%2Ffield/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jibstack64%2Ffield/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jibstack64%2Ffield/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jibstack64","download_url":"https://codeload.github.com/jibstack64/field/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jibstack64%2Ffield/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29863578,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-26T08:51:08.701Z","status":"ssl_error","status_checked_at":"2026-02-26T08:50:19.607Z","response_time":89,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["args","argument-parsing","cpp"],"created_at":"2025-02-14T12:50:45.695Z","updated_at":"2026-02-26T15:38:48.576Z","avatar_url":"https://github.com/jibstack64.png","language":"C++","readme":"# field\n\n![GitHub tag (latest by date)](https://img.shields.io/github/v/tag/jibstack64/field)\n![GitHub all releases](https://img.shields.io/github/downloads/jibstack64/field/total)\n![GitHub](https://img.shields.io/github/license/jibstack64/field)\n\n*A subcommand-based argument parsing library for C++.*\n\n### Information\n`field` is *not* a replacement for [argh!](https://github.com/adishavit/argh) and similar libraries, it is for use in specific types of programs, as described below.\n\n**It is not for multi-argument parsing**. `field` is for programs where, instead of having traditional GNU-style `--arg` arguments, you have so-called 'command arguments', that act as individual parts of the program.\n\n\u003e If you insist on using `field` for multi-argument parsing, you may set `parser.disableLock` to true. This will allow multiple subcommands to be used, instead of locking to one.\n\nFor example, say you are developing a package manager that is solely controlled using command-line arguments. When installing a package, you want the command-line syntax to look something like this:\n\n`package-manager install \u003cpackage\u003e`\n\nWell? Perfect! This is exactly what `field` is for, segmenting your program into individual chunks that play their own part in the application.\n\n*How does it work?*\nThe basic idea is that when an argument is passed, it has a matching function that is called alongside it - a `field::context` object and an `std::vector\u003cconst char *\u003e` are passed to the function, allowing the function to access the flags passed, and the values passed to it through the arguments.\n\n*What about flags?*\nThey are completely supported. As long as they are passed before the subcommand, or after all of the subcommand's positional arguments.\n\n### Basic syntax\nThe syntax in `field` is relatively basic, and is designed to be as sleek as possible.\n\nA basic application would look something like this:\n```cpp\n#include \u003ciostream\u003e\n#include \u003cvector\u003e\n\n#include \".../field.hpp\"\n\nvoid say(field::context\u0026 ctx, std::vector\u003cconst char *\u003e values) {\n    // as we did not specify a limit to the number of positional arguments,\n    // values will include all positional argument values after 'say'\n    for (const auto\u0026 c : values) {\n        std::cout \u003c\u003c c \u003c\u003c std::endl;\n    }\n}\n\nint main(int argc, char ** argv) {\n    // create the argument parser\n    field::parser parser;\n\n    // add our argument\n    // we pass our 'say' function\n    // this will be ran when the argument is passed\n    field::arg sayArg = parser.add(\"say\", say);\n\n    // now we parse\n    parser.parse(argc, argv);\n    // or alternatively drop the argc\n    // parser.parse(argv);\n\n    return 0;\n}\n```\nLets run it:\n\n`./out.o say \"hello world!\" \"and FOSS developers!!!\"`\n\nOutput:\n```\nhello world!\nand FOSS developers!!!\n```\n\n---\n\n### Context\nContext (`field::context`) is passed to every function bound to an subcommand/flag if it is passed. It contains a list of flags passed, and any values passed outside of the range of positional arguments.\n\n---\n\n### Subcommands\n\nSubcommands can be added with the `parser.add(...)` function. You pass a name, and optionally a function and `takes` (the number of positional arguments the subcommand receives).\n\nFor instance, if I wanted a basic text-mirroring program:\n```cpp\n#include \u003ciostream\u003e\n#include \u003cvector\u003e\n\n#include \".../field.hpp\"\n\n// this is ran when \"mirror\" is passed\nvoid mirror(field::context\u0026 _, std::vector\u003cconst char *\u003e text) {\n    for (const auto\u0026 c : text) {\n        std::cout \u003c\u003c c \u003c\u003c std::endl;\n    }\n}\n\nint main(int argc, char ** argv) {\n    field::parser parser;\n\n    // we now add the subcommand with its matching function\n    //                      number of pos. arguments\n    parser.add(\"mirror\", mirror, 3);\n\n    parser.parse();\n\n    return 0;\n}\n```\n\nNow, when we run the program, it takes a maximum of 3 positional arguments:\n\n`./out.o mirror hey! im very cool`\n\nOutput:\n```\nhey!\nim\nvery\n```\n\nAs you can see, `cool` was cut off due to the `takes` (number of taken values) being `3`.\n\n---\n\n### Flags\n\nFlags can be named in any way you would prefer, however I recommend using the GNU-style `-` and `--` prefixes to distinguish them from subcommands.\n\nFlags are very similar to arguments, lets try making a simple hello world program:\n```cpp\n#include \u003ciostream\u003e\n\n#include \".../field.hpp\"\n\nvoid helloWorld(field::context\u0026 _) {\n    std::cout \u003c\u003c \"hello world!\" \u003c\u003c std::endl;\n}\n\nint main(int argc, char ** argv) {\n    field::parser parser;\n\n    parser.addFlag(\"--hello-world\", helloWorld);\n\n    parser.parse();\n\n    return 0;\n}\n```\n\nAnd when we run it:\n\n`./a.out --hello-world`\n\nOutput:\n```\nhello world!\n```\n\n---\n\n### Hate using functions?\nIf you would rather not pass functions around, and instead have a series of if statements, you can do that too.\n\nInstead of passing a function, only pass a name (and optionally `takes`).\n```cpp\n#include \".../field.hpp\"\n\nint main(int argc, char ** argv) {\n    field::parser parser;\n    \n    // no function passed\n    field::arg* ar = parser.add(\"no-func\", 2);\n\n    parser.parse();\n\n    if (ar-\u003epassed) {\n        std::cout \u003c\u003c \"passed values:\" \u003c\u003c std::endl;\n        for (const auto\u0026 v : ar-\u003evalues()) {\n        std::cout \u003c\u003c v \u003c\u003c std::endl;\n        }\n        std::cout \u003c\u003c \"passed flags:\" \u003c\u003c std::endl;\n        for (auto\u0026 fl : parser.ctx.passedFlags) {\n            std::cout \u003c\u003c fl-\u003ename \u003c\u003c std::endl;\n        }\n        std::cout \u003c\u003c \"overflowing values:\" \u003c\u003c std::endl;\n        for (auto\u0026 of : parser.ctx.overflowValues) {\n            std::cout \u003c\u003c of \u003c\u003c std::endl;\n        }\n    }\n}\n\n```\n\nAs you can see, this allows you to access the `passed` boolean of the argument, and manage code based on if statements.\n\nNot only this, you can access the context outside of a function by accessing the `ctx` variable of your `parser`.\nIt is the equivalent of using the context variable passed to a function.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjibstack64%2Ffield","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjibstack64%2Ffield","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjibstack64%2Ffield/lists"}