home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume10 / parseargs / unix_args.c < prev    next >
C/C++ Source or Header  |  1990-02-16  |  7KB  |  366 lines

  1. #include <useful.h>
  2. #include <parseargs.h>
  3. #include <ctype.h>
  4.  
  5. VERSIONID("$Header: parseargs.c,v 2.1 89/12/30 20:59:48 eric Exp $");
  6.  
  7. /*
  8. **  PARSEARGS -- parse an argument vector, given a description
  9. **
  10. **    Parameters:
  11. **        argv -- pointer to the argument vector as passed to main().
  12. **        argd -- the argument descriptor array.
  13. **
  14. **    Returns:
  15. **        Nothing.
  16. **            Exits with return code 2 if error in args.
  17. **            Exits with return code 1 if system error.
  18. **
  19. **    Side Effects:
  20. **        Converts and stores arguments into variables as
  21. **        described by argd.
  22. **
  23. **    Globals:
  24. **        DefaultPath -- the pathname of a set of places to
  25. **            look for system files, set from the ROOTPATH
  26. **            environment variable, or a default.
  27. **        ProgName -- the name of this program, saved for error
  28. **            messages and the like.
  29. **
  30. **    Author:
  31. **        Eric Allman
  32. **        University of California, Berkeley
  33. */
  34.  
  35. #define ALL_AD        ad = argd; ad->ad_name != '\0'; ad++
  36. #define ALL_DEFS    ad = _DefaultArgs; ad->ad_name != '\0'; ad++
  37.  
  38. char    *ProgName;
  39.  
  40. #ifdef TRACESTUFF
  41. extern BOOL    argTrace ARGS((ARGDESC *, char *, BOOL));
  42. #endif
  43. extern BOOL    argEnd ARGS((ARGDESC *, char *, BOOL));
  44.  
  45. /* default arguments -- apply to all programs */
  46. STATIC ARGDESC    _DefaultArgs[] =
  47. {
  48.      /* name    flags    type        valp        prompt        */
  49. #ifdef TRACESTUFF
  50.     'T',    ARGOPT,    argTrace,    ARBNULL,    "TRACE",
  51. #endif
  52.     '-',    ARGOPT,    argEnd,        ARBNULL,    "ARGS",
  53.     ENDOFARGS
  54. };
  55.  
  56. /* override argument descriptor, if none given by user */
  57. STATIC ARGDESC    _NullArgDesc[] =
  58. {
  59.     ENDOFARGS
  60. };
  61.  
  62. VOID
  63. parseargs(argv, argd)
  64.     char **argv;
  65.     ARGDESC argd[];
  66. {
  67.     register ARGDESC *ad, *list;
  68.     register char **av;
  69.     register char *p;
  70.     int argc;
  71.     BOOL noflags;
  72.     BOOL error;
  73. #ifdef INTERACTIVE
  74.     BOOL shouldprompt;
  75. #endif
  76.     extern char *getenv ARGS((char *));
  77. #ifdef INTERACTIVE
  78.     extern int isatty ARGS((int));
  79. #endif
  80.  
  81.     av = argv++;
  82.     argc = 1;
  83.  
  84.     /* save the name of this program (for error messages) */
  85.     ProgName = *av;
  86.  
  87. #ifdef INTERACTIVE
  88.     /* test to see if we are interactive */
  89.     shouldprompt = (BOOL) isatty(0) && (BOOL) isatty(2);
  90. #endif
  91.  
  92.     /* allow null argument descriptor */
  93.     if (argd == (ARGDESC *) NULL)
  94.         argd = _NullArgDesc;
  95.  
  96.     /* clear out any cruft in the argument descriptor */
  97.     for (ALL_AD)
  98.     {
  99.         ad->ad_flags &= ~ARGGIVEN;
  100.     }
  101.     for (ALL_DEFS)
  102.     {
  103.         ad->ad_flags &= ~ARGGIVEN;
  104.     }
  105.  
  106.     /* run through the argument vector */
  107.     noflags = FALSE;
  108.     error = FALSE;
  109.     list = NULL;
  110.     while ((p = *++av) != CHARNULL)
  111.     {
  112.         if (*p == '-' && !noflags)
  113.         {
  114.             /* flag argument */
  115.             if (*++p == '-' && p[1] == '\0')
  116.             {
  117.                 /* -- indicates end of flags */
  118.                 noflags = TRUE;
  119.                 list = NULL;
  120.                 continue;
  121.             }
  122.             while (*p != '\0')
  123.             {
  124.                 /* find the flag in the list */
  125.                 for (ALL_AD)
  126.                 {
  127.                     if (ad->ad_name == *p)
  128.                         break;
  129.                 }
  130.                 if (ad->ad_name == '\0')
  131.                 {
  132.                     for (ALL_DEFS)
  133.                     {
  134.                         if (ad->ad_name == *p)
  135.                             break;
  136.                     }
  137.                     if (ad->ad_name == '\0')
  138.                     {
  139.                         usrerr("flag -%c unknown", *p++);
  140.                         error = TRUE;
  141.                         continue;
  142.                     }
  143.                 }
  144.  
  145.                 /* move p up to point to the (possible) value */
  146.                 p++;
  147.  
  148.                 /* booleans are special, having no value */
  149.                 if (ad->ad_type == argBool)
  150.                 {
  151.                     *(BOOL *) ad->ad_valp = TRUE;
  152.                     ad->ad_flags |= ARGGIVEN;
  153.                     continue;
  154.                 }
  155. #ifdef TRACESTUFF
  156.                 else if (ad->ad_type == argTrace)
  157.                 {
  158.                     traceset(p);
  159.                     ad->ad_flags |= ARGGIVEN;
  160.                     break;
  161.                 }
  162. #endif
  163.  
  164.                 /* now get the real value */
  165.                 if (*p == '\0')
  166.                 {
  167.                     p = *++av;
  168.                     if (p == CHARNULL || *p == '-')
  169.                     {
  170.                         av--;
  171.                         usrerr("%s required for -%c flag",
  172.                             ad->ad_prompt, ad->ad_name);
  173.                         error = TRUE;
  174.                         break;
  175.                     }
  176.                 }
  177.  
  178.                 /* try to convert the type */
  179.                 if (!(*ad->ad_type)(ad, p, FALSE))
  180.                     error = TRUE;
  181.                 else
  182.                     ad->ad_flags |= ARGGIVEN;
  183.                 if(ad->ad_type == argList)
  184.                     list = ad;
  185.                 else
  186.                     list = NULL;
  187.                 break;
  188.             }
  189.         }
  190.         else
  191.         {
  192.             /* parsing a list of arguments */
  193.             if(list) {
  194.                 if (!argList(list, p, FALSE))
  195.                     error = TRUE;
  196.                 continue;
  197.             }
  198.             /* positional argument */
  199.             for (ALL_AD)
  200.             {
  201.                 if (ad->ad_name == ' ' &&
  202.                     (ad->ad_type == argList ||
  203.                      !BITSET(ARGGIVEN, ad->ad_flags))
  204.                     )
  205.                     break;
  206.             }
  207.             if (ad->ad_name == '\0')
  208.             {
  209.                 usrerr("too any arguments");
  210.                 error = 1;
  211.                 continue;
  212.             }
  213.  
  214.             /* try to convert */
  215.             if (!(*ad->ad_type)(ad, p, FALSE))
  216.                 error = TRUE;
  217.             else
  218.                 ad->ad_flags |= ARGGIVEN;
  219.         }
  220.     }
  221.  
  222.     /* now rescan for missing required arguments */
  223.     for (ALL_AD)
  224.     {
  225.         if (BITSET(ARGREQ, ad->ad_flags) && !BITSET(ARGGIVEN, ad->ad_flags))
  226.         {
  227. #ifdef INTERACTIVE
  228.             /* can we prompt? */
  229.             while (shouldprompt && !error)
  230.             {
  231.                 char buf[MAXINPUTLINE];
  232.  
  233.                 fprintf(stderr, "%s? ", ad->ad_prompt);
  234.                 fflush(stderr);
  235.                 if (fgets(buf, sizeof buf, stdin) == CHARNULL)
  236.                     break;
  237.                 p = strchr(buf, '\n');
  238.                 if (p != CHARNULL)
  239.                     *p = '\0';
  240.                 if (buf[0] == '\0')
  241.                 {
  242.                     usrerr("value required");
  243.                     continue;
  244.                 }
  245.                 if ((*ad->ad_type)(ad, buf, TRUE))
  246.                 {
  247.                     ad->ad_flags |= ARGGIVEN;
  248.                     break;
  249.                 }
  250.             }
  251. #endif
  252.  
  253.             if (!BITSET(ARGGIVEN, ad->ad_flags))
  254.             {
  255.                 /* still didn't get a value... sigh */
  256.                 if (ad->ad_name == ' ')
  257.                 {
  258.                     usrerr("%s required",
  259.                         ad->ad_prompt);
  260.                 }
  261.                 else
  262.                 {
  263.                     usrerr("%s required for -%c flag",
  264.                         ad->ad_prompt, ad->ad_name);
  265.                 }
  266.                 error = TRUE;
  267.             }
  268.         }
  269.     }
  270.  
  271.     if (error)
  272.     {
  273.         usage(argd);
  274.         exit(2);
  275.     }
  276.  
  277.     return argc;
  278. }
  279. /*
  280. **  USAGE -- print a usage message
  281. **
  282. **    Parameters:
  283. **        argd -- the description of expected arguments.
  284. **
  285. **    Returns:
  286. **        none
  287. **
  288. **    Side Effects:
  289. **        prints on stderr
  290. **
  291. **    Globals:
  292. **        MaxOutputLine -- the length of the maximum output line
  293. **            allowed before wrapping.  This should be fetched
  294. **            from the terminal driver on systems that support
  295. **            this sort of thing.
  296. */
  297.  
  298. int    MaxOutputLine = 72;
  299.  
  300. VOID
  301. usage(argd)
  302.     ARGDESC *argd;
  303. {
  304.     register ARGDESC *ad;
  305.     int ll;
  306.     int pl;
  307.  
  308.     fprintf(stderr, "Usage: %s", ProgName);
  309.     ll = strlen(ProgName) + 7;
  310.  
  311.     for (ALL_AD)
  312.     {
  313.         /* don't display hidden arguments */
  314.         if (BITSET(ARGHIDDEN, ad->ad_flags))
  315.             continue;
  316.  
  317.         /* figure out how wide this parameter is (for printing) */
  318.         if (ad->ad_name != ' ')
  319.         {
  320.             pl = 2;                    /* -x */
  321.             if (ad->ad_type != argBool)
  322.                 pl += strlen(ad->ad_prompt) + 3;/* _< > */
  323.         }
  324.         else
  325.         {
  326.             pl = strlen(ad->ad_prompt) + 2;        /* < > */
  327.         }
  328.         if (!BITSET(ARGREQ, ad->ad_flags))
  329.             pl += 2;                /* [ ] */
  330.         if (ad->ad_type == argList)            /* ... */
  331.             pl += 3;
  332.         pl += 1;                    /* leading sp */
  333.  
  334.         /* see if this will fit */
  335.         if (ll + pl > MaxOutputLine)
  336.         {
  337.             /* no... start a new line */
  338.             fprintf(stderr, " \\\n\t");
  339.             ll = 7;
  340.         }
  341.         else
  342.         {
  343.             /* yes... just throw in a space */
  344.             fprintf(stderr, " ");
  345.         }
  346.         ll += pl;
  347.  
  348.         /* show the argument */
  349.         if (!BITSET(ARGREQ, ad->ad_flags))
  350.             fprintf(stderr, "[");
  351.         if (ad->ad_name != ' ')
  352.         {
  353.             fprintf(stderr, "-%c", ad->ad_name);
  354.             if (ad->ad_type != argBool)
  355.                 fprintf(stderr, " ");
  356.         }
  357.         if (ad->ad_name == ' ' || ad->ad_type != argBool)
  358.             fprintf(stderr, "<%s>", ad->ad_prompt);
  359.         if (!BITSET(ARGREQ, ad->ad_flags))
  360.             fprintf(stderr, "]");
  361.         if (ad->ad_type == argList)
  362.             fprintf(stderr, "...");
  363.     }
  364.     fprintf(stderr, "\n");
  365. }
  366.