home *** CD-ROM | disk | FTP | other *** search
/ Gold Fish 3 / goldfish_volume_3.bin / files / gfx / 3d / irit / misc_lib / getarg.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-02-13  |  34.3 KB  |  824 lines

  1. /*****************************************************************************
  2. *  Routines to grab the    parameters from    the command line :             *
  3. * All the routines except the main one,    starts with GA (Get Arguments) to    *
  4. * prevent from names conflicts.                             *
  5. * It is    assumed    in these routine that any pointer, for any type    has the         *
  6. * same length (i.e. length of int pointer is equal to char pointer etc.)     *
  7. *                                         *
  8. *  The following routines are available    in this    module:                 *
  9. * 1. int GAGetArgs(argc, argv, CtrlStr, Variables...)                 *
  10. *    where argc, argv as received on entry.                     *
  11. *       CtrlStr is the contrl string    (see below)                 *
  12. *       Variables are all the variables to be set according to CtrlStr .  *
  13. *       Note    that all the variables MUST be transfered by address.         *
  14. *    return 0 on correct parsing, otherwise error number (see GetArg.h).     *
  15. * 2. GAPrintHowTo(CtrlStr)                             *
  16. *    Print the control string to stderr, in the    correct    format needed.         *
  17. *    This feature is very useful in case of error during GetArgs parsing.    *
  18. *    Chars equal to SPACE_CHAR are not printed (regular spaces are NOT       *
  19. *    allowed, and so using SPACE_CHAR you can create space in PrintHowTo) .  *
  20. * 3. GAPrintErrMsg(Error)                             *
  21. *    Print the error to    stderr,    according to Error (usually returned by         *
  22. *    GAGetArgs).                                 *
  23. *                                                                            *
  24. *   Notes:                                     *
  25. *                                         *
  26. * 1. This module assumes that all the pointers to all kind of data types     *
  27. *    have the same length and format, i.e. sizeof(int *) == sizeof(char    * ). *
  28. *                                         *
  29. *                      Gershon Elber    Ver 0.2     Mar 88         *
  30. ******************************************************************************
  31. * History:                                     *
  32. * 11 Mar 88 - Version 1.0 by Gershon Elber.                     *
  33. *****************************************************************************/
  34.  
  35. #ifdef USE_VARARGS
  36. #include <varargs.h>
  37. #else
  38. #include <stdarg.h>
  39. #endif /* USE_VARARGS */
  40.  
  41. #include <stdio.h>
  42. #include <ctype.h>
  43. #include <string.h>
  44. #include "irit_sm.h"
  45. #include "getarg.h"
  46. #include "imalloc.h"
  47.  
  48. #define    MAX_PARAM    100        /* maximum number of parameters allowed. */
  49. #define    CTRL_STR_MAX_LEN    1024
  50.  
  51. #define SPACE_CHAR    '|'      /* The character not to print using HowTo. */
  52.  
  53. #ifndef    TRUE
  54. #define    TRUE -1
  55. #define    FALSE 0
  56. #endif /* TRUE */
  57.  
  58. #define    ARG_OK    0
  59.  
  60. #define    ISSPACE(x) ((x)    <= ' ')           /* Not conventional - but works fine! */
  61. /* The two characters '%' and '!' are used in the control string: */
  62. #define    ISCTRLCHAR(x) (((x) == '%') || ((x) == '!'))
  63.  
  64. static char *GAErrorToken;/* On error code, ErrorToken is set to point on it.*/
  65.  
  66. static int GATestAllSatis(char *CtrlStrCopy,
  67.               char *CtrlStr,
  68.               int *argc,
  69.               char ***argv,
  70.               int *Parameters[MAX_PARAM],
  71.               int *ParamCount);
  72. static int GAUpdateParameters(int *Parameters[],
  73.                   int *ParamCount,
  74.                   char *Option,
  75.                   char *CtrlStrCopy,
  76.                   char *CtrlStr,
  77.                   int *argc,
  78.                   char ***argv);
  79. static int GAGetParmeters(int *Parameters[],
  80.               int *ParamCount,
  81.               char *CtrlStrCopy,
  82.               char *Option,
  83.               int *argc,
  84.               char ***argv);
  85. static int GAGetMultiParmeters(int *Parameters[],
  86.                    int *ParamCount,
  87.                    char *CtrlStrCopy,
  88.                    int *argc,
  89.                    char ***argv);
  90. static void GASetParamCount(char *CtrlStr,
  91.                 int Max,
  92.                 int *ParamCount);
  93. static void GAByteCopy(char *Dst,
  94.                char *Src,
  95.                unsigned n);
  96. static int GAOptionExists(int argc,
  97.               char **argv);
  98.  
  99. /*****************************************************************************
  100. * DESCRIPTION:                                                               M
  101. * Routine to access command line arguments and interpret them, by getting    M
  102. * access to the main routine's argc/argv interface and a control string that M
  103. * prescribes the expected options.                              M
  104. *   Returns ARG_OK (0) is case of succesfull parsing, error code else...     M
  105. *                                         M
  106. *   Format of CtrlStr format:                             M
  107. *   The    control    string passed to GAGetArgs controls the way argv (argc) are  M
  108. * parsed. Each entry in    this string must have no spaces in it.               M
  109. *   The    First Entry is the name of the program which is usually ignored      M
  110. *  except when GAPrintHowTo is called. All the other entries (except the     M
  111. * last one which will be discussed shortly) must have the following format:  M
  112. * 1. One letter    which sets the option letter (i.e. 'x' for option '-x').     M
  113. * 2. '!' or '%'    to determines if this option is    really optional    ('%') or     M
  114. *    it    must be provided by the user ('!').                     M
  115. * 3. '-' always.                                 M
  116. * 4. Alpha numeric string, usually ignored, but    used by    GAPrintHowTo to         M
  117. *    describe the meaning of this option.                     M
  118. * 5. Sequences that start with either '!' or '%'.                 M
  119. *       Again if '!' then this sequence must exists (only if its option flag M
  120. *    is given), and if '%' it is optional.                     M
  121. *       Each sequence will be followed by one or two characters    which        M
  122. *    defines the kind of the input:                            M
  123. *    5.1. d, x, o, u - integer is expected (decimal, hex, octal base or         M
  124. *             unsigned).                             M
  125. *    5.2. D, X, O, U - long integer is expected (same as above).         M
  126. *    5.3. f         - float number is expected.                 M
  127. *    5.4. F         - double number is expected.                 M
  128. *    5.5. s         - string is expected.                     M
  129. *    5.6. *?    - any number of    '?' kind (d, x, o, u, D, X, O, U, f, F, s)   M
  130. *          will match this one. If '?' is numeric, it scans until     M
  131. *          none numeric input is given. If '?' is 's' then it scans   M
  132. *          up to the next option or end of argv.                 M
  133. *                                         M
  134. * If the last parameter given in the CtrlStr, is not an option (i.e. the     M
  135. * second char is not in    ['!', '%'] and the third one is not '-'), all what   M
  136. * remained from    argv is    hooked to it.                         M
  137. *                                         M
  138. * The variables passed to GAGetArgs (starting from 4th parameter) MUST       M
  139. * match    the order of options in the CtrlStr.                     M
  140. *   For    each option, an address of an integer must be passed. This integer   M
  141. * must initialized by 0. If that option is given in the command line, it     M
  142. * will be set to one. Otherwise, this integer will not be affected.         M
  143. *   In addition, the sequences that might follow an option require the         M
  144. * following parameter(s) to be passed                            M
  145. * 1. d, x, o, u - pointer to an integer (int *).                 M
  146. * 2. D, X, O, U - pointer to a long (long *).                     M
  147. * 3. f         - pointer to a float (float *).                     M
  148. * 4. F         - pointer to a double (double *).                     M
  149. * 5. s         - pointer to a char * (char **). NO pre-allocation is required. M
  150. * 6. *?         - TWO variables are passed    for each such wild character         M
  151. *              request. The first variable is an address of an integer, and  M
  152. *           it will return the number of parameters actually hooked to    M
  153. *           this sequence. The second variable is a pointer to a pointer  M
  154. *           to type ? (? **). It will return    an address of a vector of    M
  155. *           pointers of type ?, terminated with a NULL pointer.         M
  156. *           NO pre-allocation is required.                        M
  157. *             These two variables behaves very much like the argv/argc    M
  158. *           pair and are used the "trap" unused command line options.     M
  159. *                                         M
  160. *   Examples:                                     M
  161. *                                         M
  162. *    "Example1  i%-OneInteger!d  s%-Strings!*s  j%-  k!-Float!f  Files!*s"   V
  163. * Will match: Example1 -i 77 -s    String1    String2    String3    -k 88.2    File1 File2  V
  164. *   or match: Example1 -s String1 -k 88.3 -i 999 -j                 V
  165. *    but not: Example1 -i 77 78    (i expects one integer, k must be specified).V
  166. * The option k must exists in the above example and if '-i' is prescribed    M
  167. * one integer argument must follow it.                         M
  168. *   In the first example, File1 & File2, will match Files in the control     M
  169. * string.                                     M
  170. *   The order of the options in the command line is irrelevant.              M
  171. * A call to GAPrintHowTo with this CtrlStr will    print to stderr:         M
  172. *                                         M
  173. * Example1 [-i OneIngeter] [-s Strings...] [-j]    -k Float Files...         V
  174. *                                         M
  175. * The parameters below are stdarg style and in fact are expecting the        M
  176. * following:                                     M
  177. *                                         M
  178. *   GAGetArgs(argc, argv, CtrlStr, ...);                     V
  179. *                                         M
  180. * 1. argc, argv: The usual C interface from the main routine of the program. M
  181. * 2. CtrlStr:    Defining the types/options to expect in the command line.   M
  182. * 3.  ...:       list of addreses of variables to initialize according to    M
  183. *                parsed command line.                                        M
  184. *                                         M
  185. * PARAMETERS:                                                                M
  186. *   va_alist:   Do "man stdarg".                                             M
  187. *   ...:        Rest of optional parameters                                  M
  188. *                                                                            *
  189. * RETURN VALUE:                                                              M
  190. *   int:        TRUE if command line was valid, FALSE otherwise.             M
  191. *                                                                            *
  192. * KEYWORDS:                                                                  M
  193. *   GAGetArgs, command line arguments                                        M
  194. *****************************************************************************/
  195. #ifdef USE_VARARGS
  196. int GAGetArgs(int va_alist, ...)
  197. {
  198.     va_list ap;
  199.     int argc, i, Error = FALSE,
  200.     *Parameters[MAX_PARAM],           /* Save here parameter addresses. */
  201.     ParamCount = 0;
  202.     char **argv, *CtrlStr, *Option, CtrlStrCopy[CTRL_STR_MAX_LEN];
  203.  
  204.     va_start(ap);
  205.  
  206.     argc = va_arg(ap, int);
  207.     argv = va_arg(ap, char **);
  208.     CtrlStr = va_arg(ap, char *);
  209.  
  210.     strcpy(CtrlStrCopy, CtrlStr);
  211.  
  212.     /* Using base address of parameters we access other parameters addr:  */
  213.     /* Note that we (for sure!) samples data beyond the current function  */
  214.     /* frame, but we access only these set address only by demand.      */
  215.     for (i = 1; i <= MAX_PARAM; i++)
  216.     Parameters[i-1] = va_arg(ap, int *);
  217.  
  218.     va_end(ap);
  219. #else /* Using stdarg.h */
  220. int GAGetArgs(int argc, ...)
  221. {
  222.     va_list ap;
  223.     int i, Error = FALSE, ParamCount = 0,
  224.     *Parameters[MAX_PARAM];           /* Save here parameter addresses. */
  225.     char **argv, *CtrlStr, *Option, CtrlStrCopy[CTRL_STR_MAX_LEN];
  226.  
  227.     va_start(ap, argc);
  228.  
  229.     argv = va_arg(ap, char **);
  230.     CtrlStr = va_arg(ap, char *);
  231.  
  232.     strcpy(CtrlStrCopy, CtrlStr);
  233.  
  234.     /* Using base address of parameters we access other parameters addr:  */
  235.     /* Note that we (for sure!) samples data beyond the current function  */
  236.     /* frame, but we access only these set address only by demand.      */
  237.     for (i = 1; i <= MAX_PARAM; i++)
  238.     Parameters[i - 1] = va_arg(ap, int *);
  239.  
  240.     va_end(ap);
  241. #endif /* USE_VARARG */
  242.  
  243.     --argc; argv++;        /* Skip the program name (first in argv/c list). */
  244.     while (argc >= 0) {
  245.     if (!GAOptionExists(argc, argv))
  246.         break;                        /* The loop. */
  247.     argc--;
  248.     Option    = *argv++;
  249.     if ((Error = GAUpdateParameters(Parameters, &ParamCount, Option,
  250.          CtrlStrCopy, CtrlStr, &argc, &argv)) != FALSE)
  251.         return Error;
  252.     }
  253.     /*    Check for results and update trail of command line: */
  254.     return GATestAllSatis(CtrlStrCopy, CtrlStr, &argc, &argv, Parameters,
  255.                                  &ParamCount);
  256. }
  257.  
  258. /*****************************************************************************
  259. * DESCRIPTION:                                                               *
  260. * Routine to search for    unsatisfied flags - simply scan    the list for !-         *
  261. * sequences. Before this scan, this routine updates the rest of the command  *
  262. * line into the    last two parameters if it is requested by the CtrlStr         *
  263. * (when last item in CtrlStr is NOT an option).                     *
  264. *   Returns ARG_OK if all satisfied, CMD_ERR_AllSatis error else.         *
  265. *                                                                            *
  266. * PARAMETERS:                                                                *
  267. *   CtrlStrCopy:     A fresh, unmodified copy of given control string.       *
  268. *   CtrlStr:         A bashed, marked with specified option copy of the      *
  269. *                    control string.                         *
  270. *   argc, argv:      What is left of the command line, if anything.          *
  271. *   Parameters:      Where rest of command line is going to be hooked to.    *
  272. *   ParamCount:      Index into Parameters where to hook left overs.         *
  273. *                                                                            *
  274. * RETURN VALUE:                                                              *
  275. *   int:             TRUE if command line was valid, FALSE otherwise.        *
  276. *****************************************************************************/
  277. static int GATestAllSatis(char *CtrlStrCopy,
  278.               char *CtrlStr,
  279.               int *argc,
  280.               char ***argv,
  281.               int *Parameters[MAX_PARAM],
  282.               int *ParamCount)
  283. {
  284.     int    i;
  285.     static char
  286.     *LocalToken = NULL;
  287.  
  288.     /* If LocalToken is not initialized - do it now. Note that this string */
  289.     /* should be writable as well so we can not assign it directly.        */
  290.     if (LocalToken == NULL) {
  291.         LocalToken = (char *) IritMalloc(3);
  292.     strcpy(LocalToken, "-?");
  293.     }
  294.  
  295.     /* Check is    last item is an    option.    If not then copy rest of command */
  296.     /* line into it as 1. NumOfprm, 2. pointer to block    of pointers.     */
  297.     for (i = (int) strlen(CtrlStr) - 1; i > 0 && !ISSPACE(CtrlStr[i]); i--);
  298.     if (!ISCTRLCHAR(CtrlStr[i + 2])) {
  299.     GASetParamCount(CtrlStr, i, ParamCount);   /* Point in correct prm.. */
  300.     *Parameters[(*ParamCount)++] = *argc;
  301.     GAByteCopy((char *) Parameters[(*ParamCount)++], (char *) argv,
  302.                             sizeof(char *));
  303.     }
  304.  
  305.     i =    0;
  306.     while (++i < (int) strlen(CtrlStrCopy))
  307.     if ((CtrlStrCopy[i] == '-') && (CtrlStrCopy[i-1] == '!')) {
  308.         GAErrorToken = LocalToken;
  309.         LocalToken[1] = CtrlStrCopy[i-2];        /* Set the correct flag. */
  310.         return CMD_ERR_AllSatis;
  311.     }
  312.  
  313.     return ARG_OK;
  314. }
  315.  
  316. /*****************************************************************************
  317. * DESCRIPTION:                                                               *
  318. * Routine to update the    parameters according to    the given Option.         *
  319. *                                                                            *
  320. * PARAMETERS:                                                                *
  321. *   Parameters:      Where new option should update the variables.         *
  322. *   ParamCount:      Index into Parameters where to update using new option. *
  323. *   Option:          New command line option.                                *
  324. *   CtrlStrCopy:     A fresh, unmodified copy of given control string.       *
  325. *   CtrlStr:         A bashed, marked with specified option copy of the      *
  326. *   argc, argv:      Current command line state.                             *
  327. *                                                                            *
  328. * RETURN VALUE:                                                              *
  329. *   int:             Return code based on success (ARG_OK), or failure.      *
  330. *****************************************************************************/
  331. static int GAUpdateParameters(int *Parameters[],
  332.                   int *ParamCount,
  333.                   char *Option,
  334.                   char *CtrlStrCopy,
  335.                   char *CtrlStr,
  336.                   int *argc,
  337.                   char ***argv)
  338. {
  339.     int    i,
  340.     BooleanTrue = Option[2] != '-';
  341.  
  342.     if (Option[0] != '-') {
  343.     GAErrorToken = Option;
  344.     return CMD_ERR_NotAnOpt;
  345.     }
  346.     i =    0;                /* Scan the CtrlStrCopy for that option: */
  347.     while (i + 2 < (int) strlen(CtrlStrCopy)) {
  348.     if ((CtrlStrCopy[i] == Option[1]) && (ISCTRLCHAR(CtrlStrCopy[i + 1]))
  349.         && (CtrlStrCopy[i+2] == '-')) {
  350.         /* We found    that option! */
  351.         break;
  352.     }
  353.     i++;
  354.     }
  355.     if (i + 2 >= (int) strlen(CtrlStrCopy)) {
  356.     GAErrorToken = Option;
  357.     return CMD_ERR_NoSuchOpt;
  358.     }
  359.  
  360.     /* If we are here, then we found that option in CtrlStr - Strip it off:  */
  361.     CtrlStrCopy[i] = CtrlStrCopy[i + 1] = CtrlStrCopy[i + 2] = (char) ' ';
  362.     GASetParamCount(CtrlStr, i, ParamCount);/*Set it to point in correct prm.*/
  363.     i += 3;
  364.     /* Set Boolean flag for that option. */
  365.     *Parameters[(*ParamCount)++] = BooleanTrue;
  366.     if (ISSPACE(CtrlStrCopy[i]))
  367.     return ARG_OK;               /* Only a Boolean flag is needed. */
  368.  
  369.     /* Skip the    text between the Boolean option and data follows: */
  370.     while (!ISCTRLCHAR(CtrlStrCopy[i]))
  371.     i++;
  372.     /* Get the parameters and return the appropriete return code: */
  373.     return GAGetParmeters(Parameters, ParamCount, &CtrlStrCopy[i],
  374.                               Option, argc, argv);
  375. }
  376.  
  377. /*****************************************************************************
  378. * DESCRIPTION:                                                               *
  379. * Routine to get parameters from command line argc/v according to the        *
  380. * prescribed CtrlStr.                                 *
  381. *                                                                            *
  382. * PARAMETERS:                                                                *
  383. *   Parameters:      Where new option should update the variables.         *
  384. *   ParamCount:      Index into Parameters where to update using new option. *
  385. *   CtrlStrCopy:     A fresh, unmodified copy of given control string.       *
  386. *   Option:          New command line option.                                *
  387. *   argc, argv:      Current command line state.                             *
  388. *                                                                            *
  389. * RETURN VALUE:                                                              *
  390. *   int:             Return code based on success (ARG_OK), or failure.      *
  391. *****************************************************************************/
  392. static int GAGetParmeters(int *Parameters[],
  393.               int *ParamCount,
  394.               char *CtrlStrCopy,
  395.               char *Option,
  396.               int *argc,
  397.               char ***argv)
  398. {
  399.     int    ScanRes, IData,
  400.     i = 0;
  401.     long LData;
  402.     float FData;
  403.     double DData;
  404.  
  405.     while (!(ISSPACE(CtrlStrCopy[i]))) {
  406.     if (*argc == 0) {
  407.         GAErrorToken = Option;
  408.         return CMD_ERR_NumRead;
  409.     }
  410.  
  411.     switch (CtrlStrCopy[i+1]) {
  412.         case 'd':                     /* Get signed integers. */
  413.         if ((ScanRes = sscanf(*((*argv)++), "%d", &IData)) == 1)
  414.             *((int *) Parameters[(*ParamCount)++]) = IData;
  415.         break;
  416.         case 'u':                   /* Get unsigned integers. */
  417.         if ((ScanRes = sscanf(*((*argv)++), "%u", &IData)) == 1)
  418.             *((int *) Parameters[(*ParamCount)++]) = IData;
  419.         break;
  420.         case 'x':                    /* Get hex integers. */
  421.         if ((ScanRes = sscanf(*((*argv)++), "%x", &IData)) == 1)
  422.             *((int *) Parameters[(*ParamCount)++]) = IData;
  423.         break;
  424.         case 'o':                      /* Get octal integers. */
  425.         if ((ScanRes = sscanf(*((*argv)++), "%o", &IData)) == 1)
  426.             *((int *) Parameters[(*ParamCount)++]) = IData;
  427.         break;
  428.         case 'D':                     /* Get signed integers. */
  429.         if ((ScanRes = sscanf(*((*argv)++), "%ld", &LData)) == 1)
  430.             *((int *) Parameters[(*ParamCount)++]) = LData;
  431.         break;
  432.         case 'U':                   /* Get unsigned integers. */
  433.         if ((ScanRes = sscanf(*((*argv)++), "%lu", &LData)) == 1)
  434.             *((int *) Parameters[(*ParamCount)++]) = LData;
  435.         break;
  436.         case 'X':                    /* Get hex integers. */
  437.         if ((ScanRes = sscanf(*((*argv)++), "%lx", &LData)) == 1)
  438.             *((int *) Parameters[(*ParamCount)++]) = LData;
  439.         break;
  440.         case 'O':                      /* Get octal integers. */
  441.         if ((ScanRes = sscanf(*((*argv)++), "%lo", &LData)) == 1)
  442.             *((int *) Parameters[(*ParamCount)++]) = LData;
  443.         break;
  444.         case 'f':                    /* Get float number. */
  445.         if ((ScanRes = sscanf(*((*argv)++), "%f", &FData)) == 1)
  446.             *((float *) Parameters[(*ParamCount)++]) = FData;
  447.         break;
  448.         case 'F':                 /* Get double float number. */
  449.         if ((ScanRes = sscanf(*((*argv)++), "%lf", &DData)) == 1)
  450.             *((double *) Parameters[(*ParamCount)++]) = DData;
  451.         break;
  452.         case 's':                      /* It as a string. */
  453.         ScanRes    = 1;                     /* Allways O.K. */
  454.         GAByteCopy((char *) Parameters[(*ParamCount)++],
  455.                     (char *) ((*argv)++), sizeof(char *));
  456.         break;
  457.         case '*':                 /* Get few parameters into one: */
  458.         ScanRes    = GAGetMultiParmeters(Parameters, ParamCount,
  459.                           &CtrlStrCopy[i], argc, argv);
  460.         if ((ScanRes ==    0) && (CtrlStrCopy[i] == '!')) {
  461.             GAErrorToken = Option;
  462.             return CMD_ERR_WildEmpty;
  463.         }
  464.         break;
  465.         default:
  466.         ScanRes = 0;               /* Make optimizer warning silent. */
  467.     }
  468.     /* If reading fails and    this number is a must (!) then error: */
  469.     if (ScanRes == 0) {
  470.         if (CtrlStrCopy[i] == '!') {
  471.         GAErrorToken = Option;
  472.         return CMD_ERR_NumRead;
  473.         }
  474.         else {
  475.         /* It is optional but it is not there - quit. */
  476.         (*argv)--;
  477.         while (!isspace(CtrlStrCopy[i++]));
  478.         return ARG_OK;
  479.         }
  480.     }
  481.     if (CtrlStrCopy[i+1] !=    '*') {
  482.         (*argc)--;         /* Everything is OK - update to next parameter: */
  483.         i += 2;             /* Skip to next parameter (if any). */
  484.     }
  485.     else
  486.         i += 3;                       /* Skip the '*' also! */
  487.     }
  488.  
  489.     return ARG_OK;
  490. }
  491.  
  492. /*****************************************************************************
  493. * DESCRIPTION:                                                               *
  494. * Routine to get several parameters into one pointer such that the returned  *
  495. * pointer actually points on a block of    pointers on the    parameters...         *
  496. *   For example *F means a pointer to pointers on double.             *
  497. *   Returns number of parameters actually being read.                 *
  498. *   This routine assumes that all pointers (on any kind of scalar) has the   *
  499. * same size (and the union below is totally ovelapped between dif. arrays).  *
  500. *                                                                            *
  501. * PARAMETERS:                                                                *
  502. *   Parameters:      Where new option should update the variables.         *
  503. *   ParamCount:      Index into Parameters where to update using new option. *
  504. *   CtrlStrCopy:     A fresh, unmodified copy of given control string.       *
  505. *   argc, argv:      Current command line state.                             *
  506. *                                                                            *
  507. * RETURN VALUE:                                                              *
  508. *   int:             Number of parameters actually being read.               *
  509. *****************************************************************************/
  510. static int GAGetMultiParmeters(int *Parameters[],
  511.                    int *ParamCount,
  512.                    char *CtrlStrCopy,
  513.                    int *argc,
  514.                    char ***argv)
  515. {
  516.     int    ScanRes, **Pmain, **Ptemp,
  517.     i = 0,
  518.     NumOfPrm = 0;
  519.     union TmpArray {    /* Save here the temporary data before copying it to */
  520.     int    *IntArray[MAX_PARAM];          /* the returned pointer block. */
  521.     long   *LngArray[MAX_PARAM];
  522.     float  *FltArray[MAX_PARAM];
  523.     double *DblArray[MAX_PARAM];
  524.     char   *ChrArray[MAX_PARAM];
  525.     } TmpArray;
  526.  
  527.     do {
  528.     switch (CtrlStrCopy[2]) {   /* CtrlStr == '!*?' or '%*?' where ? is. */
  529.         case 'd':               /* Format to read the parameters: */
  530.         TmpArray.IntArray[NumOfPrm] =
  531.             (int *) IritMalloc(sizeof(int));
  532.         ScanRes    = sscanf(*((*argv)++), "%d",
  533.                        (int *) TmpArray.IntArray[NumOfPrm++]);
  534.         break;
  535.         case 'u':
  536.         TmpArray.IntArray[NumOfPrm] =
  537.             (int *) IritMalloc(sizeof(int));
  538.         ScanRes    = sscanf(*((*argv)++), "%u",
  539.                   (unsigned    int *) TmpArray.IntArray[NumOfPrm++]);
  540.         break;
  541.         case 'o':
  542.         TmpArray.IntArray[NumOfPrm] =
  543.             (int *) IritMalloc(sizeof(int));
  544.         ScanRes    = sscanf(*((*argv)++), "%o",
  545.                        (int *) TmpArray.IntArray[NumOfPrm++]);
  546.         break;
  547.         case 'x':
  548.         TmpArray.IntArray[NumOfPrm] =
  549.             (int *) IritMalloc(sizeof(int));
  550.         ScanRes    = sscanf(*((*argv)++), "%x",
  551.                        (int *) TmpArray.IntArray[NumOfPrm++]);
  552.         break;
  553.         case 'D':
  554.         TmpArray.LngArray[NumOfPrm] = 
  555.             (long *) IritMalloc(sizeof(long));
  556.         ScanRes    = sscanf(*((*argv)++), "%ld",
  557.                       (long *) TmpArray.LngArray[NumOfPrm++]);
  558.         break;
  559.         case 'U':
  560.         TmpArray.LngArray[NumOfPrm] = 
  561.             (long *) IritMalloc(sizeof(long));
  562.         ScanRes    = sscanf(*((*argv)++), "%lu",
  563.                  (unsigned long *) TmpArray.LngArray[NumOfPrm++]);
  564.         break;
  565.         case 'O':
  566.         TmpArray.LngArray[NumOfPrm] = 
  567.             (long *) IritMalloc(sizeof(long));
  568.         ScanRes    = sscanf(*((*argv)++), "%lo",
  569.                       (long *) TmpArray.LngArray[NumOfPrm++]);
  570.         break;
  571.         case 'X':
  572.         TmpArray.LngArray[NumOfPrm] = 
  573.             (long *) IritMalloc(sizeof(long));
  574.         ScanRes    = sscanf(*((*argv)++), "%lx",
  575.                       (long *) TmpArray.LngArray[NumOfPrm++]);
  576.         break;
  577.         case 'f':
  578.         TmpArray.FltArray[NumOfPrm] =
  579.             (float *) IritMalloc(sizeof(float));
  580.         ScanRes    = sscanf(*((*argv)++), "%f",
  581.                      (float *) TmpArray.FltArray[NumOfPrm++]);
  582.         break;
  583.         case 'F':
  584.         TmpArray.DblArray[NumOfPrm] =
  585.             (double *) IritMalloc(sizeof(double));
  586.         ScanRes    = sscanf(*((*argv)++), "%lf",
  587.                     (double *) TmpArray.DblArray[NumOfPrm++]);
  588.         break;
  589.         case 's':
  590.         while ((*argc) && ((**argv)[0] != '-'))    {
  591.             TmpArray.ChrArray[NumOfPrm++] = *((*argv)++);
  592.             (*argc)--;
  593.         }
  594.         ScanRes    = 0;               /* Force quit from do - loop. */
  595.         NumOfPrm++;        /* Updated again immediately after loop! */
  596.         (*argv)++;                           /* "" */
  597.         break;
  598.         default:
  599.         ScanRes = 0;               /* Make optimizer warning silent. */
  600.     }
  601.     (*argc)--;
  602.     }
  603.     while (ScanRes == 1);          /* Exactly one parameter was read. */
  604.     (*argv)--;
  605.     NumOfPrm--;
  606.     (*argc)++;
  607.  
  608.     /* Now allocate the    block with the exact size, and set it: */
  609.     Ptemp = Pmain = (int **) IritMalloc((unsigned) (NumOfPrm+1) * sizeof(int *));
  610.     /* And here    we use the assumption that all pointers    are the    same: */
  611.     for (i = 0; i < NumOfPrm; i++)
  612.     *Ptemp++ = TmpArray.IntArray[i];
  613.     *Ptemp = NULL;               /* Close the block with NULL pointer. */
  614.  
  615.     /* That it save the    number of parameters read as first parameter to    */
  616.     /* return and the pointer to the block as second, and return:    */
  617.     *Parameters[(*ParamCount)++] = NumOfPrm;
  618.     GAByteCopy((char *)    Parameters[(*ParamCount)++], (char *) &Pmain,
  619.                                  sizeof(char *));
  620.     return NumOfPrm;
  621. }
  622.  
  623. /*****************************************************************************
  624. * DESCRIPTION:                                                               *
  625. * Routine to scan the CtrlStr, upto Max    and count the number of    parameters   *
  626. * to that point as,                                 *
  627. * 1. Each option is counted as one parameter - Boolean variable    (int)         *
  628. * 2. Within an option, each %? or !? is    counted    once - pointer to something. *
  629. * 3. Within an option, %*? or !*? is counted twice - one for item count         *
  630. *    and one for pointer to block of pointers.                     *
  631. * ALL variables are passed by address and we assume pointers (addresses)     *
  632. * are all the same fixed size.                             *
  633. *                                                                            *
  634. * PARAMETERS:                                                                *
  635. *   CtrlStr:         A fresh, unmodified copy of given control string.       *
  636. *   Max:             Maximum number of options to scan.                      *
  637. *   ParamCOunt:      Where resulting count is saved.                         *
  638. *                                                                            *
  639. * RETURN VALUE:                                                              *
  640. *   void                                                                     *
  641. *****************************************************************************/
  642. static void GASetParamCount(char *CtrlStr, int Max, int *ParamCount)
  643. {
  644.     int    i;
  645.  
  646.     *ParamCount    = 0;
  647.     for (i = 0; i < Max; i++)
  648.     if (ISCTRLCHAR(CtrlStr[i])) {
  649.         if (CtrlStr[i+1] == '*')
  650.         *ParamCount += 2;
  651.         else
  652.         (*ParamCount)++;
  653.     }
  654. }
  655.  
  656. /*****************************************************************************
  657. * DESCRIPTION:                                                               *
  658. * Routine to copy exactly n bytes from Src to Dst.                           *
  659. *                                                                            *
  660. * PARAMETERS:                                                                *
  661. *   Dst:      Destination address.                                           *
  662. *   Src:      Source address.                                                *
  663. *   n:        Number of bytes to copy.                                       *
  664. *                                                                            *
  665. * RETURN VALUE:                                                              *
  666. *   void                                                                     *
  667. *****************************************************************************/
  668. static void GAByteCopy(char *Dst, char *Src, unsigned n)
  669. {
  670.     while (n--)    *(Dst++) = *(Src++);
  671. }
  672.  
  673. /*****************************************************************************
  674. * DESCRIPTION:                                                               *
  675. * Routine to verify if more options (i.e. first char == '-') exist in the    *
  676. * given    command line list list argc, argv (excludes just '-' which signals   *
  677. * file stdin, though).                                 *
  678. *                                                                            *
  679. * PARAMETERS:                                                                *
  680. *   argc, argv:      Current command line state.                             *
  681. *                                                                            *
  682. * RETURN VALUE:                                                              *
  683. *   int:             TRUE if more options exists, FALSE otherwise.           *
  684. *****************************************************************************/
  685. static int GAOptionExists(int argc, char **argv)
  686. {
  687.     while (argc--) {
  688.     if ((*argv)[0] == '-' && (*argv)[1] != 0)
  689.         return TRUE;
  690.     argv++;
  691.     }
  692.     return FALSE;
  693. }
  694.  
  695. /*****************************************************************************
  696. * DESCRIPTION:                                                               M
  697. * Routine to print a description of an error to stderr,    for this module:     M
  698. *                                                                            *
  699. * PARAMETERS:                                                                M
  700. *   Error:       Error type as returned by GAGetArgs.                        M
  701. *                                                                            *
  702. * RETURN VALUE:                                                              M
  703. *   void                                                                     M
  704. *                                                                            *
  705. * KEYWORDS:                                                                  M
  706. *   GAPrintErrMsg, command line arguments                                    M
  707. *****************************************************************************/
  708. void GAPrintErrMsg(int Error)
  709. {
  710.     fprintf(stderr, "Error in command line parsing - ");
  711.     switch (Error) {
  712.     case 0:;
  713.         fprintf(stderr, "Undefined error");
  714.         break;
  715.     case CMD_ERR_NotAnOpt:
  716.         fprintf(stderr, "None option found");
  717.         break;
  718.     case CMD_ERR_NoSuchOpt:
  719.         fprintf(stderr, "Undefined option found");
  720.         break;
  721.     case CMD_ERR_WildEmpty:
  722.         fprintf(stderr, "Empty input for '!*?' seq.");
  723.         break;
  724.     case CMD_ERR_NumRead:
  725.         fprintf(stderr, "Failed on reading number");
  726.         break;
  727.     case CMD_ERR_AllSatis:
  728.         fprintf(stderr, "Fail to satisfy");
  729.         break;
  730.     }
  731.     fprintf(stderr, " - '%s'.\n", GAErrorToken);
  732. }
  733.  
  734. /*****************************************************************************
  735. * DESCRIPTION:                                                               M
  736. * Routine to print the correct format of command line allowed, to stderr.    M
  737. *   For example, for the following control string,                 M
  738. *    "Example1  i%-OneInteger!d  s%-Strings!*s  j%-  k!-Float!f  Files"         V
  739. *   This routine will print                             M
  740. * Example1 [-i OneIngeter] [-s Strings...] [-j]    -k Float Files...         V
  741. *                                                                            *
  742. * PARAMETERS:                                                                M
  743. *   CtrlStr:    Defining the types/options to expect in the command line.    M
  744. *                                                                            *
  745. * RETURN VALUE:                                                              M
  746. *   void                                                                     M
  747. *                                                                            *
  748. * KEYWORDS:                                                                  M
  749. *   GAPrintHowTo, command line arguments                                     M
  750. *****************************************************************************/
  751. void GAPrintHowTo(char *CtrlStr)
  752. {
  753.     int    SpaceFlag,
  754.     i = 0;
  755.  
  756.     fprintf(stderr, "Usage: ");
  757.     /* Print program name - first word in ctrl.    str. (optional): */
  758.     while (!(ISSPACE(CtrlStr[i])) && (!ISCTRLCHAR(CtrlStr[i+1])))
  759.     fprintf(stderr, "%c", CtrlStr[i++]);
  760.  
  761.     while (i < (int) strlen(CtrlStr))    {
  762.     while ((ISSPACE(CtrlStr[i])) &&    (i < (int) strlen(CtrlStr))) i++;
  763.     switch (CtrlStr[i+1]) {
  764.         case '%':
  765.         fprintf(stderr, " [-%c", CtrlStr[i++]);
  766.         i += 2;             /* Skip the '%-' or '!- after the char! */
  767.         SpaceFlag = TRUE;
  768.         while (!ISCTRLCHAR(CtrlStr[i]) &&
  769.                (i < (int) strlen(CtrlStr)) &&
  770.                (!ISSPACE(CtrlStr[i])))
  771.             if (SpaceFlag) {
  772.             if (CtrlStr[i++] == SPACE_CHAR)
  773.                 fprintf(stderr, " ");
  774.             else
  775.                 fprintf(stderr, " %c", CtrlStr[i-1]);
  776.             SpaceFlag = FALSE;
  777.             }
  778.             else if (CtrlStr[i++] == SPACE_CHAR)
  779.             fprintf(stderr, " ");
  780.             else
  781.             fprintf(stderr, "%c", CtrlStr[i-1]);
  782.         while (!ISSPACE(CtrlStr[i]) && (i < (int) strlen(CtrlStr))) {
  783.             if (CtrlStr[i] == '*')
  784.             fprintf(stderr, "...");
  785.             i++;                 /* Skip the rest of it. */
  786.         }
  787.         fprintf(stderr, "]");
  788.         break;
  789.         case '!':
  790.         fprintf(stderr, " -%c", CtrlStr[i++]);
  791.         i += 2;             /* Skip the '%-' or '!- after the char! */
  792.         SpaceFlag = TRUE;
  793.         while (!ISCTRLCHAR(CtrlStr[i]) &&
  794.                (i < (int) strlen(CtrlStr)) &&
  795.                (!ISSPACE(CtrlStr[i])))
  796.             if (SpaceFlag) {
  797.             if (CtrlStr[i++] == SPACE_CHAR)
  798.                 fprintf(stderr, " ");
  799.             else
  800.                 fprintf(stderr, " %c", CtrlStr[i-1]);
  801.             SpaceFlag = FALSE;
  802.             }
  803.             else if (CtrlStr[i++] == SPACE_CHAR)
  804.             fprintf(stderr, " ");
  805.             else
  806.                 fprintf(stderr, "%c", CtrlStr[i-1]);
  807.         while (!ISSPACE(CtrlStr[i]) && (i < (int) strlen(CtrlStr))) {
  808.             if (CtrlStr[i] == '*')
  809.             fprintf(stderr, "...");
  810.             i++;                 /* Skip the rest of it. */
  811.         }
  812.         break;
  813.         default:               /* Not checked, but must be last one! */
  814.         fprintf(stderr, " ");
  815.         while (!ISSPACE(CtrlStr[i]) && (i < (int) strlen(CtrlStr)) &&
  816.                !ISCTRLCHAR(CtrlStr[i]))
  817.             fprintf(stderr, "%c", CtrlStr[i++]);
  818.         fprintf(stderr, "\n");
  819.         return;
  820.     }
  821.     }
  822.     fprintf(stderr, "\n");
  823. }
  824.