home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume6 / newscnt / scanargs.c < prev   
Encoding:
C/C++ Source or Header  |  1986-11-30  |  19.2 KB  |  834 lines

  1. /* 
  2.  * $Header: scanargs.c,v 1.3 83/05/22 02:21:32 thomas Exp $
  3.  *         Version 7 compatible
  4.  *     Argument scanner, scans argv style argument list.
  5.  * 
  6.  *     Some stuff is a kludge because sscanf screws up
  7.  * 
  8.  *     Gary Newman - 10/4/1979 - Ampex Corp. 
  9.  * 
  10.  *     Modified by Spencer W. Thomas, Univ. of Utah, 5/81 to
  11.  *     add args introduced by     a flag, add qscanargs call,
  12.  *     allow empty flags.
  13.  * 
  14.  *     Compiling with QUICK defined generates 'qscanargs' ==
  15.  *     scanargs w/o floating point support; avoids huge size
  16.  *     of scanf.
  17.  * 
  18.  *     If you make improvements we'd like to get them too.
  19.  *     Jay Lepreau    lepreau@utah-20, decvax!harpo!utah-cs!lepreau
  20.  *     Spencer Thomas    thomas@utah-20, decvax!harpo!utah-cs!thomas 
  21.  * 
  22.  *    (I know the code is ugly, but it just grew, you see ...)
  23.  * 
  24.  * Modified by:    Spencer W. Thomas
  25.  *     Date:    Feb 25 1983
  26.  * 1. Fixed scanning of optional args.  Now args introduced by a flag
  27.  *    must follow the flag which introduces them and precede any other
  28.  *    flag argument.  It is still possible for a flag introduced
  29.  *    argument to be mistaken for a "bare" argument which occurs
  30.  *    earlier in the format string.  This implies that flags may not
  31.  *    be conditional upon other flags, and a message will be generated
  32.  *    if this is attempted.
  33.  * 
  34.  * 2. Usage message can be formatted by inserting newlines, tabs and
  35.  *    spaces into the format string.  This is especially useful for
  36.  *    long argument lists.
  37.  * 
  38.  * 3. Added n/N types for "numeric" args.  These args are scanned
  39.  *    using the C language conventions - a number starting 0x is
  40.  *    hexadecimal, a number starting with 0 is octal, otherwise it is
  41.  *    decimal.
  42.  */
  43.  
  44. #include <stdio.h>
  45. #include <ctype.h>
  46. #include <varargs.h>
  47.  
  48. typedef char bool;
  49. /* 
  50.  * An explicit assumption is made in this code that all pointers look
  51.  * alike, except possible char * pointers.
  52.  */
  53. typedef int *ptr;
  54.  
  55. #define YES 1
  56. #define NO 0
  57. #define ERROR(msg)  {fprintf(stderr, "msg\n"); goto error; }
  58.  
  59. /* 
  60.  * Storage allocation macros
  61.  */
  62. #define NEW( type, cnt )    (type *) malloc( (cnt) * sizeof( type ) )
  63. #define RENEW( type, ptr, cnt )    (type *) realloc( ptr, (cnt) * sizeof( type ) )
  64.  
  65. static char * prformat();
  66. static bool isnum();
  67.  
  68. /* 
  69.  * Argument list is (argc, argv, format, ... )
  70.  */
  71. #ifndef    QUICK
  72. scanargs ( va_alist )
  73. #else
  74. qscanargs ( va_alist )
  75. #endif
  76. va_dcl
  77. {
  78.     int     argc;            /* Actual arguments */
  79.     char  **argv;
  80.     char   *format;
  81.     va_list argl;
  82.  
  83.     register    check;            /* check counter to be sure all argvs
  84.                        are processed */
  85.     register char  *cp;
  86.     register    cnt;
  87.     int        optarg = 0;            /* where optional args start */
  88.     int        nopt;
  89.     char    tmpflg,            /* temp flag */
  90.         typchr;            /* type char from format string */
  91.     char    c;
  92.     bool  * arg_used;            /* array of flags */
  93.     char  * malloc();
  94.     ptr        aptr;            /* pointer to return loc */
  95.  
  96.     bool    required;
  97.     int        excnt;            /* which flag is set */
  98.     bool    exflag;            /* when set, one of a set of exclusive
  99.                        flags is set */
  100.  
  101.     bool    list_of;            /* set if parsing off a list of args */
  102.     bool    comma_list;            /* set if AT&T style multiple args */
  103.     int      * cnt_arg;            /* where to stuff list count */
  104.     int        list_cnt;            /* how many in list */
  105.     /* These are used to build return lists */
  106.     char ** strlist;
  107.     int   * intlist;
  108.     long  * longlist;
  109.     float * fltlist;
  110.     double *dbllist;
  111.  
  112.     char   *ncp;            /* remember cp during flag scanning */
  113. #ifndef    QUICK
  114.     char   *cntrl;            /* control string for scanf's */
  115.     char    junk[2];            /* junk buffer for scanf's */
  116.  
  117.     cntrl = "% %1s";            /* control string initialization for
  118.                        scanf's */
  119. #endif
  120.  
  121.     va_start( argl );
  122.     argc = va_arg( argl, int );
  123.     argv = va_arg( argl, char ** );
  124.     format = va_arg( argl, char * );
  125.  
  126.     arg_used = NEW( bool, argc );
  127.     if (arg_used == NULL)
  128.     {
  129.     fprintf(stderr, "malloc failed in scanargs, exiting\n");
  130.     exit(-1);
  131.     }
  132.     else
  133.     {
  134.     for (cnt=0; cnt<argc; cnt++)
  135.         arg_used[cnt] = NO;
  136.     }
  137.  
  138.     check = 0;
  139.     cp = format;
  140.     /* 
  141.      * Skip program name
  142.      */
  143.     while ( *cp != ' ' && *cp != '\t' && *cp != '\n' && *cp != '\0' )
  144.     cp++;
  145.  
  146.     while (*cp)
  147.     {
  148.     required = NO;            /* reset per-arg flags */
  149.     list_of = NO;
  150.     comma_list = NO;
  151.     list_cnt = 0;
  152.     switch (*(cp++))
  153.     {
  154.         default:             /* all other chars */
  155.         break;
  156.         case ' ':            /* separators */
  157.         case '\t':
  158.         case '\n':
  159.         optarg = 0;        /* end of optional arg string */
  160.         break;
  161.  
  162.         case '!':             /* required argument */
  163.         required = YES;
  164.         case '%':             /* not required argument */
  165. reswitch:                /* after finding '*' or ',' */
  166.         switch (typchr = *(cp++))
  167.         {
  168.             case ',':        /* argument is AT&T list of things */
  169.             comma_list = YES;
  170.             case '*':        /* argument is list of things */
  171.             list_of = YES;
  172.             list_cnt = 0;    /* none yet */
  173.             cnt_arg = va_arg( argl, int *);    /* item count * here */
  174.             goto reswitch;    /* try again */
  175.  
  176.             case '$':        /* "rest" of argument list */
  177.             while ( argc > 1 && !arg_used[argc-1] )
  178.                 argc--;    /* find last used argument */
  179.             *va_arg( argl, int * ) = argc;
  180.             break;
  181.  
  182.             case '-':         /* argument is flag */
  183.             if (optarg > 0)
  184.                 ERROR(Format error: flag conditional on flag not allowed);
  185.  
  186.             /* go back to label */
  187.             ncp = cp-1;    /* remember */
  188.             cp -= 3;
  189.             for (excnt = exflag = 0
  190.                 ; *cp != ' ' && !(*cp=='-' &&(cp[-1]=='!'||cp[-1]=='%'));
  191.                 (--cp, excnt++))
  192.             {
  193.                 for (cnt = optarg+1; cnt < argc; cnt++)
  194.                 {
  195.                 /* flags all start with - */
  196.                 if (*argv[cnt] == '-' && !arg_used[cnt] &&
  197.                     !isdigit(argv[cnt][1]))
  198.                     if (*(argv[cnt] + 1) == *cp)
  199.                     {
  200.                     if (*(argv[cnt] + 2) != 0)
  201.                         ERROR (extra flags ignored);
  202.                     if (exflag)
  203.                         ERROR (more than one exclusive flag chosen);
  204.                     exflag++;
  205.                     required = NO;
  206.                     check += cnt;
  207.                     arg_used[cnt] = 1;
  208.                     nopt = cnt;
  209.                     *va_arg( argl, int *) |= (1 << excnt);
  210.                     break;
  211.                     }
  212.                 }
  213.             }
  214.             if (required)
  215.                 ERROR (flag argument missing);
  216.             cp = ncp;
  217.             /* 
  218.              * If none of these flags were found, skip any
  219.              * optional arguments (in the varargs list, too).
  220.              */
  221.             if (!exflag)
  222.             {
  223.                 va_arg( argl, int * );    /* skip the arg, too */
  224.                 while (*++cp && ! isspace(*cp))
  225.                 if (*cp == '!' || *cp == '%')
  226.                 {
  227.                     if ( *++cp == '*' || *cp == ',' )
  228.                     {
  229.                     cp++;
  230.                     va_arg( argl, int * );
  231.                     }
  232.                     /* 
  233.                      * Assume that char * might be a
  234.                      * different size, but that all
  235.                      * other pointers are same size.
  236.                      */
  237.                     if ( *cp == 's' )
  238.                     va_arg( argl, char * );
  239.                     else
  240.                     va_arg( argl, ptr );
  241.                 }
  242.             }
  243.             else
  244.             {
  245.                 optarg = nopt;
  246.                 cp++;    /* skip over - */
  247.             }
  248.  
  249.             break;
  250.  
  251.             case 's':         /* char string */
  252.             case 'd':         /* decimal # */
  253.             case 'o':         /* octal # */
  254.             case 'x':         /* hexadecimal # */
  255.             case 'n':        /* "number" in C syntax */
  256. #ifndef    QUICK
  257.             case 'f':         /* floating # */
  258. #endif
  259.             case 'D':         /* long decimal # */
  260.             case 'O':         /* long octal # */
  261.             case 'X':         /* long hexadecimal # */
  262.             case 'N':        /* long number in C syntax */
  263. #ifndef    QUICK
  264.             case 'F':         /* double precision floating # */
  265. #endif
  266.             for (cnt = optarg+1; cnt < argc; cnt++)
  267.             {
  268.                 ncp = argv[cnt];
  269.  
  270.                 if ( isnum( ncp, typchr, comma_list ) )
  271.                 {
  272.                 if ( typchr == 's' )    /* string? */
  273.                     continue;    /* don't want numbers, then */
  274.                 }
  275.                 else if ( *ncp == '-' )
  276.                 if ( optarg > 0 ) /* end optional args? */
  277.                 {
  278.                     /* Eat the arg, too, if necessary */
  279.                     if ( list_cnt == 0 )
  280.                     if ( typchr == 's' )
  281.                         va_arg( argl, char * );
  282.                     else
  283.                         va_arg( argl, ptr );
  284.                     break;
  285.                 }
  286.                 else
  287.                     continue;
  288.                 else if ( typchr != 's' )
  289.                 continue;    /* not number, keep looking */
  290.                 
  291.                 /* 
  292.                  * Otherwise usable argument may already
  293.                  * be used.  (Must check this after
  294.                  * checking for flag, though.)
  295.                  */
  296.                 if (arg_used[cnt]) continue;
  297.  
  298.                 /* 
  299.                  * If it's a comma-and-or-space-separated
  300.                  * list then count how many, and separate
  301.                  * the list into an array of strings.
  302.                  */
  303.                 if ( comma_list )
  304.                 {
  305.                 register char * s;
  306.                 int pass;
  307.  
  308.                 /* 
  309.                  * On pass 0, just count them.  On
  310.                  * pass 1, null terminate each string 
  311.                  */
  312.                 for ( pass = 0; pass <= 1; pass++ )
  313.                 {
  314.                     for ( s = ncp; *s != '\0'; )
  315.                     {
  316.                     if ( pass )
  317.                         strlist[list_cnt] = s;
  318.                     while ( (c = *s) != '\0' && c != ' ' &&
  319.                         c != '\t' && c != ',' )
  320.                         s++;
  321.                     if ( pass )
  322.                         *s = '\0';
  323.  
  324.                     list_cnt++;    /* count separators */
  325.                     /* 
  326.                      * Two commas in a row give a null
  327.                      * string, but two spaces
  328.                      * don't.  Also skip spaces
  329.                      * after a comma.
  330.                      */
  331.                     if ( c != '\0' )
  332.                         while ( *++s == ' ' || *s == '\t' )
  333.                         ;
  334.                     }
  335.                     if ( pass == 0 )
  336.                     {
  337.                     strlist = NEW( char *, list_cnt );
  338.                     list_cnt = 0;
  339.                     }
  340.                 }
  341.                 }
  342.                 else if ( list_of )
  343.                 list_cnt++;   /* getting them one at a time */
  344.                 /* 
  345.                  * If it's either type of list, then alloc
  346.                  * storage space for the returned values
  347.                  * (except that comma-separated string
  348.                  * lists already are done).
  349.                  */
  350.                 if ( list_of )
  351.                 {
  352.                 if ( list_cnt == 1 || comma_list )
  353.                     switch( typchr )
  354.                     {
  355.                     case 's':
  356.                         if ( !comma_list )
  357.                         strlist = NEW( char *, 1 );
  358.                         aptr = (ptr) &strlist[0];
  359.                         break;
  360.                     case 'n':
  361.                     case 'd':
  362.                     case 'o':
  363.                     case 'x':
  364.                         intlist = NEW( int, list_cnt );
  365.                         aptr = (ptr) &intlist[0];
  366.                         break;
  367.                     case 'N':
  368.                     case 'D':
  369.                     case 'O':
  370.                     case 'X':
  371.                         longlist = NEW( long, list_cnt );
  372.                         aptr = (ptr) &longlist[0];
  373.                         break;
  374.                     case 'f':
  375.                         fltlist = NEW( float, list_cnt );
  376.                         aptr = (ptr) &fltlist[0];
  377.                         break;
  378.                     case 'F':
  379.                         dbllist = NEW( double, list_cnt );
  380.                         aptr = (ptr) &dbllist[0];
  381.                         break;
  382.                     }
  383.                 else
  384.                     switch( typchr )
  385.                     {
  386.                     case 's':
  387.                         strlist = RENEW( char *, strlist,
  388.                                  list_cnt );
  389.                         aptr = (ptr) &strlist[list_cnt-1];
  390.                         break;
  391.                     case 'n':
  392.                     case 'd':
  393.                     case 'o':
  394.                     case 'x':
  395.                         intlist = RENEW( int, intlist,
  396.                                  list_cnt );
  397.                         aptr = (ptr) &intlist[list_cnt-1];
  398.                         break;
  399.                     case 'N':
  400.                     case 'D':
  401.                     case 'O':
  402.                     case 'X':
  403.                         longlist = RENEW( long, longlist,
  404.                                   list_cnt );
  405.                         aptr = (ptr) &longlist[list_cnt-1];
  406.                         break;
  407.                     case 'f':
  408.                         fltlist = RENEW( float, fltlist,
  409.                                  list_cnt );
  410.                         aptr = (ptr) &fltlist[list_cnt-1];
  411.                         break;
  412.                     case 'F':
  413.                         dbllist = RENEW( double, dbllist,
  414.                                  list_cnt );
  415.                         aptr = (ptr) &dbllist[list_cnt-1];
  416.                         break;
  417.                     }
  418.                 }
  419.                 else
  420.                 aptr = va_arg( argl, ptr );
  421.  
  422.                 if ( typchr == 's' )
  423.                 {
  424.                 if ( ! comma_list )
  425.                     *(char **)aptr = ncp;
  426.                 }
  427.                 else
  428.                 {
  429.                 nopt = 0;
  430.                 do {
  431.                     /* 
  432.                      * Need to update aptr if parsing
  433.                      * a comma list
  434.                      */
  435.                     if ( comma_list && nopt > 0 )
  436.                     {
  437.                     ncp = strlist[nopt];
  438.                     switch( typchr )
  439.                     {
  440.                         case 'n':
  441.                         case 'd':
  442.                         case 'o':
  443.                         case 'x':
  444.                         aptr = (ptr) &intlist[nopt];
  445.                         break;
  446.                         case 'N':
  447.                         case 'D':
  448.                         case 'O':
  449.                         case 'X':
  450.                         aptr = (ptr) &longlist[nopt];
  451.                         break;
  452.                         case 'f':
  453.                         aptr = (ptr) &fltlist[nopt];
  454.                         break;
  455.                         case 'F':
  456.                         aptr = (ptr) &dbllist[nopt];
  457.                         break;
  458.                     }
  459.                     }
  460.                     /* 
  461.                      * Do conversion for n and N types
  462.                      */
  463.                     tmpflg = typchr;
  464.                     if (typchr == 'n' || typchr == 'N' )
  465.                     if (*ncp != '0')
  466.                         tmpflg = 'd';
  467.                     else if (*(ncp+1) == 'x' ||
  468.                          *(ncp+1) == 'X')
  469.                     {
  470.                         tmpflg = 'x';
  471.                         ncp += 2;
  472.                     }
  473.                     else
  474.                         tmpflg = 'o';
  475.                     if (typchr == 'N')
  476.                     toupper( tmpflg );
  477.  
  478.  
  479. #ifndef    QUICK
  480.                     cntrl[1] = tmpflg;/* put in conversion */
  481.                     if (sscanf (ncp, cntrl, aptr, junk) != 1)
  482.                     ERROR (Bad numeric argument);
  483. #else
  484.                     if (numcvt(ncp, tmpflg, aptr) != 1)
  485.                     ERROR (Bad numeric argument);
  486. #endif
  487.                 } while ( comma_list && ++nopt < list_cnt );
  488.                 }
  489.                 check += cnt;
  490.                 arg_used[cnt] = 1;
  491.                 required = NO;
  492.                 /*
  493.                  * If not looking for multiple args,
  494.                  * then done, otherwise, keep looking.
  495.                  */
  496.                 if ( !( list_of && !comma_list ) )
  497.                 break;
  498.                 else
  499.                 continue;
  500.             }
  501.             if (required)
  502.                 switch (typchr)
  503.                 {
  504.                 case 'x': 
  505.                 case 'X': 
  506.                     ERROR (missing hexadecimal argument);
  507.                 case 's': 
  508.                     ERROR (missing string argument);
  509.                 case 'o': 
  510.                 case 'O': 
  511.                     ERROR (missing octal argument);
  512.                 case 'd': 
  513.                 case 'D': 
  514.                     ERROR (missing decimal argument);
  515.                 case 'f': 
  516.                 case 'F': 
  517.                     ERROR (missing floating argument);
  518.                 case 'n':
  519.                 case 'N':
  520.                     ERROR (missing numeric argument);
  521.                 }
  522.             if ( list_cnt > 0 )
  523.             {
  524.                 *cnt_arg = list_cnt;
  525.                 switch ( typchr )
  526.                 {
  527.                 case 's':
  528.                     *va_arg( argl, char *** ) = strlist;
  529.                     break;
  530.                 case 'n':
  531.                 case 'd':
  532.                 case 'o':
  533.                 case 'x':
  534.                     *va_arg( argl, int ** ) = intlist;
  535.                     break;
  536.                 case 'N':
  537.                 case 'D':
  538.                 case 'O':
  539.                 case 'X':
  540.                     *va_arg( argl, long ** ) = longlist;
  541.                     break;
  542.                 case 'f':
  543.                     *va_arg( argl, float ** ) = fltlist;
  544.                     break;
  545.                 case 'F':
  546.                     *va_arg( argl, double **) = dbllist;
  547.                     break;
  548.                 }
  549.                 if ( typchr != 's' )
  550.                 free( (char *) strlist );
  551.             }
  552.             else if ( cnt >= argc )
  553.             {
  554.                 /* Fell off end looking, so must eat the arg */
  555.                 if ( typchr == 's' )
  556.                 va_arg( argl, char * );
  557.                 else
  558.                 va_arg( argl, ptr );
  559.             }
  560.             break;
  561.             default:         /* error */
  562.             fprintf (stderr, "error in call to scanargs\n");
  563.             return (0);
  564.         }
  565.     }
  566.     }
  567.  
  568.     /*  Count up empty flags */
  569.     for (cnt=1; cnt<argc; cnt++)
  570.     if (argv[cnt][0] == '-' && argv[cnt][1] == '-' && argv[cnt][2] == 0
  571.         && !arg_used[cnt] )
  572.         check += cnt;
  573.  
  574.     /* sum from 1 to N = n*(n+1)/2 used to count up checks */
  575.     if (check != (((argc - 1) * argc) / 2))
  576.     ERROR (extra arguments not processed);
  577.  
  578.     free(arg_used);
  579.     return (1);
  580.  
  581. error: 
  582.     fprintf (stderr, "usage : ");
  583.     if (*(cp = format) != ' ')
  584.     {
  585.     if ( *cp == '%' )
  586.     {
  587.         /* 
  588.          * This is bogus, but until everyone can agree on a name
  589.          * for (rindex/strrchr) ....
  590.          */
  591.         for ( cp = argv[0]; *cp != '\0'; cp++ )
  592.         ;            /* find the end of the string */
  593.         for ( ; cp > argv[0] && *cp != '/'; cp-- )
  594.         ;            /* find the last / */
  595.         if ( *cp == '/' )
  596.         cp++;
  597.         fprintf( stderr, "%s", cp );
  598.  
  599.         cp = format + 1;        /* reset to where it should be */
  600.     }
  601.     while (putc (*cp++, stderr) != ' ');
  602.     }
  603.     else
  604.     fprintf (stderr, "?? ");
  605.     while (*cp == ' ')
  606.     cp++;
  607.     prformat (cp, NO);
  608.     free(arg_used);
  609.     return 0;
  610. }
  611.  
  612. static char *
  613. prformat (format, recurse)
  614. char   *format;
  615. {
  616.     register char  *cp;
  617.     bool    required, comma_list;
  618.     int    list_of;
  619.  
  620.     cp = format;
  621.     if (recurse)
  622.     putc (' ', stderr);
  623.  
  624.     required = NO;
  625.     list_of = 0;
  626.     comma_list = NO;
  627.     while (*cp)
  628.     {
  629.     switch (*cp)
  630.     {
  631.         default: 
  632.         cp++;
  633.         break;
  634.         case ' ':
  635.         case '\t':
  636.         case '\n':
  637.         putc(*cp, stderr);
  638.         format = ++cp;
  639.         break;
  640.         case '!': 
  641.         required = YES;
  642.         case '%': 
  643. reswitch:
  644.         switch (*++cp)
  645.         {
  646.             case ',':
  647.             comma_list++;
  648.             case '*':
  649.             list_of++;
  650.             goto reswitch;
  651.  
  652.             case '$':        /* "rest" of argument list */
  653.             if (!required)
  654.                 putc ('[', stderr);
  655.             for (; format < cp - 1 - list_of; format++)
  656.                 putc (*format, stderr);
  657.             fputs( " ...", stderr );
  658.             if ( !required )
  659.                 putc( ']', stderr );
  660.             break;
  661.  
  662.             case '-':         /* flags */
  663.             if (!required)
  664.                 putc ('[', stderr);
  665.             putc ('-', stderr);
  666.  
  667.             if (cp - format > 2 + list_of)
  668.                 putc ('{', stderr);
  669.             cp = format;
  670.             while (*cp != '%' && *cp != '!')
  671.                 putc (*cp++, stderr);
  672.             if (cp - format > 1 + list_of)
  673.                 putc ('}', stderr);
  674.             cp += 2;    /* skip !- or %- */
  675.             if (*cp && !isspace(*cp))
  676.                 cp = prformat (cp, YES);
  677.                     /* this is a recursive call */
  678.             if (!required)
  679.                 putc (']', stderr);
  680.             break;
  681.             case 's':         /* char string */
  682.             case 'd':         /* decimal # */
  683.             case 'o':         /* octal # */
  684.             case 'x':         /* hexadecimal # */
  685.             case 'f':         /* floating # */
  686.             case 'D':         /* long decimal # */
  687.             case 'O':         /* long octal # */
  688.             case 'X':         /* long hexadecimal # */
  689.             case 'F':         /* double precision floating # */
  690.             case 'n':        /* numeric arg (C format) */
  691.             case 'N':        /* long numeric arg */
  692.             if (!required)
  693.                 putc ('[', stderr);
  694.             for (; format < cp - 1 - list_of; format++)
  695.                 putc (*format, stderr);
  696.             if ( list_of != 0 )
  697.             {
  698.                 if ( comma_list )
  699.                 putc( ',', stderr );
  700.                 else
  701.                 putc( ' ', stderr );
  702.                 fputs( "...", stderr );
  703.             }
  704.             if (!required)
  705.                 putc (']', stderr);
  706.             break;
  707.             default: 
  708.             break;
  709.         }
  710.         required = NO;
  711.         list_of = NO;
  712.         comma_list = NO;
  713.         if (*cp)        /* check for end of string */
  714.             format = ++cp;
  715.         if (*cp && !isspace(*cp))
  716.             putc (' ', stderr);
  717.     }
  718.     if (recurse && isspace(*cp))
  719.         break;
  720.     }
  721.     if (!recurse)
  722.     putc ('\n', stderr);
  723.     return (cp);
  724. }
  725.  
  726. /* 
  727.  * isnum - determine whether a string MIGHT represent a number.
  728.  * typchr indicates the type of argument we are looking for, and
  729.  * determines the legal character set.  If comma_list is YES, then
  730.  * space and comma are also legal characters.
  731.  */
  732. static bool
  733. isnum( str, typchr, comma_list )
  734. register char * str;
  735. char typchr;
  736. bool comma_list;
  737. {
  738.     register char * allowed, * digits, * cp;
  739.     bool hasdigit = NO;
  740.  
  741.     switch( typchr )
  742.     {
  743.     case 'n':
  744.     case 'N':
  745.         allowed = " \t,+-x0123456789abcdefABCDEF";
  746.         break;
  747.     case 'd':
  748.     case 'D':
  749.         allowed = " \t,+-0123456789";
  750.         break;
  751.     case 'o':
  752.     case 'O':
  753.         allowed = " \t,01234567";
  754.         break;
  755.     case 'x':
  756.     case 'X':
  757.         allowed = " \t,0123456789abcdefABCDEF";
  758.         break;
  759.     case 'f':
  760.     case 'F':
  761.         allowed = " \t,+-eE.0123456789";
  762.         break;
  763.     case 's':            /* only throw out decimal numbers */
  764.     default:
  765.         allowed = " \t,+-.0123456789";
  766.         break;
  767.     }
  768.     digits = allowed;
  769.     while ( *digits != '0' )
  770.     digits++;
  771.     if ( ! comma_list )
  772.     allowed += 3;              /* then don't allow space, tab, comma */
  773.  
  774.     while ( *str != '\0' )
  775.     {
  776.         for ( cp = allowed; *cp != '\0' && *cp != *str; cp++ )
  777.             ;
  778.         if ( *cp == '\0' )
  779.         return NO;             /* if not in allowed chars, not number */
  780.     if ( cp - digits >= 0 )
  781.         hasdigit = YES;
  782.     str++;
  783.     }
  784.     return hasdigit;
  785. }
  786.  
  787. #ifdef    QUICK
  788. numcvt(str, conv, val)
  789. register char *str;
  790. char conv;
  791. int *val;
  792. {
  793.     int base, neg = 0;
  794.     register unsigned int d;
  795.     long retval = 0;
  796.     register char *digits;
  797.     extern char *index();
  798.     if (conv == 'o' || conv == 'O')
  799.     base = 8;
  800.     else if (conv == 'd' || conv == 'D')
  801.     base = 10;
  802.     else if (conv == 'x' || conv == 'X')
  803.     base = 16;
  804.     else
  805.     return 0;
  806.  
  807.     if (*str == '-')
  808.     {
  809.     neg = 1;
  810.     str++;
  811.     }
  812.     while (*str)
  813.     {
  814.     if (*str >= '0' && *str < '0'+base)
  815.         d = *str - '0';
  816.     else if (base == 16 && *str >= 'a' && *str <= 'f')
  817.         d = 10 + *str - 'a';
  818.     else if (base == 16 && *str >= 'A' && *str <= 'F')
  819.         d = 10 + *str - 'A';
  820.     else
  821.         return 0;
  822.     retval = retval*base + d;
  823.     str++;
  824.     }
  825.     if (neg)
  826.     retval = -retval;
  827.     if (conv == 'D' || conv == 'O' || conv == 'X')
  828.     *(long *) val = retval;
  829.     else
  830.     *val = (int) retval;
  831.     return 1;
  832. }
  833. #endif    QUICK
  834.