home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 446.lha / parseargs / unix_args.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-12-06  |  8.3 KB  |  438 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. #define HANDLE(a,n,f) ((*(a)->ad_type)(a,n,f))
  39.  
  40. char    *ProgName;
  41.  
  42. extern BOOL    argEnd ARGS((ARGDESC *, char *, BOOL));
  43.  
  44. /* default arguments -- apply to all programs */
  45. STATIC ARGDESC    _DefaultArgs[] =
  46. {
  47.      /* name    flags    type        valp        prompt        */
  48.     '-',    ARGOPT,    argEnd,        ARBNULL,    "ARGS",
  49.     ENDOFARGS
  50. };
  51.  
  52. /* override argument descriptor, if none given by user */
  53. STATIC ARGDESC    _NullArgDesc[] =
  54. {
  55.     ENDOFARGS
  56. };
  57.  
  58. VOID
  59. parseargs(argv, argd)
  60.     char **argv;
  61.     ARGDESC argd[];
  62. {
  63.     register ARGDESC *ad, *list;
  64.     register char **av;
  65.     register char *p;
  66.     int argc;
  67.     BOOL noflags;
  68.     BOOL error;
  69.     extern char *getenv ARGS((char *));
  70.  
  71.     av = argv++;
  72.     argc = 1;
  73.  
  74.     /* save the name of this program (for error messages) */
  75.     ProgName = *av;
  76.  
  77.     /* allow null argument descriptor */
  78.     if (argd == (ARGDESC *) NULL)
  79.         argd = _NullArgDesc;
  80.  
  81.     /* clear out any cruft in the argument descriptor */
  82.     for (ALL_AD)
  83.     {
  84.         ad->ad_flags &= ~ARGGIVEN;
  85.     }
  86.     for (ALL_DEFS)
  87.     {
  88.         ad->ad_flags &= ~ARGGIVEN;
  89.     }
  90.  
  91.     /* run through the argument vector */
  92.     noflags = FALSE;
  93.     error = FALSE;
  94.     list = NULL;
  95.     while ((p = *++av) != CHARNULL)
  96.     {
  97.         if(*p == '+' && !noflags)
  98.         {
  99.             char *s;
  100.             
  101.             s = strchr(p, '=');
  102.             if(s) {
  103.                 *s++ = 0;
  104.             }
  105.  
  106.             if(*++p == '+' && p[1] == '\0')
  107.             {
  108.                 /* ++ indicates end of flags */
  109.                 noflags = TRUE;
  110.                 list = NULL;
  111.                 continue;
  112.             }
  113.             for(ALL_AD)
  114.             {
  115.                 if(match(p, ad->ad_prompt) == 0)
  116.                     break;
  117.             }
  118.             if (ad->ad_name == '\0')
  119.             {
  120.                 for (ALL_DEFS)
  121.                 {
  122.                     if(match(p, ad->ad_prompt) == 0)
  123.                         break;
  124.                 }
  125.                 if (ad->ad_name == '\0')
  126.                 {
  127.                     usrerr("option %s unknown", p);
  128.                     error = TRUE;
  129.                     continue;
  130.                 }
  131.             }
  132.  
  133.             /* booleans are special, having no value */
  134.             if (ad->ad_type == argBool)
  135.             {
  136.                 if(s) /* Error... no arg to bool */
  137.                 {
  138.                     usrerr("option %s takes no arguments", p);
  139.                     error = TRUE;
  140.                     continue;
  141.                 }
  142.                 *(BOOL *) ad->ad_valp = TRUE;
  143.                 ad->ad_flags |= ARGGIVEN;
  144.                 continue;
  145.             }
  146.  
  147.             /* now get the real value */
  148.             if (!s)
  149.             {
  150.                 s = *++av;
  151.                 if (s == CHARNULL || *s == '-' || *s == '+')
  152.                 {
  153.                     av--;
  154.                     usrerr("option %s requires an argument",
  155.                         ad->ad_prompt);
  156.                     error = TRUE;
  157.                     continue;
  158.                 }
  159.             }
  160.  
  161.             /* try to convert the type */
  162.             if (!HANDLE(ad, s, FALSE))
  163.                 error = TRUE;
  164.             else
  165.                 ad->ad_flags |= ARGGIVEN;
  166.             if(ad->ad_flags & ARGLIST)
  167.                 list = ad;
  168.             else
  169.                 list = NULL;
  170.             continue;
  171.         }
  172.         else if (*p == '-' && !noflags)
  173.         {
  174.             /* flag argument */
  175.             if (*++p == '-' && p[1] == '\0')
  176.             {
  177.                 /* -- indicates end of flags */
  178.                 noflags = TRUE;
  179.                 list = NULL;
  180.                 continue;
  181.             }
  182.             while (*p != '\0')
  183.             {
  184.                 /* find the flag in the list */
  185.                 for (ALL_AD)
  186.                 {
  187.                     if (ad->ad_name == *p)
  188.                         break;
  189.                 }
  190.                 if (ad->ad_name == '\0')
  191.                 {
  192.                     for (ALL_DEFS)
  193.                     {
  194.                         if (ad->ad_name == *p)
  195.                             break;
  196.                     }
  197.                     if (ad->ad_name == '\0')
  198.                     {
  199.                         usrerr("flag -%c unknown", *p++);
  200.                         error = TRUE;
  201.                         continue;
  202.                     }
  203.                 }
  204.  
  205.                 /* move p up to point to the (possible) value */
  206.                 p++;
  207.  
  208.                 /* booleans are special, having no value */
  209.                 if (ad->ad_type == argBool)
  210.                 {
  211.                     *(BOOL *) ad->ad_valp = TRUE;
  212.                     ad->ad_flags |= ARGGIVEN;
  213.                     continue;
  214.                 }
  215.  
  216.                 /* now get the real value */
  217.                 if (*p == '\0')
  218.                 {
  219.                     p = *++av;
  220.                     if (p == CHARNULL || *p == '-' || *p == '+')
  221.                     {
  222.                         av--;
  223.                         usrerr("%s required for -%c flag",
  224.                             ad->ad_prompt, ad->ad_name);
  225.                         error = TRUE;
  226.                         break;
  227.                     }
  228.                 }
  229.  
  230.                 /* try to convert the type */
  231.                 if (!HANDLE(ad, p, FALSE))
  232.                     error = TRUE;
  233.                 else
  234.                     ad->ad_flags |= ARGGIVEN;
  235.                 if(ad->ad_flags & ARGLIST)
  236.                     list = ad;
  237.                 else
  238.                     list = NULL;
  239.                 break;
  240.             }
  241.         }
  242.         else
  243.         {
  244.             /* parsing a list of arguments */
  245.             if(list) {
  246.                 if (!HANDLE(list, p, FALSE))
  247.                     error = TRUE;
  248.                 continue;
  249.             }
  250.             /* positional argument */
  251.             for (ALL_AD)
  252.             {
  253.                 if (ad->ad_name == ' ' &&
  254.                     ( (ad->ad_flags & ARGLIST) ||
  255.                      !BITSET(ARGGIVEN, ad->ad_flags))
  256.                     )
  257.                     break;
  258.             }
  259.             if (ad->ad_name == '\0')
  260.             {
  261.                 usrerr("too any arguments");
  262.                 error = 1;
  263.                 continue;
  264.             }
  265.  
  266.             /* try to convert */
  267.             if (!HANDLE(ad, p, FALSE))
  268.                 error = TRUE;
  269.             else
  270.                 ad->ad_flags |= ARGGIVEN;
  271.         }
  272.     }
  273.  
  274.     /* now rescan for missing required arguments */
  275.     for (ALL_AD)
  276.     {
  277.         if (BITSET(ARGREQ, ad->ad_flags) && !BITSET(ARGGIVEN, ad->ad_flags))
  278.         {
  279.             if (!BITSET(ARGGIVEN, ad->ad_flags))
  280.             {
  281.                 /* still didn't get a value... sigh */
  282.                 if (ad->ad_name == ' ')
  283.                 {
  284.                     usrerr("%s required",
  285.                         ad->ad_prompt);
  286.                 }
  287.                 else
  288.                 {
  289.                     usrerr("%s required for -%c flag",
  290.                         ad->ad_prompt, ad->ad_name);
  291.                 }
  292.                 error = TRUE;
  293.             }
  294.         }
  295.     }
  296.  
  297.     if (error)
  298.     {
  299.         usage(argd);
  300.         exit(2);
  301.     }
  302.  
  303.     cleanup_lists(argd);
  304. }
  305. /*
  306. **  USAGE -- print a usage message
  307. **
  308. **    Parameters:
  309. **        argd -- the description of expected arguments.
  310. **
  311. **    Returns:
  312. **        none
  313. **
  314. **    Side Effects:
  315. **        prints on stderr
  316. **
  317. **    Globals:
  318. **        MaxOutputLine -- the length of the maximum output line
  319. **            allowed before wrapping.  This should be fetched
  320. **            from the terminal driver on systems that support
  321. **            this sort of thing.
  322. */
  323.  
  324. int    MaxOutputLine = 72;
  325.  
  326. VOID
  327. usage(argd)
  328.     ARGDESC *argd;
  329. {
  330.     register ARGDESC *ad;
  331.     int ll;
  332.     int pl;
  333.  
  334.     fprintf(stderr, "Usage: %s", ProgName);
  335.     ll = strlen(ProgName) + 7;
  336.  
  337.     for (ALL_AD)
  338.     {
  339.         /* don't display hidden arguments */
  340.         if (BITSET(ARGHIDDEN, ad->ad_flags))
  341.             continue;
  342.  
  343.         /* figure out how wide this parameter is (for printing) */
  344.         if (ad->ad_name != ' ')
  345.         {
  346.             pl = 2;                    /* -x */
  347.             pl += strlen(ad->ad_prompt) + 3;/* _< >  or _( ) */
  348.         }
  349.         else
  350.         {
  351.             pl = strlen(ad->ad_prompt) + 2;        /* < > */
  352.         }
  353.         if (!BITSET(ARGREQ, ad->ad_flags))
  354.             pl += 2;                /* [ ] */
  355.         if (ad->ad_flags & ARGLIST)            /* ... */
  356.             pl += 3;
  357.         pl += 1;                    /* leading sp */
  358.  
  359.         /* see if this will fit */
  360.         if (ll + pl > MaxOutputLine)
  361.         {
  362.             /* no... start a new line */
  363.             fprintf(stderr, " \\\n\t");
  364.             ll = 7;
  365.         }
  366.         else
  367.         {
  368.             /* yes... just throw in a space */
  369.             fprintf(stderr, " ");
  370.         }
  371.         ll += pl;
  372.  
  373.         /* show the argument */
  374.         if (!BITSET(ARGREQ, ad->ad_flags))
  375.             fprintf(stderr, "[");
  376.         if (ad->ad_name != ' ')
  377.         {
  378.             fprintf(stderr, "-%c ", ad->ad_name);
  379.         }
  380.         if (ad->ad_name == ' ' || ad->ad_type != argBool)
  381.             fprintf(stderr, "<%s>", ad->ad_prompt);
  382.         else
  383.             fprintf(stderr, "(%s)", ad->ad_prompt);
  384.         if (!BITSET(ARGREQ, ad->ad_flags))
  385.             fprintf(stderr, "]");
  386.         if (ad->ad_flags & ARGLIST)
  387.             fprintf(stderr, "...");
  388.     }
  389.     fprintf(stderr, "\n");
  390. }
  391.  
  392. /* match(s1, s2)
  393. **
  394. ** Compares two strings, returning >0, <0, or =0 if they match. First a
  395. ** check is done on letters capitalised in the second word, and if this
  396. ** fails then a complete match is done. Case is ignored in both matches.
  397. ** This lets you use case to indicate what part of a keyword is significant.
  398. */
  399. int match(candidate, target)
  400. char *target, *candidate;
  401. {
  402.     int i, j;
  403.     char c;
  404.  
  405.     i = j = 0;
  406.  
  407.     while(target[i] || candidate[i]) {
  408.         while(islower(target[i])) i++;
  409.         if(!target[i]) {
  410.             if(!candidate[j]) return 0;
  411.             return dictcmp(target, candidate);
  412.         }
  413.         c = islower(candidate[j])
  414.             ? toupper(candidate[j])
  415.             : candidate[j];
  416.         if(target[i] != c) return dictcmp(target, candidate);
  417.         i++;
  418.         j++;
  419.     }
  420.     return 0;
  421. }
  422.  
  423. int dictcmp(s1, s2)    /* "Dictionary" comparison of two strings */
  424. char *s1, *s2;
  425. {
  426.     char c1, c2;
  427.  
  428.     while(*s1 || *s2) {
  429.         c1 = *s1++;
  430.         c2 = *s2++;
  431.         if(!c1 || !c2) return c1 - c2;
  432.         if(isupper(c1)) c1 = tolower(c1);
  433.         if(isupper(c2)) c2 = tolower(c2);
  434.         if(c1 != c2) return c1 - c2;
  435.     }
  436.     return 0;
  437. }
  438.