1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /******************************************************************************
3  *
4  * Module Name: getopt
5  *
6  * Copyright (C) 2000 - 2021, Intel Corp.
7  *
8  *****************************************************************************/
9 
10 /*
11  * ACPICA getopt() implementation
12  *
13  * Option strings:
14  *    "f"       - Option has no arguments
15  *    "f:"      - Option requires an argument
16  *    "f+"      - Option has an optional argument
17  *    "f^"      - Option has optional single-char sub-options
18  *    "f|"      - Option has required single-char sub-options
19  */
20 
21 #include <acpi/acpi.h>
22 #include "accommon.h"
23 #include "acapps.h"
24 
25 #define ACPI_OPTION_ERROR(msg, badchar) \
26 	if (acpi_gbl_opterr) {fprintf (stderr, "%s%c\n", msg, badchar);}
27 
28 int acpi_gbl_opterr = 1;
29 int acpi_gbl_optind = 1;
30 int acpi_gbl_sub_opt_char = 0;
31 char *acpi_gbl_optarg;
32 
33 static int current_char_ptr = 1;
34 
35 /*******************************************************************************
36  *
37  * FUNCTION:    acpi_getopt_argument
38  *
39  * PARAMETERS:  argc, argv          - from main
40  *
41  * RETURN:      0 if an argument was found, -1 otherwise. Sets acpi_gbl_Optarg
42  *              to point to the next argument.
43  *
44  * DESCRIPTION: Get the next argument. Used to obtain arguments for the
45  *              two-character options after the original call to acpi_getopt.
46  *              Note: Either the argument starts at the next character after
47  *              the option, or it is pointed to by the next argv entry.
48  *              (After call to acpi_getopt, we need to backup to the previous
49  *              argv entry).
50  *
51  ******************************************************************************/
52 
acpi_getopt_argument(int argc,char ** argv)53 int acpi_getopt_argument(int argc, char **argv)
54 {
55 
56 	acpi_gbl_optind--;
57 	current_char_ptr++;
58 
59 	if (argv[acpi_gbl_optind][(int)(current_char_ptr + 1)] != '\0') {
60 		acpi_gbl_optarg =
61 		    &argv[acpi_gbl_optind++][(int)(current_char_ptr + 1)];
62 	} else if (++acpi_gbl_optind >= argc) {
63 		ACPI_OPTION_ERROR("\nOption requires an argument", 0);
64 
65 		current_char_ptr = 1;
66 		return (-1);
67 	} else {
68 		acpi_gbl_optarg = argv[acpi_gbl_optind++];
69 	}
70 
71 	current_char_ptr = 1;
72 	return (0);
73 }
74 
75 /*******************************************************************************
76  *
77  * FUNCTION:    acpi_getopt
78  *
79  * PARAMETERS:  argc, argv          - from main
80  *              opts                - options info list
81  *
82  * RETURN:      Option character or ACPI_OPT_END
83  *
84  * DESCRIPTION: Get the next option
85  *
86  ******************************************************************************/
87 
acpi_getopt(int argc,char ** argv,char * opts)88 int acpi_getopt(int argc, char **argv, char *opts)
89 {
90 	int current_char;
91 	char *opts_ptr;
92 
93 	if (current_char_ptr == 1) {
94 		if (acpi_gbl_optind >= argc ||
95 		    argv[acpi_gbl_optind][0] != '-' ||
96 		    argv[acpi_gbl_optind][1] == '\0') {
97 			return (ACPI_OPT_END);
98 		} else if (strcmp(argv[acpi_gbl_optind], "--") == 0) {
99 			acpi_gbl_optind++;
100 			return (ACPI_OPT_END);
101 		}
102 	}
103 
104 	/* Get the option */
105 
106 	current_char = argv[acpi_gbl_optind][current_char_ptr];
107 
108 	/* Make sure that the option is legal */
109 
110 	if (current_char == ':' ||
111 	    (opts_ptr = strchr(opts, current_char)) == NULL) {
112 		ACPI_OPTION_ERROR("Illegal option: -", current_char);
113 
114 		if (argv[acpi_gbl_optind][++current_char_ptr] == '\0') {
115 			acpi_gbl_optind++;
116 			current_char_ptr = 1;
117 		}
118 
119 		return ('?');
120 	}
121 
122 	/* Option requires an argument? */
123 
124 	if (*++opts_ptr == ':') {
125 		if (argv[acpi_gbl_optind][(int)(current_char_ptr + 1)] != '\0') {
126 			acpi_gbl_optarg =
127 			    &argv[acpi_gbl_optind++][(int)
128 						     (current_char_ptr + 1)];
129 		} else if (++acpi_gbl_optind >= argc) {
130 			ACPI_OPTION_ERROR("Option requires an argument: -",
131 					  current_char);
132 
133 			current_char_ptr = 1;
134 			return ('?');
135 		} else {
136 			acpi_gbl_optarg = argv[acpi_gbl_optind++];
137 		}
138 
139 		current_char_ptr = 1;
140 	}
141 
142 	/* Option has an optional argument? */
143 
144 	else if (*opts_ptr == '+') {
145 		if (argv[acpi_gbl_optind][(int)(current_char_ptr + 1)] != '\0') {
146 			acpi_gbl_optarg =
147 			    &argv[acpi_gbl_optind++][(int)
148 						     (current_char_ptr + 1)];
149 		} else if (++acpi_gbl_optind >= argc) {
150 			acpi_gbl_optarg = NULL;
151 		} else {
152 			acpi_gbl_optarg = argv[acpi_gbl_optind++];
153 		}
154 
155 		current_char_ptr = 1;
156 	}
157 
158 	/* Option has optional single-char arguments? */
159 
160 	else if (*opts_ptr == '^') {
161 		if (argv[acpi_gbl_optind][(int)(current_char_ptr + 1)] != '\0') {
162 			acpi_gbl_optarg =
163 			    &argv[acpi_gbl_optind][(int)(current_char_ptr + 1)];
164 		} else {
165 			acpi_gbl_optarg = "^";
166 		}
167 
168 		acpi_gbl_sub_opt_char = acpi_gbl_optarg[0];
169 		acpi_gbl_optind++;
170 		current_char_ptr = 1;
171 	}
172 
173 	/* Option has a required single-char argument? */
174 
175 	else if (*opts_ptr == '|') {
176 		if (argv[acpi_gbl_optind][(int)(current_char_ptr + 1)] != '\0') {
177 			acpi_gbl_optarg =
178 			    &argv[acpi_gbl_optind][(int)(current_char_ptr + 1)];
179 		} else {
180 			ACPI_OPTION_ERROR
181 			    ("Option requires a single-character suboption: -",
182 			     current_char);
183 
184 			current_char_ptr = 1;
185 			return ('?');
186 		}
187 
188 		acpi_gbl_sub_opt_char = acpi_gbl_optarg[0];
189 		acpi_gbl_optind++;
190 		current_char_ptr = 1;
191 	}
192 
193 	/* Option with no arguments */
194 
195 	else {
196 		if (argv[acpi_gbl_optind][++current_char_ptr] == '\0') {
197 			current_char_ptr = 1;
198 			acpi_gbl_optind++;
199 		}
200 
201 		acpi_gbl_optarg = NULL;
202 	}
203 
204 	return (current_char);
205 }
206