command parsing.
[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
20 ncmdfield(char *p, int n)
21 {
22         int white, nwhite;
23         char *ep;
24         int nf;
25
26         if(p == NULL)
27                 return 1;
28
29         nf = 0;
30         ep = p+n;
31         white = 1;      /* first text will start field */
32         while(p < ep){
33                 nwhite = (strchr(" \t\r\n", *p++ & 0xFF) != 0); /* UTF is irrelevant */
34                 if(white && !nwhite)    /* beginning of field */
35                         nf++;
36                 white = nwhite;
37         }
38         return nf+1;    /* +1 for NULL */
39 }
40
41 /*
42  *  parse a command written to a device
43  */
44 struct cmdbuf*
45 parsecmd(char *p, int n)
46 {
47         ERRSTACK(2);
48         struct cmdbuf *volatile cb;
49         int nf;
50         char *sp;
51
52         nf = ncmdfield(p, n);
53
54         /* allocate Cmdbuf plus string pointers plus copy of string including \0 */
55         sp = kzmalloc(sizeof(*cb) + nf * sizeof(char *) + n + 1, 0);
56         cb = (struct cmdbuf*)sp;
57         cb->f = ( char **)(&cb[1]);
58         cb->buf = ( char *)(&cb->f[nf]);
59
60         if(current!=NULL && waserror()){
61                 kfree(cb);
62                 nexterror();
63         }
64         memmove(cb->buf, p, n);
65         if(current != NULL)
66                 poperror();
67
68         /* dump new line and null terminate */
69         if(n > 0 && cb->buf[n-1] == '\n')
70                 n--;
71         cb->buf[n] = '\0';
72
73         cb->nf = tokenize(cb->buf, cb->f, nf-1);
74         cb->f[cb->nf] = NULL;
75
76         return cb;
77 }
78
79 /*
80  * Reconstruct original message, for error diagnostic
81  */
82 void
83 cmderror(struct cmdbuf *cb, char *s)
84 {
85         int i;
86         char *p, *e;
87
88         p = get_cur_genbuf();
89         e = p+GENBUF_SZ-10;
90         p = seprintf(p, e, "%s \"", s);
91         for(i=0; i<cb->nf; i++){
92                 if(i > 0)
93                         p = seprintf(p, e, " ");
94                 p = seprintf(p, e, "%q", cb->f[i]);
95         }
96         strncpy(p,  "\"", sizeof(p));
97         error(get_cur_genbuf());
98 }
99
100 /*
101  * Look up entry in table
102  */
103 struct cmdtab*
104 lookupcmd(struct cmdbuf *cb, struct cmdtab *ctab, int nctab)
105 {
106         int i;
107         struct cmdtab *ct;
108
109         if(cb->nf == 0)
110                 error("empty control message");
111
112         for(ct = ctab, i=0; i<nctab; i++, ct++){
113                 if(strcmp(ct->cmd, "*") !=0)    /* wildcard always matches */
114                 if(strcmp(ct->cmd, cb->f[0]) != 0)
115                         continue;
116                 if(ct->narg != 0 && ct->narg != cb->nf)
117                         cmderror(cb, Ecmdargs);
118                 return ct;
119         }
120
121         cmderror(cb, "unknown control message");
122         return NULL;
123 }