Mercurial > hg > toybox
changeset 1704:f9926018344c draft
More 'splaining.
author | Rob Landley <rob@landley.net> |
---|---|
date | Thu, 26 Feb 2015 21:07:33 -0600 |
parents | b248ef9d3f3e |
children | e618a873a946 |
files | www/code.html |
diffstat | 1 files changed, 51 insertions(+), 27 deletions(-) [+] |
line wrap: on
line diff
--- a/www/code.html Wed Feb 25 20:42:24 2015 -0600 +++ b/www/code.html Thu Feb 26 21:07:33 2015 -0600 @@ -877,20 +877,21 @@ <a name="lib_args"><h3>lib/args.c</h3> <p>Toybox's main.c automatically parses command line options before calling the -command's main function. Option parsing starts in get_optflags(), which stores +command's main function. Option parsing starts in get_optflags(), which stores results in the global structures "toys" (optflags and optargs) and "this".</p> <p>The option parsing infrastructure stores a bitfield in toys.optflags to -indicate which options the current command line contained. Arguments +indicate which options the current command line contained, and defines FLAG +macros code can use to check whether each argument's bit is set. Arguments attached to those options are saved into the command's global structure -("this"). Any remaining command line arguments are collected together into -the null-terminated array toys.optargs, with the length in toys.optc. (Note +("this"). Any remaining command line arguments are collected together into +the null-terminated array toys.optargs, with the length in toys.optc. (Note that toys.optargs does not contain the current command name at position zero, -use "toys.which->name" for that.) The raw command line arguments get_optflags() +use "toys.which->name" for that.) The raw command line arguments get_optflags() parsed are retained unmodified in toys.argv[].</p> <p>Toybox's option parsing logic is controlled by an "optflags" string, using -a format reminiscent of getopt's optargs but has several important differences. +a format reminiscent of getopt's optargs but with several important differences. Toybox does not use the getopt() function out of the C library, get_optflags() is an independent implementation which doesn't permute the original arguments (and thus doesn't change how the @@ -904,14 +905,14 @@ If a command has no option definition string (I.E. the argument is NULL), option parsing is skipped for that command, which must look at the raw data in toys.argv to parse its -own arguments. (If no currently enabled command uses option parsing, +own arguments. (If no currently enabled command uses option parsing, get_optflags() is optimized out of the resulting binary by the compiler's --gc-sections option.)</p> <p>You don't have to free the option strings, which point into the environment -space (I.E. the string data is not copied). A TOYFLAG_NOFORK command +space (I.E. the string data is not copied). A TOYFLAG_NOFORK command that uses the linked list type "*" should free the list objects but not -the data they point to, via "llist_free(TT.mylist, NULL);". (If it's not +the data they point to, via "llist_free(TT.mylist, NULL);". (If it's not NOFORK, exit() will free all the malloced data anyway unless you want to implement a CONFIG_TOYBOX_FREE cleanup for it.)</p> @@ -932,7 +933,7 @@ <ul> <li><p>In <b>struct toys</b>: <ul> -<li>toys.optflags = 13; // -a = 8 | -b = 4 | -d = 1</li> +<li>toys.optflags = 13; // FLAG_a = 8 | FLAG_b = 4 | FLAG_d = 1</li> <li>toys.optargs[0] = "walrus"; // leftover argument</li> <li>toys.optargs[1] = NULL; // end of list</li> <li>toys.optc = 1; // there was 1 leftover argument</li> @@ -958,6 +959,7 @@ long a; ) </pre></blockquote> + <p>That would mean TT.c == NULL, TT.b == "fruit", and TT.a == 42. (Remember, each entry that receives an argument must be a long or pointer, to line up with the array position. Right to left in the optflags string corresponds to @@ -976,19 +978,39 @@ rightmost argument is (1<<0), the next to last is (1<<1) and so on. If the option isn't encountered while parsing argv[], its bit remains 0.</p> +<p>Each option -x has a FLAG_x macro for the command letter. Bare --longopts +with no corresponding short option have a FLAG_longopt macro for the long +optionname. Commands enable these macros by #defining FOR_commandname before +#including <toys.h>. When multiple commands are implemented in the same +source file, you can switch flag contexts later in the file by +#defining CLEANUP_oldcommand and #defining FOR_newcommand, then +#including <generated/flags.h>.</p> + +<p>Options disabled in the current configuration (wrapped in +a USE_BLAH() macro for a CONFIG_BLAH that's switched off) have their +corresponding FLAG macro set to zero, so code checking them ala +if (toys.optargs & FLAG_x) gets optimized out via dead code elimination. +#defining FORCE_FLAGS when switching flag context disables this +behavior: the flag is never zero even if the config is disabled. This +allows code shared between multiple commands to use the same flag +values, as long as the common flags match up right to left in both option +strings.</p> + <p>For example, the optflags string "abcd" would parse the command line argument "-c" to set optflags to 2, "-a" would set optflags to 8, "-bd" would set optflags to -6 (I.E. 4|2), and "-a -c" would set optflags to 10 (2|8).</p> +6 (I.E. 4|2), and "-a -c" would set optflags to 10 (2|8). To check if -c +was encountered, code could test: if (toys.optflags & FLAG_c) printf("yup"); +(See the toys/examples directory for more.)</p> <p>Only letters are relevant to optflags, punctuation is skipped: in the -string "a*b:c#d", d=1, c=2, b=4, a=8. The punctuation after a letter +string "a*b:c#d", d=1, c=2, b=4, a=8. The punctuation after a letter usually indicate that the option takes an argument.</p> -<p>Since toys.optflags is an unsigned int, it only stores 32 bits. (Which is +<p>Since toys.optflags is an unsigned int, it only stores 32 bits. (Which is the amount a long would have on 32-bit platforms anyway; 64 bit code on 32 bit platforms is too expensive to require in common code used by almost -all commands.) Bit positions beyond the 1<<31 aren't recorded, but +all commands.) Bit positions beyond the 1<<31 aren't recorded, but parsing higher options can still set global variables.</p> <p><b>Automatically setting global variables from arguments (union this)</b></p> @@ -1010,15 +1032,6 @@ </ul> </ul> -<p>A note about "." and CFG_TOYBOX_FLOAT: option parsing only understands <>= -after . when CFG_TOYBOX_FLOAT -is enabled. (Otherwise the code to determine where floating point constants -end drops out; it requires floating point). When disabled, it can reserve a -global data slot for the argument (so offsets won't change in your -GLOBALS[] block), but will never fill it out. You can handle -this by using the USE_BLAH() macros with C string concatenation, ala: -"abc." USE_TOYBOX_FLOAT("<1.23>4.56=7.89") "def"</p> - <p><b>GLOBALS</b></p> <p>Options which have an argument fill in the corresponding slot in the global @@ -1033,7 +1046,7 @@ consecutive variables of register size. Thus the first few entries can be longs or pointers corresponding to the saved arguments.</p> -<p>See toys/other/hello.c for a longer example of parsing options into the +<p>See toys/example/*.c for longer examples of parsing options into the GLOBALS block.</p> <p><b>char *toys.optargs[]</b></p> @@ -1087,7 +1100,7 @@ <p>Option parsing only understands <>= after . when CFG_TOYBOX_FLOAT is enabled. (Otherwise the code to determine where floating point constants end drops out. When disabled, it can reserve a global data slot for the -argument so offsets won't change, but will never fill it out.). You can handle +argument so offsets won't change, but will never fill it out.) You can handle this by using the USE_BLAH() macros with C string concatenation, ala:</p> <blockquote>"abc." USE_TOYBOX_FLOAT("<1.23>4.56=7.89") "def"</blockquote> @@ -1095,13 +1108,13 @@ <p><b>--longopts</b></p> <p>The optflags string can contain long options, which are enclosed in -parentheses. They may be appended to an existing option character, in +parentheses. They may be appended to an existing option character, in which case the --longopt is a synonym for that option, ala "a:(--fred)" which understands "-a blah" or "--fred blah" as synonyms.</p> <p>Longopts may also appear before any other options in the optflags string, in which case they have no corresponding short argument, but instead set -their own bit based on position. So for "(walrus)#(blah)xy:z" "command +their own bit based on position. So for "(walrus)#(blah)xy:z", "command --walrus 42" would set toys.optflags = 16 (-z = 1, -y = 2, -x = 4, --blah = 8) and would assign this[1] = 42;</p> @@ -1109,6 +1122,17 @@ each "bare longopt" (ala "(one)(two)abc" before any option characters) always sets its own bit (although you can group them with +X).</p> +<p>Only bare longopts have a FLAG_ macro with the longopt name +(ala --fred would #define FLAG_fred). Other longopts use the short +option's FLAG macro to test the toys.optflags bit.</p> + +<p>Options with a semicolon ";" after their data type can only set their +corresponding GLOBALS() entry via "--longopt=value". For example, option +string "x(boing): y" would set TT.x if it saw "--boing=value", but would +treat "--boing value" as setting FLAG_x in toys.optargs, leaving TT.x NULL, +and keeping "value" in toys.optargs[]. (This lets "ls --color" and +"ls --color=auto" both work.)</p> + <p><b>[groups]</b></p> <p>At the end of the option string, square bracket groups can define