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