xref: /PHP-7.1/main/getopt.c (revision ccd4716e)
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