1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 7 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 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 #include <stdio.h>
20 #include <string.h>
21 #include <assert.h>
22 #include <stdlib.h>
23 #include "php_getopt.h"
24
25 #define OPTERRCOLON (1)
26 #define OPTERRNF (2)
27 #define OPTERRARG (3)
28
29 // Print error message to stderr and return -2 to distinguish it from '?' command line option.
php_opt_error(int argc,char * const * argv,int oint,int optchr,int err,int show_err)30 static int php_opt_error(int argc, char * const *argv, int oint, int optchr, int err, int show_err) /* {{{ */
31 {
32 if (show_err)
33 {
34 fprintf(stderr, "Error in argument %d, char %d: ", oint, optchr+1);
35 switch(err)
36 {
37 case OPTERRCOLON:
38 fprintf(stderr, ": in flags\n");
39 break;
40 case OPTERRNF:
41 fprintf(stderr, "option not found %c\n", argv[oint][optchr]);
42 break;
43 case OPTERRARG:
44 fprintf(stderr, "no argument for option %c\n", argv[oint][optchr]);
45 break;
46 default:
47 fprintf(stderr, "unknown\n");
48 break;
49 }
50 }
51 return PHP_GETOPT_INVALID_ARG;
52 }
53 /* }}} */
54
55 PHPAPI int php_optidx = -1;
56
php_getopt(int argc,char * const * argv,const opt_struct opts[],char ** optarg,int * optind,int show_err,int arg_start)57 PHPAPI int php_getopt(int argc, char* const *argv, const opt_struct opts[], char **optarg, int *optind, int show_err, int arg_start) /* {{{ */
58 {
59 static int optchr = 0;
60 static int dash = 0; /* have already seen the - */
61 static char **prev_optarg = NULL;
62
63 php_optidx = -1;
64
65 if(prev_optarg && prev_optarg != optarg) {
66 /* reset the state */
67 optchr = 0;
68 dash = 0;
69 }
70 prev_optarg = optarg;
71
72 if (*optind >= argc) {
73 return(EOF);
74 }
75 if (!dash) {
76 if ((argv[*optind][0] != '-')) {
77 return(EOF);
78 } else {
79 if (!argv[*optind][1])
80 {
81 /*
82 * use to specify stdin. Need to let pgm process this and
83 * the following args
84 */
85 return(EOF);
86 }
87 }
88 }
89 if ((argv[*optind][0] == '-') && (argv[*optind][1] == '-')) {
90 const char *pos;
91 size_t arg_end = strlen(argv[*optind])-1;
92
93 /* '--' indicates end of args if not followed by a known long option name */
94 if (argv[*optind][2] == '\0') {
95 (*optind)++;
96 return(EOF);
97 }
98
99 arg_start = 2;
100
101 /* Check for <arg>=<val> */
102 if ((pos = php_memnstr(&argv[*optind][arg_start], "=", 1, argv[*optind]+arg_end)) != NULL) {
103 arg_end = pos-&argv[*optind][arg_start];
104 arg_start++;
105 } else {
106 arg_end--;
107 }
108
109 while (1) {
110 php_optidx++;
111 if (opts[php_optidx].opt_char == '-') {
112 (*optind)++;
113 return(php_opt_error(argc, argv, *optind-1, optchr, OPTERRARG, show_err));
114 } 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)) {
115 break;
116 }
117 }
118
119 optchr = 0;
120 dash = 0;
121 arg_start += (int)strlen(opts[php_optidx].opt_name);
122 } else {
123 if (!dash) {
124 dash = 1;
125 optchr = 1;
126 }
127 /* Check if the guy tries to do a -: kind of flag */
128 if (argv[*optind][optchr] == ':') {
129 dash = 0;
130 (*optind)++;
131 return (php_opt_error(argc, argv, *optind-1, optchr, OPTERRCOLON, show_err));
132 }
133 arg_start = 1 + optchr;
134 }
135 if (php_optidx < 0) {
136 while (1) {
137 php_optidx++;
138 if (opts[php_optidx].opt_char == '-') {
139 int errind = *optind;
140 int errchr = optchr;
141
142 if (!argv[*optind][optchr+1]) {
143 dash = 0;
144 (*optind)++;
145 } else {
146 optchr++;
147 arg_start++;
148 }
149 return(php_opt_error(argc, argv, errind, errchr, OPTERRNF, show_err));
150 } else if (argv[*optind][optchr] == opts[php_optidx].opt_char) {
151 break;
152 }
153 }
154 }
155 if (opts[php_optidx].need_param) {
156 /* Check for cases where the value of the argument
157 is in the form -<arg> <val>, -<arg>=<varl> or -<arg><val> */
158 dash = 0;
159 if (!argv[*optind][arg_start]) {
160 (*optind)++;
161 if (*optind == argc) {
162 /* Was the value required or is it optional? */
163 if (opts[php_optidx].need_param == 1) {
164 return(php_opt_error(argc, argv, *optind-1, optchr, OPTERRARG, show_err));
165 }
166 /* Optional value is not supported with -<arg> <val> style */
167 } else if (opts[php_optidx].need_param == 1) {
168 *optarg = argv[(*optind)++];
169 }
170 } else if (argv[*optind][arg_start] == '=') {
171 arg_start++;
172 *optarg = &argv[*optind][arg_start];
173 (*optind)++;
174 } else {
175 *optarg = &argv[*optind][arg_start];
176 (*optind)++;
177 }
178 return opts[php_optidx].opt_char;
179 } else {
180 /* multiple options specified as one (exclude long opts) */
181 if (arg_start >= 2 && !((argv[*optind][0] == '-') && (argv[*optind][1] == '-'))) {
182 if (!argv[*optind][optchr+1])
183 {
184 dash = 0;
185 (*optind)++;
186 } else {
187 optchr++;
188 }
189 } else {
190 (*optind)++;
191 }
192 return opts[php_optidx].opt_char;
193 }
194 assert(0);
195 return(0); /* never reached */
196 }
197 /* }}} */
198