162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
262306a36Sopenharmony_ci/******************************************************************************
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Module Name: getopt
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Copyright (C) 2000 - 2023, Intel Corp.
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci *****************************************************************************/
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci/*
1162306a36Sopenharmony_ci * ACPICA getopt() implementation
1262306a36Sopenharmony_ci *
1362306a36Sopenharmony_ci * Option strings:
1462306a36Sopenharmony_ci *    "f"       - Option has no arguments
1562306a36Sopenharmony_ci *    "f:"      - Option requires an argument
1662306a36Sopenharmony_ci *    "f+"      - Option has an optional argument
1762306a36Sopenharmony_ci *    "f^"      - Option has optional single-char sub-options
1862306a36Sopenharmony_ci *    "f|"      - Option has required single-char sub-options
1962306a36Sopenharmony_ci */
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#include <acpi/acpi.h>
2262306a36Sopenharmony_ci#include "accommon.h"
2362306a36Sopenharmony_ci#include "acapps.h"
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#define ACPI_OPTION_ERROR(msg, badchar) \
2662306a36Sopenharmony_ci	if (acpi_gbl_opterr) {fprintf (stderr, "%s%c\n", msg, badchar);}
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ciint acpi_gbl_opterr = 1;
2962306a36Sopenharmony_ciint acpi_gbl_optind = 1;
3062306a36Sopenharmony_ciint acpi_gbl_sub_opt_char = 0;
3162306a36Sopenharmony_cichar *acpi_gbl_optarg;
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_cistatic int current_char_ptr = 1;
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci/*******************************************************************************
3662306a36Sopenharmony_ci *
3762306a36Sopenharmony_ci * FUNCTION:    acpi_getopt_argument
3862306a36Sopenharmony_ci *
3962306a36Sopenharmony_ci * PARAMETERS:  argc, argv          - from main
4062306a36Sopenharmony_ci *
4162306a36Sopenharmony_ci * RETURN:      0 if an argument was found, -1 otherwise. Sets acpi_gbl_Optarg
4262306a36Sopenharmony_ci *              to point to the next argument.
4362306a36Sopenharmony_ci *
4462306a36Sopenharmony_ci * DESCRIPTION: Get the next argument. Used to obtain arguments for the
4562306a36Sopenharmony_ci *              two-character options after the original call to acpi_getopt.
4662306a36Sopenharmony_ci *              Note: Either the argument starts at the next character after
4762306a36Sopenharmony_ci *              the option, or it is pointed to by the next argv entry.
4862306a36Sopenharmony_ci *              (After call to acpi_getopt, we need to backup to the previous
4962306a36Sopenharmony_ci *              argv entry).
5062306a36Sopenharmony_ci *
5162306a36Sopenharmony_ci ******************************************************************************/
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ciint acpi_getopt_argument(int argc, char **argv)
5462306a36Sopenharmony_ci{
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	acpi_gbl_optind--;
5762306a36Sopenharmony_ci	current_char_ptr++;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	if (argv[acpi_gbl_optind][(int)(current_char_ptr + 1)] != '\0') {
6062306a36Sopenharmony_ci		acpi_gbl_optarg =
6162306a36Sopenharmony_ci		    &argv[acpi_gbl_optind++][(int)(current_char_ptr + 1)];
6262306a36Sopenharmony_ci	} else if (++acpi_gbl_optind >= argc) {
6362306a36Sopenharmony_ci		ACPI_OPTION_ERROR("\nOption requires an argument", 0);
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci		current_char_ptr = 1;
6662306a36Sopenharmony_ci		return (-1);
6762306a36Sopenharmony_ci	} else {
6862306a36Sopenharmony_ci		acpi_gbl_optarg = argv[acpi_gbl_optind++];
6962306a36Sopenharmony_ci	}
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	current_char_ptr = 1;
7262306a36Sopenharmony_ci	return (0);
7362306a36Sopenharmony_ci}
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci/*******************************************************************************
7662306a36Sopenharmony_ci *
7762306a36Sopenharmony_ci * FUNCTION:    acpi_getopt
7862306a36Sopenharmony_ci *
7962306a36Sopenharmony_ci * PARAMETERS:  argc, argv          - from main
8062306a36Sopenharmony_ci *              opts                - options info list
8162306a36Sopenharmony_ci *
8262306a36Sopenharmony_ci * RETURN:      Option character or ACPI_OPT_END
8362306a36Sopenharmony_ci *
8462306a36Sopenharmony_ci * DESCRIPTION: Get the next option
8562306a36Sopenharmony_ci *
8662306a36Sopenharmony_ci ******************************************************************************/
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ciint acpi_getopt(int argc, char **argv, char *opts)
8962306a36Sopenharmony_ci{
9062306a36Sopenharmony_ci	int current_char;
9162306a36Sopenharmony_ci	char *opts_ptr;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	if (current_char_ptr == 1) {
9462306a36Sopenharmony_ci		if (acpi_gbl_optind >= argc ||
9562306a36Sopenharmony_ci		    argv[acpi_gbl_optind][0] != '-' ||
9662306a36Sopenharmony_ci		    argv[acpi_gbl_optind][1] == '\0') {
9762306a36Sopenharmony_ci			return (ACPI_OPT_END);
9862306a36Sopenharmony_ci		} else if (strcmp(argv[acpi_gbl_optind], "--") == 0) {
9962306a36Sopenharmony_ci			acpi_gbl_optind++;
10062306a36Sopenharmony_ci			return (ACPI_OPT_END);
10162306a36Sopenharmony_ci		}
10262306a36Sopenharmony_ci	}
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	/* Get the option */
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	current_char = argv[acpi_gbl_optind][current_char_ptr];
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	/* Make sure that the option is legal */
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	if (current_char == ':' ||
11162306a36Sopenharmony_ci	    (opts_ptr = strchr(opts, current_char)) == NULL) {
11262306a36Sopenharmony_ci		ACPI_OPTION_ERROR("Illegal option: -", current_char);
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci		if (argv[acpi_gbl_optind][++current_char_ptr] == '\0') {
11562306a36Sopenharmony_ci			acpi_gbl_optind++;
11662306a36Sopenharmony_ci			current_char_ptr = 1;
11762306a36Sopenharmony_ci		}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci		return ('?');
12062306a36Sopenharmony_ci	}
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	/* Option requires an argument? */
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	if (*++opts_ptr == ':') {
12562306a36Sopenharmony_ci		if (argv[acpi_gbl_optind][(int)(current_char_ptr + 1)] != '\0') {
12662306a36Sopenharmony_ci			acpi_gbl_optarg =
12762306a36Sopenharmony_ci			    &argv[acpi_gbl_optind++][(int)
12862306a36Sopenharmony_ci						     (current_char_ptr + 1)];
12962306a36Sopenharmony_ci		} else if (++acpi_gbl_optind >= argc) {
13062306a36Sopenharmony_ci			ACPI_OPTION_ERROR("Option requires an argument: -",
13162306a36Sopenharmony_ci					  current_char);
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci			current_char_ptr = 1;
13462306a36Sopenharmony_ci			return ('?');
13562306a36Sopenharmony_ci		} else {
13662306a36Sopenharmony_ci			acpi_gbl_optarg = argv[acpi_gbl_optind++];
13762306a36Sopenharmony_ci		}
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci		current_char_ptr = 1;
14062306a36Sopenharmony_ci	}
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	/* Option has an optional argument? */
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	else if (*opts_ptr == '+') {
14562306a36Sopenharmony_ci		if (argv[acpi_gbl_optind][(int)(current_char_ptr + 1)] != '\0') {
14662306a36Sopenharmony_ci			acpi_gbl_optarg =
14762306a36Sopenharmony_ci			    &argv[acpi_gbl_optind++][(int)
14862306a36Sopenharmony_ci						     (current_char_ptr + 1)];
14962306a36Sopenharmony_ci		} else if (++acpi_gbl_optind >= argc) {
15062306a36Sopenharmony_ci			acpi_gbl_optarg = NULL;
15162306a36Sopenharmony_ci		} else {
15262306a36Sopenharmony_ci			acpi_gbl_optarg = argv[acpi_gbl_optind++];
15362306a36Sopenharmony_ci		}
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci		current_char_ptr = 1;
15662306a36Sopenharmony_ci	}
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	/* Option has optional single-char arguments? */
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	else if (*opts_ptr == '^') {
16162306a36Sopenharmony_ci		if (argv[acpi_gbl_optind][(int)(current_char_ptr + 1)] != '\0') {
16262306a36Sopenharmony_ci			acpi_gbl_optarg =
16362306a36Sopenharmony_ci			    &argv[acpi_gbl_optind][(int)(current_char_ptr + 1)];
16462306a36Sopenharmony_ci		} else {
16562306a36Sopenharmony_ci			acpi_gbl_optarg = "^";
16662306a36Sopenharmony_ci		}
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci		acpi_gbl_sub_opt_char = acpi_gbl_optarg[0];
16962306a36Sopenharmony_ci		acpi_gbl_optind++;
17062306a36Sopenharmony_ci		current_char_ptr = 1;
17162306a36Sopenharmony_ci	}
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	/* Option has a required single-char argument? */
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	else if (*opts_ptr == '|') {
17662306a36Sopenharmony_ci		if (argv[acpi_gbl_optind][(int)(current_char_ptr + 1)] != '\0') {
17762306a36Sopenharmony_ci			acpi_gbl_optarg =
17862306a36Sopenharmony_ci			    &argv[acpi_gbl_optind][(int)(current_char_ptr + 1)];
17962306a36Sopenharmony_ci		} else {
18062306a36Sopenharmony_ci			ACPI_OPTION_ERROR
18162306a36Sopenharmony_ci			    ("Option requires a single-character suboption: -",
18262306a36Sopenharmony_ci			     current_char);
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci			current_char_ptr = 1;
18562306a36Sopenharmony_ci			return ('?');
18662306a36Sopenharmony_ci		}
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci		acpi_gbl_sub_opt_char = acpi_gbl_optarg[0];
18962306a36Sopenharmony_ci		acpi_gbl_optind++;
19062306a36Sopenharmony_ci		current_char_ptr = 1;
19162306a36Sopenharmony_ci	}
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	/* Option with no arguments */
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	else {
19662306a36Sopenharmony_ci		if (argv[acpi_gbl_optind][++current_char_ptr] == '\0') {
19762306a36Sopenharmony_ci			current_char_ptr = 1;
19862306a36Sopenharmony_ci			acpi_gbl_optind++;
19962306a36Sopenharmony_ci		}
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci		acpi_gbl_optarg = NULL;
20262306a36Sopenharmony_ci	}
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	return (current_char);
20562306a36Sopenharmony_ci}
206