xref: /linux/tools/include/nolibc/getopt.h (revision 015a99fa76650e7d6efa3e36f20c0f5b346fe9ce)
1 /* SPDX-License-Identifier: LGPL-2.1 OR MIT */
2 /*
3  * getopt function definitions for NOLIBC, adapted from musl libc
4  * Copyright (C) 2005-2020 Rich Felker, et al.
5  * Copyright (C) 2025 Thomas Weißschuh <linux@weissschuh.net>
6  */
7 
8 /* make sure to include all global symbols */
9 #include "nolibc.h"
10 
11 #ifndef _NOLIBC_GETOPT_H
12 #define _NOLIBC_GETOPT_H
13 
14 struct FILE;
15 static struct FILE *const stderr;
16 static int fprintf(struct FILE *stream, const char *fmt, ...);
17 
18 __attribute__((weak,unused,section(".data.nolibc_getopt")))
19 char *optarg;
20 
21 __attribute__((weak,unused,section(".data.nolibc_getopt")))
22 int optind = 1, opterr = 1, optopt;
23 
24 static __attribute__((unused))
getopt(int argc,char * const argv[],const char * optstring)25 int getopt(int argc, char * const argv[], const char *optstring)
26 {
27 	static int __optpos;
28 	int i;
29 	char c, d;
30 	char *optchar;
31 
32 	if (!optind) {
33 		__optpos = 0;
34 		optind = 1;
35 	}
36 
37 	if (optind >= argc || !argv[optind])
38 		return -1;
39 
40 	if (argv[optind][0] != '-') {
41 		if (optstring[0] == '-') {
42 			optarg = argv[optind++];
43 			return 1;
44 		}
45 		return -1;
46 	}
47 
48 	if (!argv[optind][1])
49 		return -1;
50 
51 	if (argv[optind][1] == '-' && !argv[optind][2])
52 		return optind++, -1;
53 
54 	if (!__optpos)
55 		__optpos++;
56 	c = argv[optind][__optpos];
57 	optchar = argv[optind] + __optpos;
58 	__optpos++;
59 
60 	if (!argv[optind][__optpos]) {
61 		optind++;
62 		__optpos = 0;
63 	}
64 
65 	if (optstring[0] == '-' || optstring[0] == '+')
66 		optstring++;
67 
68 	i = 0;
69 	d = 0;
70 	do {
71 		d = optstring[i++];
72 	} while (d && d != c);
73 
74 	if (d != c || c == ':') {
75 		optopt = c;
76 		if (optstring[0] != ':' && opterr)
77 			fprintf(stderr, "%s: unrecognized option: %c\n", argv[0], *optchar);
78 		return '?';
79 	}
80 	if (optstring[i] == ':') {
81 		optarg = 0;
82 		if (optstring[i + 1] != ':' || __optpos) {
83 			optarg = argv[optind++];
84 			if (__optpos)
85 				optarg += __optpos;
86 			__optpos = 0;
87 		}
88 		if (optind > argc) {
89 			optopt = c;
90 			if (optstring[0] == ':')
91 				return ':';
92 			if (opterr)
93 				fprintf(stderr, "%s: option requires argument: %c\n",
94 					argv[0], *optchar);
95 			return '?';
96 		}
97 	}
98 	return c;
99 }
100 
101 #endif /* _NOLIBC_GETOPT_H */
102