diff --git a/libc/include/unistd.h b/libc/include/unistd.h index 76c46ba9a8..21748a03dd 100644 --- a/libc/include/unistd.h +++ b/libc/include/unistd.h @@ -160,7 +160,7 @@ 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); +int getopt(int argc, char* const argv[], const char* optstring); pid_t getpgid(pid_t pid); pid_t getpgrp(void); pid_t getpid(void); diff --git a/libc/unistd.cpp b/libc/unistd.cpp index ec01c51c5a..508b825629 100644 --- a/libc/unistd.cpp +++ b/libc/unistd.cpp @@ -295,6 +295,91 @@ int rmdir(const char* path) return syscall(SYS_UNLINK, path); } +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(current + idx + 1); + optind += 1; + } + else + { + optarg = const_cast(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 '?'; +} + pid_t getpid(void) { return syscall(SYS_GET_PID);