aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/args.c98
1 files changed, 58 insertions, 40 deletions
diff --git a/lib/args.c b/lib/args.c
index 5cdd3738..26de5665 100644
--- a/lib/args.c
+++ b/lib/args.c
@@ -6,10 +6,50 @@
#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:
+// 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.
+ *
+ * Each option in the get_opt string corresponds to a bit position in the
+ * return value. The rightmost argument is (1<<0), the next to last is (1<<1)
+ * and so on. If the option isn't seen in argv[], its bit remains 0.
+ *
+ * Options which have an argument fill in the corresponding slot in the global
+ * union "this" (see generated/globals.h), which it treats as an array of longs
+ * (note that sizeof(long)==sizeof(pointer) is guaranteed by LP64).
+ *
+ * You don't have to free the option strings, which point into the environment
+ * space. List objects should be freed by main() when command_main() returns.
+ *
+ * Example:
+ * Calling get_optflags() when toys.which->options="ab:c:d" and
+ * argv = ["command", "-b", "fruit", "-d", "walrus"] results in:
+ *
+ * Changes to struct toys:
+ * 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
@@ -17,19 +57,19 @@
// <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 signed long argument defaulting to negative (say + for positive)
// . plus a double precision floating point argument (with CFG_TOYBOX_FLOAT)
-// Chop this out with USE_TOYBOX_FLOAT() around option string
+// 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=
+// | 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
+// " " (space char) the "plus an argument" must be separate
// I.E. "-j 3" not "-j3". So "kill -stop" != "kill -s top"
//
-// at the beginning:
+// 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)
@@ -49,38 +89,10 @@
// - and -- cannot be arguments.
// -- force end of arguments
// - is a synonym for stdin in file arguments
-// -abc means -a -b -c
-
-/* This uses a getopt-like option string, but not getopt() itself. We call
- * it the get_opt string.
- *
- * Each option in the get_opt string corresponds to a bit position in the
- * return value. The rightmost argument is (1<<0), the next to last is (1<<1)
- * and so on. If the option isn't seen in argv[], its bit remains 0.
- *
- * Options which have an argument fill in the corresponding slot in the global
- * union "this" (see generated/globals.h), which it treats as an array of longs
- * (note that sizeof(long)==sizeof(pointer) is guaranteed by LP64).
- *
- * You don't have to free the option strings, which point into the environment
- * space. List objects should be freed by main() when command_main() returns.
- *
- * Example:
- * Calling get_optflags() when toys.which->options="ab:c:d" and
- * 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)
- *
- * Changes to union this:
- * this[0]=NULL (because -c didn't get an argument this time)
- * this[1]="fruit" (argument to -b)
- */
+// -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 @@ struct opts {
} 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 @@ void parse_optflaglist(struct getoptflagstate *gof)
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++) != ']') {