home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume10 / parseargs / amiga_args.c next >
C/C++ Source or Header  |  1990-02-16  |  8KB  |  388 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 -- the argument vector as passed to main().
  12. **        argd -- the argument descriptor array.
  13. **
  14. **    Returns:
  15. **        Nothing
  16. **            Exits with return code 20 if error in args.
  17. **            Exits with return code 10 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.     BOOL noflags;
  71.     BOOL error;
  72.     extern char *getenv ARGS((char *));
  73.  
  74.     av = argv++;
  75.     /* save the name of this program (for error messages) */
  76.     ProgName = *av;
  77.  
  78.     /* allow null argument descriptor */
  79.     if (argd == (ARGDESC *) NULL)
  80.         argd = _NullArgDesc;
  81.  
  82.     /* clear out any cruft in the argument descriptor */
  83.     for (ALL_AD)
  84.     {
  85.         ad->ad_flags &= ~ARGGIVEN;
  86.     }
  87.     for (ALL_DEFS)
  88.     {
  89.         ad->ad_flags &= ~ARGGIVEN;
  90.     }
  91.  
  92.     /* run through the argument vector */
  93.     noflags = FALSE;
  94.     error = FALSE;
  95.     ad = NULL; /* No argument requested */
  96.     list = NULL;
  97.     while (*++av != CHARNULL)
  98.     {
  99.         /* Previous keyword required a value */
  100.         if(ad)
  101.         {
  102.             /* try to convert the type */
  103.             if (!(*ad->ad_type)(ad, *av, FALSE))
  104.                 error = TRUE;
  105.             else
  106.                 ad->ad_flags |= ARGGIVEN;
  107.             ad = NULL;
  108.             continue;
  109.         }
  110.         
  111.         /* If looking for keywords, see if this is one */
  112.         if(!noflags) {
  113.             for(ALL_AD)
  114.                 if(match(*av, ad->ad_prompt) == 0)
  115.                     break;
  116.             if(ad->ad_name == '\0')
  117.                 for(ALL_DEFS)
  118.                     if(match(*av, ad->ad_prompt) == 0)
  119.                         break;
  120.         }
  121.         if(ad->ad_name == '\0')
  122.             ad = NULL;
  123.  
  124.         /* If we have a keyword here */
  125.         if(!noflags && ad)
  126.         {
  127.             list = NULL;
  128.             p = strchr(*av, '=');
  129.             if(p) /* matched NAME=VALUE */
  130.             {
  131.                 p++;
  132.                 /* try to convert the type */
  133.                 if (!(*ad->ad_type)(ad, p, FALSE))
  134.                     error = TRUE;
  135.                 else
  136.                     ad->ad_flags |= ARGGIVEN;
  137.                 ad = NULL;
  138.             }
  139.             else
  140.             {
  141.                 if (ad->ad_type == argBool)
  142.                 {
  143.                     *(BOOL *) ad->ad_valp = TRUE;
  144.                     ad->ad_flags |= ARGGIVEN;
  145.                     ad = NULL;
  146.                 }
  147.                 else if (ad->ad_type == argEnd)
  148.                 {
  149.                     noflags = TRUE;
  150.                     ad->ad_flags |= ARGGIVEN;
  151.                     ad = NULL;
  152.                 }
  153.                 else if (ad->ad_type == argList)
  154.                 {
  155.                     list = ad;
  156.                     ad = NULL;
  157.                 }
  158.             }
  159.         }
  160.         else /* it's a positional argument */
  161.         {
  162.             if(list) {
  163.                 if (!argList(list, *av, FALSE))
  164.                     error = TRUE;
  165.                 list->ad_flags |= ARGGIVEN;
  166.                 continue;
  167.             }
  168.             else
  169.             {
  170.                 for (ALL_AD)
  171.                 {
  172.                     if (ad->ad_name == ' ' &&
  173.                         (ad->ad_type == argList ||
  174.                          !BITSET(ARGGIVEN, ad->ad_flags))
  175.                        )
  176.                         break;
  177.                 }
  178.                 if (ad->ad_name == '\0')
  179.                 {
  180.                     usrerr("too any arguments");
  181.                     error = TRUE;
  182.                     ad = NULL;
  183.                 }
  184.                 else
  185.                 {
  186.                     /* try to convert */
  187.                     if (!(*ad->ad_type)(ad, *av, FALSE))
  188.                         error = TRUE;
  189.                     else
  190.                         ad->ad_flags |= ARGGIVEN;
  191.                     ad = NULL;
  192.                 }
  193.             }
  194.         }
  195.     }
  196.  
  197.     /* If last argument was a keyword and required an option
  198.      * then complain about it
  199.      */
  200.     if(ad) {
  201.         usrerr("missing argument for %s", ad->ad_prompt);
  202.         error = TRUE;
  203.     }
  204.     *argv = NULL;
  205.  
  206.     /* now rescan for missing required arguments */
  207.     for (ALL_AD)
  208.     {
  209.         if (BITSET(ARGREQ, ad->ad_flags) && !BITSET(ARGGIVEN, ad->ad_flags))
  210.         {
  211.             if (!BITSET(ARGGIVEN, ad->ad_flags))
  212.             {
  213.                 /* still didn't get a value... sigh */
  214.                 if (ad->ad_name == ' ')
  215.                 {
  216.                     usrerr("%s required",
  217.                         ad->ad_prompt);
  218.                 }
  219.                 else
  220.                 {
  221.                     usrerr("%s required for -%c flag",
  222.                         ad->ad_prompt, ad->ad_name);
  223.                 }
  224.                 error = TRUE;
  225.             }
  226.         }
  227.     }
  228.  
  229.     if (error)
  230.     {
  231.         usage(argd);
  232.         exit(20);
  233.     }
  234. }
  235. /*
  236. **  USAGE -- print a usage message
  237. **
  238. **    Parameters:
  239. **        argd -- the description of expected arguments.
  240. **
  241. **    Returns:
  242. **        none
  243. **
  244. **    Side Effects:
  245. **        prints on stderr
  246. **
  247. **    Globals:
  248. **        MaxOutputLine -- the length of the maximum output line
  249. **            allowed before wrapping.  This should be fetched
  250. **            from the terminal driver on systems that support
  251. **            this sort of thing.
  252. */
  253.  
  254. int    MaxOutputLine = 72;
  255.  
  256. VOID
  257. usage(argd)
  258.     ARGDESC *argd;
  259. {
  260.     register ARGDESC *ad;
  261.     int ll;
  262.     int pl;
  263.  
  264.     fprintf(stderr, "Usage: %s", ProgName);
  265.     ll = strlen(ProgName) + 7;
  266.  
  267.     for (ALL_AD)
  268.     {
  269.         char keyword[BUFSIZ];
  270.         char name[BUFSIZ];
  271.         int i, j;
  272.  
  273.         j = 0;
  274.         for(i = 0; ad->ad_prompt[i]; i++) {
  275.             if(isupper(ad->ad_prompt[i])) {
  276.                 keyword[j++] = ad->ad_prompt[i];
  277.                 name[i] = tolower(ad->ad_prompt[i]);
  278.             }
  279.             else
  280.                 name[i] = ad->ad_prompt[i];
  281.         }
  282.         name[i] = 0;
  283.         if(j > 0)
  284.             keyword[j] = 0;
  285.         else
  286.             strcpy(keyword, ad->ad_prompt);
  287.  
  288.         /* don't display hidden arguments */
  289.         if (BITSET(ARGHIDDEN, ad->ad_flags))
  290.             continue;
  291.  
  292.         /* figure out how wide this parameter is (for printing) */
  293.         if (ad->ad_name != ' ')
  294.         {
  295.             pl = strlen(keyword);
  296.             if (ad->ad_type != argBool)
  297.                 pl += strlen(name) + 3;/* _< > */
  298.         }
  299.         else
  300.         {
  301.             pl = strlen(name) + 2;        /* < > */
  302.         }
  303.         if (!BITSET(ARGREQ, ad->ad_flags))
  304.             pl += 2;                /* [ ] */
  305.         if (ad->ad_type == argList)
  306.             pl += 3;            /* ... */
  307.         pl += 1;                    /* leading sp */
  308.  
  309.         /* see if this will fit */
  310.         if (ll + pl > MaxOutputLine)
  311.         {
  312.             /* no... start a new line */
  313.             fprintf(stderr, " +\n\t");
  314.             ll = 7;
  315.         }
  316.         else
  317.         {
  318.             /* yes... just throw in a space */
  319.             fprintf(stderr, " ");
  320.         }
  321.         ll += pl;
  322.  
  323.         /* show the argument */
  324.         if (!BITSET(ARGREQ, ad->ad_flags))
  325.             fprintf(stderr, "[");
  326.         if (ad->ad_name != ' ')
  327.         {
  328.             fprintf(stderr, "%s", keyword);
  329.             if (ad->ad_type != argBool)
  330.                 fprintf(stderr, " ");
  331.         }
  332.         if (ad->ad_name == ' ' || ad->ad_type != argBool)
  333.             fprintf(stderr, "<%s>", name);
  334.         if (!BITSET(ARGREQ, ad->ad_flags))
  335.             fprintf(stderr, "]");
  336.         if (ad->ad_type == argList)
  337.             fprintf(stderr, "...");
  338.     }
  339.     fprintf(stderr, "\n");
  340. }
  341.  
  342. /* match(s1, s2)
  343. **
  344. ** Compares two strings, returning >0, <0, or =0 if they match. First a
  345. ** check is done on letters capitalised in the second word, and if this
  346. ** fails then a complete match is done. Case is ignored in both matches.
  347. ** This lets you use case to indicate what part of a keyword is significant.
  348. */
  349. int match(candidate, target)
  350. char *target, *candidate;
  351. {
  352.     int i, j;
  353.     char c;
  354.  
  355.     i = j = 0;
  356.  
  357.     while(target[i] || candidate[i]) {
  358.         while(islower(target[i])) i++;
  359.         if(!target[i]) {
  360.             if(!candidate[j]) return 0;
  361.             return dictcmp(target, candidate);
  362.         }
  363.         c = islower(candidate[j])
  364.             ? toupper(candidate[j])
  365.             : candidate[j];
  366.         if(target[i] != c) return dictcmp(target, candidate);
  367.         i++;
  368.         j++;
  369.     }
  370.     return 0;
  371. }
  372.  
  373. int dictcmp(s1, s2)    /* "Dictionary" comparison of two strings */
  374. char *s1, *s2;
  375. {
  376.     char c1, c2;
  377.  
  378.     while(*s1 || *s2) {
  379.         c1 = *s1++;
  380.         c2 = *s2++;
  381.         if(!c1 || !c2) return c1 - c2;
  382.         if(isupper(c1)) c1 = tolower(c1);
  383.         if(isupper(c2)) c2 = tolower(c2);
  384.         if(c1 != c2) return c1 - c2;
  385.     }
  386.     return 0;
  387. }
  388.