0e4128e257ab604a1e76398e5786c6ed0fded347
[akaros.git] / kern / src / ns / parse.c
1 // INFERNO
2 #include <vfs.h>
3 #include <kfs.h>
4 #include <slab.h>
5 #include <kmalloc.h>
6 #include <kref.h>
7 #include <string.h>
8 #include <stdio.h>
9 #include <assert.h>
10 #include <error.h>
11 #include <cpio.h>
12 #include <pmap.h>
13 #include <smp.h>
14 #include <ip.h>
15
16 /*
17  * Generous estimate of number of fields, including terminal NULL pointer
18  */
19 static int ncmdfield(char *p, int n)
20 {
21         int white, nwhite;
22         char *ep;
23         int nf;
24
25         if (p == NULL)
26                 return 1;
27
28         nf = 0;
29         ep = p + n;
30         white = 1;      /* first text will start field */
31         while (p < ep) {
32                 nwhite = (strchr(" \t\r\n", *p++ & 0xFF) != 0); /* UTF is irrelevant */
33                 if (white && !nwhite)   /* beginning of field */
34                         nf++;
35                 white = nwhite;
36         }
37         return nf + 1;  /* +1 for NULL */
38 }
39
40 /*
41  *  parse a command written to a device
42  */
43 struct cmdbuf *parsecmd(char *p, int n)
44 {
45         ERRSTACK(1);
46         struct cmdbuf *volatile cb;
47         int nf;
48         char *sp;
49
50         nf = ncmdfield(p, n);
51
52         /* allocate Cmdbuf plus string pointers plus copy of string including \0 */
53         sp = kzmalloc(sizeof(*cb) + nf * sizeof(char *) + n + 1, 0);
54         cb = (struct cmdbuf *)sp;
55         cb->f = (char **)(&cb[1]);
56         cb->buf = (char *)(&cb->f[nf]);
57
58         if (current != NULL && waserror()) {
59                 kfree(cb);
60                 nexterror();
61         }
62         memmove(cb->buf, p, n);
63         if (current != NULL)
64                 poperror();
65
66         /* dump new line and null terminate */
67         if (n > 0 && cb->buf[n - 1] == '\n')
68                 n--;
69         cb->buf[n] = '\0';
70
71         cb->nf = tokenize(cb->buf, cb->f, nf - 1);
72         cb->f[cb->nf] = NULL;
73
74         return cb;
75 }
76
77 /*
78  * Reconstruct original message, for error diagnostic
79  */
80 void cmderror(struct cmdbuf *cb, char *s)
81 {
82         int i;
83         char *p, *e;
84
85         p = get_cur_genbuf();
86         e = p + GENBUF_SZ - 10;
87         p = seprintf(p, e, "%s \"", s);
88         for (i = 0; i < cb->nf; i++) {
89                 if (i > 0)
90                         p = seprintf(p, e, " ");
91                 p = seprintf(p, e, "%s", cb->f[i]);
92         }
93         strncpy(p, "\"", sizeof(p));
94         error(get_cur_genbuf());
95 }
96
97 void debugcmd(struct cmdbuf *cb)
98 {
99         printk("cb %p, nr %d\n", cb, cb->nf);
100         for (int i = 0; i < cb->nf; i++) {
101                 printk("%d: %s\n", i, cb->f[i]);
102         }
103 }
104
105 /*
106  * Look up entry in table
107  */
108 struct cmdtab *lookupcmd(struct cmdbuf *cb, struct cmdtab *ctab, int nctab)
109 {
110         int i;
111         struct cmdtab *ct;
112
113         if (cb->nf == 0)
114                 error("empty control message");
115
116         for (ct = ctab, i = 0; i < nctab; i++, ct++) {
117                 if (strcmp(ct->cmd, "*") != 0)  /* wildcard always matches */
118                         if (strcmp(ct->cmd, cb->f[0]) != 0)
119                                 continue;
120                 if (ct->narg != 0 && ct->narg != cb->nf) {
121                         // oh how I hate plan 9 error handling sometimes.
122                         printk("%s for %s have %d want %d", Ecmdargs, cb->f[0], cb->nf, ct->narg);
123                         cmderror(cb, "bring me another fucking rock");
124                 }
125                 return ct;
126         }
127
128         cmderror(cb, "unknown control message");
129         return NULL;
130 }