Exemplo n.º 1
0
Arquivo: options.c Projeto: mej/libast
/**
 * Check for a match to the current option.
 *
 * This function does some initial parsing, then calls the appropriate
 * sub-function to look for matches.
 *
 * @param opt The argument string.
 * @return    TRUE if a match is found, FALSE otherwise.
 *
 * @see @link DOXGRP_OPT Command Line Option Parser @endlink, spifopt_parse(), find_long_option(),
 *      find_short_option()
 * @ingroup DOXGRP_OPT
 */
static spif_bool_t
is_valid_option(spif_charptr_t opt)
{
    REQUIRE_RVAL(opt != NULL, FALSE);

    if (*opt != '-') {
        return FALSE;
    }
    opt++;
    if (*opt == '-') {
        opt++;
        if (find_long_option(opt) >= 0) {
            return TRUE;
        }
    } else {
        if (find_short_option(*opt) >= 0) {
            return TRUE;
        }
    }
    return FALSE;
}
Exemplo n.º 2
0
Arquivo: options.c Projeto: mej/libast
/**
 * Parse the command line arguments for options.
 *
 * This function iterates through the command line arguments looking
 * for options which have been defined.  Each option encountered is
 * handled according to its type.
 *
 * @param argc The number of arguments.
 * @param argv The array of argument strings.
 *
 * @see @link DOXGRP_OPT Command Line Option Parser @endlink
 * @ingroup DOXGRP_OPT
 */
