| // © 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; |
| } |