B.2 Command-Line Parser [ToC] [Index]     [Skip Back]     [Prev] [Up] [Next]

The option parser in the previous section handles the general form of command-line options. The code in this section applies that option parser to the specific options used by the BST test program. It has helper functions for argument parsing and advice to users. Here is all of it together:

591. <Command line parser 591> =
/* Command line parser. */

/* If a is a prefix for b or vice versa, returns the length of the 
   match. Otherwise, returns 0. */ size_t
match_len (const char *a, const char *b)
{ size_t cnt; for (cnt = 0; *a == *b && *a != '\0'; a++, b++) cnt++; return (*a != *b && *a != '\0' && *b != '\0') ? 0 : cnt; } /* s should point to a decimal representation of an integer. Returns the value of s, if successful, or 0 on failure. */ static int
stoi (const char *s)
{ long x = strtol (s, NULL, 10); return x >= INT_MIN && x <= INT_MAX ? x : 0; } /* Print helpful syntax message and exit. */ static void
usage (void)
{ static const char *help[] =
    { "bsttest, unit test for GNU libavl.\n\n", "Usage: %s [OPTION]...\n\n", "In the option descriptions below, CAPITAL denote arguments.\n", "If a long option shows an argument as mandatory, then it is\n", "mandatory for the equivalent short option also. See the GNU\n", "libavl manual for more information.\n\n", "t, -test=TEST Sets test to perform. TEST is one of:\n", " correctness insert/delete/... (default)\n", " overflow stack overflow test\n", " benchmark benchmark test\n", " null no test\n", "s, -size=TREESIZE Sets tree size in nodes (default 16).\n", "r, -repeat=COUNT Repeats operation COUNT times (default 16).\n", "i, -insert=ORDER Sets the insertion order. ORDER is one of:\n", " random random permutation (default)\n", " ascending ascending order 0...n1\n", " descending descending order n1...0\n", " balanced balanced tree order\n", " zigzag zigzag tree\n", " ascshifted n/2...n1, 0...n/21\n", " custom custom, read from stdin\n", "d, -delete=ORDER Sets the deletion order. ORDER is one of:\n", " random random permutation (default)\n", " reverse reverse order of insertion\n", " same same as insertion order\n", " custom custom, read from stdin\n", "a, -alloc=POLICY Sets allocation policy. POLICY is one of:\n", " track track memory leaks (default)\n", " notrack turn off leak detection\n", " failCNT fail after CNT allocations\n", " fail%%PCT fail random PCT%% of allocations\n", " subB,A divide Bbyte blocks in Abyte units\n", " (Ignored for `benchmark' test.)\n", "A, -incr=INC Fail policies: arg increment per repetition.\n", "S, -seed=SEED Sets initial number seed to SEED.\n", " (default based on system time)\n", "n, -nonstop Don't stop after a single error.\n", "q, -quiet Turns down verbosity level.\n", "v, -verbose Turns up verbosity level.\n", "h, -help Displays this help screen.\n", "V, -version Reports version and copyright information.\n", NULL, }; const char **p; for (p = help; *p != NULL; p++) printf (*p, pgm_name); exit (EXIT_SUCCESS); } /* Parses command-line arguments from null-terminated array args. Sets up options appropriately to correspond. */ static void