void
spifopt_parse(int argc, char *argv[])
{
    spif_int32_t i, j;
    spif_charptr_t opt;

    REQUIRE(argc > 1);
    REQUIRE(argv != NULL);

    /* Process each command line arg one-by-one. */
    for (i = 1, opt = SPIF_CHARPTR(argv[1]); i < argc; ) {
        spif_charptr_t val_ptr = NULL;
        spif_char_t islong = 0, hasequal = 0;

        D_OPTIONS(("argv[%d] == \"%s\", opt == \"%s\"\n", i, argv[i], opt));

        if (SPIF_PTR_ISNULL(opt)) {
            /* NEXT_ARG(); */
            break;
        } else if (opt == SPIF_CHARPTR(argv[i])) {
            /* If it's not an option, skip it. */
            if (*opt != '-') {
                NEXT_ARG();
            } else {
                opt++;
            }
        }

        /* If the second character is also a hyphen, it's a long option. */
        if (*opt == '-') {
            islong = 1;
            /* Skip the leading "--" */
            opt++;
            D_OPTIONS(("Long option detected\n"));
            if ((j = find_long_option(opt)) == -1) {
                NEXT_ARG();
            }
        } else {
            if ((j = find_short_option(*opt)) == -1) {
                NEXT_LETTER();
            }
        }
        if (!SPIFOPT_FLAGS_IS_SET(SPIFOPT_SETTING_PREPARSE) && SPIFOPT_FLAGS_IS_SET(SPIFOPT_SETTING_REMOVE_ARGS)) {
            argv[i] = NULL;
        }

        /* If a value was passed to this option, set val_ptr to point to it. */
        if (islong) {
            val_ptr = find_value_long(SPIF_CHARPTR(opt), SPIF_CHARPTR(argv[i + 1]), &hasequal);
        } else {
            val_ptr = find_value_short(opt, SPIF_CHARPTR(argv[i + 1]));
        }

        /* Boolean options may or may not have a value... */
        if (val_ptr) {
            if (SPIFOPT_OPT_IS_BOOLEAN(j) && !is_boolean_value(val_ptr)) {
                val_ptr = NULL;
            } else if (SPIFOPT_OPT_IS_ABSTRACT(j) && is_valid_option(val_ptr)) {
                val_ptr = NULL;
            }
        }
        if (val_ptr) {
            if (val_ptr == SPIF_CHARPTR(argv[i + 1])) {
                i++;
                opt += strlen((char *) opt);
            }
        }

        /* If this option is deprecated, print a warning before continuing. */
        if (SPIFOPT_OPT_IS_DEPRECATED(j)) {
            spif_str_t warn;

            warn = spif_str_new_from_buff(SPIF_CHARPTR("The "), 128);
            if (SPIFOPT_OPT_SHORT(j)) {
                spif_str_append_char(warn, '-');
                spif_str_append_char(warn, SPIFOPT_OPT_SHORT(j));
                spif_str_append_from_ptr(warn, SPIF_CHARPTR(" / --"));
            } else {
                spif_str_append_from_ptr(warn, SPIF_CHARPTR("--"));
            }
            spif_str_append_from_ptr(warn, SPIFOPT_OPT_LONG(j));
            spif_str_append_from_ptr(warn, SPIF_CHARPTR(" option is deprecated and should not be used.\n"));
            libast_print_warning((char *) SPIF_STR_STR(warn));
            spif_str_del(warn);
        }

        /* Make sure that options which require a parameter have them. */
        if (SPIFOPT_OPT_NEEDS_VALUE(j)) {
            if (!val_ptr) {
                if (islong) {
                    libast_print_error("long option --%s requires a%s value\n", SPIFOPT_OPT_LONG(j),
                                (SPIFOPT_OPT_IS_INTEGER(j)
                                 ? ("n integer")
                                 : (SPIFOPT_OPT_IS_STRING(j)
                                    ? " string"
                                    : (SPIFOPT_OPT_IS_ARGLIST(j)
                                       ? "n argument list"
                                       : ""))));
                } else {
                    libast_print_error("option -%c requires a%s value\n", SPIFOPT_OPT_SHORT(j),
                                (SPIFOPT_OPT_IS_INTEGER(j)
                                 ? ("n integer")
                                 : (SPIFOPT_OPT_IS_STRING(j)
                                    ? " string"
                                    : (SPIFOPT_OPT_IS_ARGLIST(j)
                                       ? "n argument list"
                                       : ""))));
                }
                CHECK_BAD();
                continue;
            }
            /* Also make sure we know what to do with the value. */
            if (!SPIFOPT_OPT_VALUE(j)) {
                NEXT_LOOP();
            }
        } else if (SPIFOPT_OPT_IS_ABSTRACT(j) && !SPIFOPT_OPT_VALUE(j)) {
            /* Also make sure that abstract options have a function pointer. */
            NEXT_LOOP();
        }

        if (SPIFOPT_OPT_IS_BOOLEAN(j)) {
            if (!handle_boolean(j, val_ptr, islong)) {
                i--;
            }
        } else if (SPIFOPT_OPT_IS_STRING(j)) {
            if (SHOULD_PARSE(j)) {
                handle_string(j, val_ptr);
            }
        } else if (SPIFOPT_OPT_IS_INTEGER(j)) {
            if (SHOULD_PARSE(j)) {
                handle_integer(j, val_ptr);
            }
        } else if (SPIFOPT_OPT_IS_ARGLIST(j)) {
            if (SHOULD_PARSE(j)) {
                handle_arglist(j, val_ptr, hasequal, i, argc, argv);
            }
            if (!hasequal) {
                break;
            }
        } else if (SPIFOPT_OPT_IS_ABSTRACT(j)) {
            if (SHOULD_PARSE(j)) {
                D_OPTIONS(("Abstract option detected\n"));
                ((spifopt_abstract_handler_t) SPIFOPT_OPT_VALUE(j))(val_ptr);
            }
        }
        if (!SPIFOPT_FLAGS_IS_SET(SPIFOPT_SETTING_PREPARSE) && SPIFOPT_FLAGS_IS_SET(SPIFOPT_SETTING_REMOVE_ARGS)) {
            argv[i] = NULL;
        }
        NEXT_LOOP();
    }

    if (SPIFOPT_FLAGS_IS_SET(SPIFOPT_SETTING_PREPARSE)) {
        SPIFOPT_FLAGS_CLEAR(SPIFOPT_SETTING_PREPARSE);
    } else if (SPIFOPT_FLAGS_IS_SET(SPIFOPT_SETTING_REMOVE_ARGS)) {
        for (i = 1, j = 1; i < argc; i++) {
            if (argv[i]) {
                argv[j] = argv[i];
                j++;
            }
        }
        if (j > 1) {
            argv[j] = NULL;
        }
    }
}
Exemplo n.º 3
0
/* Parse the next argument in PARSER (as indicated by PARSER->state.next).
   Any error from the parsers is returned, and *ARGP_EBADKEY indicates
   whether a value of EBADKEY is due to an unrecognized argument (which is
   generally not fatal).  */
