1#include "libc.h"
2#include "locale_impl.h"
3#include <limits.h>
4#include <stdlib.h>
5#include <string.h>
6#include <unistd.h>
7#include <wchar.h>
8
9char* optarg;
10int optind = 1, opterr = 1, optopt, __optpos, __optreset = 0;
11
12#define optpos __optpos
13weak_alias(__optreset, optreset);
14
15void __getopt_msg(const char* a, const char* b, const char* c, size_t l) {
16    FILE* f = stderr;
17    b = __lctrans_cur(b);
18    flockfile(f);
19    (void)(fputs(a, f) >= 0 && fwrite(b, strlen(b), 1, f) && fwrite(c, 1, l, f) == l && putc('\n', f));
20    funlockfile(f);
21}
22
23int getopt(int argc, char* const argv[], const char* optstring) {
24    int i;
25    wchar_t c, d;
26    int k, l;
27    char* optchar;
28
29    if (!optind || __optreset) {
30        __optreset = 0;
31        __optpos = 0;
32        optind = 1;
33    }
34
35    if (optind >= argc || !argv[optind])
36        return -1;
37
38    if (argv[optind][0] != '-') {
39        if (optstring[0] == '-') {
40            optarg = argv[optind++];
41            return 1;
42        }
43        return -1;
44    }
45
46    if (!argv[optind][1])
47        return -1;
48
49    if (argv[optind][1] == '-' && !argv[optind][2])
50        return optind++, -1;
51
52    if (!optpos)
53        optpos++;
54    if ((k = mbtowc(&c, argv[optind] + optpos, MB_LEN_MAX)) < 0) {
55        k = 1;
56        c = 0xfffd; /* replacement char */
57    }
58    optchar = argv[optind] + optpos;
59    optopt = c;
60    optpos += k;
61
62    if (!argv[optind][optpos]) {
63        optind++;
64        optpos = 0;
65    }
66
67    if (optstring[0] == '-' || optstring[0] == '+')
68        optstring++;
69
70    i = 0;
71    d = 0;
72    do {
73        l = mbtowc(&d, optstring + i, MB_LEN_MAX);
74        if (l > 0)
75            i += l;
76        else
77            i++;
78    } while (l && d != c);
79
80    if (d != c) {
81        if (optstring[0] != ':' && opterr)
82            __getopt_msg(argv[0], ": unrecognized option: ", optchar, k);
83        return '?';
84    }
85    if (optstring[i] == ':') {
86        if (optstring[i + 1] == ':')
87            optarg = 0;
88        else if (optind >= argc) {
89            if (optstring[0] == ':')
90                return ':';
91            if (opterr)
92                __getopt_msg(argv[0], ": option requires an argument: ", optchar, k);
93            return '?';
94        }
95        if (optstring[i + 1] != ':' || optpos) {
96            optarg = argv[optind++] + optpos;
97            optpos = 0;
98        }
99    }
100    return c;
101}
102
103weak_alias(getopt, __posix_getopt);
104