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