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