changeset 1071:e7454bb7af5a draft

Fluff out option parsing documentation, add another DEBUG test.
author Rob Landley <rob@landley.net>
date Sat, 21 Sep 2013 12:24:04 -0500
parents 16167a7c1b5a
children 7a45b9b54d3d
files lib/args.c
diffstat 1 files changed, 66 insertions(+), 48 deletions(-) [+]
line wrap: on
line diff
--- a/lib/args.c	Mon Sep 16 23:41:51 2013 -0500
+++ b/lib/args.c	Sat Sep 21 12:24:04 2013 -0500
@@ -6,50 +6,9 @@
 #include "toys.h"
 
 // Design goals:
-//   Don't use getopt()
-//   Don't permute original arguments.
-//   handle --long gracefully "(noshort)a(along)b(blong1)(blong2)"
-//   After each argument:
-//       Note that pointer and long are always the same size, even on 64 bit.
-//     : plus a string argument, keep most recent if more than one
-//     * plus a string argument, appended to a list
-//     # plus a signed long argument
-//       <LOW     - die if less than LOW
-//       >HIGH    - die if greater than HIGH
-//       =DEFAULT - value if not specified
-//     - plus a signed long argument defaulting to negative
-//     . plus a double precision floating point argument (with CFG_TOYBOX_FLOAT)
-//       Chop this out with USE_TOYBOX_FLOAT() around option string
-//       Same <LOW>HIGH=DEFAULT as #
-//     @ plus an occurrence counter (which is a long)
-//     (longopt)
-//     | this is required.  If more than one marked, only one required.
-//     ; long option's argument is optional, can only be supplied with --opt=
-//     ^ Stop parsing after encountering this argument
-//    " " (space char) the "plus an  argument" must be separate
-//        I.E. "-j 3" not "-j3". So "kill -stop" != "kill -s top"
-//
-//   at the beginning:
-//     ^ stop at first nonoption argument
-//     <0 die if less than # leftover arguments (default 0)
-//     >9 die if > # leftover arguments (default MAX_INT)
-//     ? Allow unknown arguments (pass them through to command).
-//     & first argument has imaginary dash (ala tar/ps)
-//       If given twice, all arguments have imaginary dash
-//
-//   At the end: [groups] of previously seen options
-//     - Only one in group (switch off)    [-abc] means -ab=-b, -ba=-a, -abc=-c
-//     | Synonyms (switch on all)          [|abc] means -ab=-abc, -c=-abc
-//     ! More than one in group is error   [!abc] means -ab calls error_exit()
-//     + First in group switches rest on   [+abc] means -a=-abc, -b=-b, -c=-c
-//       primarily useful if you can switch things back off again.
-//     
-
-// Notes from getopt man page
-//   - and -- cannot be arguments.
-//     -- force end of arguments
-//     - is a synonym for stdin in file arguments
-//   -abc means -a -b -c
+//   Don't use getopt() out of libc.
+//   Don't permute original arguments (screwing up ps/top output).
+//   Integrated --long options "(noshort)a(along)b(blong1)(blong2)"
 
 /* This uses a getopt-like option string, but not getopt() itself. We call
  * it the get_opt string.
@@ -70,17 +29,70 @@
  *   argv = ["command", "-b", "fruit", "-d", "walrus"] results in:
  *
  *     Changes to struct toys:
- *       toys.optflags = 5  (-b=4 | -d=1)
- *       toys.optargs[0]="walrus" (leftover argument)
- *       toys.optargs[1]=NULL (end of list)
- *       toys.optc=1 (there was 1 leftover argument)
+ *       toys.optflags = 5 (I.E. 0101 so -b = 4 | -d = 1)
+ *       toys.optargs[0] = "walrus" (leftover argument)
+ *       toys.optargs[1] = NULL (end of list)
+ *       toys.optc = 1 (there was 1 leftover argument)
  *
  *     Changes to union this:
  *       this[0]=NULL (because -c didn't get an argument this time)
  *       this[1]="fruit" (argument to -b)
  */
 
