| // © 2016 and later: Unicode, Inc. and others. | |
| // License & terms of use: http://www.unicode.org/copyright.html | |
| /* | |
| ******************************************************************************* | |
| * | |
| * Copyright (C) 2000-2015, International Business Machines | |
| * Corporation and others. All Rights Reserved. | |
| * | |
| ******************************************************************************* | |
| * file name: uoptions.c | |
| * encoding: UTF-8 | |
| * tab size: 8 (not used) | |
| * indentation:4 | |
| * | |
| * created on: 2000apr17 | |
| * created by: Markus W. Scherer | |
| * | |
| * This file provides a command line argument parser. | |
| */ | |
| #include "unicode/utypes.h" | |
| #include "cstring.h" | |
| #include "uoptions.h" | |
| U_CAPI int U_EXPORT2 | |
| u_parseArgs(int argc, char* argv[], | |
| int optionCount, UOption options[]) { | |
| char *arg; | |
| int i=1, remaining=1; | |
| char c, stopOptions=0; | |
| while(i<argc) { | |
| arg=argv[i]; | |
| if(!stopOptions && *arg=='-' && (c=arg[1])!=0) { | |
| /* process an option */ | |
| UOption *option=NULL; | |
| arg+=2; | |
| if(c=='-') { | |
| /* process a long option */ | |
| if(*arg==0) { | |
| /* stop processing options after "--" */ | |
| stopOptions=1; | |
| } else { | |
| /* search for the option string */ | |
| int j; | |
| for(j=0; j<optionCount; ++j) { | |
| if(options[j].longName && uprv_strcmp(arg, options[j].longName)==0) { | |
| option=options+j; | |
| break; | |
| } | |
| } | |
| if(option==NULL) { | |
| /* no option matches */ | |
| return -i; | |
| } | |
| option->doesOccur=1; | |
| if(option->hasArg!=UOPT_NO_ARG) { | |
| /* parse the argument for the option, if any */ | |
| if(i+1<argc && !(argv[i+1][0]=='-' && argv[i+1][1]!=0)) { | |
| /* argument in the next argv[], and there is not an option in there */ | |
| option->value=argv[++i]; | |
| } else if(option->hasArg==UOPT_REQUIRES_ARG) { | |
| /* there is no argument, but one is required: return with error */ | |
| option->doesOccur=0; | |
| return -i; | |
| } | |
| } | |
| if(option->optionFn!=NULL && option->optionFn(option->context, option)<0) { | |
| /* the option function was called and returned an error */ | |
| option->doesOccur=0; | |
| return -i; | |
| } | |
| } | |
| } else { | |
| /* process one or more short options */ | |
| do { | |
| /* search for the option letter */ | |
| int j; | |
| for(j=0; j<optionCount; ++j) { | |
| if(c==options[j].shortName) { | |
| option=options+j; | |
| break; | |
| } | |
| } | |
| if(option==NULL) { | |
| /* no option matches */ | |
| return -i; | |
| } | |
| option->doesOccur=1; | |
| if(option->hasArg!=UOPT_NO_ARG) { | |
| /* parse the argument for the option, if any */ | |
| if(*arg!=0) { | |
| /* argument following in the same argv[] */ | |
| option->value=arg; | |
| /* do not process the rest of this arg as option letters */ | |
| break; | |
| } else if(i+1<argc && !(argv[i+1][0]=='-' && argv[i+1][1]!=0)) { | |
| /* argument in the next argv[], and there is not an option in there */ | |
| option->value=argv[++i]; | |
| /* this break is redundant because we know that *arg==0 */ | |
| break; | |
| } else if(option->hasArg==UOPT_REQUIRES_ARG) { | |
| /* there is no argument, but one is required: return with error */ | |
| option->doesOccur=0; | |
| return -i; | |
| } | |
| } | |
| if(option->optionFn!=NULL && option->optionFn(option->context, option)<0) { | |
| /* the option function was called and returned an error */ | |
| option->doesOccur=0; | |
| return -i; | |
| } | |
| /* get the next option letter */ | |
| option=NULL; | |
| c=*arg++; | |
| } while(c!=0); | |
| } | |
| /* go to next argv[] */ | |
| ++i; | |
| } else { | |
| /* move a non-option up in argv[] */ | |
| argv[remaining++]=arg; | |
| ++i; | |
| } | |
| } | |
| return remaining; | |
| } |