1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 7 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2018 The PHP Group |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Author: Marcus Boerger <helly@php.net> |
16 +----------------------------------------------------------------------+
17 */
18
19 /* $Id$ */
20
21 #include <stdio.h>
22 #include <string.h>
23 #include <assert.h>
24 #include <stdlib.h>
25 #include "php_getopt.h"
26
27 #define OPTERRCOLON (1)
28 #define OPTERRNF (2)
29 #define OPTERRARG (3)
30
php_opt_error(int argc,char * const * argv,int oint,int optchr,int err,int show_err)31 static int php_opt_error(int argc, char * const *argv, int oint, int optchr, int err, int show_err) /* {{{ */
32 {
33 if (show_err)
34 {
35 fprintf(stderr, "Error in argument %d, char %d: ", oint, optchr+1);
36 switch(err)
37 {
38 case OPTERRCOLON:
39 fprintf(stderr, ": in flags\n");
40 break;
41 case OPTERRNF:
42 fprintf(stderr, "option not found %c\n", argv[oint][optchr]);
43 break;
44 case OPTERRARG:
45 fprintf(stderr, "no argument for option %c\n", argv[oint][optchr]);
46 break;
47 default:
48 fprintf(stderr, "unknown\n");
49 break;
50 }
51 }
52 return('?');
53 }
54 /* }}} */
55
56 PHPAPI int php_optidx = -1;
57
php_getopt(int argc,char * const * argv,const opt_struct opts[],char ** optarg,int * optind,int show_err,int arg_start)58 PHPAPI int php_getopt(int argc, char* const *argv, const opt_struct opts[], char **optarg, int *optind, int show_err, int arg_start) /* {{{ */
59 {
60 static int optchr = 0;
61 static int dash = 0; /* have already seen the - */
62 static char **prev_optarg = NULL;
63
64 php_optidx = -1;
65
66 if(prev_optarg && prev_optarg != optarg) {
67 /* reset the state */
68 optchr = 0;
69 dash = 0;
70 }
71 prev_optarg = optarg;
72
73 if (*optind >= argc) {
74 return(EOF);
75 }
76 if (!dash) {
77 if ((argv[*optind][0] != '-')) {
78 return(EOF);
79 } else {
80 if (!argv[*optind][1])
81 {
82 /*
83 * use to specify stdin. Need to let pgm process this and
84 * the following args
85 */
86 return(EOF);
87 }
88 }
89 }
90 if ((argv[*optind][0] == '-') && (argv[*optind][1] == '-')) {
91 const char *pos;
92 size_t arg_end = strlen(argv[*optind])-1;
93
94 /* '--' indicates end of args if not followed by a known long option name */
95 if (argv[*optind][2] == '\0') {
96 (*optind)++;
97 return(EOF);
98 }
99
100 arg_start = 2;
101
102 /* Check for <arg>=<val> */
103 if ((pos = php_memnstr(&argv[*optind][arg_start], "=", 1, argv[*optind]+arg_end)) != NULL) {
104 arg_end = pos-&argv[*optind][arg_start];
105 arg_start++;
106 } else {
107 arg_end--;
108 }
109
110 while (1) {
111 php_optidx++;
112 if (opts[php_optidx].opt_char == '-') {
113 (*optind)++;
114 return(php_opt_error(argc, argv, *optind-1, optchr, OPTERRARG, show_err));
115 } else if (opts[php_optidx].opt_name && !strncmp(&argv[*optind][2], opts[php_optidx].opt_name, arg_end) && arg_end == strlen(opts[php_optidx].opt_name)) {
116 break;
117 }
118 }
119
120 optchr = 0;
121 dash = 0;
122 arg_start += (int)strlen(opts[php_optidx].opt_name);
123 } else {
124 if (!dash) {
125 dash = 1;
126 optchr = 1;
127 }
128 /* Check if the guy tries to do a -: kind of flag */
129 if (argv[*optind][optchr] == ':') {
130 dash = 0;
131 (*optind)++;
132 return (php_opt_error(argc, argv, *optind-1, optchr, OPTERRCOLON, show_err));
133 }
134 arg_start = 1 + optchr;
135 }
136 if (php_optidx < 0) {
137 while (1) {
138 php_optidx++;
139 if (opts[php_optidx].opt_char == '-') {
140 int errind = *optind;
141 int errchr = optchr;
142
143 if (!argv[*optind][optchr+1]) {
144 dash = 0;
145 (*optind)++;
146 } else {
147 optchr++;
148 arg_start++;
149 }
150 return(php_opt_error(argc, argv, errind, errchr, OPTERRNF, show_err));
151 } else if (argv[*optind][optchr] == opts[php_optidx].opt_char) {
152 break;
153 }
154 }
155 }
156 if (opts[php_optidx].need_param) {
157 /* Check for cases where the value of the argument
158 is in the form -<arg> <val>, -<arg>=<varl> or -<arg><val> */
159 dash = 0;
160 if (!argv[*optind][arg_start]) {
161 (*optind)++;
162 if (*optind == argc) {
163 /* Was the value required or is it optional? */
164 if (opts[php_optidx].need_param == 1) {
165 return(php_opt_error(argc, argv, *optind-1, optchr, OPTERRARG, show_err));
166 }
167 /* Optional value is not supported with -<arg> <val> style */
168 } else if (opts[php_optidx].need_param == 1) {
169 *optarg = argv[(*optind)++];
170 }
171 } else if (argv[*optind][arg_start] == '=') {
172 arg_start++;
173 *optarg = &argv[*optind][arg_start];
174 (*optind)++;
175 } else {
176 *optarg = &argv[*optind][arg_start];
177 (*optind)++;
178 }
179 return opts[php_optidx].opt_char;
180 } else {
181 /* multiple options specified as one (exclude long opts) */
182 if (arg_start >= 2 && !((argv[*optind][0] == '-') && (argv[*optind][1] == '-'))) {
183 if (!argv[*optind][optchr+1])
184 {
185 dash = 0;
186 (*optind)++;
187 } else {
188 optchr++;
189 }
190 } else {
191 (*optind)++;
192 }
193 return opts[php_optidx].opt_char;
194 }
195 assert(0);
196 return(0); /* never reached */
197 }
198 /* }}} */
199
200 /*
201 * Local variables:
202 * tab-width: 4
203 * c-basic-offset: 4
204 * End:
205 * vim600: sw=4 ts=4 fdm=marker
206 * vim<600: sw=4 ts=4
207 */
208