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