forked from Bananymous/banan-os
				
			LibC: Implement getopt_long{,_only}
Few ports attempt to use this so lets add them :D
This commit is contained in:
		
							parent
							
								
									c9355ad94a
								
							
						
					
					
						commit
						fde4d4662e
					
				|  | @ -12,6 +12,7 @@ set(LIBC_SOURCES | |||
| 	fenv.cpp | ||||
| 	fnmatch.cpp | ||||
| 	ftw.cpp | ||||
| 	getopt.cpp | ||||
| 	grp.cpp | ||||
| 	ifaddrs.cpp | ||||
| 	inttypes.cpp | ||||
|  |  | |||
|  | @ -0,0 +1,194 @@ | |||
| #include <assert.h> | ||||
| #include <getopt.h> | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| 
 | ||||
| char* optarg = nullptr; | ||||
| int opterr = 1; | ||||
| int optind = 1; | ||||
| int optopt = 0; | ||||
| 
 | ||||
| static int s_idx_in_arg = -1; | ||||
| static int s_old_optind = 1; | ||||
| 
 | ||||
| static int getopt_long_impl(int argc, char* const argv[], const char* optstring, const struct option* longopts, int* longindex, bool need_double_hyphen) | ||||
| { | ||||
| 	if (optind >= argc) | ||||
| 		return -1; | ||||
| 
 | ||||
| 	if (optind == 0) | ||||
| 	{ | ||||
| 		s_old_optind = -1; | ||||
| 		s_idx_in_arg = -1; | ||||
| 		optind = 1; | ||||
| 	} | ||||
| 
 | ||||
| 	const char* curr = argv[optind]; | ||||
| 	if (curr == nullptr || curr[0] != '-' || curr[1] == '\0') | ||||
| 		return -1; | ||||
| 
 | ||||
| 	if (curr[1] == '-' && curr[2] == '\0') | ||||
| 	{ | ||||
| 		optind++; | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
| 	if (s_old_optind != optind) | ||||
| 		s_idx_in_arg = -1; | ||||
| 	struct dummy { ~dummy() { s_old_optind = optind; }} _; | ||||
| 
 | ||||
| 	if (s_idx_in_arg == -1 && (!need_double_hyphen || curr[1] == '-')) | ||||
| 	{ | ||||
| 		for (size_t i = 0; longopts[i].name; i++) | ||||
| 		{ | ||||
| 			const auto& opt = longopts[i]; | ||||
| 			const size_t name_len = strlen(opt.name); | ||||
| 			if (strncmp(curr + 2, opt.name, name_len) != 0) | ||||
| 				continue; | ||||
| 			if (curr[2 + name_len] != '=' && curr[2 + name_len] != '\0') | ||||
| 				continue; | ||||
| 
 | ||||
| 			bool has_argument; | ||||
| 			switch (opt.has_arg) | ||||
| 			{ | ||||
| 				case no_argument: | ||||
| 					has_argument = false; | ||||
| 					break; | ||||
| 				case required_argument: | ||||
| 					has_argument = true; | ||||
| 					break; | ||||
| 				case optional_argument: | ||||
| 					has_argument = (curr[2 + name_len] == '=') | ||||
| 						|| (optind + 1 < argc && argv[optind + 1][0] != '-'); | ||||
| 					break; | ||||
| 				default: | ||||
| 					assert(false); | ||||
| 			} | ||||
| 
 | ||||
| 			if (!has_argument) | ||||
| 			{ | ||||
| 				if (curr[2 + name_len] == '=') | ||||
| 				{ | ||||
| 					if (opterr && optstring[0] != ':') | ||||
| 						fprintf(stderr, "%s: option takes no argument -- %.*s\n", argv[0], static_cast<int>(name_len), curr + 2); | ||||
| 					optind++; | ||||
| 					return (optstring[0] == ':') ? ':' : '?'; | ||||
| 				} | ||||
| 				optarg = nullptr; | ||||
| 				optind++; | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				if (curr[2 + name_len] == '=') | ||||
| 				{ | ||||
| 					optarg = const_cast<char*>(curr + 2 + name_len + 1); | ||||
| 					optind++; | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
| 					if (optind + 1 >= argc) | ||||
| 					{ | ||||
| 						if (opterr && optstring[0] != ':') | ||||
| 							fprintf(stderr, "%s: option requires an argument -- %.*s\n", argv[0], static_cast<int>(name_len), curr + 2); | ||||
| 						optind++; | ||||
| 						return (optstring[0] == ':') ? ':' : '?'; | ||||
| 					} | ||||
| 					optarg = argv[optind + 1]; | ||||
| 					optind += 2; | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			if (longindex != nullptr) | ||||
| 				*longindex = i; | ||||
| 
 | ||||
| 			if (opt.flag == nullptr) | ||||
| 				return opt.val; | ||||
| 			*opt.flag = opt.val; | ||||
| 			return 0; | ||||
| 		} | ||||
| 
 | ||||
| 		if (curr[1] == '-') | ||||
| 		{ | ||||
| 			if (opterr && optstring[0] != ':') | ||||
| 				fprintf(stderr, "%s: illegal option -- %s\n", argv[0], curr + 2); | ||||
| 			optind++; | ||||
| 			return '?'; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (s_idx_in_arg == -1) | ||||
| 		s_idx_in_arg = 1; | ||||
| 
 | ||||
| 	for (size_t i = 0; optstring[i]; i++) | ||||
| 	{ | ||||
| 		if (optstring[i] == ':') | ||||
| 			continue; | ||||
| 		if (curr[s_idx_in_arg] != optstring[i]) | ||||
| 			continue; | ||||
| 
 | ||||
| 		const bool has_argument = (optstring[i + 1] == ':'); | ||||
| 		if (!has_argument) | ||||
| 		{ | ||||
| 			s_idx_in_arg++; | ||||
| 			if (curr[s_idx_in_arg] == '\0') | ||||
| 			{ | ||||
| 				s_idx_in_arg = -1; | ||||
| 				optind++; | ||||
| 			} | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			if (curr[s_idx_in_arg + 1] != '\0') | ||||
| 			{ | ||||
| 				optarg = const_cast<char*>(curr + s_idx_in_arg + 1); | ||||
| 				optind++; | ||||
| 				s_idx_in_arg = -1; | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				if (optind + 1 >= argc) | ||||
| 				{ | ||||
| 					if (opterr && optstring[0] != ':') | ||||
| 						fprintf(stderr, "%s: option requires an argument -- %c\n", argv[0], optstring[i]); | ||||
| 					optopt = optstring[i]; | ||||
| 					optind++; | ||||
| 					return optstring[0] == ':' ? ':' : '?'; | ||||
| 				} | ||||
| 				optarg = const_cast<char*>(argv[optind + 1]); | ||||
| 				optind += 2; | ||||
| 				s_idx_in_arg = -1; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		return optstring[i]; | ||||
| 	} | ||||
| 
 | ||||
| 	if (opterr && optstring[0] != ':') | ||||
| 		fprintf(stderr, "%s: illegal option -- %c\n", argv[0], curr[s_idx_in_arg]); | ||||
| 	optopt = curr[s_idx_in_arg]; | ||||
| 
 | ||||
| 	s_idx_in_arg++; | ||||
| 	if (curr[s_idx_in_arg] == '\0') | ||||
| 	{ | ||||
| 		s_idx_in_arg = -1; | ||||
| 		optind++; | ||||
| 	} | ||||
| 
 | ||||
| 	return '?'; | ||||
| } | ||||
| 
 | ||||
| int getopt(int argc, char* const argv[], const char* optstring) | ||||
| { | ||||
| 	struct option option {}; | ||||
| 	return getopt_long_impl(argc, argv, optstring, &option, nullptr, true); | ||||
| } | ||||
| 
 | ||||
| int getopt_long(int argc, char* argv[], const char* optstring, const struct option* longopts, int* longindex) | ||||
| { | ||||
| 	return getopt_long_impl(argc, argv, optstring, longopts, longindex, true); | ||||
| } | ||||
| 
 | ||||
| int getopt_long_only(int argc, char* argv[], const char* optstring, const struct option* longopts, int* longindex) | ||||
| { | ||||
| 	return getopt_long_impl(argc, argv, optstring, longopts, longindex, false); | ||||
| } | ||||
|  | @ -0,0 +1,15 @@ | |||
| #ifndef _BITS_GETOPT_H | ||||
| #define _BITS_GETOPT_H 1 | ||||
| 
 | ||||
| #include <sys/cdefs.h> | ||||
| 
 | ||||
| __BEGIN_DECLS | ||||
| 
 | ||||
| int getopt(int argc, char* const argv[], const char* optstring); | ||||
| 
 | ||||
| extern char* optarg; | ||||
| extern int   opterr, optind, optopt; | ||||
| 
 | ||||
| __END_DECLS | ||||
| 
 | ||||
| #endif | ||||
|  | @ -0,0 +1,27 @@ | |||
| #ifndef _GETOPT_H | ||||
| #define _GETOPT_H 1 | ||||
| 
 | ||||
| #include <sys/cdefs.h> | ||||
| 
 | ||||
| __BEGIN_DECLS | ||||
| 
 | ||||
| #include <bits/getopt.h> | ||||
| 
 | ||||
| struct option | ||||
| { | ||||
| 	const char* name; | ||||
| 	int has_arg; | ||||
| 	int* flag; | ||||
| 	int val; | ||||
| }; | ||||
| 
 | ||||
| #define no_argument 0 | ||||
| #define required_argument 1 | ||||
| #define optional_argument 2 | ||||
| 
 | ||||
| int getopt_long(int argc, char* argv[], const char* optstring, const struct option* longopts, int* longindex); | ||||
| int getopt_long_only(int argc, char* argv[], const char* optstring, const struct option* longopts, int* longindex); | ||||
| 
 | ||||
| __END_DECLS | ||||
| 
 | ||||
| #endif | ||||
|  | @ -124,6 +124,8 @@ __BEGIN_DECLS | |||
| #define __need_useconds_t | ||||
| #include <sys/types.h> | ||||
| 
 | ||||
| #include <bits/getopt.h> | ||||
| 
 | ||||
| enum | ||||
| { | ||||
| 	_CS_PATH = 1, | ||||
|  | @ -547,7 +549,6 @@ long				gethostid(void); | |||
| int					gethostname(char* name, size_t namelen); | ||||
| char*				getlogin(void); | ||||
| int					getlogin_r(char* name, size_t namesize); | ||||
| int					getopt(int argc, char* const argv[], const char* optstring); | ||||
| pid_t				getpgid(pid_t pid); | ||||
| pid_t				getpgrp(void); | ||||
| pid_t				getpid(void); | ||||
|  | @ -600,9 +601,6 @@ int					chroot(const char* path); | |||
| int					getpagesize(void); | ||||
| char*				getpass(const char* prompt); | ||||
| 
 | ||||
| extern char*	optarg; | ||||
| extern int		opterr, optind, optopt; | ||||
| 
 | ||||
| long syscall(long syscall, ...); | ||||
| 
 | ||||
| __END_DECLS | ||||
|  |  | |||
|  | @ -541,91 +541,6 @@ int rmdir(const char* path) | |||
| 	return unlinkat(AT_FDCWD, path, AT_REMOVEDIR); | ||||
| } | ||||
| 
 | ||||
| char* optarg = nullptr; | ||||
| int opterr = 1; | ||||
| int optind = 1; | ||||
| int optopt = 0; | ||||
| 
 | ||||
| int getopt(int argc, char* const argv[], const char* optstring) | ||||
| { | ||||
| 	if (optind >= argc) | ||||
| 		return -1; | ||||
| 
 | ||||
| 	static int idx = 1; | ||||
| 	const char* current = argv[optind]; | ||||
| 
 | ||||
| 	// if "--" is encountered, no more options are parsed
 | ||||
| 	if (idx == -1) | ||||
| 		return -1; | ||||
| 
 | ||||
| 	// if current is nullptr, does not start with '-' or is string "-", return -1
 | ||||
| 	if (current == nullptr || current[0] != '-' || current[1] == '\0') | ||||
| 		return -1; | ||||
| 
 | ||||
| 	// if current points to string "--" increment optind and return -1
 | ||||
| 	if (current[1] == '-' && current[2] == '\0') | ||||
| 	{ | ||||
| 		idx = -1; | ||||
| 		optind++; | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
| 	for (size_t i = 0; optstring[i]; i++) | ||||
| 	{ | ||||
| 		if (optstring[i] == ':') | ||||
| 			continue; | ||||
| 		if (current[idx] != optstring[i]) | ||||
| 			continue; | ||||
| 
 | ||||
| 		if (optstring[i + 1] == ':') | ||||
| 		{ | ||||
| 			if (current[idx + 1]) | ||||
| 			{ | ||||
| 				optarg = const_cast<char*>(current + idx + 1); | ||||
| 				optind += 1; | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				optarg = const_cast<char*>(argv[optind + 1]); | ||||
| 				optind += 2; | ||||
| 			} | ||||
| 
 | ||||
| 			idx = 1; | ||||
| 
 | ||||
| 			if (optind > argc) | ||||
| 			{ | ||||
| 				if (opterr && optstring[0] != ':') | ||||
| 					fprintf(stderr, "%s: option requires an argument -- %c\n", argv[0], optstring[i]); | ||||
| 				optopt = optstring[i]; | ||||
| 				return optstring[0] == ':' ? ':' : '?'; | ||||
| 			} | ||||
| 
 | ||||
| 			return optstring[i]; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			if (current[++idx] == '\0') | ||||
| 			{ | ||||
| 				idx = 1; | ||||
| 				optind++; | ||||
| 			} | ||||
| 
 | ||||
| 			return optstring[i]; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (opterr && optstring[0] != ':') | ||||
| 		fprintf(stderr, "%s: illegal option -- %c\n", argv[0], current[idx]); | ||||
| 
 | ||||
| 	if (current[++idx] == '\0') | ||||
| 	{ | ||||
| 		idx = 1; | ||||
| 		optind++; | ||||
| 	} | ||||
| 
 | ||||
| 	return '?'; | ||||
| } | ||||
| 
 | ||||
| int chroot(const char* path) | ||||
| { | ||||
| 	return syscall(SYS_CHROOT, path); | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue