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 
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