1// © 2016 and later: Unicode, Inc. and others. 2// License & terms of use: http://www.unicode.org/copyright.html 3/* 4******************************************************************************* 5* 6* Copyright (C) 2000-2015, International Business Machines 7* Corporation and others. All Rights Reserved. 8* 9******************************************************************************* 10* file name: uoptions.c 11* encoding: UTF-8 12* tab size: 8 (not used) 13* indentation:4 14* 15* created on: 2000apr17 16* created by: Markus W. Scherer 17* 18* This file provides a command line argument parser. 19*/ 20 21#include "unicode/utypes.h" 22#include "cstring.h" 23#include "uoptions.h" 24 25U_CAPI int U_EXPORT2 26u_parseArgs(int argc, char* argv[], 27 int optionCount, UOption options[]) { 28 char *arg; 29 int i=1, remaining=1; 30 char c, stopOptions=0; 31 32 while(i<argc) { 33 arg=argv[i]; 34 if(!stopOptions && *arg=='-' && (c=arg[1])!=0) { 35 /* process an option */ 36 UOption *option=nullptr; 37 arg+=2; 38 if(c=='-') { 39 /* process a long option */ 40 if(*arg==0) { 41 /* stop processing options after "--" */ 42 stopOptions=1; 43 } else { 44 /* search for the option string */ 45 int j; 46 for(j=0; j<optionCount; ++j) { 47 if(options[j].longName && uprv_strcmp(arg, options[j].longName)==0) { 48 option=options+j; 49 break; 50 } 51 } 52 if(option==nullptr) { 53 /* no option matches */ 54 return -i; 55 } 56 option->doesOccur=1; 57 58 if(option->hasArg!=UOPT_NO_ARG) { 59 /* parse the argument for the option, if any */ 60 if(i+1<argc && !(argv[i+1][0]=='-' && argv[i+1][1]!=0)) { 61 /* argument in the next argv[], and there is not an option in there */ 62 option->value=argv[++i]; 63 } else if(option->hasArg==UOPT_REQUIRES_ARG) { 64 /* there is no argument, but one is required: return with error */ 65 option->doesOccur=0; 66 return -i; 67 } 68 } 69 70 if(option->optionFn!=nullptr && option->optionFn(option->context, option)<0) { 71 /* the option function was called and returned an error */ 72 option->doesOccur=0; 73 return -i; 74 } 75 } 76 } else { 77 /* process one or more short options */ 78 do { 79 /* search for the option letter */ 80 int j; 81 for(j=0; j<optionCount; ++j) { 82 if(c==options[j].shortName) { 83 option=options+j; 84 break; 85 } 86 } 87 if(option==nullptr) { 88 /* no option matches */ 89 return -i; 90 } 91 option->doesOccur=1; 92 93 if(option->hasArg!=UOPT_NO_ARG) { 94 /* parse the argument for the option, if any */ 95 if(*arg!=0) { 96 /* argument following in the same argv[] */ 97 option->value=arg; 98 /* do not process the rest of this arg as option letters */ 99 break; 100 } else if(i+1<argc && !(argv[i+1][0]=='-' && argv[i+1][1]!=0)) { 101 /* argument in the next argv[], and there is not an option in there */ 102 option->value=argv[++i]; 103 /* this break is redundant because we know that *arg==0 */ 104 break; 105 } else if(option->hasArg==UOPT_REQUIRES_ARG) { 106 /* there is no argument, but one is required: return with error */ 107 option->doesOccur=0; 108 return -i; 109 } 110 } 111 112 if(option->optionFn!=nullptr && option->optionFn(option->context, option)<0) { 113 /* the option function was called and returned an error */ 114 option->doesOccur=0; 115 return -i; 116 } 117 118 /* get the next option letter */ 119 option=nullptr; 120 c=*arg++; 121 } while(c!=0); 122 } 123 124 /* go to next argv[] */ 125 ++i; 126 } else { 127 /* move a non-option up in argv[] */ 128 argv[remaining++]=arg; 129 ++i; 130 } 131 } 132 return remaining; 133} 134