summaryrefslogtreecommitdiff
path: root/klibc/klibc/getopt.c
diff options
context:
space:
mode:
Diffstat (limited to 'klibc/klibc/getopt.c')
-rw-r--r--klibc/klibc/getopt.c74
1 files changed, 74 insertions, 0 deletions
diff --git a/klibc/klibc/getopt.c b/klibc/klibc/getopt.c
new file mode 100644
index 0000000000..5a992dcdd7
--- /dev/null
+++ b/klibc/klibc/getopt.c
@@ -0,0 +1,74 @@
+/*
+ * getopt.c
+ *
+ * Simple POSIX getopt(), no GNU extensions...
+ */
+
+#include <stdint.h>
+#include <unistd.h>
+#include <string.h>
+
+char *optarg;
+int optind = 1;
+int opterr, optopt;
+static const char *__optptr;
+
+int getopt(int argc, char * const *argv, const char *optstring)
+{
+ const char *carg = argv[optind];
+ const char *osptr;
+ int opt;
+
+ /* We don't actually need argc */
+ (void)argc;
+
+ /* First, eliminate all non-option cases */
+
+ if ( !carg || carg[0] != '-' || !carg[1] ) {
+ return -1;
+ }
+
+ if ( carg[1] == '-' && !carg[2] ) {
+ optind++;
+ return -1;
+ }
+
+ if ( (uintptr_t)(__optptr-carg) > (uintptr_t)strlen(carg) )
+ __optptr = carg+1; /* Someone frobbed optind, change to new opt. */
+
+ opt = *__optptr++;
+
+ if ( opt != ':' && (osptr = strchr(optstring, opt)) ) {
+ if ( osptr[1] == ':' ) {
+ if ( *__optptr ) {
+ /* Argument-taking option with attached argument */
+ optarg = (char *)__optptr;
+ optind++;
+ } else {
+ /* Argument-taking option with non-attached argument */
+ if ( argv[optind+1] ) {
+ optarg = (char *)argv[optind+1];
+ optind += 2;
+ } else {
+ /* Missing argument */
+ return (optstring[0] == ':') ? ':' : '?';
+ }
+ }
+ return opt;
+ } else {
+ /* Non-argument-taking option */
+ /* __optptr will remember the exact position to resume at */
+ if ( ! *__optptr )
+ optind++;
+ return opt;
+ }
+ } else {
+ /* Unknown option */
+ optopt = opt;
+ if ( ! *__optptr )
+ optind++;
+ return '?';
+ }
+}
+
+