+// Enabling TOYBOX_DEBUG in .config adds syntax checks to option string parsing
+// which aren't needed in the final code (your option string is hardwired and
+// should be correct when you ship), but are useful for development.
+
+// What you can put in a get_opt string:
+//   Any otherwise unused character (all letters, unprefixed numbers) specify
+//   an option that sets a flag. The bit value is the same as the binary digit
+//   if you string the option characters together in order.
+//   So in "abcdefgh" a = 128, h = 1
+//
+//   Suffixes specify that this option takes an argument (stored in GLOBALS):
+//       Note that pointer and long are always the same size, even on 64 bit.
+//     : plus a string argument, keep most recent if more than one
+//     * plus a string argument, appended to a list
+//     # plus a signed long argument
+//       <LOW     - die if less than LOW
+//       >HIGH    - die if greater than HIGH
+//       =DEFAULT - value if not specified
+//     - plus a signed long argument defaulting to negative (say + for positive)
+//     . plus a double precision floating point argument (with CFG_TOYBOX_FLOAT)
+//       Chop this option out with USE_TOYBOX_FLOAT() in option string
+//       Same <LOW>HIGH=DEFAULT as #
+//     @ plus an occurrence counter (which is a long)
+//     (longopt)
+//     | this is required. If more than one marked, only one required.
+//     ; long option's argument is optional (can only be supplied with --opt=)
+//     ^ Stop parsing after encountering this argument
+//    " " (space char) the "plus an argument" must be separate
+//        I.E. "-j 3" not "-j3". So "kill -stop" != "kill -s top"
+//
+//   At the beginning of the get_opt string (before any options):
+//     ^ stop at first nonoption argument
+//     <0 die if less than # leftover arguments (default 0)
+//     >9 die if > # leftover arguments (default MAX_INT)
+//     ? Allow unknown arguments (pass them through to command).
+//     & first argument has imaginary dash (ala tar/ps)
+//       If given twice, all arguments have imaginary dash
+//
+//   At the end: [groups] of previously seen options
+//     - Only one in group (switch off)    [-abc] means -ab=-b, -ba=-a, -abc=-c
+//     | Synonyms (switch on all)          [|abc] means -ab=-abc, -c=-abc
+//     ! More than one in group is error   [!abc] means -ab calls error_exit()
+//     + First in group switches rest on   [+abc] means -a=-abc, -b=-b, -c=-c
+//       primarily useful if you can switch things back off again.
+//     
+
+// Notes from getopt man page
+//   - and -- cannot be arguments.
+//     -- force end of arguments
+//     - is a synonym for stdin in file arguments
+//   -abcd means -a -b -c -d (but if -b takes an argument, then it's -a -b cd)
+
 // Linked list of all known options (option string parsed into this).
+// Hangs off getoptflagstate, freed at end of option parsing.
 struct opts {
   struct opts *next;
   long *arg;         // Pointer into union "this" to store arguments at.
@@ -94,6 +106,10 @@
   } val[3];          // low, high, default - range of allowed values
 };
 
+// linked list of long options. (Hangs off getoptflagstate, free at end of
+// option parsing, details about flag to set and global slot to fill out
+// stored in related short option struct, but if opt->c = -1 the long option
+// is "bare" (has no corresponding short option).
 struct longopts {
   struct longopts *next;
   struct opts *opt;
@@ -325,6 +341,8 @@
 
     idx = stridx("-|!+", *++options);
     if (CFG_TOYBOX_DEBUG && idx == -1) error_exit("[ needs +-!");
+    if (CFG_TOYBOX_DEBUG && (*options == ']' || !options))
+      error_exit("empty []");
 
     // Don't advance past ] but do process it once in loop.
     while (*(options++) != ']') {