1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 5 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2014 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
63 php_optidx = -1;
64
65 if (*optind >= argc) {
66 return(EOF);
67 }
68 if (!dash) {
69 if ((argv[*optind][0] != '-')) {
70 return(EOF);
71 } else {
72 if (!argv[*optind][1])
73 {
74 /*
75 * use to specify stdin. Need to let pgm process this and
76 * the following args
77 */
78 return(EOF);
79 }
80 }
81 }
82 if ((argv[*optind][0] == '-') && (argv[*optind][1] == '-')) {
83 char *pos;
84 int arg_end = strlen(argv[*optind])-1;
85
86 /* '--' indicates end of args if not followed by a known long option name */
87 if (argv[*optind][2] == '\0') {
88 (*optind)++;
89 return(EOF);
90 }
91
92 arg_start = 2;
93
94 /* Check for <arg>=<val> */
95 if ((pos = php_memnstr(&argv[*optind][arg_start], "=", 1, argv[*optind]+arg_end)) != NULL) {
96 arg_end = pos-&argv[*optind][arg_start];
97 arg_start++;
98 } else {
99 arg_end--;
100 }
101
102 while (1) {
103 php_optidx++;
104 if (opts[php_optidx].opt_char == '-') {
105 (*optind)++;
106 return(php_opt_error(argc, argv, *optind-1, optchr, OPTERRARG, show_err));
107 } 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)) {
108 break;
109 }
110 }
111
112 optchr = 0;
113 dash = 0;
114 arg_start += strlen(opts[php_optidx].opt_name);
115 } else {
116 if (!dash) {
117 dash = 1;
118 optchr = 1;
119 }
120 /* Check if the guy tries to do a -: kind of flag */
121 if (argv[*optind][optchr] == ':') {
122 dash = 0;
123 (*optind)++;
124 return (php_opt_error(argc, argv, *optind-1, optchr, OPTERRCOLON, show_err));
125 }
126 arg_start = 1 + optchr;
127 }
128 if (php_optidx < 0) {
129 while (1) {
130 php_optidx++;
131 if (opts[php_optidx].opt_char == '-') {
132 int errind = *optind;
133 int errchr = optchr;
134
135 if (!argv[*optind][optchr+1]) {
136 dash = 0;
137 (*optind)++;
138 } else {
139 optchr++;
140 arg_start++;
141 }
142 return(php_opt_error(argc, argv, errind, errchr, OPTERRNF, show_err));
143 } else if (argv[*optind][optchr] == opts[php_optidx].opt_char) {
144 break;
145 }
146 }
147 }
148 if (opts[php_optidx].need_param) {
149 /* Check for cases where the value of the argument
150 is in the form -<arg> <val>, -<arg>=<varl> or -<arg><val> */
151 dash = 0;
152 if (!argv[*optind][arg_start]) {
153 (*optind)++;
154 if (*optind == argc) {
155 /* Was the value required or is it optional? */
156 if (opts[php_optidx].need_param == 1) {
157 return(php_opt_error(argc, argv, *optind-1, optchr, OPTERRARG, show_err));
158 }
159 /* Optional value is not supported with -<arg> <val> style */
160 } else if (opts[php_optidx].need_param == 1) {
161 *optarg = argv[(*optind)++];
162 }
163 } else if (argv[*optind][arg_start] == '=') {
164 arg_start++;
165 *optarg = &argv[*optind][arg_start];
166 (*optind)++;
167 } else {
168 *optarg = &argv[*optind][arg_start];
169 (*optind)++;
170 }
171 return opts[php_optidx].opt_char;
172 } else {
173 /* multiple options specified as one (exclude long opts) */
174 if (arg_start >= 2 && !((argv[*optind][0] == '-') && (argv[*optind][1] == '-'))) {
175 if (!argv[*optind][optchr+1])
176 {
177 dash = 0;
178 (*optind)++;
179 } else {
180 optchr++;
181 }
182 } else {
183 (*optind)++;
184 }
185 return opts[php_optidx].opt_char;
186 }
187 assert(0);
188 return(0); /* never reached */
189 }
190 /* }}} */
191
192 /*
193 * Local variables:
194 * tab-width: 4
195 * c-basic-offset: 4
196 * End:
197 * vim600: sw=4 ts=4 fdm=marker
198 * vim<600: sw=4 ts=4
199 */
200