Beispiel #1
0
/* Call the user parsers to parse the non-option argument VAL, at the
   current position, returning any error. The state NEXT pointer
   should point to the argument; this function will adjust it
   correctly to reflect however many args actually end up being
   consumed. */
static error_t
parser_parse_arg(struct parser *parser, char *val)
{
  /* Save the starting value of NEXT: */
  int parser_index = parser->state.next;
  error_t err = EBADKEY;
  struct group *group;
  int key = 0;			/* Which of ARGP_KEY_ARG[S] we used.  */

  /* Try to parse the argument in each parser.  */
  for (group = parser->groups
       ; group < parser->egroup && err == EBADKEY
       ; group++)
    {
      parser->state.next++;	/* For ARGP_KEY_ARG, consume the arg.  */
      key = ARGP_KEY_ARG;
      err = group_parse (group, &parser->state, key, val);

      if (err == EBADKEY)
	/* This parser doesn't like ARGP_KEY_ARG; try ARGP_KEY_ARGS instead. */
	{
	  parser->state.next--;	/* For ARGP_KEY_ARGS, put back the arg.  */
	  key = ARGP_KEY_ARGS;
	  err = group_parse (group, &parser->state, key, 0);
	}
    }

  if (! err)
    {
      if (key == ARGP_KEY_ARGS)
	/* The default for ARGP_KEY_ARGS is to assume that if NEXT isn't
	   changed by the user, *all* arguments should be considered
	   consumed.  */
	parser->state.next = parser->state.argc;

		if (parser->state.next > parser_index) {
			/* Remember that we successfully processed a non-option
			 * argument -- but only if the user has NOT gotten tricky and set
			 * the clock back.  */
			(--group)->args_processed += (unsigned)(parser->state.next - parser_index);
		} else {
			/* The user wants to reparse some args, so try looking for options
			 * again.  */
			parser->args_only = 0;
		}
    }

  return err;
}
Beispiel #2
0
static void test_errors(void) {
	const char *errors[] = {
		"",
		":root:0",
		":::",
		"0:::"
	};
	size_t i,count,oldFree;
	test_caseStart("Testing errors");

	for(i = 0; i < ARRAY_SIZE(errors); i++) {
		sGroup *g;
		oldFree = heapspace();
		g = group_parse(errors[i],&count);
		test_assertTrue(g == NULL);
		test_assertSize(heapspace(),oldFree);
	}

	test_caseSucceeded();
}
Beispiel #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();
	    }
	}
    }
}
Beispiel #4
0
/* Free any storage consumed by PARSER (but not PARSER itself).  */
static error_t
parser_finalize (struct parser *parser,
		 error_t err, int arg_ebadkey, int *end_index)
{
  struct group *group;

  if (err == EBADKEY && arg_ebadkey)
    /* Suppress errors generated by unparsed arguments.  */
    err = 0;

  if (! err)
    {
      if (parser->state.next == parser->state.argc)
	/* We successfully parsed all arguments!  Call all the parsers again,
	   just a few more times... */
	{
	  for (group = parser->groups;
	       group < parser->egroup && (!err || err==EBADKEY);
	       group++)
	    if (group->args_processed == 0)
	      err = group_parse (group, &parser->state, ARGP_KEY_NO_ARGS, 0);
	  for (group = parser->egroup - 1;
	       group >= parser->groups && (!err || err==EBADKEY);
	       group--)
	    err = group_parse (group, &parser->state, ARGP_KEY_END, 0);

	  if (err == EBADKEY)
	    err = 0;		/* Some parser didn't understand.  */

	  /* Tell the user that all arguments are parsed.  */
	  if (end_index)
	    *end_index = parser->state.next;
	}
      else if (end_index)
	/* Return any remaining arguments to the user.  */
	*end_index = parser->state.next;
      else
	/* No way to return the remaining arguments, they must be bogus. */
	{
	  if (!(parser->state.flags & ARGP_NO_ERRS)
	      && parser->state.err_stream)
	    fprintf (parser->state.err_stream,
		     dgettext (parser->argp->argp_domain,
			       "%s: Too many arguments\n"),
		     parser->state.name);
	  err = EBADKEY;
	}
    }

  /* Okay, we're all done, with either an error or success; call the parsers
     to indicate which one.  */

  if (err)
    {
      /* Maybe print an error message.  */
      if (err == EBADKEY)
	/* An appropriate message describing what the error was should have
	   been printed earlier.  */
	__argp_state_help (&parser->state, parser->state.err_stream,
			   ARGP_HELP_STD_ERR);

      /* Since we didn't exit, give each parser an error indication.  */
      for (group = parser->groups; group < parser->egroup; group++)
	group_parse (group, &parser->state, ARGP_KEY_ERROR, 0);
    }
  else
    /* Notify parsers of success, and propagate back values from parsers.  */
    {
      /* We pass over the groups in reverse order so that child groups are
	 given a chance to do there processing before passing back a value to
	 the parent.  */
      for (group = parser->egroup - 1
	   ; group >= parser->groups && (!err || err == EBADKEY)
	   ; group--)
	err = group_parse (group, &parser->state, ARGP_KEY_SUCCESS, 0);
      if (err == EBADKEY)
	err = 0;		/* Some parser didn't understand.  */
    }

  /* Call parsers once more, to do any final cleanup.  Errors are ignored.  */
  for (group = parser->egroup - 1; group >= parser->groups; group--)
    group_parse (group, &parser->state, ARGP_KEY_FINI, 0);

  if (err == EBADKEY)
    err = EINVAL;

  free (parser->storage);

  return err;
}
Beispiel #5
0
/* Initializes PARSER to parse ARGP in a manner described by FLAGS.  */
static error_t
parser_init(struct parser *parser, const struct argp *argp,
			int argc, char **argv, int flags, void *input)
{
  error_t err = 0;
  struct group *group;
  struct parser_sizes szs;

  parser->posixly_correct = getenv ("POSIXLY_CORRECT");

  if (flags & ARGP_IN_ORDER)
    parser->ordering = RETURN_IN_ORDER;
  else if (flags & ARGP_NO_ARGS)
    parser->ordering = REQUIRE_ORDER;
  else if (parser->posixly_correct)
    parser->ordering = REQUIRE_ORDER;
  else
    parser->ordering = PERMUTE;

  szs.short_len = 0;
  szs.num_groups = 0;
  szs.num_child_inputs = 0;

  if (argp)
    calc_sizes (argp, &szs);

  if (!(flags & ARGP_LONG_ONLY))
    /* We have no use for the short option array. */
    szs.short_len = 0;

  /* Lengths of the various bits of storage used by PARSER.  */
#define GLEN (szs.num_groups + 1) * sizeof (struct group)
#define CLEN (szs.num_child_inputs * sizeof (void *))
#define SLEN (szs.short_len + 1)
#define STORAGE(offset) ((void *) (((char *) parser->storage) + (offset)))

  parser->storage = malloc(GLEN + CLEN + SLEN);
  if (! parser->storage) {
	  return ENOMEM;
  }

  parser->groups = (struct group *)parser->storage;

  parser->child_inputs = (void **)STORAGE(GLEN);
  memset(parser->child_inputs, 0, (szs.num_child_inputs * sizeof(void *)));

  if (flags & ARGP_LONG_ONLY) {
	  parser->short_opts = (char *)STORAGE(GLEN + CLEN);
  } else {
	  parser->short_opts = NULL;
  }

  parser_convert (parser, argp);

  memset (&parser->state, 0, sizeof (struct argp_state));

  parser->state.root_argp = parser->argp;
  parser->state.argc = argc;
  parser->state.argv = argv;
  parser->state.flags = (unsigned)flags;
  parser->state.err_stream = stderr;
  parser->state.out_stream = stdout;
  parser->state.pstate = parser;

  parser->args_only = 0;
  parser->nextchar = NULL;
  parser->first_nonopt = parser->last_nonopt = 0;

  /* Call each parser for the first time, giving it a chance to propagate
     values to child parsers.  */
  if (parser->groups < parser->egroup)
    parser->groups->input = input;
  for (group = parser->groups;
       group < parser->egroup && (!err || err == EBADKEY);
       group++)
    {
      if (group->parent)
	/* If a child parser, get the initial input value from the parent. */
	group->input = group->parent->child_inputs[group->parent_index];

      if (!group->parser
	  && group->argp->children && group->argp->children->argp)
	/* For the special case where no parsing function is supplied for an
	   argp, propagate its input to its first child, if any (this just
	   makes very simple wrapper argps more convenient).  */
	group->child_inputs[0] = group->input;

      err = group_parse (group, &parser->state, ARGP_KEY_INIT, 0);
    }
  if (err == EBADKEY)
    err = 0;			/* Some parser didn't understand.  */

  if (err)
    return err;

  if (argv[0] && !(parser->state.flags & ARGP_PARSE_ARGV0))
    /* There's an argv[0]; use it for messages.  */
    {
      parser->state.name = __argp_basename(argv[0]);

      /* Don't parse it as an argument. */
      parser->state.next = 1;
    }
  else
    parser->state.name = __argp_short_program_name(NULL);

  return 0;
}
Beispiel #6
0
static void test_basics(void) {
	size_t count,oldFree;
	test_caseStart("Testing basics");

	{
		sGroup *g;
		oldFree = heapspace();
		g = group_parse("0:root:0",&count);
		test_assertTrue(g != NULL);
		test_assertSize(count,1);
		if(g) {
			test_assertTrue(g->next == NULL);
			test_assertUInt(g->gid,0);
			test_assertStr(g->name,"root");
			test_assertSize(g->userCount,1);
			test_assertUInt(g->users[0],0);
		}
		group_free(g);
		test_assertSize(heapspace(),oldFree);
	}

	{
		sGroup *g;
		oldFree = heapspace();
		g = group_parse("0:root\n",&count);
		test_assertTrue(g != NULL);
		test_assertSize(count,1);
		if(g) {
			test_assertTrue(g->next == NULL);
			test_assertUInt(g->gid,0);
			test_assertStr(g->name,"root");
			test_assertSize(g->userCount,0);
		}
		group_free(g);
		test_assertSize(heapspace(),oldFree);
	}

	{
		sGroup *g;
		oldFree = heapspace();
		g = group_parse("0:root:",&count);
		test_assertTrue(g != NULL);
		test_assertSize(count,1);
		if(g) {
			test_assertTrue(g->next == NULL);
			test_assertUInt(g->gid,0);
			test_assertStr(g->name,"root");
			test_assertSize(g->userCount,0);
		}
		group_free(g);
		test_assertSize(heapspace(),oldFree);
	}

	{
		sGroup *g;
		oldFree = heapspace();
		g = group_parse("2444:a:100:200",&count);
		test_assertTrue(g != NULL);
		test_assertSize(count,1);
		if(g) {
			test_assertTrue(g->next == NULL);
			test_assertUInt(g->gid,2444);
			test_assertStr(g->name,"a");
			test_assertSize(g->userCount,2);
			test_assertUInt(g->users[0],100);
			test_assertUInt(g->users[1],200);
		}
		group_free(g);
		test_assertSize(heapspace(),oldFree);
	}

	{
		sGroup *g,*res;
		oldFree = heapspace();
		res = group_parse("1:a:1:2\n\n2:b:4",&count);
		test_assertSize(count,2);
		g = res;
		test_assertTrue(g != NULL);
		if(g) {
			test_assertUInt(g->gid,1);
			test_assertStr(g->name,"a");
			test_assertSize(g->userCount,2);
			test_assertUInt(g->users[0],1);
			test_assertUInt(g->users[1],2);
			g = g->next;
		}
		test_assertTrue(g != NULL);
		if(g) {
			test_assertUInt(g->gid,2);
			test_assertStr(g->name,"b");
			test_assertSize(g->userCount,1);
			test_assertUInt(g->users[0],4);
		}
		group_free(res);
		test_assertSize(heapspace(),oldFree);
	}

	test_caseSucceeded();
}