## modules/up/src/util/Argv.cc

/* [<][>][^][v][top][bottom][index][help] */

## FUNCTIONS

This source file includes following functions.

1. ParseArgv
2. PrintUsage

       1 /*
       2  * Argv.c --
       3  *
       4  *      Targvle contains a procedure that handles table-based
       5  *      argv-argc parsing.
       6  *
       7  * Copyright (c) 1990-1994 The Regents of the University of California.
       8  * Copyright (c) 1994 Sun Microsystems, Inc.
       9  *
      10 This software is copyrighted by the Regents of the University of
      11 California, Sun Microsystems, Inc., and other parties.  The following
      12 terms apply to all files associated with the software unless explicitly
      13 disclaimed in individual files.
      14
      15 The authors hereby grant permission to use, copy, modify, distribute,
      16 and license this software and its documentation for any purpose, provided
      17 that existing copyright notices are retained in all copies and that this
      18 notice is included verbatim in any distributions. No written agreement,
      19 license, or royalty fee is required for any of the authorized uses.
      20 Modifications to this software may be copyrighted by their authors
      21 and need not follow the licensing terms described here, provided that
      22 the new terms are clearly indicated on the first page of each file where
      23 they apply.
      24
      25 IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
      26 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
      27 ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
      28 DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
      29 POSSIBILITY OF SUCH DAMAGE.
      30
      31 THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
      32 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
      33 FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE
      34 IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
      35 NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
      36 MODIFICATIONS.
      37
      38 RESTRICTED RIGHTS: Use, duplication or disclosure by the government
      39 is subject to the restrictions as set forth in subparagraph (c) (1) (ii)
      40 of the Rights in Technical Data and Computer Software Clause as DFARS
      41 252.227-7013 and FAR 52.227-19.
      42  *
      43  */
      44
      45 #include "config.h"
      46 #include <iostream.h>
      47 #include <cstring>
      48 #include <cstdlib>
      49 #include "Argv.hh"
      50 #include "version.hh"   /* For version control */
      51
      52 /*
      53  * Default table of argument descriptors.  These are normally available
      54  * in every application.
      55  */
      56
      57 static ArgvInfo defaultTable[] = {
      58     {"-help",   ARGV_HELP,      (char *) NULL,  (char *) NULL,
      59         "Print summary of command-line options and abort"},
      60     {NULL,      ARGV_END,       (char *) NULL,  (char *) NULL,
      61         (char *) NULL}
      62 };
      63
      64 /*
      65  * Forward declarations for procedures defined in this file:
      66  */
      67
      68 static void PrintUsage(ArgvInfo *argTable, int flags);
      69
      70 /*
      71  *----------------------------------------------------------------------
      72  *
      73  * ParseArgv --
      74  *
      75  *      Process an argv array according to a table of expected
      76  *      command-line options.  See the manual page for more details.
      77  *
      78  * Results:
      79  *      Under normal conditions, both *argcPtr and *argv are modified
      80  *      to return the arguments that couldn't be processed here (they
      81  *      didn't match the option table, or followed an ARGV_REST
      82  *      argument).
      83  *
      84  * Side effects:
      85  *      Variables may be modified, or procedures may be called.  It
      86  *      all depends on the arguments
      87  *      and their entries in argTable.  See the user documentation
      88  *      for details.
      89  *
      90  *----------------------------------------------------------------------
      91  */
      92
      93 int ParseArgv(int *argcPtr, char **argv, ArgvInfo *argTable, int flags)
         /* [<][>][^][v][top][bottom][index][help] */
      94     /* argcPtr: Number of arguments in argv.  Modified
      95      * to hold # args left in argv at end. */
      96     /* argv: Array of arguments.  Modified to hold
      97      * those that couldn't be processed here. */
      98     /* argTable: Array of option descriptions */
      99     /* flags: Or'ed combination of various flag bits,
     100      * such as ARGV_NO_DEFAULTS. */
     101 {
     102     register ArgvInfo *infoPtr;
     103                                 /* Pointer to the current entry in the
     104                                  * table of argument descriptions. */
     105     ArgvInfo *matchPtr; /* Descriptor that matches current argument. */
     106     char *curArg;               /* Current argument */
     107     register char c;            /* Second character of current arg (used for
     108                                  * quick check for matching;  use 2nd char.
     109                                  * because first char. will almost always
     110                                  * be '-'). */
     111     int srcIndex;               /* Location from which to read next argument
     112                                  * from argv. */
     113     int dstIndex;               /* Index into argv to which next unused
     114                                  * argument should be copied (never greater
     115                                  * than srcIndex). */
     116     int argc;                   /* # arguments in argv still to process. */
     117     int length;                 /* Number of characters in current argument. */
     118     int i;
     119
     120     /* Try to fill the name of current program into ProjectGoal[64] -- wlee@ISI.EDU */
     121     int len = strlen(argv[0]);
     122     char *pGoal = argv[0] + len;
     123     while (*pGoal != '/' && *pGoal != '\\' && --len >= 0) pGoal--;
     124     strcpy(ProjectGoal, pGoal);
     125
     126     if (flags & ARGV_DONT_SKIP_FIRST_ARG) {
     127         srcIndex = dstIndex = 0;
     128         argc = *argcPtr;
     129     } else {
     130         srcIndex = dstIndex = 1;
     131         argc = *argcPtr-1;
     132     }
     133
     134     while (argc > 0) {
     135         curArg = argv[srcIndex];
     136         srcIndex++;
     137         argc--;
     138         length = strlen(curArg);
     139         if (length > 0) {
     140             c = curArg[1];
     141         } else {
     142             c = 0;
     143         }
     144
     145         /*
     146          * Loop throught the argument descriptors searching for one with
     147          * the matching key string.  If found, leave a pointer to it in
     148          * matchPtr.
     149          */
     150
     151         matchPtr = NULL;
     152         for (i = 0; i < 2; i++) {
     153             if (i == 0) {
     154                 infoPtr = argTable;
     155             } else {
     156                 infoPtr = defaultTable;
     157             }
     158             for (; (infoPtr != NULL) && (infoPtr->type != ARGV_END);
     159                     infoPtr++) {
     160                  if (infoPtr->key == NULL) {
     161                      continue;
     162                  }
     163                  if ((infoPtr->key[1] != c)
     164                          || (strncmp(infoPtr->key, curArg, length) != 0)) {
     165                      continue;
     166                  }
     167                  if (infoPtr->key[length] == 0) {
     168                      matchPtr = infoPtr;
     169                      goto gotMatch;
     170                  }
     171                  if (flags & ARGV_NO_ABBREV) {
     172                      continue;
     173                  }
     174                  if (matchPtr != NULL) {
     175                     cerr << "ambiguous option \"" << curArg << "\"";
     176                      return ARGV_ERROR;
     177                  }
     178                  matchPtr = infoPtr;
     179             }
     180         }
     181         if (matchPtr == NULL) {
     182
     183             /*
     184              * Unrecognized argument.  Just copy it down, unless the caller
     185              * prefers an error to be registered.
     186              */
     187
     188             if (flags & ARGV_NO_LEFTOVERS) {
     189                cerr << "unrecognized argument \"" << curArg << "\"";
     190                 return ARGV_ERROR;
     191             }
     192             argv[dstIndex] = curArg;
     193             dstIndex++;
     194             continue;
     195         }
     196
     197         /*
     198          * Take the appropriate action based on the option type
     199          */
     200
     201         gotMatch:
     202         infoPtr = matchPtr;
     203         switch (infoPtr->type) {
     204             case ARGV_BOOL:
     205                 *((bool *) infoPtr->dst) = ! *((bool *) infoPtr->dst);
     206                 break;
     207             case ARGV_CONSTANT:
     208                 *((int *) infoPtr->dst) = (int) infoPtr->src;
     209                 break;
     210             case ARGV_INT:
     211                 if (argc == 0) {
     212                     goto missingArg;
     213                 } else {
     214                     char *endPtr;
     215
     216                     *((int *) infoPtr->dst) =
     217                             strtol(argv[srcIndex], &endPtr, 0);
     218                     if ((endPtr == argv[srcIndex]) || (*endPtr != 0)) {
     219                        cerr << "expected integer argument for \""
     220                             << infoPtr->key << "\" but got \""
     221                             << argv[srcIndex] << "\"";
     222                         return ARGV_ERROR;
     223                     }
     224                     srcIndex++;
     225                     argc--;
     226                 }
     227                 break;
     228             case ARGV_STRING:
     229                 if (argc == 0) {
     230                     goto missingArg;
     231                 } else {
     232                     *((char **)infoPtr->dst) = argv[srcIndex];
     233                     srcIndex++;
     234                     argc--;
     235                 }
     236                 break;
     237             case ARGV_REST:
     238                 *((int *) infoPtr->dst) = dstIndex;
     239                 goto argsDone;
     240             case ARGV_FLOAT:
     241                 if (argc == 0) {
     242                     goto missingArg;
     243                 } else {
     244                     char *endPtr;
     245
     246                     *((double *) infoPtr->dst) =
     247                             strtod(argv[srcIndex], &endPtr);
     248                     if ((endPtr == argv[srcIndex]) || (*endPtr != 0)) {
     249                        cerr << "expected floating-point argument for \""
     250                             << infoPtr->key << "\" but got \""
     251                             << argv[srcIndex] <<  "\"";
     252                         return ARGV_ERROR;
     253                     }
     254                     srcIndex++;
     255                     argc--;
     256                 }
     257                 break;
     258             case ARGV_FUNC: {
     259                 int (*handlerProc)(...);
     260
     261                 handlerProc = (int (*)(...))infoPtr->src;
     262
     263                 if ((*handlerProc)(infoPtr->dst, infoPtr->key,
     264                         argv[srcIndex])) {
     265                     srcIndex += 1;
     266                     argc -= 1;
     267                 }
     268                 break;
     269             }
     270             case ARGV_GENFUNC: {
     271                 int         (*handlerProc)(...);
     272
     273                 handlerProc = (int (*)(...))infoPtr->src;
     274
     275                 argc = (*handlerProc)(infoPtr->dst, infoPtr->key,
     276                         argc, argv+srcIndex);
     277                 if (argc < 0) {
     278                     return ARGV_ERROR;
     279                 }
     280                 break;
     281             }
     282             case ARGV_HELP:
     283                 PrintUsage (argTable, flags);
     284                 return ARGV_ERROR;
     285             default:
     286                cerr << "bad argument type %d in ArgvInfo" << infoPtr->type;
     287                 return ARGV_ERROR;
     288         }
     289     }
     290
     291     /*
     292      * If we broke out of the loop because of an OPT_REST argument,
     293      * copy the remaining arguments down.
     294      */
     295
     296     argsDone:
     297     while (argc) {
     298         argv[dstIndex] = argv[srcIndex];
     299         srcIndex++;
     300         dstIndex++;
     301         argc--;
     302     }
     303     argv[dstIndex] = (char *) NULL;
     304     *argcPtr = dstIndex;
     305     return ARGV_OK;
     306
     307     missingArg:
     308     cerr << "\"" << curArg << "\" option requires an additional argument";
     309     return ARGV_ERROR;
     310 }
     311
     312 /*
     313  *----------------------------------------------------------------------
     314  *
     315  * PrintUsage --
     316  *
     317  *      Print (in cerr) a help string describing command-line options.
     318  *
     319  * Results:
     320  *      None.
     321  *
     322  * Side effects:
     323  *      None.
     324  *
     325  *----------------------------------------------------------------------
     326  */
     327
     328 static void
     329 PrintUsage(ArgvInfo *argTable, int flags)
         /* [<][>][^][v][top][bottom][index][help] */
     330    /* argTable: Array of command-specific argument
     331     * descriptions. */
     332    /* flags: If the ARGV_NO_DEFAULTS bit is set
     333     * in this word, then don't generate
     334     * information for default options. */
     335 {
     336     register ArgvInfo *infoPtr;
     337     int width, i, numSpaces;
     338 #define NUM_SPACES 20
     339     static char spaces[] = "                    ";
     340     char tmp[30];
     341
     342     /*
     343      * First, compute the width of the widest option key, so that we
     344      * can make everything line up.
     345      */
     346
     347     width = 4;
     348     for (i = 0; i < 2; i++) {
     349         for (infoPtr = i ? defaultTable : argTable;
     350                 infoPtr->type != ARGV_END; infoPtr++) {
     351             int length;
     352             if (infoPtr->key == NULL) {
     353                 continue;
     354             }
     355             length = strlen(infoPtr->key);
     356             if (length > width) {
     357                 width = length;
     358             }
     359         }
     360     }
     361
     362     // Added by wlee@isi.edu
     363     cerr << endl;
     364
     365     cerr << "Command-specific options:";
     366     for (i = 0; ; i++) {
     367         for (infoPtr = i ? defaultTable : argTable;
     368                 infoPtr->type != ARGV_END; infoPtr++) {
     369             if ((infoPtr->type == ARGV_HELP) && (infoPtr->key == NULL)) {
     370                cerr << "\n" << infoPtr->help;
     371                 continue;
     372             }
     373             // Modified by wlee@isi.edu to get rid of ':'
     374             cerr << "\n " << infoPtr->key << " ";
     375 //          cerr << "\n " << infoPtr->key << ":";
     376             numSpaces = width + 1 - strlen(infoPtr->key);
     377             while (numSpaces > 0) {
     378                 if (numSpaces >= NUM_SPACES) {
     379                    cerr << spaces;
     380                 } else {
     381                    cerr << spaces+NUM_SPACES-numSpaces;
     382                 }
     383                 numSpaces -= NUM_SPACES;
     384             }
     385             cerr << infoPtr->help;
     386             switch (infoPtr->type) {
     387                 case ARGV_INT: {
     388                     cerr << "\n\t\tDefault value: " << *((int *) infoPtr->dst);
     389                     break;
     390                 }
     391                 case ARGV_FLOAT: {
     392                     cerr << "\n\t\tDefault value: " << *((double *) infoPtr->dst);
     393                     break;
     394                 }
     395                 case ARGV_STRING: {
     396                     char *string;
     397
     398                     string = *((char **) infoPtr->dst);
     399                     if (string != NULL) {
     400                        cerr << "\n\t\tDefault value: \"" << string << "\"";
     401                     }
     402                     break;
     403                 }
     404                 default: {
     405                     break;
     406                 }
     407             }
     408         }
     409
     410         if ((flags & ARGV_NO_DEFAULTS) || (i > 0)) {
     411             break;
     412         }
     413         cerr << "\nGeneric options for all commands:";
     414     }
     415     // Added by wlee@isi.edu
     416     cerr << endl;
     417 }
     418
     419
     420

/* [<][>][^][v][top][bottom][index][help] */