126 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			126 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			C
		
	
	
	
| // SPDX-License-Identifier: GPL-2.0-only
 | |
| /*
 | |
|  * getopt.c - a simple getopt(3) implementation. See getopt.h for explanation.
 | |
|  *
 | |
|  * Copyright (C) 2020 Sean Anderson <seanga2@gmail.com>
 | |
|  * Copyright (c) 2007 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
 | |
|  */
 | |
| 
 | |
| #define LOG_CATEGORY LOGC_CORE
 | |
| 
 | |
| #include <common.h>
 | |
| #include <getopt.h>
 | |
| #include <log.h>
 | |
| 
 | |
| void getopt_init_state(struct getopt_state *gs)
 | |
| {
 | |
| 	gs->index = 1;
 | |
| 	gs->arg_index = 1;
 | |
| }
 | |
| 
 | |
| int __getopt(struct getopt_state *gs, int argc, char *const argv[],
 | |
| 	     const char *optstring, bool silent)
 | |
| {
 | |
| 	char curopt;   /* current option character */
 | |
| 	const char *curoptp; /* pointer to the current option in optstring */
 | |
| 
 | |
| 	while (1) {
 | |
| 		log_debug("arg_index: %d index: %d\n", gs->arg_index,
 | |
| 			  gs->index);
 | |
| 
 | |
| 		/* `--` indicates the end of options */
 | |
| 		if (gs->arg_index == 1 && argv[gs->index] &&
 | |
| 		    !strcmp(argv[gs->index], "--")) {
 | |
| 			gs->index++;
 | |
| 			return -1;
 | |
| 		}
 | |
| 
 | |
| 		/* Out of arguments */
 | |
| 		if (gs->index >= argc)
 | |
| 			return -1;
 | |
| 
 | |
| 		/* Can't parse non-options */
 | |
| 		if (*argv[gs->index] != '-')
 | |
| 			return -1;
 | |
| 
 | |
| 		/* We have found an option */
 | |
| 		curopt = argv[gs->index][gs->arg_index];
 | |
| 		if (curopt)
 | |
| 			break;
 | |
| 		/*
 | |
| 		 * no more options in current argv[] element; try the next one
 | |
| 		 */
 | |
| 		gs->index++;
 | |
| 		gs->arg_index = 1;
 | |
| 	}
 | |
| 
 | |
| 	/* look up current option in optstring */
 | |
| 	curoptp = strchr(optstring, curopt);
 | |
| 
 | |
| 	if (!curoptp) {
 | |
| 		if (!silent)
 | |
| 			printf("%s: invalid option -- %c\n", argv[0], curopt);
 | |
| 		gs->opt = curopt;
 | |
| 		gs->arg_index++;
 | |
| 		return '?';
 | |
| 	}
 | |
| 
 | |
| 	if (*(curoptp + 1) != ':') {
 | |
| 		/* option with no argument. Just return it */
 | |
| 		gs->arg = NULL;
 | |
| 		gs->arg_index++;
 | |
| 		return curopt;
 | |
| 	}
 | |
| 
 | |
| 	if (*(curoptp + 1) && *(curoptp + 2) == ':') {
 | |
| 		/* optional argument */
 | |
| 		if (argv[gs->index][gs->arg_index + 1]) {
 | |
| 			/* optional argument with directly following arg */
 | |
| 			gs->arg = argv[gs->index++] + gs->arg_index + 1;
 | |
| 			gs->arg_index = 1;
 | |
| 			return curopt;
 | |
| 		}
 | |
| 		if (gs->index + 1 == argc) {
 | |
| 			/* We are at the last argv[] element */
 | |
| 			gs->arg = NULL;
 | |
| 			gs->index++;
 | |
| 			return curopt;
 | |
| 		}
 | |
| 		if (*argv[gs->index + 1] != '-') {
 | |
| 			/*
 | |
| 			 * optional argument with arg in next argv[] element
 | |
| 			 */
 | |
| 			gs->index++;
 | |
| 			gs->arg = argv[gs->index++];
 | |
| 			gs->arg_index = 1;
 | |
| 			return curopt;
 | |
| 		}
 | |
| 
 | |
| 		/* no optional argument found */
 | |
| 		gs->arg = NULL;
 | |
| 		gs->arg_index = 1;
 | |
| 		gs->index++;
 | |
| 		return curopt;
 | |
| 	}
 | |
| 
 | |
| 	if (argv[gs->index][gs->arg_index + 1]) {
 | |
| 		/* required argument with directly following arg */
 | |
| 		gs->arg = argv[gs->index++] + gs->arg_index + 1;
 | |
| 		gs->arg_index = 1;
 | |
| 		return curopt;
 | |
| 	}
 | |
| 
 | |
| 	gs->index++;
 | |
| 	gs->arg_index = 1;
 | |
| 
 | |
| 	if (gs->index >= argc || argv[gs->index][0] == '-') {
 | |
| 		if (!silent)
 | |
| 			printf("option requires an argument -- %c\n", curopt);
 | |
| 		gs->opt = curopt;
 | |
| 		return ':';
 | |
| 	}
 | |
| 
 | |
| 	gs->arg = argv[gs->index++];
 | |
| 	return curopt;
 | |
| }
 |