home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume24 / qterm5.0 / part01 / options.c < prev    next >
C/C++ Source or Header  |  1991-03-21  |  11KB  |  464 lines

  1. /*
  2.  * Copyright (c) 1990 Michael A. Cooper.
  3.  * This software may be freely distributed provided it is not sold for 
  4.  * profit and the author is credited appropriately.
  5.  */
  6.  
  7. #ifndef lint
  8. static char *RCSid = "$Header: /am/sol/src/common/usc/lib/libgen/RCS/options.c,v 1.13 90/12/15 18:13:28 mcooper Exp $";
  9. #endif
  10.  
  11. /*
  12.  * $Log:    options.c,v $
  13.  * Revision 1.13  90/12/15  18:13:28  mcooper
  14.  * Add copywrite notice.
  15.  * 
  16.  * Revision 1.12  90/12/15  17:51:46  mcooper
  17.  * Add #ifdef HAS_VARARGS around include for <varargs>.
  18.  * 
  19.  * Revision 1.11  90/11/13  16:39:28  mcooper
  20.  * Add #ifdef HAS_VARARGS for systems without
  21.  * varargs.
  22.  * 
  23.  * Revision 1.10  90/11/13  15:28:01  mcooper
  24.  * - Add OptBool cvtarg routine.
  25.  * - Print default values in HelpOptions() 
  26.  *   when appropriate.
  27.  * 
  28.  * Revision 1.9  90/11/13  15:19:00  mcooper
  29.  * Added supported for options being both
  30.  * SepArg and StickyArg.
  31.  * 
  32.  * Revision 1.8  90/10/30  21:02:31  mcooper
  33.  * Need to exit() if -help is specified.
  34.  * 
  35.  * Revision 1.7  90/10/30  20:24:33  mcooper
  36.  * Fixed bug in UsageString().
  37.  * 
  38.  * Revision 1.6  90/10/30  19:53:05  mcooper
  39.  * Cleaned up some NeXT cc and lint stuff.
  40.  * 
  41.  * Revision 1.5  90/10/30  19:45:31  mcooper
  42.  * Remove unneeded paramter to HelpOptions().
  43.  * 
  44.  * Revision 1.4  90/10/29  14:47:42  mcooper
  45.  * Added real function UsageString() to
  46.  * handle formating usage option strings.
  47.  * 
  48.  * Revision 1.3  90/10/29  14:17:00  mcooper
  49.  * Allow options to be abbreviated 
  50.  * (for all non StickArg options).
  51.  * 
  52.  * Revision 1.2  90/10/26  15:56:11  mcooper
  53.  * - Fix bug in SepArg code that ate arguments.
  54.  * - Cleanup help message.
  55.  * - Add ArgHidden code.
  56.  * 
  57.  * Revision 1.1  90/10/26  14:42:51  mcooper
  58.  * Initial revision
  59.  * 
  60.  */
  61.  
  62. /*
  63.  * Functions to parse options.
  64.  */
  65.  
  66. #include "options.h"
  67. #ifdef HAS_VARARGS
  68. #include <varargs.h>
  69. #endif
  70.  
  71. char *OptionChars = "-+";    /* Default option switching characters */
  72. char *ProgramName = NULL;    /* Name of this program */
  73. char *UsageString();
  74. static int isopt();
  75. static int suppress_help_msg = 0;
  76. char *strcat();
  77.  
  78. /*
  79.  * ParseOptions - Parse options found in argv using "options".
  80.  *          Returns the number of options parsed if there
  81.  *          were no errors.  Returns -1 if an error occurs.
  82.  */
  83. int ParseOptions(options, num_options, argc, argv)
  84.      OptionDescRec *options;
  85.      int num_options;
  86.      int argc;
  87.      char **argv;
  88. {
  89.     OptionDescRec *opt;
  90.     register int x;
  91.     char *p;
  92.  
  93.     if (ProgramName == NULL)
  94.     ProgramName = argv[0];
  95.  
  96. #ifdef OPTION_DEBUG
  97.     (void) printf("Option list is:\n");
  98.     for (x = 0; x < num_options; ++x) {
  99.     opt = &options[x];
  100.     (void) printf("%s\n", opt->option);
  101.     }
  102.  
  103.     (void) printf("Arguments (%d):", argc);
  104.     for (x = 0; x < argc; ++x) {
  105.     (void) printf(" %s", argv[x]);
  106.     }
  107.     (void) printf("\n");
  108. #endif /* OPTION_DEBUG */
  109.  
  110.     for (x = 1; x < argc; ++x) {
  111.     if (strcmp(HELPSTR, argv[x]) == 0) {
  112.         HelpOptions(options, num_options, (char **)NULL);
  113.         exit(0);
  114.     }
  115.  
  116.     opt = FindOption(options, num_options, argv[x]);
  117.     if (opt == NULL) {
  118.         if (isopt(argv[x])) { /* this was suppose to be an option */
  119.         UsageOptions(options, num_options, argv[x]);
  120.         return(-1);
  121.         } else { /* must be end of options */
  122.         break;
  123.         }
  124.     }
  125.  
  126.     if (opt->flags & NoArg) {
  127.         if (!(*opt->cvtarg)(opt, opt->value, FALSE)) {
  128.         UsageOptions(options, num_options, opt->option);
  129.         return(-1);
  130.         }
  131.     } else if (opt->flags & IsArg) {
  132.         if (!(*opt->cvtarg)(opt, opt->option, FALSE)) {
  133.         UsageOptions(options, num_options, opt->option);
  134.         return(-1);
  135.         }
  136.     } else if ((opt->flags & StickyArg) && (opt->flags & SepArg)) {
  137.         p = (char *) &argv[x][strlen(opt->option)];
  138.         if (!*p) {        /*** SepArg ***/
  139.         if (x + 1 >= argc || isopt(argv[x+1])) {
  140.             if (opt->value == (caddr_t) NULL) {
  141.             UserError("%s: Option requires an argument.", argv[x]);
  142.             UsageOptions(options, num_options, opt->option);
  143.             return(-1);
  144.             }
  145.             p = opt->value;
  146.         } else {
  147.             p = argv[++x];
  148.         }
  149.         }
  150.         if (!(*opt->cvtarg)(opt, p, TRUE)) {
  151.         UsageOptions(options, num_options, opt->option);
  152.         return(-1);
  153.         }
  154.     } else if (opt->flags & StickyArg) {
  155.         p = (char *) &argv[x][strlen(opt->option)];
  156.         if (!*p) {
  157.         if (opt->value == (caddr_t) NULL) {
  158.             UserError("%s: Option requires an argument.", argv[x]);
  159.             UsageOptions(options, num_options, opt->option);
  160.             return(-1);
  161.         } else {
  162.             p = opt->value;
  163.         }
  164.         }
  165.         if (!(*opt->cvtarg)(opt, p, TRUE)) {
  166.         UsageOptions(options, num_options, opt->option);
  167.         return(-1);
  168.         }
  169.     } else if (opt->flags & SepArg) {
  170.         if (x + 1 >= argc || isopt(argv[x+1])) {
  171.         if (opt->value == (caddr_t) NULL) {
  172.             UserError("%s: Option requires an argument.", argv[x]);
  173.             UsageOptions(options, num_options, opt->option);
  174.             return(-1);
  175.         } else {
  176.             p = opt->value;
  177.         }
  178.         } else {
  179.         p = argv[++x];
  180.         }
  181.         if (!(*opt->cvtarg)(opt, p, TRUE)) {
  182.         UsageOptions(options, num_options, opt->option);
  183.         return(-1);
  184.         }
  185.     } else if (opt->flags & SkipArg) {
  186.         x += 2;
  187.     } else if (opt->flags & SkipLine) {
  188.         return(x);
  189.     } else if (opt->flags & SkipNArgs) {
  190.         if (opt->value) {
  191.         x += atoi(opt->value);
  192.         } else {
  193.         UserError("Internal Error: No 'value' set for SkipNArgs.");
  194.         return(-1);
  195.         }
  196.     } else {
  197.         UserError("Internal Error: Unknown argument type for option '%s'.",
  198.              opt->option);
  199.         return(-1);
  200.     }
  201.     }
  202.  
  203.     return(x);
  204. }
  205.  
  206. /*
  207.  * FindOption - Find "option" in "options".  Returns NULL if not found.
  208.  */
  209. OptionDescRec *FindOption(options, num_options, option)
  210.      OptionDescRec *options;
  211.      int num_options;
  212.      char *option;
  213. {
  214.     OptionDescRec *opt;
  215.     register int x;
  216.  
  217.     for (x = 0; x < num_options; ++x) {
  218.     opt = &options[x];
  219.     if (opt->flags & StickyArg) {
  220.         if (strncmp(option, opt->option, strlen(opt->option)) == 0)
  221.         return(opt);
  222.     } else {
  223.         if (strncmp(option, opt->option, strlen(option)) == 0)
  224.         return(opt);
  225.     }
  226.     }
  227.  
  228.     return(NULL);
  229. }
  230.  
  231. /*
  232.  * isopt - Is "str" an option string?  Compare first char of str against
  233.  *       list of option switch characters.  Returns TRUE if it is an option.
  234.  */
  235. static int isopt(str)
  236.      char *str;
  237. {
  238.     register char *p;
  239.  
  240.     for (p = OptionChars; p && *p; *++p) {
  241.     if (*str == *p) {
  242.         return(TRUE);
  243.     }
  244.     }
  245.  
  246.     return(FALSE);
  247. }
  248.  
  249. /*
  250.  * UsageOptions - Print a usage message based on "options".
  251.  */
  252. void UsageOptions(options, num_opts, badOption)
  253.      OptionDescRec *options;
  254.      int num_opts;
  255.      char *badOption;
  256. {
  257.     OptionDescRec *opt;
  258.     char *optstr;
  259.     register int x;
  260.     int col, len;
  261.  
  262.     if (badOption) 
  263.     (void) fprintf (stderr, "%s:  bad command line option \"%s\"\r\n\n",
  264.             ProgramName, badOption);
  265.  
  266.     (void) fprintf (stderr, "usage:  %s", ProgramName);
  267.     col = 8 + strlen(ProgramName);
  268.     for (x = 0; x < num_opts; x++) {
  269.     opt = &options[x];
  270.     if (opt->flags & ArgHidden)
  271.         continue;
  272.     optstr = UsageString(opt);
  273.     len = strlen(optstr) + 3;    /* space [ string ] */
  274.     if (col + len > 79) {
  275.         (void) fprintf (stderr, "\r\n   ");  /* 3 spaces */
  276.         col = 3;
  277.     }
  278.     (void) fprintf (stderr, " [%s]", optstr);
  279.     col += len;
  280.     }
  281.  
  282.     if (suppress_help_msg)
  283.     (void) fprintf(stderr, "\r\n\n");
  284.     else
  285.     (void) fprintf(stderr, 
  286.                "\r\n\nType \"%s %s\" for a full description.\r\n\n",
  287.                ProgramName, HELPSTR);
  288. }
  289.  
  290. /*
  291.  * HelpOptions - Print a nice help/usage message based on options.
  292.  */
  293. void HelpOptions(options, num_opts, message)
  294.      OptionDescRec *options;
  295.      int num_opts;
  296.      char **message;
  297. {
  298.     OptionDescRec *opt;
  299.     register int x;
  300.     char **cpp;
  301.  
  302.     suppress_help_msg = 1;
  303.     UsageOptions(options, num_opts, (char *)NULL);
  304.     suppress_help_msg = 0;
  305.  
  306.     (void) fprintf (stderr, "where options include:\n");
  307.     for (x = 0; x < num_opts; x++) {
  308.     opt = &options[x];
  309.     if (opt->flags & ArgHidden)
  310.         continue;
  311.     (void) fprintf (stderr, "    %-28s %s\n", UsageString(opt), 
  312.          (opt->desc) ? opt->desc : "");
  313.     if (opt->value && opt->cvtarg != OptBool)
  314.         (void) fprintf (stderr, "    %-28s [ Default value is %s ]\n", 
  315.                 "", opt->value);
  316.     }
  317.  
  318.     if (message) {
  319.     (void) putc ('\n', stderr);
  320.     for (cpp = message; *cpp; cpp++) {
  321.         (void) fputs (*cpp, stderr);
  322.         (void) putc ('\n', stderr);
  323.     }
  324.     (void) putc ('\n', stderr);
  325.     }
  326. }
  327.  
  328. /*
  329.  * UserError - Print a user error.
  330.  */
  331. #ifdef HAS_VARARGS
  332. void UserError(va_alist)
  333.      va_dcl
  334. {
  335.     va_list args;
  336.     char *fmt;
  337.  
  338.     va_start(args);
  339.     if (ProgramName)
  340.     (void) fprintf(stderr, "%s: ", ProgramName);
  341.     fmt = (char *) va_arg(args, char *);
  342.     (void) vfprintf(stderr, fmt, args);
  343.     va_end(args);
  344.     (void) fprintf(stderr, "\n");
  345. }
  346. #else
  347. void UserError(fmt, a1, a2, a3, a4, a5, a6)
  348.      char *fmt;
  349. {
  350.     if (ProgramName)
  351.     (void) fprintf(stderr, "%s: ", ProgramName);
  352.     (void) fprintf(stderr, fmt, a1, a2, a3, a4, a5, a6);
  353.     (void) fprintf(stderr, "\n");
  354. }
  355. #endif
  356.  
  357. OptBool(opt, value, docopy)
  358.      OptionDescRec *opt;
  359.      caddr_t value;
  360.      int docopy; /*ARGSUSED*/
  361. {
  362.     char *vpp;
  363.  
  364.     *(int *) opt->valp = (int) strtol(value, &vpp, 0);
  365.     if (*vpp) {
  366.     UserError("Invalid integer argument for '%s'.", opt->option);
  367.     return(FALSE);
  368.     } else {
  369.     return(TRUE);
  370.     }
  371. }
  372.  
  373. OptInt(opt, value, docopy)
  374.      OptionDescRec *opt;
  375.      caddr_t value;
  376.      int docopy; /*ARGSUSED*/
  377. {
  378.     char *vpp;
  379.  
  380.     *(int *) opt->valp = (int) strtol(value, &vpp, 0);
  381.     if (*vpp) {
  382.     UserError("Invalid integer argument for '%s'.", opt->option);
  383.     return(FALSE);
  384.     } else {
  385.     return(TRUE);
  386.     }
  387. }
  388.  
  389. OptShort(opt, value, docopy)
  390.      OptionDescRec *opt;
  391.      caddr_t value;
  392.      int docopy; /*ARGSUSED*/
  393. {
  394.     char *vpp;
  395.  
  396.     *(short *) opt->valp = (short) strtol(value, &vpp, 0);
  397.     if (*vpp) {
  398.     UserError("Invalid integer argument for '%s'.", opt->option);
  399.     return(FALSE);
  400.     } else {
  401.     return(TRUE);
  402.     }
  403. }
  404.  
  405. OptLong(opt, value, docopy)
  406.      OptionDescRec *opt;
  407.      caddr_t value;
  408.      int docopy; /*ARGSUSED*/
  409. {
  410.     char *vpp;
  411.  
  412.     *(long *) opt->valp = (long) strtol(value, &vpp, 0);
  413.     if (*vpp) {
  414.     UserError("Invalid integer argument for '%s'.", opt->option);
  415.     return(FALSE);
  416.     } else {
  417.     return(TRUE);
  418.     }
  419. }
  420.  
  421. OptStr(opt, value, docopy)
  422.      OptionDescRec *opt;
  423.      caddr_t value;
  424.      int docopy;
  425. {
  426.     char *p;
  427.  
  428.     if (docopy) {
  429.     if ((p = (char *) malloc((unsigned)strlen(value)+1)) == NULL) {
  430.         UserError("Cannot malloc memory: %s", SYSERR);
  431.         return(FALSE);
  432.     }
  433.     (void) strcpy(p, value);
  434.     } else {
  435.     p = value;
  436.     }
  437.  
  438.     *(char **) opt->valp = p;
  439.  
  440.     return(TRUE);
  441. }
  442.  
  443. static char *UsageString(opt)
  444.      OptionDescRec *opt;
  445. {
  446.     static char buf[BUFSIZ], buf2[BUFSIZ];
  447.  
  448.     (void) sprintf(buf, opt->option);
  449.     (void) strcpy(buf2, "");
  450.     if (opt->usage) {
  451.     (void) sprintf(buf2, "%s%s%s%s",
  452.                ((opt->flags & StickyArg) && 
  453.             !((opt->flags & StickyArg) && (opt->flags & SepArg))) 
  454.                ? "" : " ",
  455.                (opt->value) ? "[" : "",
  456.                opt->usage,
  457.                (opt->value) ? "]" : ""
  458.                );
  459.     }
  460.     (void) strcat(buf, buf2);
  461.  
  462.     return(buf);
  463. }
  464.