1 #include "a.h"
2 
3 Sx *Brdsx1(Biobuf*);
4 
5 Sx*
Brdsx(Biobuf * b)6 Brdsx(Biobuf *b)
7 {
8 	Sx **sx, *x;
9 	int nsx;
10 
11 	nsx = 0;
12 	sx = nil;
13 	while((x = Brdsx1(b)) != nil){
14 		sx = erealloc(sx, (nsx+1)*sizeof sx[0]);
15 		sx[nsx++] = x;
16 	}
17 	x = emalloc(sizeof *x);
18 	x->sx = sx;
19 	x->nsx = nsx;
20 	x->type = SxList;
21 	return x;
22 }
23 
24 int
sxwalk(Sx * sx)25 sxwalk(Sx *sx)
26 {
27 	int i, n;
28 
29 	if(sx == nil)
30 		return 1;
31 	switch(sx->type){
32 	default:
33 	case SxAtom:
34 	case SxString:
35 	case SxNumber:
36 		return 1;
37 	case SxList:
38 		n = 0;
39 		for(i=0; i<sx->nsx; i++)
40 			n += sxwalk(sx->sx[i]);
41 		return n;
42 	}
43 }
44 
45 void
freesx(Sx * sx)46 freesx(Sx *sx)
47 {
48 	int i;
49 
50 	if(sx == nil)
51 		return;
52 	switch(sx->type){
53 	case SxAtom:
54 	case SxString:
55 		free(sx->data);
56 		break;
57 	case SxList:
58 		for(i=0; i<sx->nsx; i++)
59 			freesx(sx->sx[i]);
60 		free(sx->sx);
61 		break;
62 	}
63 	free(sx);
64 }
65 
66 Sx*
Brdsx1(Biobuf * b)67 Brdsx1(Biobuf *b)
68 {
69 	int c, len, nbr;
70 	char *s;
71 	vlong n;
72 	Sx *x;
73 
74 	c = Bgetc(b);
75 	if(c == ' ')
76 		c = Bgetc(b);
77 	if(c < 0)
78 		return nil;
79 	if(c == '\r')
80 		c = Bgetc(b);
81 	if(c == '\n')
82 		return nil;
83 	if(c == ')'){	/* end of list */
84 		Bungetc(b);
85 		return nil;
86 	}
87 	if(c == '('){	/* parenthesized list */
88 		x = Brdsx(b);
89 		c = Bgetc(b);
90 		if(c != ')')	/* oops! not good */
91 			Bungetc(b);
92 		return x;
93 	}
94 	if(c == '{'){	/* length-prefixed string */
95 		len = 0;
96 		while((c = Bgetc(b)) >= 0 && isdigit(c))
97 			len = len*10 + c-'0';
98 		if(c != '}')	/* oops! not good */
99 			Bungetc(b);
100 		c = Bgetc(b);
101 		if(c != '\r')	/* oops! not good */
102 			;
103 		c = Bgetc(b);
104 		if(c != '\n')	/* oops! not good */
105 			;
106 		x = emalloc(sizeof *x);
107 		x->data = emalloc(len+1);
108 		if(Bread(b, x->data, len) != len)
109 			;	/* oops! */
110 		x->data[len] = 0;
111 		x->ndata = len;
112 		x->type = SxString;
113 		return x;
114 	}
115 	if(c == '"'){	/* quoted string */
116 		s = nil;
117 		len = 0;
118 		while((c = Bgetc(b)) >= 0 && c != '"'){
119 			if(c == '\\')
120 				c = Bgetc(b);
121 			s = erealloc(s, len+1);
122 			s[len++] = c;
123 		}
124 		s = erealloc(s, len+1);
125 		s[len] = 0;
126 		x = emalloc(sizeof *x);
127 		x->data = s;
128 		x->ndata = len;
129 		x->type = SxString;
130 		return x;
131 	}
132 	if(isdigit(c)){	/* number */
133 		n = c-'0';;
134 		while((c = Bgetc(b)) >= 0 && isdigit(c))
135 			n = n*10 + c-'0';
136 		Bungetc(b);
137 		x = emalloc(sizeof *x);
138 		x->number = n;
139 		x->type = SxNumber;
140 		return x;
141 	}
142 	/* atom */
143 	len = 1;
144 	s = emalloc(1);
145 	s[0] = c;
146 	nbr = 0;
147 	while((c = Bgetc(b)) >= 0 && c > ' ' && !strchr("(){}", c)){
148 		/* allow embedded brackets as in BODY[] */
149 		if(c == '['){
150 			if(s[0] == '[')
151 				break;
152 			else
153 				nbr++;
154 		}
155 		if(c == ']'){
156 			if(nbr > 0)
157 				nbr--;
158 			else
159 				break;
160 		}
161 		s = erealloc(s, len+1);
162 		s[len++] = c;
163 	}
164 	if(c != ' ')
165 		Bungetc(b);
166 	s = erealloc(s, len+1);
167 	s[len] = 0;
168 	x = emalloc(sizeof *x);
169 	x->type = SxAtom;
170 	x->data = s;
171 	x->ndata = len;
172 	return x;
173 }
174 
175 int
sxfmt(Fmt * fmt)176 sxfmt(Fmt *fmt)
177 {
178 	int i, paren;
179 	Sx *sx;
180 
181 	sx = va_arg(fmt->args, Sx*);
182 	if(sx == nil)
183 		return 0;
184 
185 	switch(sx->type){
186 	case SxAtom:
187 	case SxString:
188 		return fmtprint(fmt, "%q", sx->data);
189 
190 	case SxNumber:
191 		return fmtprint(fmt, "%lld", sx->number);
192 
193 	case SxList:
194 		paren = !(fmt->flags&FmtSharp);
195 		if(paren)
196 			fmtrune(fmt, '(');
197 		for(i=0; i<sx->nsx; i++){
198 			if(i)
199 				fmtrune(fmt, ' ');
200 			fmtprint(fmt, "%$", sx->sx[i]);
201 		}
202 		if(paren)
203 			return fmtrune(fmt, ')');
204 		return 0;
205 
206 	default:
207 		return fmtstrcpy(fmt, "?");
208 	}
209 }
210 
211 int
oksx(Sx * sx)212 oksx(Sx *sx)
213 {
214 	return sx->nsx >= 2
215 		&& sx->sx[1]->type == SxAtom
216 		&& cistrcmp(sx->sx[1]->data, "OK") == 0;
217 }
218