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