parse_command_line (char **args, struct test_options *options)
{ static const struct option option_tab[] =
    { {"test", 't', 1},
      {"insert", 'i', 1},
      {"delete", 'd', 1}, {"alloc", 'a', 1},
      {"incr", 'A', 1},
      {"size", 's', 1}, {"repeat", 'r', 1},
      {"operation", 'o', 1},
      {"seed", 'S', 1}, {"nonstop", 'n', 0},
      {"quiet", 'q', 0},
      {"verbose", 'v', 0}, {"help", 'h', 0},
      {"version", 'V', 0},
      {NULL, 0, 0}, }; struct option_state *state; /* Default options. */ options->test = TST_CORRECTNESS;
  options->insert_order = INS_RANDOM; options->delete_order = DEL_RANDOM;
  options->alloc_policy = MT_TRACK; options->alloc_arg[0] = 0;
  options->alloc_arg[1] = 0; options->alloc_incr = 0;
  options->node_cnt = 15; options->iter_cnt = 15;
  options->seed_given = 0; options->verbosity = 0;
  options->nonstop = 0; if (*args == NULL) return; state = option_init (option_tab, args + 1); for (;;)
    { char *arg; int id = option_get (state, &arg); if (id == -1) break; switch (id)
        { case 't': if (match_len (arg, "correctness") >= 3) options->test = TST_CORRECTNESS; else if (match_len (arg, "overflow") >= 3) options->test = TST_OVERFLOW; else if (match_len (arg, "null") >= 3) options->test = TST_NULL; else fail ("unknown test \"%s\"", arg); break; case 'i':
          { static const char *orders[INS_CNT] =
              { "random", "ascending", "descending", "balanced", "zigzag", "ascshifted", "custom", }; const char **iter; assert (sizeof orders / sizeof *orders == INS_CNT); for (iter = orders; ; iter++) if (iter >= orders + INS_CNT) fail ("unknown order \"%s\"", arg); else if (match_len (*iter, arg) >= 3)
                { options->insert_order = iter - orders; break; } } break; case 'd':
          { static const char *orders[DEL_CNT] =
              { "random", "reverse", "same", "custom", }; const char **iter; assert (sizeof orders / sizeof *orders == DEL_CNT); for (iter = orders; ; iter++) if (iter >= orders + DEL_CNT) fail ("unknown order \"%s\"", arg); else if (match_len (*iter, arg) >= 3)
                { options->delete_order = iter - orders; break; } } break; case 'a': if (match_len (arg, "track") >= 3) options->alloc_policy = MT_TRACK; else if (match_len (arg, "notrack") >= 3) options->alloc_policy = MT_NO_TRACK; else if (!strncmp (arg, "fail", 3))
            { const char *p = arg + strcspn (arg, "%"); if (*p == )
                options->alloc_policy = MT_FAIL_COUNT; else if (*p == '%')
                options->alloc_policy = MT_FAIL_PERCENT; else
                fail ("invalid allocation policy \"%s\"", arg); options->alloc_arg[0] = stoi (p + 1); } else if (!strncmp (arg, "suballoc", 3))
            { const char *p = strchr (arg, ); const char *q = strchr (arg, ','); if (p == NULL || q == NULL) fail ("invalid allocation policy \"%s\"", arg); options->alloc_policy = MT_SUBALLOC; options->alloc_arg[0] = stoi (p + 1); options->alloc_arg[1] = stoi (q + 1); if (options->alloc_arg[MT_BLOCK_SIZE] < 32) fail ("block size too small"); else if (options->alloc_arg[MT_ALIGN] > options->alloc_arg[MT_BLOCK_SIZE]) fail ("alignment cannot be greater than block size"); else if (options->alloc_arg[MT_ALIGN] < 1) fail ("alignment must be at least 1"); } break; case 'A':
          options->alloc_incr = stoi (arg);
          break; case 's': options->node_cnt = stoi (arg); if (options->node_cnt < 1) fail ("bad tree size \"%s\"", arg); break; case 'r': options->iter_cnt = stoi (arg); if (options->iter_cnt < 1) fail ("bad repeat count \"%s\"", arg); break; case 'S': options->seed_given = 1; options->seed = strtoul (arg, NULL, 0); break; case 'n':
          options->nonstop = 1;
          break; case 'q':
          options->verbosity--;
          break; case 'v':
          options->verbosity++;
          break; case 'h':
          usage ();
          break; case 'V': fputs ("GNU libavl 2.0.3\n" "Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004 " "Free Software Foundation, Inc.\n" "This program comes with NO WARRANTY, not even for\n" "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n" "You may redistribute copies under the terms of the\n" "GNU General Public License. For more information on\n" "these matters, see the file named COPYING.\n", stdout); exit (EXIT_SUCCESS); default:
          assert (0); } } }

This code is included in 98.