static error_t
parser_parse_next (struct parser *parser, int *arg_ebadkey)
{
  if (parser->state.quoted && parser->state.next < parser->state.quoted)
    /* The next argument pointer has been moved to before the quoted
       region, so pretend we never saw the quoting `--', and start
       looking for options again. If the `--' is still there we'll just
       process it one more time. */
    parser->state.quoted = parser->args_only = 0;

  /* Give FIRST_NONOPT & LAST_NONOPT rational values if NEXT has been
     moved back by the user (who may also have changed the arguments).  */
  if (parser->last_nonopt > parser->state.next)
    parser->last_nonopt = parser->state.next;
  if (parser->first_nonopt > parser->state.next)
    parser->first_nonopt = parser->state.next;

  if (parser->nextchar)
    /* Deal with short options. */
    {
      struct group *group;
      char c;
      const struct argp_option *option;
      char *value = NULL;;

      assert(!parser->args_only);

      c = *parser->nextchar++;

      option = find_short_option(parser, c, &group);
      if (!option)
	{
	  if (parser->posixly_correct)
	    /* 1003.2 specifies the format of this message.  */
	    fprintf (parser->state.err_stream,
		     dgettext(parser->state.root_argp->argp_domain,
			      "%s: illegal option -- %c\n"),
		     parser->state.name, c);
	  else
	    fprintf (parser->state.err_stream,
		     dgettext(parser->state.root_argp->argp_domain,
			      "%s: invalid option -- %c\n"),
		     parser->state.name, c);

	  *arg_ebadkey = 0;
	  return EBADKEY;
	}

      if (!*parser->nextchar)
	parser->nextchar = NULL;

      if (option->arg)
	{
	  value = parser->nextchar;
	  parser->nextchar = NULL;

	  if (!value
	      && !(option->flags & OPTION_ARG_OPTIONAL))
	    /* We need an mandatory argument. */
	    {
	      if (parser->state.next == parser->state.argc)
		/* Missing argument */
		{
		  /* 1003.2 specifies the format of this message.  */
		  fprintf (parser->state.err_stream,
			   dgettext(parser->state.root_argp->argp_domain,
				    "%s: option requires an argument -- %c\n"),
			   parser->state.name, c);

		  *arg_ebadkey = 0;
		  return EBADKEY;
		}
	      value = parser->state.argv[parser->state.next++];
	    }
	}
      return group_parse(group, &parser->state,
			 option->key, value);
    }
  else
    /* Advance to the next ARGV-element.  */
    {
      if (parser->args_only)
	{
	  *arg_ebadkey = 1;
	  if (parser->state.next >= parser->state.argc)
	    /* We are done: */
	    return EBADKEY;
	  else
	    return parser_parse_arg(parser,
				    parser->state.argv[parser->state.next]);
	}

      if (parser->state.next >= parser->state.argc)
	/* Almost done. If there are non-options that we skipped
	   previously, we should process them now. */
	{
	  *arg_ebadkey = 1;
	  if (parser->first_nonopt != parser->last_nonopt)
	    {
	      exchange(parser);

	      /* Start processing the arguments we skipped previously: */
	      parser->state.next = parser->first_nonopt;

	      parser->first_nonopt = parser->last_nonopt = 0;

	      parser->args_only = 1;
	      return 0;
	    }
	  else
	    /* Indicate that we are really done. */
	    return EBADKEY;
	}
      else
	/* Look for options. */
	{
	  char *arg = parser->state.argv[parser->state.next];

	  char *optstart;
	  enum arg_type token = classify_arg(parser, arg, &optstart);

	  switch (token)
	    {
	    case ARG_ARG:
	      switch (parser->ordering)
		{
		case PERMUTE:
                  if (parser->first_nonopt == parser->last_nonopt) {
		    /* Skipped sequence is empty; start a new one: */
		    parser->first_nonopt = parser->last_nonopt = parser->state.next;
		  } else if (parser->last_nonopt != parser->state.next) {
                    /* We have a non-empty skipped sequence, and we are not
                     * at the end-point, so move it. */
		    exchange(parser);
                  }

		  assert(parser->last_nonopt == parser->state.next);

		  /* Skip this argument for now: */
		  parser->state.next++;
		  parser->last_nonopt = parser->state.next;

		  return 0;

		case REQUIRE_ORDER:
		  /* Implicit quote before the first argument. */
		   parser->args_only = 1;
		   return 0;

		case RETURN_IN_ORDER:
		  *arg_ebadkey = 1;
		  return parser_parse_arg(parser, arg);

		default:
		  abort();
		}
	    case ARG_QUOTE:
	      /* Skip it, then exchange with any previous non-options: */
	      parser->state.next++;
	      assert(parser->last_nonopt != parser->state.next);

	      if (parser->first_nonopt != parser->last_nonopt)
		{
		  exchange(parser);

		  /* Start processing the skipped and the quoted
		     arguments. */

		  parser->state.quoted = parser->state.next = parser->first_nonopt;

		  /* Also empty the skipped-list, to avoid confusion
		     if the user resets the next pointer. */
		  parser->first_nonopt = parser->last_nonopt = 0;
		}
	      else
		parser->state.quoted = parser->state.next;

	      parser->args_only = 1;
	      return 0;

	    case ARG_LONG_ONLY_OPTION:
	    case ARG_LONG_OPTION:
	      {
		struct group *group;
		const struct argp_option *option;
		char *value;

		parser->state.next++;
		option = find_long_option(parser, optstart, &group);

		if (!option)
		  {
		    /* NOTE: This includes any "=something" in the output: */
		    fprintf(parser->state.err_stream,
			    dgettext(parser->state.root_argp->argp_domain,
                                     "%s: unrecognized option `%s'\n"),
			    parser->state.name, arg);
		    *arg_ebadkey = 0;
		    return EBADKEY;
		  }

		value = strchr(optstart, '=');
		if (value)
		  value++;

		if (value && !option->arg)
		  /* Unexpected argument. */
		  {
		    if (token == ARG_LONG_OPTION)
		      /* --option */
		      fprintf(parser->state.err_stream,
			      dgettext(parser->state.root_argp->argp_domain,
                                       "%s: option `--%s' does NOT allow an argument\n"),
			      parser->state.name, option->name);
		    else
		      /* +option or -option */
		      fprintf(parser->state.err_stream,
			      dgettext(parser->state.root_argp->argp_domain,
                                       "%s: option `%c%s' does NOT allow an argument\n"),
			      parser->state.name, arg[0], option->name);

		    *arg_ebadkey = 0;
		    return EBADKEY;
		  }

		if (option->arg && !value
		    && !(option->flags & OPTION_ARG_OPTIONAL))
		  /* We need an mandatory argument. */
		  {
		    if (parser->state.next == parser->state.argc)
		      /* Missing argument */
		      {
			if (token == ARG_LONG_OPTION)
			  /* --option */
			  fprintf (parser->state.err_stream,
				   dgettext(parser->state.root_argp->argp_domain,
					    "%s: option `--%s' requires an argument\n"),
				 parser->state.name, option->name);
			else
			  /* +option or -option */
			  fprintf (parser->state.err_stream,
				   dgettext(parser->state.root_argp->argp_domain,
					    "%s: option `%c%s' requires an argument\n"),
				   parser->state.name, arg[0], option->name);

			*arg_ebadkey = 0;
			return EBADKEY;
		      }

		    value = parser->state.argv[parser->state.next++];
		  }
		*arg_ebadkey = 0;
		return group_parse(group, &parser->state,
				   option->key, value);
	      }
	    case ARG_SHORT_OPTION:
	      parser->state.next++;
	      parser->nextchar = optstart;
	      return 0;

	    default:
	      abort();
	    }
	}
    }
}
Exemplo n.º 4
0
/*
 * args_ok
 *
 * prepare args, check & parse user args, display error and
 * help message if neccessary
 *
 * result: TRUE if all args ok
 */
