chiark / gitweb /
[PATCH] klibc: strlcpy/strlcat - don't alter destination if size == 0
[elogind.git] / klibc / klibc / getopt.c
1 /*
2  * getopt.c
3  *
4  * Simple POSIX getopt(), no GNU extensions...
5  */
6
7 #include <stdint.h>
8 #include <unistd.h>
9 #include <string.h>
10
11 char *optarg;
12 int optind = 1;
13 int opterr, optopt;
14 static const char *__optptr;
15
16 int getopt(int argc, char * const *argv, const char *optstring)
17 {
18   const char *carg = argv[optind];
19   const char *osptr;
20   int opt;
21
22   /* We don't actually need argc */
23   (void)argc;
24
25   /* First, eliminate all non-option cases */
26   
27   if ( !carg || carg[0] != '-' || !carg[1] ) {
28     return -1;
29   }
30
31   if ( carg[1] == '-' && !carg[2] ) {
32     optind++;
33     return -1;
34   }
35
36   if ( (uintptr_t)(__optptr-carg) > (uintptr_t)strlen(carg) )
37     __optptr = carg+1;  /* Someone frobbed optind, change to new opt. */
38
39   opt = *__optptr++;
40
41   if ( opt != ':' && (osptr = strchr(optstring, opt)) ) {
42     if ( osptr[1] == ':' ) {
43       if ( *__optptr ) {
44         /* Argument-taking option with attached argument */
45         optarg = (char *)__optptr;
46         optind++;
47       } else {
48         /* Argument-taking option with non-attached argument */
49         if ( argv[optind+1] ) {
50           optarg = (char *)argv[optind+1];
51           optind += 2;
52         } else {
53           /* Missing argument */
54           optind++;
55           return (optstring[0] == ':') ? ':' : '?';
56         }
57       }
58       return opt;
59     } else {
60       /* Non-argument-taking option */
61       /* __optptr will remember the exact position to resume at */
62       if ( ! *__optptr )
63         optind++;
64       return opt;
65     }
66   } else {
67     /* Unknown option */
68     optopt = opt;
69     if ( ! *__optptr )
70       optind++;
71     return '?';
72   }
73 }
74
75