blob: e9175e2fff49adec2795337e5b0dc89adf794f35 [file] [log] [blame]
Sean Anderson3b4a6f52020-10-27 19:55:36 -04001// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * getopt.c - a simple getopt(3) implementation. See getopt.h for explanation.
4 *
5 * Copyright (C) 2020 Sean Anderson <seanga2@gmail.com>
6 * Copyright (c) 2007 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
7 */
8
9#define LOG_CATEGORY LOGC_CORE
10
Sean Anderson3b4a6f52020-10-27 19:55:36 -040011#include <getopt.h>
12#include <log.h>
Tom Rinia877ce12023-12-14 13:16:58 -050013#include <linux/string.h>
Sean Anderson3b4a6f52020-10-27 19:55:36 -040014
15void getopt_init_state(struct getopt_state *gs)
16{
17 gs->index = 1;
18 gs->arg_index = 1;
19}
20
21int __getopt(struct getopt_state *gs, int argc, char *const argv[],
22 const char *optstring, bool silent)
23{
24 char curopt; /* current option character */
25 const char *curoptp; /* pointer to the current option in optstring */
26
27 while (1) {
28 log_debug("arg_index: %d index: %d\n", gs->arg_index,
29 gs->index);
30
31 /* `--` indicates the end of options */
32 if (gs->arg_index == 1 && argv[gs->index] &&
33 !strcmp(argv[gs->index], "--")) {
34 gs->index++;
35 return -1;
36 }
37
38 /* Out of arguments */
39 if (gs->index >= argc)
40 return -1;
41
42 /* Can't parse non-options */
43 if (*argv[gs->index] != '-')
44 return -1;
45
46 /* We have found an option */
47 curopt = argv[gs->index][gs->arg_index];
48 if (curopt)
49 break;
50 /*
51 * no more options in current argv[] element; try the next one
52 */
53 gs->index++;
54 gs->arg_index = 1;
55 }
56
57 /* look up current option in optstring */
58 curoptp = strchr(optstring, curopt);
59
60 if (!curoptp) {
61 if (!silent)
62 printf("%s: invalid option -- %c\n", argv[0], curopt);
63 gs->opt = curopt;
64 gs->arg_index++;
65 return '?';
66 }
67
68 if (*(curoptp + 1) != ':') {
69 /* option with no argument. Just return it */
70 gs->arg = NULL;
71 gs->arg_index++;
72 return curopt;
73 }
74
75 if (*(curoptp + 1) && *(curoptp + 2) == ':') {
76 /* optional argument */
77 if (argv[gs->index][gs->arg_index + 1]) {
78 /* optional argument with directly following arg */
79 gs->arg = argv[gs->index++] + gs->arg_index + 1;
80 gs->arg_index = 1;
81 return curopt;
82 }
83 if (gs->index + 1 == argc) {
84 /* We are at the last argv[] element */
85 gs->arg = NULL;
86 gs->index++;
87 return curopt;
88 }
89 if (*argv[gs->index + 1] != '-') {
90 /*
91 * optional argument with arg in next argv[] element
92 */
93 gs->index++;
94 gs->arg = argv[gs->index++];
95 gs->arg_index = 1;
96 return curopt;
97 }
98
99 /* no optional argument found */
100 gs->arg = NULL;
101 gs->arg_index = 1;
102 gs->index++;
103 return curopt;
104 }
105
106 if (argv[gs->index][gs->arg_index + 1]) {
107 /* required argument with directly following arg */
108 gs->arg = argv[gs->index++] + gs->arg_index + 1;
109 gs->arg_index = 1;
110 return curopt;
111 }
112
113 gs->index++;
114 gs->arg_index = 1;
115
116 if (gs->index >= argc || argv[gs->index][0] == '-') {
117 if (!silent)
118 printf("option requires an argument -- %c\n", curopt);
119 gs->opt = curopt;
120 return ':';
121 }
122
123 gs->arg = argv[gs->index++];
124 return curopt;
125}