Merge tag 'efi-2021-10-rc2-2' of https://source.denx.de/u-boot/custodians/u-boot-efi
[platform/kernel/u-boot.git] / lib / getopt.c
1 // 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
11 #include <common.h>
12 #include <getopt.h>
13 #include <log.h>
14
15 void getopt_init_state(struct getopt_state *gs)
16 {
17         gs->index = 1;
18         gs->arg_index = 1;
19 }
20
21 int __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 }