home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / i / iritsm3s.zip / misc_lib / getarg.c < prev    next >
C/C++ Source or Header  |  1992-02-02  |  26KB  |  666 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. *     CtrlStr format:                               *
  25. *   The    control    string passed to GetArgs controls the way argv (argc) are  *
  26. * parsed. Each entry in    this string must not have any spaces in    it. The       *
  27. * First    Entry is the name of the program which is usually ignored except   *
  28. * when GAPrintHowTo is called. All the other entries (except the last one  *
  29. * which    we will    come back to it    later) must have the following format:       *
  30. * 1. One letter    which sets the option letter.                   *
  31. * 2. '!' or '%'    to determines if this option is    really optional    ('%') or   *
  32. *    it    must exists ('!')...                           *
  33. * 3. '-' allways.                               *
  34. * 4. Alpha numeric string, usually ignored, but    used by    GAPrintHowTo to       *
  35. *    print the meaning of this input.                       *
  36. * 5. Sequences starts with '!' or '%'. Again if    '!' then this sequence       *
  37. *    must exists (only if its option flag is given of course), and if '%'  *
  38. *    it    is optional. Each sequence will    continue with one or two       *
  39. *    characters    which defines the kind of the input:               *
  40. *    a.    d, x, o, u - integer is expected (decimal, hex, octal base or       *
  41. *          unsigned).                           *
  42. *    b.    D, X, O, U - long integer is expected (same as above).           *
  43. *    c.    f    - float    number is expected.                   *
  44. *    d.    F    - double number    is expected.                   *
  45. *    e.    s    - string is expected.                       *
  46. *    f.    *?    - any number of    '?' kind (d, x, o, u, D, X, O, U, f, F, s) *
  47. *          will match this one. If '?' is numeric, it scans until   *
  48. *          none numeric input is given. If '?' is 's' then it scans *
  49. *          up to the next option or end of argv.               *
  50. *                                       *
  51. *   If the last    parameter given    in the CtrlStr,    is not an option (i.e. the *
  52. * second char is not in    ['!', '%'] and the third one is not '-'), all what *
  53. * remained from    argv is    linked to it.                       *
  54. *                                       *
  55. *   The    variables passed to GAGetArgs (starting    from 4th parameter) MUST   *
  56. * match    the order of the CtrlStr:                       *
  57. *   For    each option, one integer address must be passed. This integer must *
  58. * initialized by 0. If that option is given in the command line, it will   *
  59. * be set to one.                               *
  60. *   In addition, the sequences that might follow an option require the       *
  61. * following parameters to pass:                           *
  62. * 1. d, x, o, u - pointer to integer (int *).                   *
  63. * 2. D, X, O, U - pointer to long (long *).                   *
  64. * 3. f         - pointer to float      (float *).                   *
  65. * 4. F         - pointer to double  (double *).                   *
  66. * 5. s         - pointer to char      (char    *). NO allocation is needed!       *
  67. * 6. *?         - TWO variables are passed    for each wild request. the first   *
  68. *           one is (address of) integer, and    it will    return number of   *
  69. *           parameters actually matched this    sequence, and the second   *
  70. *           one is a    pointer    to pointer to ?    (? **),    and will return    an *
  71. *           address to a block of pointers to ? kind, terminated with   *
  72. *           NULL pointer. NO    pre-allocation is needed.           *
  73. *           note that these two variables are pretty    like the argv/argc *
  74. *           pair...                               *
  75. *                                       *
  76. *   Examples:                                   *
  77. *                                       *
  78. *    "Example1  i%-OneInteger!d  s%-Strings!*s  j%-  k!-Float!f  Files"       *
  79. * Will match: Example1 -i 77 -s    String1    String2    String3    -k 88.2    File1 File2*
  80. *   or match: Example1 -s String1 -k 88.3 -i 999 -j               *
  81. *    but not: Example1 -i 77 78    (option    i expects one integer, k must be). *
  82. * Note the option k must exists, and that the order of the options is not  *
  83. * not important. In the    first examples File1 & File2 will match    the Files  *
  84. * in the command line.                               *
  85. * A call to GAPrintHowTo with this CtrlStr will    print to stderr:       *
  86. * Example1 [-i OneIngeter] [-s Strings...] [-j]    -k Float Files...       *
  87. *                                       *
  88. *   Notes:                                   *
  89. *                                       *
  90. * 1. This module assumes that all the pointers to all kind of data types   *
  91. *    have the same length and format, i.e. sizeof(int *) == sizeof(char    *).*
  92. *                                       *
  93. *                      Gershon Elber    Ver 0.2     Mar 88       *
  94. ****************************************************************************
  95. * History:                                   *
  96. * 11 Mar 88 - Version 1.0 by Gershon Elber.                   *
  97. ***************************************************************************/
  98.  
  99. #ifdef __MSDOS__
  100. #include <stdlib.h>
  101. #include <alloc.h>
  102. #endif /* __MSDOS__ */
  103.  
  104. #ifdef USE_VARARGS
  105. #include <varargs.h>
  106. #else
  107. #include <stdarg.h>
  108. #endif /* USE_VARARGS */
  109.  
  110. #include <stdio.h>
  111. #include <string.h>
  112. #include "getarg.h"
  113.  
  114. #define    MYMALLOC       /* If no "MyAlloc" routine elsewhere define this. */
  115.  
  116. #define    MAX_PARAM    100        /* maximum number of parameters allowed. */
  117. #define    CTRL_STR_MAX_LEN    1024
  118.  
  119. #define SPACE_CHAR    '|'      /* The character not to print using HowTo. */
  120.  
  121. #ifndef    TRUE
  122. #define    TRUE -1
  123. #define    FALSE 0
  124. #endif /* TRUE */
  125.  
  126. #define    ARG_OK    0
  127.  
  128. #define    ISSPACE(x) ((x)    <= ' ')           /* Not conventional - but works fine! */
  129. /* The two characters '%' and '!' are used in the control string: */
  130. #define    ISCTRLCHAR(x) (((x) == '%') || ((x) == '!'))
  131.  
  132. static char *GAErrorToken;/* On error code, ErrorToken is set to point on it.*/
  133.  
  134. static int GATestAllSatis(char *CtrlStrCopy, char *CtrlStr, int *argc,
  135.     char ***argv, int *Parameters[MAX_PARAM], int *ParamCount);
  136. static int GAUpdateParameters(int *Parameters[], int *ParamCount,
  137.     char *Option, char *CtrlStrCopy, char *CtrlStr, int *argc,
  138.     char ***argv);
  139. static int GAGetParmeters(int *Parameters[], int *ParamCount,
  140.     char *CtrlStrCopy , char *Option, int *argc, char ***argv);
  141. static int GAGetMultiParmeters(int *Parameters[], int *ParamCount,
  142.     char *CtrlStrCopy, int *argc, char ***argv);
  143. static void GASetParamCount(char *CtrlStr, int Max, int *ParamCount);
  144. static void GAByteCopy(char *Dst, char *Src, unsigned n);
  145. static int GAOptionExists(int argc, char **argv);
  146. #ifdef    MYMALLOC
  147. static char *MyMalloc(unsigned size);
  148. #endif    /* MYMALLOC */
  149.  
  150. /***************************************************************************
  151. * Routine to access the    command    line argument and interpret them:       *
  152. * Return ARG_OK (0) is case of succesfull parsing, error code else...       *
  153. ***************************************************************************/
  154. #ifdef USE_VARARGS
  155. int
  156. #ifdef __MSDOS__
  157. cdecl        /* So we can use -rp in Borland 3.0 (parameters in registers.). */
  158. #endif /* __MSDOS__ */
  159. GAGetArgs(int va_alist, ...)
  160. {
  161.     va_list ap;
  162.     int argc, i, Error = FALSE,
  163.     *Parameters[MAX_PARAM],           /* Save here parameter addresses. */
  164.     ParamCount = 0;
  165.     char **argv, *CtrlStr, *Option, CtrlStrCopy[CTRL_STR_MAX_LEN];
  166.  
  167.     va_start(ap);
  168.  
  169.     argc = va_arg(ap, int);
  170.     argv = va_arg(ap, char **);
  171.     CtrlStr = va_arg(ap, char *);
  172.  
  173.     strcpy(CtrlStrCopy, CtrlStr);
  174.  
  175.     /* Using base address of parameters we access other parameters addr:  */
  176.     /* Note that we (for sure!) samples data beyond the current function  */
  177.     /* frame, but we access only these set address only by demand.      */
  178.     for (i = 1; i <= MAX_PARAM; i++) Parameters[i-1] = va_arg(ap, int *);
  179.  
  180.     va_end(ap);
  181. #else /* Using stdarg.h */
  182. int
  183. #ifdef __MSDOS__
  184. cdecl        /* So we can use -rp in Borland 3.0 (parameters in registers.). */
  185. #endif /* __MSDOS__ */
  186. GAGetArgs(int argc, ...)
  187. {
  188.     va_list ap;
  189.     int i, Error = FALSE, ParamCount = 0,
  190.     *Parameters[MAX_PARAM];           /* Save here parameter addresses. */
  191.     char **argv, *CtrlStr, *Option, CtrlStrCopy[CTRL_STR_MAX_LEN];
  192.  
  193.     va_start(ap, argc);
  194.  
  195.     argv = va_arg(ap, char **);
  196.     CtrlStr = va_arg(ap, char *);
  197.  
  198.     strcpy(CtrlStrCopy, CtrlStr);
  199.  
  200.     /* Using base address of parameters we access other parameters addr:  */
  201.     /* Note that we (for sure!) samples data beyond the current function  */
  202.     /* frame, but we access only these set address only by demand.      */
  203.     for (i = 1; i <= MAX_PARAM; i++) Parameters[i-1] = va_arg(ap, int *);
  204.  
  205.     va_end(ap);
  206. #endif /* USE_VARARG */
  207.  
  208.     --argc; argv++;        /* Skip the program name (first in argv/c list). */
  209.     while (argc >= 0) {
  210.     if (!GAOptionExists(argc, argv)) break;            /* The loop. */
  211.     argc--;
  212.     Option    = *argv++;
  213.     if ((Error = GAUpdateParameters(Parameters, &ParamCount, Option,
  214.          CtrlStrCopy, CtrlStr, &argc, &argv)) != FALSE) return Error;
  215.     }
  216.     /*    Check for results and update trail of command line: */
  217.     return GATestAllSatis(CtrlStrCopy, CtrlStr, &argc, &argv, Parameters,
  218.                                  &ParamCount);
  219. }
  220.  
  221. /***************************************************************************
  222. * Routine to search for    unsatisfied flags - simply scan    the list for !-       *
  223. * sequence. Before this    scan, this routine updates the rest of the command *
  224. * line into the    last two parameters if it is requested by the CtrlStr       *
  225. * (last    item in    CtrlStr    is NOT an option).                   *
  226. * Return ARG_OK if all satisfied, CMD_ERR_AllSatis error else.           *
  227. ***************************************************************************/
  228. static int GATestAllSatis(char *CtrlStrCopy, char *CtrlStr, int *argc,
  229.     char ***argv, int *Parameters[MAX_PARAM], int *ParamCount)
  230. {
  231.     int    i;
  232.     static char    *LocalToken = NULL;
  233.  
  234.     /* If LocalToken is not initialized - do it now. Note that this string */
  235.     /* should be writable as well so we can not assign it directly.        */
  236.     if (LocalToken == NULL) {
  237.         LocalToken = (char *) malloc(3);
  238.     strcpy(LocalToken, "-?");
  239.     }
  240.  
  241.     /* Check is    last item is an    option.    If not then copy rest of command */
  242.     /* line into it as 1. NumOfprm, 2. pointer to block    of pointers.     */
  243.     for (i = (int) strlen(CtrlStr) - 1; i > 0 && !ISSPACE(CtrlStr[i]); i--);
  244.     if (!ISCTRLCHAR(CtrlStr[i + 2])) {
  245.     GASetParamCount(CtrlStr, i, ParamCount);   /* Point in correct prm.. */
  246.     *Parameters[(*ParamCount)++] = *argc;
  247.     GAByteCopy((char *) Parameters[(*ParamCount)++], (char *) argv,
  248.                             sizeof(char *));
  249.     }
  250.  
  251.     i =    0;
  252.     while (++i < (int) strlen(CtrlStrCopy))
  253.     if ((CtrlStrCopy[i] == '-') && (CtrlStrCopy[i-1] == '!')) {
  254.         GAErrorToken = LocalToken;
  255.         LocalToken[1] = CtrlStrCopy[i-2];        /* Set the corrent flag. */
  256.         return CMD_ERR_AllSatis;
  257.     }
  258.  
  259.     return ARG_OK;
  260. }
  261.  
  262. /***************************************************************************
  263. * Routine to update the    parameters according to    the given Option:       *
  264. ***************************************************************************/
  265. static int GAUpdateParameters(int *Parameters[], int *ParamCount,
  266.        char *Option, char *CtrlStrCopy, char *CtrlStr, int *argc, char ***argv)
  267. {
  268.     int    i,
  269.     BooleanTrue = Option[2] != '-';
  270.  
  271.     if (Option[0] != '-') {
  272.     GAErrorToken = Option;
  273.     return CMD_ERR_NotAnOpt;
  274.     }
  275.     i =    0;                /* Scan the CtrlStrCopy for that option: */
  276.     while (i + 2 < (int) strlen(CtrlStrCopy)) {
  277.     if ((CtrlStrCopy[i] == Option[1]) && (ISCTRLCHAR(CtrlStrCopy[i + 1]))
  278.         && (CtrlStrCopy[i+2] == '-')) {
  279.         /* We found    that option! */
  280.         break;
  281.     }
  282.     i++;
  283.     }
  284.     if (i + 2 >= (int) strlen(CtrlStrCopy)) {
  285.     GAErrorToken = Option;
  286.     return CMD_ERR_NoSuchOpt;
  287.     }
  288.  
  289.     /* If we are here, then we found that option in CtrlStr - Strip it off:  */
  290.     CtrlStrCopy[i] = CtrlStrCopy[i + 1] = CtrlStrCopy[i + 2] = (char) ' ';
  291.     GASetParamCount(CtrlStr, i, ParamCount);/*Set it to point in correct prm.*/
  292.     i += 3;
  293.     /* Set boolean flag for that option. */
  294.     *Parameters[(*ParamCount)++] = BooleanTrue;
  295.     if (ISSPACE(CtrlStrCopy[i]))
  296.     return ARG_OK;               /* Only a boolean flag is needed. */
  297.  
  298.     /* Skip the    text between the boolean option and data follows: */
  299.     while (!ISCTRLCHAR(CtrlStrCopy[i]))    i++;
  300.     /* Get the parameters and return the appropriete return code: */
  301.     return GAGetParmeters(Parameters, ParamCount, &CtrlStrCopy[i],
  302.                               Option, argc, argv);
  303. }
  304.  
  305. /***************************************************************************
  306. * Routine to get parameters according to the CtrlStr given from    argv/c :   *
  307. ***************************************************************************/
  308. static int GAGetParmeters(int *Parameters[], int *ParamCount,
  309.     char *CtrlStrCopy , char *Option, int *argc, char ***argv)
  310. {
  311.     int    ScanRes,
  312.     i = 0;
  313.  
  314.     if ( *argc == 0 )
  315.     {
  316.     GAErrorToken = Option;
  317.     return CMD_ERR_NumRead;
  318.     }
  319.  
  320.     while (!(ISSPACE(CtrlStrCopy[i]))) {
  321.     switch (CtrlStrCopy[i+1]) {
  322.         case 'd':                     /* Get signed integers. */
  323.         ScanRes    = sscanf(*((*argv)++), "%d",
  324.                      (int *) Parameters[(*ParamCount)++]);
  325.         break;
  326.         case 'u':                   /* Get unsigned integers. */
  327.         ScanRes    = sscanf(*((*argv)++), "%u",
  328.                     (unsigned *) Parameters[(*ParamCount)++]);
  329.         break;
  330.         case 'x':                    /* Get hex integers. */
  331.         ScanRes    = sscanf(*((*argv)++), "%x",
  332.                      (int *) Parameters[(*ParamCount)++]);
  333.         break;
  334.         case 'o':                      /* Get octal integers. */
  335.         ScanRes    = sscanf(*((*argv)++), "%o",
  336.                      (int *) Parameters[(*ParamCount)++]);
  337.         break;
  338.         case 'D':                /* Get signed long integers. */
  339.         ScanRes    = sscanf(*((*argv)++), "%ld",
  340.                     (long *) Parameters[(*ParamCount)++]);
  341.         break;
  342.         case 'U':                  /* Get unsigned long integers. */
  343.         ScanRes    = sscanf(*((*argv)++), "%lu",
  344.                    (unsigned long *) Parameters[(*ParamCount)++]);
  345.         break;
  346.         case 'X':                   /* Get hex long integers. */
  347.         ScanRes    = sscanf(*((*argv)++), "%lx",
  348.                     (long *) Parameters[(*ParamCount)++]);
  349.         break;
  350.         case 'O':                 /* Get octal long integers. */
  351.         ScanRes    = sscanf(*((*argv)++), "%lo",
  352.                     (long *) Parameters[(*ParamCount)++]);
  353.         break;
  354.         case 'f':                    /* Get float number. */
  355.         ScanRes    = sscanf(*((*argv)++), "%f",
  356.                        (float *) Parameters[(*ParamCount)++]);
  357.         break;
  358.         case 'F':                 /* Get double float number. */
  359.         ScanRes    = sscanf(*((*argv)++), "%lf",
  360.                       (double *) Parameters[(*ParamCount)++]);
  361.         break;
  362.         case 's':                      /* It as a string. */
  363.         ScanRes    = 1;                     /* Allways O.K. */
  364.         GAByteCopy((char *) Parameters[(*ParamCount)++],
  365.                     (char *) ((*argv)++), sizeof(char *));
  366.         break;
  367.         case '*':                 /* Get few parameters into one: */
  368.         ScanRes    = GAGetMultiParmeters(Parameters, ParamCount,
  369.                           &CtrlStrCopy[i], argc, argv);
  370.         if ((ScanRes ==    0) && (CtrlStrCopy[i] == '!')) {
  371.             GAErrorToken = Option;
  372.             return CMD_ERR_WildEmpty;
  373.         }
  374.         break;
  375.         default:
  376.         ScanRes = 0;               /* Make optimizer warning silent. */
  377.     }
  378.     /* If reading fails and    this number is a must (!) then error: */
  379.     if ((ScanRes ==    0) && (CtrlStrCopy[i] == '!')) {
  380.         GAErrorToken = Option;
  381.         return CMD_ERR_NumRead;
  382.     }
  383.     if (CtrlStrCopy[i+1] !=    '*') {
  384.         (*argc)--;         /* Everything is OK - update to next parameter: */
  385.         i += 2;             /* Skip to next parameter (if any). */
  386.     }
  387.     else
  388.         i += 3;                       /* Skip the '*' also! */
  389.     }
  390.  
  391.     return ARG_OK;
  392. }
  393.  
  394. /***************************************************************************
  395. * Routine to get few parameters    into one pointer such that the returned       *
  396. * pointer actually points on a block of    pointers to the    parameters...       *
  397. * For example *F means a pointer to pointers on    floats.               *
  398. * Returns number of parameters actually    read.                   *
  399. * This routine assumes that all    pointers (on any kind of scalar) has the   *
  400. * same size (and the union below is totally ovelapped bteween dif. arrays) *
  401. ***************************************************************************/
  402. static int GAGetMultiParmeters(int *Parameters[], int *ParamCount,
  403.     char *CtrlStrCopy, int *argc, char ***argv)
  404. {
  405.     int    ScanRes, **Pmain, **Ptemp,
  406.     i = 0,
  407.     NumOfPrm = 0;
  408.     union TmpArray {    /* Save here the temporary data before copying it to */
  409.     int    *IntArray[MAX_PARAM];          /* the returned pointer block. */
  410.     long   *LngArray[MAX_PARAM];
  411.     float  *FltArray[MAX_PARAM];
  412.     double *DblArray[MAX_PARAM];
  413.     char   *ChrArray[MAX_PARAM];
  414.     } TmpArray;
  415.  
  416.     do {
  417.     switch (CtrlStrCopy[2]) {   /* CtrlStr == '!*?' or '%*?' where ? is. */
  418.         case 'd':               /* Format to read the parameters: */
  419.         TmpArray.IntArray[NumOfPrm] = (int *) MyMalloc(sizeof(int));
  420.         ScanRes    = sscanf(*((*argv)++), "%d",
  421.                        (int *) TmpArray.IntArray[NumOfPrm++]);
  422.         break;
  423.         case 'u':
  424.         TmpArray.IntArray[NumOfPrm] = (int *) MyMalloc(sizeof(int));
  425.         ScanRes    = sscanf(*((*argv)++), "%u",
  426.                   (unsigned    int *) TmpArray.IntArray[NumOfPrm++]);
  427.         break;
  428.         case 'o':
  429.         TmpArray.IntArray[NumOfPrm] = (int *) MyMalloc(sizeof(int));
  430.         ScanRes    = sscanf(*((*argv)++), "%o",
  431.                        (int *) TmpArray.IntArray[NumOfPrm++]);
  432.         break;
  433.         case 'x':
  434.         TmpArray.IntArray[NumOfPrm] = (int *) MyMalloc(sizeof(int));
  435.         ScanRes    = sscanf(*((*argv)++), "%x",
  436.                        (int *) TmpArray.IntArray[NumOfPrm++]);
  437.         break;
  438.         case 'D':
  439.         TmpArray.LngArray[NumOfPrm] = (long *) MyMalloc(sizeof(long));
  440.         ScanRes    = sscanf(*((*argv)++), "%ld",
  441.                       (long *) TmpArray.LngArray[NumOfPrm++]);
  442.         break;
  443.         case 'U':
  444.         TmpArray.LngArray[NumOfPrm] = (long *) MyMalloc(sizeof(long));
  445.         ScanRes    = sscanf(*((*argv)++), "%lu",
  446.                  (unsigned long *) TmpArray.LngArray[NumOfPrm++]);
  447.         break;
  448.         case 'O':
  449.         TmpArray.LngArray[NumOfPrm] = (long *) MyMalloc(sizeof(long));
  450.         ScanRes    = sscanf(*((*argv)++), "%lo",
  451.                       (long *) TmpArray.LngArray[NumOfPrm++]);
  452.         break;
  453.         case 'X':
  454.         TmpArray.LngArray[NumOfPrm] = (long *) MyMalloc(sizeof(long));
  455.         ScanRes    = sscanf(*((*argv)++), "%lx",
  456.                       (long *) TmpArray.LngArray[NumOfPrm++]);
  457.         break;
  458.         case 'f':
  459.         TmpArray.FltArray[NumOfPrm] = (float *)    MyMalloc(sizeof(float));
  460.         ScanRes    = sscanf(*((*argv)++), "%f",
  461.                      (float *) TmpArray.FltArray[NumOfPrm++]);
  462.         break;
  463.         case 'F':
  464.         TmpArray.DblArray[NumOfPrm] =
  465.                        (double *) MyMalloc(sizeof(double));
  466.         ScanRes    = sscanf(*((*argv)++), "%lf",
  467.                     (double *) TmpArray.DblArray[NumOfPrm++]);
  468.         break;
  469.         case 's':
  470.         while ((*argc) && ((**argv)[0] != '-'))    {
  471.             TmpArray.ChrArray[NumOfPrm++] = *((*argv)++);
  472.             (*argc)--;
  473.         }
  474.         ScanRes    = 0;               /* Force quit from do - loop. */
  475.         NumOfPrm++;        /* Updated again immediately after loop! */
  476.         (*argv)++;                           /* "" */
  477.         break;
  478.         default:
  479.         ScanRes = 0;               /* Make optimizer warning silent. */
  480.     }
  481.     (*argc)--;
  482.     }
  483.     while (ScanRes == 1);          /* Exactly one parameter was read. */
  484.     (*argv)--; NumOfPrm--; (*argc)++;
  485.  
  486.     /* Now allocate the    block with the exact size, and set it: */
  487.     Ptemp = Pmain = (int **) MyMalloc((unsigned) (NumOfPrm+1) *    sizeof(int *));
  488.     /* And here    we use the assumption that all pointers    are the    same: */
  489.     for (i = 0; i < NumOfPrm; i++)
  490.     *Ptemp++ = TmpArray.IntArray[i];
  491.     *Ptemp = NULL;               /* Close the block with NULL pointer. */
  492.  
  493.     /* That it save the    number of parameters read as first parameter to    */
  494.     /* return and the pointer to the block as second, and return:    */
  495.     *Parameters[(*ParamCount)++] = NumOfPrm;
  496.     GAByteCopy((char *)    Parameters[(*ParamCount)++], (char *) &Pmain,
  497.                                  sizeof(char *));
  498.     return NumOfPrm;
  499. }
  500.  
  501. /***************************************************************************
  502. * Routine to scan the CtrlStr, upto Max    and count the number of    parameters *
  503. * to that point:                               *
  504. * 1. Each option is counted as one parameter - boolean variable    (int)       *
  505. * 2. Within an option, each %? or !? is    counted    once - pointer to something*
  506. * 3. Within an option, %*? or !*? is counted twice - one for item count       *
  507. *    and one for pointer to block pointers.                   *
  508. * Note ALL variables are passed    by address and so of fixed size    (address). *
  509. ***************************************************************************/
  510. static void GASetParamCount(char *CtrlStr, int Max, int *ParamCount)
  511. {
  512.     int    i;
  513.  
  514.     *ParamCount    = 0;
  515.     for (i = 0; i < Max; i++) if (ISCTRLCHAR(CtrlStr[i])) {
  516.     if (CtrlStr[i+1] == '*')
  517.         *ParamCount += 2;
  518.     else
  519.         (*ParamCount)++;
  520.     }
  521. }
  522.  
  523. /***************************************************************************
  524. * Routine to copy exactly n bytes from Src to Dst. Note system library       *
  525. * routine strncpy should do the    same, but it stops on NULL char    !       *
  526. ***************************************************************************/
  527. static void GAByteCopy(char *Dst, char *Src, unsigned n)
  528. {
  529.     while (n--)    *(Dst++) = *(Src++);
  530. }
  531.  
  532. /***************************************************************************
  533. * Routine to check if more option (i.e.    first char == '-') exists in the   *
  534. * given    list argc, argv:                           *
  535. ***************************************************************************/
  536. static int GAOptionExists(int argc, char **argv)
  537. {
  538.     while (argc--)
  539.     if ((*argv++)[0] == '-') return TRUE;
  540.     return FALSE;
  541. }
  542.  
  543. /***************************************************************************
  544. * Routine to print some    error messages,    for this module:           *
  545. ***************************************************************************/
  546. void GAPrintErrMsg(int Error)
  547. {
  548.     fprintf(stderr, "Error in command line parsing - ");
  549.     switch (Error) {
  550.     case 0:;
  551.         fprintf(stderr, "Undefined error");
  552.         break;
  553.     case CMD_ERR_NotAnOpt:
  554.         fprintf(stderr, "None option found");
  555.         break;
  556.     case CMD_ERR_NoSuchOpt:
  557.         fprintf(stderr, "Undefined option found");
  558.         break;
  559.     case CMD_ERR_WildEmpty:
  560.         fprintf(stderr, "Empty input for '!*?' seq.");
  561.         break;
  562.     case CMD_ERR_NumRead:
  563.         fprintf(stderr, "Failed on reading number");
  564.         break;
  565.     case CMD_ERR_AllSatis:
  566.         fprintf(stderr, "Fail to satisfy");
  567.         break;
  568.     }
  569.     fprintf(stderr, " - '%s'.\n", GAErrorToken);
  570. }
  571.  
  572. /***************************************************************************
  573. * Routine to print correct format of command line allowed:           *
  574. ***************************************************************************/
  575. void GAPrintHowTo(char *CtrlStr)
  576. {
  577.     int    SpaceFlag,
  578.     i = 0;
  579.  
  580.     fprintf(stderr, "Usage: ");
  581.     /* Print program name - first word in ctrl.    str. (optional): */
  582.     while (!(ISSPACE(CtrlStr[i])) && (!ISCTRLCHAR(CtrlStr[i+1])))
  583.     fprintf(stderr, "%c", CtrlStr[i++]);
  584.  
  585.     while (i < (int) strlen(CtrlStr))    {
  586.     while ((ISSPACE(CtrlStr[i])) &&    (i < (int) strlen(CtrlStr))) i++;
  587.     switch (CtrlStr[i+1]) {
  588.         case '%':
  589.         fprintf(stderr, " [-%c", CtrlStr[i++]);
  590.         i += 2;             /* Skip the '%-' or '!- after the char! */
  591.         SpaceFlag = TRUE;
  592.         while (!ISCTRLCHAR(CtrlStr[i]) &&
  593.                (i < (int) strlen(CtrlStr)) &&
  594.                (!ISSPACE(CtrlStr[i])))
  595.             if (SpaceFlag) {
  596.             if (CtrlStr[i++] == SPACE_CHAR)
  597.                 fprintf(stderr, " ");
  598.             else
  599.                 fprintf(stderr, " %c", CtrlStr[i-1]);
  600.             SpaceFlag = FALSE;
  601.             }
  602.             else if (CtrlStr[i++] == SPACE_CHAR)
  603.             fprintf(stderr, " ");
  604.             else
  605.             fprintf(stderr, "%c", CtrlStr[i-1]);
  606.         while (!ISSPACE(CtrlStr[i]) && (i < (int) strlen(CtrlStr))) {
  607.             if (CtrlStr[i] == '*') fprintf(stderr, "...");
  608.             i++;                 /* Skip the rest of it. */
  609.         }
  610.         fprintf(stderr, "]");
  611.         break;
  612.         case '!':
  613.         fprintf(stderr, " -%c", CtrlStr[i++]);
  614.         i += 2;             /* Skip the '%-' or '!- after the char! */
  615.         SpaceFlag = TRUE;
  616.         while (!ISCTRLCHAR(CtrlStr[i]) &&
  617.                (i < (int) strlen(CtrlStr)) &&
  618.                (!ISSPACE(CtrlStr[i])))
  619.             if (SpaceFlag) {
  620.             if (CtrlStr[i++] == SPACE_CHAR)
  621.                 fprintf(stderr, " ");
  622.             else
  623.                 fprintf(stderr, " %c", CtrlStr[i-1]);
  624.             SpaceFlag = FALSE;
  625.             }
  626.             else if (CtrlStr[i++] == SPACE_CHAR)
  627.             fprintf(stderr, " ");
  628.             else
  629.                 fprintf(stderr, "%c", CtrlStr[i-1]);
  630.         while (!ISSPACE(CtrlStr[i]) && (i < (int) strlen(CtrlStr))) {
  631.             if (CtrlStr[i] == '*') fprintf(stderr, "...");
  632.             i++;                 /* Skip the rest of it. */
  633.         }
  634.         break;
  635.         default:               /* Not checked, but must be last one! */
  636.         fprintf(stderr, " ");
  637.         while (!ISSPACE(CtrlStr[i]) && (i < (int) strlen(CtrlStr)) &&
  638.                !ISCTRLCHAR(CtrlStr[i]))
  639.             fprintf(stderr, "%c", CtrlStr[i++]);
  640.         fprintf(stderr, "\n");
  641.         return;
  642.     }
  643.     }
  644.     fprintf(stderr, "\n");
  645. }
  646.  
  647. #ifdef    MYMALLOC
  648.  
  649. /***************************************************************************
  650. * My Routine to    allocate dynamic memory. All program requests must call    *
  651. * this routine (no direct call to malloc). Dies if no memory.           *
  652. ***************************************************************************/
  653. static char *MyMalloc(unsigned size)
  654. {
  655.     char *p;
  656.  
  657.     if ((p = (char *) malloc(size)) != NULL) return p;
  658.  
  659.     fprintf(stderr, "Not enough memory, exit.\n");
  660.     exit(2);
  661.  
  662.     return NULL;                    /* Makes warning silent. */
  663. }
  664.  
  665. #endif    /* MYMALLOC */
  666.