github.com/shijuvar/go@v0.0.0-20141209052335-e8f13700b70c/src/lib9/flag.c (about) 1 // Copyright 2012 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 #include <u.h> 6 #include <libc.h> 7 8 // Flag hash. 9 typedef struct Flag Flag; 10 11 struct Flag 12 { 13 char *name; 14 int namelen; 15 char *desc; 16 int iscount; 17 void (*set)(char*, void*); 18 void (*set2)(char*, char*, void*); 19 void *arg; 20 Flag *next; 21 Flag *allnext; 22 }; 23 24 static Flag *curflag; 25 26 static Flag *fhash[512]; 27 static Flag *first, *last; 28 29 char *argv0; 30 31 /* 32 * Mac OS can't deal with files that only declare data. 33 * ARGBEGIN mentions this function so that this file gets pulled in. 34 */ 35 void __fixargv0(void) { } 36 37 // FNV-1 hash. http://isthe.com/chongo/tech/comp/fnv/ 38 static uint32 39 fnv(char *p, int n) 40 { 41 uint32 h; 42 43 h = 2166136261U; 44 while(n-- > 0) 45 h = (h*16777619) ^ (uchar)*p++; 46 return h; 47 } 48 49 static Flag* 50 lookflag(char *name, int namelen, int creat) 51 { 52 uint32 h; 53 Flag *f; 54 55 h = fnv(name, namelen) & (nelem(fhash)-1); 56 for(f=fhash[h]; f; f=f->next) { 57 if(f->namelen == namelen && memcmp(f->name, name, (size_t)namelen) == 0) { 58 if(creat) 59 sysfatal("multiple definitions of flag -%s", name); 60 return f; 61 } 62 } 63 64 if(!creat) 65 return nil; 66 67 f = malloc(sizeof *f); 68 if(f == nil) 69 sysfatal("out of memory"); 70 memset(f, 0, sizeof *f); 71 f->name = name; 72 f->namelen = namelen; 73 f->next = fhash[h]; 74 if(first == nil) 75 first = f; 76 else 77 last->allnext = f; 78 last = f; 79 fhash[h] = f; 80 return f; 81 } 82 83 static void 84 count(char *arg, void *p) 85 { 86 int *ip; 87 88 ip = p; 89 if(arg != nil) 90 *ip = atoi(arg); 91 else 92 (*ip)++; 93 } 94 95 void 96 flagcount(char *name, char *desc, int *p) 97 { 98 Flag *f; 99 100 f = lookflag(name, (int)strlen(name), 1); 101 f->desc = desc; 102 f->iscount = 1; 103 f->set = count; 104 f->arg = p; 105 } 106 107 static void 108 atollwhex(char *s, void *p) 109 { 110 char *t; 111 112 *(int64*)p = strtoll(s, &t, 0); 113 if(*s == '\0' || *t != '\0') 114 sysfatal("invalid numeric argument -%s=%s", curflag->name, s); 115 } 116 117 void 118 flagint64(char *name, char *desc, int64 *p) 119 { 120 Flag *f; 121 122 f = lookflag(name, (int)strlen(name), 1); 123 f->desc = desc; 124 f->set = atollwhex; 125 f->arg = p; 126 } 127 128 static void 129 atolwhex(char *s, void *p) 130 { 131 char *t; 132 133 *(int32*)p = (int32)strtol(s, &t, 0); 134 if(*s == '\0' || *t != '\0') 135 sysfatal("invalid numeric argument -%s=%s", curflag->name, s); 136 } 137 138 void 139 flagint32(char *name, char *desc, int32 *p) 140 { 141 Flag *f; 142 143 f = lookflag(name, (int)strlen(name), 1); 144 f->desc = desc; 145 f->set = atolwhex; 146 f->arg = p; 147 } 148 149 static void 150 string(char *s, void *p) 151 { 152 *(char**)p = s; 153 } 154 155 void 156 flagstr(char *name, char *desc, char **p) 157 { 158 159 Flag *f; 160 161 f = lookflag(name, (int)strlen(name), 1); 162 f->desc = desc; 163 f->set = string; 164 f->arg = p; 165 } 166 167 static void 168 fn0(char *s, void *p) 169 { 170 USED(s); 171 ((void(*)(void))p)(); 172 } 173 174 void 175 flagfn0(char *name, char *desc, void (*fn)(void)) 176 { 177 Flag *f; 178 179 f = lookflag(name, (int)strlen(name), 1); 180 f->desc = desc; 181 f->set = fn0; 182 f->arg = fn; 183 f->iscount = 1; 184 } 185 186 static void 187 fn1(char *s, void *p) 188 { 189 ((void(*)(char*))p)(s); 190 } 191 192 void 193 flagfn1(char *name, char *desc, void (*fn)(char*)) 194 { 195 Flag *f; 196 197 f = lookflag(name, (int)strlen(name), 1); 198 f->desc = desc; 199 f->set = fn1; 200 f->arg = fn; 201 } 202 203 static void 204 fn2(char *s, char *t, void *p) 205 { 206 ((void(*)(char*, char*))p)(s, t); 207 } 208 209 void 210 flagfn2(char *name, char *desc, void (*fn)(char*, char*)) 211 { 212 Flag *f; 213 214 f = lookflag(name, (int)strlen(name), 1); 215 f->desc = desc; 216 f->set2 = fn2; 217 f->arg = fn; 218 } 219 220 void 221 flagparse(int *argcp, char ***argvp, void (*usage)(void)) 222 { 223 int argc; 224 char **argv, *p, *q; 225 char *name; 226 int namelen; 227 Flag *f; 228 229 argc = *argcp; 230 argv = *argvp; 231 232 argv0 = argv[0]; 233 argc--; 234 argv++; 235 236 while(argc > 0) { 237 p = *argv; 238 // stop before non-flag or - 239 if(*p != '-' || p[1] == '\0') 240 break; 241 argc--; 242 argv++; 243 // stop after -- 244 if(p[1] == '-' && p[2] == '\0') { 245 break; 246 } 247 248 // turn --foo into -foo 249 if(p[1] == '-' && p[2] != '-') 250 p++; 251 252 // allow -flag=arg if present 253 name = p+1; 254 q = strchr(name, '='); 255 if(q != nil) 256 namelen = (int)(q++ - name); 257 else 258 namelen = (int)strlen(name); 259 f = lookflag(name, namelen, 0); 260 if(f == nil) { 261 if(strcmp(p, "-h") == 0 || strcmp(p, "-help") == 0 || strcmp(p, "-?") == 0) 262 usage(); 263 sysfatal("unknown flag %s", p); 264 } 265 curflag = f; 266 267 // otherwise consume next argument if non-boolean 268 if(!f->iscount && q == nil) { 269 if(argc-- == 0) 270 sysfatal("missing argument to flag %s", p); 271 q = *argv++; 272 } 273 274 // and another if we need two 275 if(f->set2 != nil) { 276 if(argc-- == 0) 277 sysfatal("missing second argument to flag %s", p); 278 f->set2(q, *argv++, f->arg); 279 continue; 280 } 281 282 f->set(q, f->arg); 283 } 284 285 *argcp = argc; 286 *argvp = argv; 287 } 288 289 void 290 flagprint(int fd) 291 { 292 Flag *f; 293 char *p, *q; 294 295 for(f=first; f; f=f->allnext) { 296 p = f->desc; 297 if(p == nil || *p == '\0') // undocumented flag 298 continue; 299 q = strstr(p, ": "); 300 if(q) 301 fprint(fd, " -%s %.*s\n \t%s\n", f->name, utfnlen(p, q-p), p, q+2); 302 else if(f->namelen > 1) 303 fprint(fd, " -%s\n \t%s\n", f->name, p); 304 else 305 fprint(fd, " -%s\t%s\n", f->name, p); 306 } 307 }