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 <getopt.h> 12#include <log.h> 13#include <linux/string.h> 14 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} 126