xref: /inferno-os/os/port/parse.c (revision ecc9caba0e344ed50c05ee8156b2734f4d76e463)
1 #include	"u.h"
2 #include	"../port/lib.h"
3 #include	"mem.h"
4 #include	"dat.h"
5 #include	"fns.h"
6 #include	"../port/error.h"
7 
8 /*
9  * Generous estimate of number of fields, including terminal nil pointer
10  */
11 static int
12 ncmdfield(char *p, int n)
13 {
14 	int white, nwhite;
15 	char *ep;
16 	int nf;
17 
18 	if(p == nil)
19 		return 1;
20 
21 	nf = 0;
22 	ep = p+n;
23 	white = 1;	/* first text will start field */
24 	while(p < ep){
25 		nwhite = (strchr(" \t\r\n", *p++ & 0xFF) != 0);	/* UTF is irrelevant */
26 		if(white && !nwhite)	/* beginning of field */
27 			nf++;
28 		white = nwhite;
29 	}
30 	return nf+1;	/* +1 for nil */
31 }
32 
33 /*
34  *  parse a command written to a device
35  */
36 Cmdbuf*
37 parsecmd(char *p, int n)
38 {
39 	Cmdbuf *volatile cb;
40 	int nf;
41 	char *sp;
42 
43 	nf = ncmdfield(p, n);
44 
45 	/* allocate Cmdbuf plus string pointers plus copy of string including \0 */
46 	sp = smalloc(sizeof(*cb) + nf * sizeof(char*) + n + 1);
47 	cb = (Cmdbuf*)sp;
48 	cb->f = (char**)(&cb[1]);
49 	cb->buf = (char*)(&cb->f[nf]);
50 
51 	if(up!=nil && waserror()){
52 		free(cb);
53 		nexterror();
54 	}
55 	memmove(cb->buf, p, n);
56 	if(up != nil)
57 		poperror();
58 
59 	/* dump new line and null terminate */
60 	if(n > 0 && cb->buf[n-1] == '\n')
61 		n--;
62 	cb->buf[n] = '\0';
63 
64 	cb->nf = tokenize(cb->buf, cb->f, nf-1);
65 	cb->f[cb->nf] = nil;
66 
67 	return cb;
68 }
69 
70 /*
71  * Reconstruct original message, for error diagnostic
72  */
73 void
74 cmderror(Cmdbuf *cb, char *s)
75 {
76 	int i;
77 	char *p, *e;
78 
79 	p = up->genbuf;
80 	e = p+ERRMAX-10;
81 	p = seprint(p, e, "%s \"", s);
82 	for(i=0; i<cb->nf; i++){
83 		if(i > 0)
84 			p = seprint(p, e, " ");
85 		p = seprint(p, e, "%q", cb->f[i]);
86 	}
87 	strcpy(p, "\"");
88 	error(up->genbuf);
89 }
90 
91 /*
92  * Look up entry in table
93  */
94 Cmdtab*
95 lookupcmd(Cmdbuf *cb, Cmdtab *ctab, int nctab)
96 {
97 	int i;
98 	Cmdtab *ct;
99 
100 	if(cb->nf == 0)
101 		error("empty control message");
102 
103 	for(ct = ctab, i=0; i<nctab; i++, ct++){
104 		if(strcmp(ct->cmd, "*") !=0)	/* wildcard always matches */
105 		if(strcmp(ct->cmd, cb->f[0]) != 0)
106 			continue;
107 		if(ct->narg != 0 && ct->narg != cb->nf)
108 			cmderror(cb, Ecmdargs);
109 		return ct;
110 	}
111 
112 	cmderror(cb, "unknown control message");
113 	return nil;
114 }
115