1 // Copyright (C) 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: US-ASCII
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
25 U_CAPI int U_EXPORT2
u_parseArgs(int argc,char * argv[],int optionCount,UOption options[])26 u_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=NULL;
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==NULL) {
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!=NULL && 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==NULL) {
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!=NULL && 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=NULL;
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