BOOL args_ok(HSCPRC * hp, int argc, char *argv[])
{
   static const struct hscoption opts[] = {
      {"from",        "Input file(s)",                                             "FILE",  NULL,ARG_OBL, OPT_TXT, 'f'},
      {"to",          "Output file",                                               "FILE",  NULL,ARG_OBL, OPT_TXT, 'o'},
      {"prj",         "Project file",                                              "FILE",  NULL,ARG_OBL, OPT_TXT, 'p'},
      {"syntax",      "Syntax definition file (default: hsc.prefs)",               "FILE",  NULL,ARG_OBL, OPT_TXT, 's'},
      {"msgfile",     "Message file for output (default: stderr)",                 "FILE",  NULL,ARG_OBL, OPT_TXT, 0},
      {"msgfmt",      "printf-style format for messages",                          "FORMAT",NULL,ARG_OBL, OPT_TXT, 0},
      {"browser",     "Message browser program to use",                            "PROG",  NULL,ARG_OBL, OPT_TXT, 0},
      {"maxerr",      "Maximum numer of errors (default: " DEFAULT_MAXERR ")",     "NUM",   NULL,ARG_OBL, OPT_DEC, 0},
      {"maxmsg",      "Maximum numer of messages (default: " DEFAULT_MAXMSG ")",   "NUM",   NULL,ARG_OBL, OPT_DEC, 0},
      {"ext",         "Output file extension (default: " DEFAULT_EXTENSION ")",    "WORD",  NULL,ARG_OBL, OPT_TXT, 0},
      {"define",      "Define global attribute",                                   "WORD",  NULL,ARG_OBL, OPT_TXT, 'D'},
      {"ignore",      "Ignore message number or class",                            "WORD",  NULL,ARG_OBL, OPT_TXT, 'i'},
      {"enable",      "Enable message number or class",                            "WORD",  NULL,ARG_OBL, OPT_TXT, 'e'},
      {"msgmode",     "Syntax checking mode (" MODE_ENUMSTR ")",                   "WORD",  NULL,ARG_OBL, OPT_TXT, 'm'},
      {"qstyle",      "Quote style  (" QMODE_ENUMSTR ")",                          "WORD",  NULL,ARG_OBL, OPT_TXT, 0},
      {"estyle",      "Entity style  (" EMODE_ENUMSTR ")",                         "WORD",  NULL,ARG_OBL, OPT_TXT, 0},
      {"incdir",      "Add include directory",                                     "DIR",   NULL,ARG_OBL, OPT_TXT, 'I'},
      {"compact",     "Strip superfluous whitespace",                              NULL,    NULL,ARG_NONE,OPT_NONE,'c'},
      {"getsize",     "Set width and height attributes for images",                NULL,    NULL,ARG_NONE,OPT_NONE,'g'},
      {"rplcent",     "Replace non-ASCII characters with entities (cf. --estyle)", NULL,    NULL,ARG_NONE,OPT_NONE,0},
      {"rplcquote",   "Replace double quotes with `&quot;'",                       NULL,    NULL,ARG_NONE,OPT_NONE,0},
      {"stripbadws",  "Strip bad whitespace",                                      NULL,    NULL,ARG_NONE,OPT_NONE,0},
      {"stripcomment","Strip SGML comments",                                       NULL,    NULL,ARG_NONE,OPT_NONE,0},
      {"stripext",    "Strip tags with external URIs",                             NULL,    NULL,ARG_NONE,OPT_NONE,0},
      {"striptags",   "Tags to be stripped",                                       "LIST",  NULL,ARG_OBL, ARG_TEXT, 0},
      {"iconbase",    "Base URI for icon entities",                                "URI",   NULL,ARG_OBL, ARG_TEXT, 0},
      {"serverdir",   "Base directory for server relative URIs",                   "DIR",   NULL,ARG_OBL, ARG_TEXT, 0},
      {"status",      "Status message verbosity (" STATUS_ENUM_STR ")",            "LIST",  NULL,ARG_OBL, ARG_TEXT, 0},
      {"quiet",       "Be quiet. Equivalent to --status=QUIET",                    NULL,    NULL,ARG_NONE,OPT_NONE,'q'}, 
      {"nonesterr",   "Don't show \"previous call\" tracebacks on error",          NULL,    NULL,ARG_NONE,OPT_NONE,0},
      {"lowercase",   "Force all tags and attributes to lowercase",                NULL,    NULL,ARG_NONE,OPT_NONE,'l'},
      {"xhtml",       "Use XHTML mode (implies -l --qstyle=DOUBLE)",               NULL,    NULL,ARG_NONE,OPT_NONE,'x'},
      {"nocss",       "Don't validate CSS in STYLE attributes",                    NULL,    NULL,ARG_NONE,OPT_NONE,0},
      {"ckxuri",      "Check external links",                                      NULL,    NULL,ARG_NONE,OPT_NONE,0},
      {"debug",       "Enable debugging output if enabled at compile time",        NULL,    NULL,ARG_NONE,OPT_NONE,'d'},
      {"license",     "Display the license",                                       NULL,    NULL,ARG_NONE,OPT_NONE,0},
      {"help",        "Show this help",                                            NULL,    NULL,ARG_NONE,OPT_NONE,'h'},
   };                                              
   int c;
   int nopts=sizeof(opts)/sizeof(opts[0]);
   struct option *lop = hscopts_to_getopt_long(opts,nopts);
   char *sop = hscopts_to_getopt_short(opts,nopts);
   EXPSTR *destdir = init_estr(32);       /* destination dir */
   EXPSTR *rel_destdir = init_estr(32);   /* relative destination dir */
   EXPSTR *kack_name = init_estr(0);      /* temp. str for outfilename */
   LONG maximum_number_of_errors = strtol(DEFAULT_MAXERR, (char **) NULL, 10);
   LONG maximum_number_of_messages = strtol(DEFAULT_MAXMSG, (char **) NULL, 10);

   arg_hp = hp;
   arg_mode_CB(DEFAULT_MODE_STR);

   while(1) {
      int opt_index;

      c = getopt_long(argc, argv, sop, lop, &opt_index);
      if(-1 == c) break;

      if(c) {
         if(!verify_option(hp, find_short_option(hp,opts,nopts,c), optarg))
            return FALSE;
         process_short_option(hp, c, optarg);
      } else {
         if(!verify_option(hp, find_long_option(hp,opts,nopts,lop[opt_index].name), optarg))
            return FALSE;
         process_long_option(hp, lop[opt_index].name, optarg);
         break;
      }
   }
   ufree(lop);
   ufree(sop);
   return TRUE;
}