1/*
2*******************************************************************************
3*
4*   Copyright (C) 2000, 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                            return -i;
64                        }
65                    }
66                }
67            } else {
68                /* process one or more short options */
69                do {
70                    /* search for the option letter */
71                    int j;
72                    for(j=0; j<optionCount; ++j) {
73                        if(c==options[j].shortName) {
74                            option=options+j;
75                            break;
76                        }
77                    }
78                    if(option==NULL) {
79                        /* no option matches */
80                        return -i;
81                    }
82                    option->doesOccur=1;
83
84                    if(option->hasArg!=UOPT_NO_ARG) {
85                        /* parse the argument for the option, if any */
86                        if(*arg!=0) {
87                            /* argument following in the same argv[] */
88                            option->value=arg;
89                            /* do not process the rest of this arg as option letters */
90                            break;
91                        } else if(i+1<argc && !(argv[i+1][0]=='-' && argv[i+1][1]!=0)) {
92                            /* argument in the next argv[], and there is not an option in there */
93                            option->value=argv[++i];
94                            /* this break is redundant because we know that *arg==0 */
95                            break;
96                        } else if(option->hasArg==UOPT_REQUIRES_ARG) {
97                            /* there is no argument, but one is required: return with error */
98                            return -i;
99                        }
100                    }
101
102                    /* get the next option letter */
103                    option=NULL;
104                    c=*arg++;
105                } while(c!=0);
106            }
107
108            if(option!=0 && option->optionFn!=0 && option->optionFn(option->context, option)<0) {
109                /* the option function was called and returned an error */
110                return -i;
111            }
112
113            /* go to next argv[] */
114            ++i;
115        } else {
116            /* move a non-option up in argv[] */
117            argv[remaining++]=arg;
118            ++i;
119        }
120    }
121    return remaining;
122}
123