Exemple #1
0
int
Clp_Next(Clp_Parser *clp)
     /* Gets and parses the next argument from the argument list.
	
        If there are no more arguments, returns Clp_Done.
	If the next argument isn't an option, returns Clp_NotOption;
	the argument is stored in clp->arg.
	If the next argument is an option, returns that option's option_id.
	
	If the next argument is an unrecognizable or ambiguous option,
	an error message is given and Clp_BadOption is returned.
	
	If an option has an argument, that argument is stored in clp->arg
	and clp->have_arg is set to 1.
	Furthermore, that argument's parsed value (according to its type)
	is stored in the clp->val union.
	
	If an option needs an argument but isn't given one;
	if it doesn't need an argument but IS given one;
	or if the argument is the wrong type,
	an error message is given and Clp_BadOption is returned. */
{
  Clp_Internal *cli = clp->internal;
  Clp_Option *opt;
  Clp_ParserState clpsave;
  int complain;
  
  /** Set up clp **/
  cli->current_option = 0;
  cli->ambiguous = 0;
  
  /** Get the next argument or option **/
  if (!next_argument(clp, cli->option_processing ? 0 : 2))
    return clp->have_arg ? Clp_NotOption : Clp_Done;
  
  clp->negated = cli->whole_negated;
  if (cli->is_short)
    opt = find_short(clp, cli->text[0]);
  else
    opt = find_long(clp, cli->text);
  
  /** If there's ambiguity between long & short options, and we couldn't find
      a long option, look for a short option **/
  if (!opt && cli->could_be_short) {
    switch_to_short_argument(clp);
    opt = find_short(clp, cli->text[0]);
  }
  
  /** If we didn't find an option... **/
  if (!opt || (clp->negated && !TEST(opt, Clp_Negate))) {
    
    /* default processing for the "--" option: turn off option processing
       and return the next argument */
    if (strcmp(cli->argv[0], "--") == 0) {
      Clp_SetOptionProcessing(clp, 0);
      return Clp_Next(clp);
    }
    
    /* otherwise, report some error or other */
    if (cli->ambiguous)
      ambiguity_error(clp, cli->ambiguous, cli->ambiguous_values,
		      cli->opt, cli->option_chars,
		      "option `%s%s' is ambiguous",
		      cli->option_chars, cli->text);
    else if (cli->is_short && !cli->could_be_short)
      Clp_OptionError(clp, "unrecognized option `%s%c'",
		      cli->option_chars, cli->text[0]);
    else
      Clp_OptionError(clp, "unrecognized option `%s%s'",
		      cli->option_chars, cli->text);
    return Clp_BadOption;
  }
  
  /** Set the current option **/
  cli->current_option = opt;
  cli->current_short = cli->is_short;
  cli->negated_by_no = clp->negated && !cli->whole_negated;
  
  /** The no-argument (or should-have-no-argument) case **/
  if (clp->negated || !TEST(opt, Clp_AnyArgument)) {
    if (clp->have_arg) {
      Clp_OptionError(clp, "`%O' can't take an argument");
      return Clp_BadOption;
    } else
      return opt->option_id;
  }
  
  /** Get an argument if we need one, or if it's optional **/
  /* Sanity-check the argument type. */
  if (opt->arg_type <= 0 || opt->arg_type >= cli->nargtype
      || cli->argtype[ opt->arg_type ].func == 0)
    return Clp_Error;
  
  /* complain == 1 only if the argument was explicitly given,
     or it is mandatory. */
  complain = (clp->have_arg != 0) || TEST(opt, Clp_Mandatory);
  Clp_SaveParser(clp, &clpsave);
  
  if (TEST(opt, Clp_Mandatory) && !clp->have_arg) {
    /* Mandatory argument case */
    /* Allow arguments to options to start with a dash, but only if the
       argument type allows it by not setting Clp_DisallowOptions */
    int disallow = TEST(&cli->argtype[opt->arg_type], Clp_DisallowOptions);
    next_argument(clp, disallow ? 1 : 2);
    if (!clp->have_arg) {
      int got_option = cli->text != 0;
      Clp_RestoreParser(clp, &clpsave);
      if (got_option)
	Clp_OptionError(clp, "`%O' requires a non-option argument");
      else
	Clp_OptionError(clp, "`%O' requires an argument");
      return Clp_BadOption;
    }
    
  } else if (cli->is_short && !clp->have_arg && cli->text[1] != 0)
    /* The -[option]argument case:
       Assume that the rest of the current string is the argument. */
    next_argument(clp, 1);
  
  /** Parse the argument **/
  if (clp->have_arg) {
    Clp_ArgType *atr = &cli->argtype[ opt->arg_type ];
    if (atr->func(clp, clp->arg, complain, atr->thunk) <= 0) {
      /* parser failed */
      clp->have_arg = 0;
      if (TEST(opt, Clp_Mandatory))
	return Clp_BadOption;
      else
	Clp_RestoreParser(clp, &clpsave);
    }
  }
  
  return opt->option_id;
}
Exemple #2
0
int CLIF_parse_cmdline (int argc, char *argv[],
			CLIF_option *option_list,
			CLIF_argument *argument_list,
			unsigned int parse_flags) {
	int i, j;
	CLIF_option *optn;
	CLIF_argument *argm;
	int num_args = 0;
	int num_argm = 0, strict_beg = 0, strict_end = 0;
	_CLIF_index arg_n[MAX_ARGC_NUMBER];
	unsigned int dirty_flags = 0;
	int dirty_plus = 0;
	int exclusive_cnt = 0;
	int posix = getenv ("POSIXLY_CORRECT") != NULL ||
					    (parse_flags & CLIF_POSIX);

	curr.argc = argc;
	curr.argv = argv;
	curr.option_list = option_list;
	curr.argument_list = argument_list;
	curr.parse_flags = parse_flags;

	if (argc <= 1 && (parse_flags & CLIF_HELP_EMPTY)) {
		CLIF_current_help ();
		exit (0);
	}

	/*  Scan argument_list for check and some info.  */
	if (argument_list) {
	    enum stages { STRICT_BEG, OPTIONAL, STRICT_END };
	    int stage = STRICT_BEG;

	    for (argm = argument_list; argm->name; argm++) {
		
		if (argm->flags & CLIF_STRICT) {

		    if (stage == STRICT_BEG)  strict_beg++;
		    else if (stage == OPTIONAL) {
			stage = STRICT_END;
			strict_end++;
		    }
		    else if (stage == STRICT_END)
			    strict_end++;
		} else {
		    if (stage == STRICT_BEG)  stage = OPTIONAL;
		    else if (stage == STRICT_END) {
			err_report ("Incorrect argument list set in program "
				    "source: more than one optional area.");
			return -1;
		    }
		}

		num_argm++;
	    }
	}
	
	/*  Scan option_list for some info.  */
	if (option_list) {

	    dirty_flags = parse_flags;

	    for (optn = option_list;
		    optn->short_opt || optn->long_opt;
			optn++
	    ) {
		dirty_flags |= optn->flags;
		if (optn->function_plus)  dirty_plus = 1;
	    }
	}

	if (dirty_flags & CLIF_EXCL)
		exclusive_cnt = 1;	/*  only one is allowed...  */


	/*  Go !   Store arguments, parse options.  */

	for (i = 1; i < argc; i++) {
	    char *arg = argv[i];
	    char *opt_arg = NULL;
	    char sym = '-';

	    if (!option_list)
		    goto  handle_arg;

	    if (*arg == '+' && dirty_plus)
		    sym = '+';

	    if (*arg != sym) {	/*  argument or keyword   */

		if (dirty_flags & CLIF_MAY_KEYWORD) {
		    optn = find_long (arg, &opt_arg, CLIF_MAY_KEYWORD, 0);
		    if (optn)  goto long_found;
		}

		if (num_args == 0 && (parse_flags & CLIF_FIRST_GROUP)) {
		    /*  ugly...  */
		    parse_flags &= ~CLIF_FIRST_GROUP;
		    dirty_flags &= ~CLIF_FIRST_GROUP;	/*  to be correct   */

		    goto  handle_short;
		}

		/*  else it is an argument   */
		goto  handle_arg;

	    }
	    else if (*++arg == sym) {	/*  `--' - long option   */
		arg++;

		if (*arg == sym ||	/*  `---' - let it be not option... */
		    (parse_flags & (_CLIF_STRICT_KEYWORD|_CLIF_STRICT_ONEDASH)) 
		) {
		    arg -= 2;
		    goto  handle_arg;	/*  not option anyway  */
		}
	
		optn = find_long (arg, &opt_arg, 0,
				_CLIF_STRICT_KEYWORD | _CLIF_STRICT_ONEDASH);
		if (optn)  goto long_found;
	
		/*  XXX: May be allow only for `--', not `++' too...  */
		if (!*arg && sym == '-') {  /*  `--' and no empty longoption */
		    option_list = NULL;	    /*  POSIX way...  */
		    continue;
		}
	
		/*  XXX: or treat as an argument sometimes???  */
		err_bad_opt (argv[i], 0, i);
		return -1;
	    }
	    else {	/*  short option, or several short options...  */

		if (dirty_flags & CLIF_MAY_ONEDASH) {
		    optn = find_long (arg, &opt_arg, CLIF_MAY_ONEDASH, 0);
		    if (optn)  goto long_found;
		}
    
		if (!*arg) {	/*  POSIX say: only "stdout specification"... */
		    arg--;
		    goto handle_arg;
		}
    
		goto  handle_short;
	    }


    long_found:	
	    if (check_sym (optn, sym) < 0) {	/*  Oops...  */
		err_bad_opt (argv[i], 0, i);
		return -1;
	    }

	    if (optn->flags & CLIF_EXCL) {
		if (!exclusive_cnt) {
		    err_bad_excl (optn, 0, i);
		    return -1;
		}
		exclusive_cnt--;
	    }
		
	    if (optn->arg_name && !opt_arg) {
		unsigned int flags = optn->flags | parse_flags;

		if (++i >= argc ||
		    !(flags & CLIF_MAY_NOEQUAL)
		) {	/*  missing opt arg   */
		    i--;

		    if (!(flags & CLIF_OPTARG)) {
			err_bad_arg (optn, 0, i);
			return -1;
		    }

		    opt_arg = NULL;
		} else
		    opt_arg = argv[i];
		   
	    }


	    if (call_function (optn, opt_arg, sym) < 0) {
		err_bad_res (optn, 0, opt_arg, i);
		return -1;
	    }

	    if (optn->flags & CLIF_EXIT)
		    exit (0);

	    continue;


    handle_arg:
	    if (argument_list) {
		if (i < MAX_ARGC_NUMBER)    /*  XXX: ugly, better report   */
			arg_n[num_args++] = i;
	    } else {
		err_report ("`%s' (argc %d): arguments are not allowed",
								 argv[i], i);
		return -1;
	    }

	    /*  POSIX say: No more options after args...  */
	    if (posix)  option_list = NULL;	/*  geniously...  */
	
	    continue;


    handle_short:

	    opt_arg = NULL;

	    do {

		for (optn = option_list;
			optn->short_opt || optn->long_opt;
			    optn++
		) {
		    if (optn->short_opt && optn->short_opt[0] == *arg)
			    break;
		}
		if (!optn->short_opt ||
		    check_sym (optn, sym) < 0
		) {
		    err_bad_opt (argv[i], *arg, i);
		    return -1;
		}

		if (optn->flags & CLIF_EXCL) {
		    if (!exclusive_cnt) {
			err_bad_excl (optn, *arg, i);
			return -1;
		    }
		    exclusive_cnt--;
		}


		if (optn->arg_name) {
		    unsigned int flags = parse_flags | optn->flags;

		    if (arg[1] == '\0') {	/*  a last one   */

			/*  POSIX say: an option with arg cannot be grouped. */
			if (posix && arg != argv[i] && arg[-1] != sym) {
				err_bad_arg (optn, *arg, i);	/*  good way? */
				return -1;
			}

			if (++i >= argc ||
			    (flags & _CLIF_STRICT_JOIN_ARG)
			) {
			    i--;

			    if (!(flags & CLIF_OPTARG)) {
				err_bad_arg (optn, *arg, i);
				return -1;
			    }

			    opt_arg = NULL;
			} else
			    opt_arg = argv[i];
		    }
		    else if ((arg == argv[i] || arg[-1] == sym) &&	
			     (flags & CLIF_MAY_JOIN_ARG)
		    ) {
			opt_arg = ++arg;
		    }
		    else {	/*  inside a group...  */
			if (!(flags & CLIF_OPTARG) ||
			    (flags & CLIF_MAY_JOIN_ARG)
			) {
			    err_bad_arg (optn, *arg, i);
			    return -1;
			}

			opt_arg = NULL;
		    }
		}

		if (call_function (optn, opt_arg, sym) < 0) {
		    err_bad_res (optn, optn->short_opt[0], opt_arg, i);
		    return -1;
		}

		if (optn->flags & CLIF_EXIT)
			exit (0);

	    } while (!opt_arg && *++arg);

	}	/*  for ( ...  )   */

	if ((parse_flags & CLIF_STRICT_EXCL) && exclusive_cnt != 0) {
		err_report ("One of these must be specified:\n    %s\n",
						    show_excl (option_list, 0));
		return -1;
	}


	/*  Now, after *ALL* options, handle arguments, if any.  */

	if (num_args < strict_beg + strict_end) {
	    /*  Missing some needed arguments.  */

	    if (num_args < strict_beg)  argm = argument_list + num_args;
	    else
		argm = argument_list +
			    ((num_args - strict_beg) + (num_argm - strict_end));

	    if (num_args == strict_beg + strict_end - 1)
		err_report ("Specify \"%s\" missing argument.", argm->name);
	    else
		err_report ("Specify \"%s\" and other missing arguments.",
								    argm->name);
	    return -1;
	}

	if (num_args > 0) {
	    _CLIF_index argm_index[MAX_ARGC_NUMBER];

	    /*  assing argm (by index) for each arg...  */
		    
	    for (i = 0, j = 0; i < strict_beg; i++, j++)
		    argm_index[i] = j;
	    for (i = num_args - strict_end, j = num_argm - strict_end;
			i < num_args; i++, j++
	    )  argm_index[i] = j;
	    for (i = strict_beg, j = strict_beg;
		    i < num_args - strict_end && j < num_argm - strict_end;
			i++
	    ) {
		argm_index[i] = j;
		if (!(argument_list[j].flags & CLIF_MORE))
			j++;
	    }

	    if (i < num_args - strict_end) {	/*  there are extra args...  */
		err_report ("Extra arg `%s' (position %d, argc %d)",
				    argv[arg_n[i]], i + 1, arg_n[i]);
		return -1;
	    }

	    if (j < num_argm - strict_end &&	
		!(argument_list[j].flags & CLIF_MORE) &&
		/*  ...i.e, there are some missing optional args...  */
		(argument_list[j].flags & CLIF_ACC_PREV)
	    ) {
		if (j == 0)
		    err_report ("Incorrect argument list set: first arg "
				"cannot be `accompanied with previous'.");
		else
		    err_report ("Arg \"%s\" must be specified because "
				"\"%s\" `%s' is used.", argument_list[j].name,
				argument_list[j - 1].name, argv[arg_n[i - 1]]);
		return -1;
	    }
		
	    if (argm_index[--i] == j &&
		    /*  above is true only after OPTIONAL area scan
		       and when `j' is stopped on CLIF_MORE  */
		++j < num_argm - strict_end
		    /*  i.e: there is a *last* one (after CLIF_MORE)
			in the OPTIONAL area  */
	    )  argm_index[i] = j;	/*  *last* is better than *more*   */
		    

	    /*  ...and work now   */

	    for (i = 0; i < num_args; i++) {
		argm = argument_list + argm_index[i];

		if (argm->function &&
		    argm->function (argm, argv[arg_n[i]], i) < 0
		) {
		    err_report ("Cannot handle \"%s\" cmdline arg `%s' "
				"on position %d (argc %d)",
				argm->name, argv[arg_n[i]], i + 1, arg_n[i]);
		    return -1;
		}
	    }

	    /*  That`s all.  */
	}

	return 0;
}
Exemple #3
0
UpoptStatus
upopt_next(UpoptContext* context, int* constant, const char** value, char** error)
{
    const char* arg;
    const char* val = NULL;
    const UpoptOptionInfo* info = NULL;
   
    if (context->index >= context->argc)
        return UPOPT_STATUS_DONE;

    arg = context->argv[context->index++];

    if (!context->only_normal)
    {
        if (is_long(arg))
        {
            if (!arg[2])
            {
                context->only_normal = 1;
                return upopt_next(context, constant, value, error);
            }
            else
            {
                char* equal = strchr(arg, '=');
                
                if (equal)
                {
                    *equal = '\0';
                    val = equal + 1;
                }
                
                info = find_long(context->options, arg+2);
                
                if (equal)
                {
                    *equal = '=';
                }
                
                if (!info)
                {
                    *error = format("Unrecognized option: %s\n", arg);
                    return UPOPT_STATUS_ERROR;
                }
            }
        }
        else if (is_short(arg))
        {
            if (arg[2])
            {
                val = arg+2;
            }

            info = find_short(context->options, arg[1]);
            
            if (!info)
            {
                *error = format("Unrecognized option: %s\n", arg);
                return UPOPT_STATUS_ERROR;
            }
        }
    }
     
    if (info)
    {
        if (val && !info->argument)
        {
            if (is_long(arg))
            {
                *error = format("Did not expect an argument after --%s\n", 
                                info->longname);
            }
            else
            {
                *error = format("Did not expect an argument after -%c\n", 
                                info->shortname);
            }
            return UPOPT_STATUS_ERROR;
        }
        else if (!val && info->argument)
        {
            if ((context->index >= context->argc ||
                 (!context->only_normal &&
                  is_option(context->argv[context->index]))))
            {
                *error = format("Expected argument after %s\n", arg);
                return UPOPT_STATUS_ERROR;
            }
            val = context->argv[context->index++];
        }

        *constant = info->constant;
        *value = val;
        *error = NULL;
        return UPOPT_STATUS_NORMAL;
    }
    else
    {
        *constant = UPOPT_ARG_NORMAL;
        *value = arg;
        *error = NULL;
        return UPOPT_STATUS_NORMAL;
    }
}