1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include "cpp.h"
5 
6 static char wbuf[2*OBS];
7 static char *wbp = wbuf;
8 
9 /*
10  * 1 for tokens that don't need whitespace when they get inserted
11  * by macro expansion
12  */
13 static const char wstab[] = {
14 	0,	/* END */
15 	0,	/* UNCLASS */
16 	0,	/* NAME */
17 	0,	/* NUMBER */
18 	0,	/* STRING */
19 	0,	/* CCON */
20 	1,	/* NL */
21 	0,	/* WS */
22 	0,	/* DSHARP */
23 	0,	/* EQ */
24 	0,	/* NEQ */
25 	0,	/* LEQ */
26 	0,	/* GEQ */
27 	0,	/* LSH */
28 	0,	/* RSH */
29 	0,	/* LAND */
30 	0,	/* LOR */
31 	0,	/* PPLUS */
32 	0,	/* MMINUS */
33 	0,	/* ARROW */
34 	1,	/* SBRA */
35 	1,	/* SKET */
36 	1,	/* LP */
37 	1,	/* RP */
38 	0,	/* DOT */
39 	0,	/* AND */
40 	0,	/* STAR */
41 	0,	/* PLUS */
42 	0,	/* MINUS */
43 	0,	/* TILDE */
44 	0,	/* NOT */
45 	0,	/* SLASH */
46 	0,	/* PCT */
47 	0,	/* LT */
48 	0,	/* GT */
49 	0,	/* CIRC */
50 	0,	/* OR */
51 	0,	/* QUEST */
52 	0,	/* COLON */
53 	0,	/* ASGN */
54 	1,	/* COMMA */
55 	0,	/* SHARP */
56 	1,	/* SEMIC */
57 	1,	/* CBRA */
58 	1,	/* CKET */
59 	0,	/* ASPLUS */
60  	0,	/* ASMINUS */
61  	0,	/* ASSTAR */
62  	0,	/* ASSLASH */
63  	0,	/* ASPCT */
64  	0,	/* ASCIRC */
65  	0,	/* ASLSH */
66 	0,	/* ASRSH */
67  	0,	/* ASOR */
68  	0,	/* ASAND */
69 	0,	/* ELLIPS */
70 	0,	/* DSHARP1 */
71 	0,	/* NAME1 */
72 	0,	/* DEFINED */
73 	0,	/* UMINUS */
74 };
75 
76 void
maketokenrow(int size,Tokenrow * trp)77 maketokenrow(int size, Tokenrow *trp)
78 {
79 	trp->max = size;
80 	if (size>0)
81 		trp->bp = (Token *)domalloc(size*sizeof(Token));
82 	else
83 		trp->bp = NULL;
84 	trp->tp = trp->bp;
85 	trp->lp = trp->bp;
86 }
87 
88 Token *
growtokenrow(Tokenrow * trp)89 growtokenrow(Tokenrow *trp)
90 {
91 	int ncur = trp->tp - trp->bp;
92 	int nlast = trp->lp - trp->bp;
93 
94 	trp->max = 3*trp->max/2 + 1;
95 	trp->bp = (Token *)realloc(trp->bp, trp->max*sizeof(Token));
96 	if (trp->bp == NULL)
97 		error(FATAL, "Out of memory from realloc");
98 	trp->lp = &trp->bp[nlast];
99 	trp->tp = &trp->bp[ncur];
100 	return trp->lp;
101 }
102 
103 /*
104  * Compare a row of tokens, ignoring the content of WS; return !=0 if different
105  */
106 int
comparetokens(Tokenrow * tr1,Tokenrow * tr2)107 comparetokens(Tokenrow *tr1, Tokenrow *tr2)
108 {
109 	Token *tp1, *tp2;
110 
111 	tp1 = tr1->tp;
112 	tp2 = tr2->tp;
113 	if (tr1->lp-tp1 != tr2->lp-tp2)
114 		return 1;
115 	for (; tp1<tr1->lp ; tp1++, tp2++) {
116 		if (tp1->type != tp2->type
117 		 || (tp1->wslen==0) != (tp2->wslen==0)
118 		 || tp1->len != tp2->len
119 		 || strncmp((char*)tp1->t, (char*)tp2->t, tp1->len)!=0)
120 			return 1;
121 	}
122 	return 0;
123 }
124 
125 /*
126  * replace ntok tokens starting at dtr->tp with the contents of str.
127  * tp ends up pointing just beyond the replacement.
128  * Canonical whitespace is assured on each side.
129  */
130 void
insertrow(Tokenrow * dtr,int ntok,Tokenrow * str)131 insertrow(Tokenrow *dtr, int ntok, Tokenrow *str)
132 {
133 	int nrtok = rowlen(str);
134 
135 	dtr->tp += ntok;
136 	adjustrow(dtr, nrtok-ntok);
137 	dtr->tp -= ntok;
138 	movetokenrow(dtr, str);
139 	makespace(dtr);
140 	dtr->tp += nrtok;
141 	makespace(dtr);
142 }
143 
144 /*
145  * make sure there is WS before trp->tp, if tokens might merge in the output
146  */
147 void
makespace(Tokenrow * trp)148 makespace(Tokenrow *trp)
149 {
150 	uchar *tt;
151 	Token *tp = trp->tp;
152 
153 	if (tp >= trp->lp)
154 		return;
155 	if (tp->wslen) {
156 		if (tp->flag&XPWS
157 		 && (wstab[tp->type] || (trp->tp>trp->bp && wstab[(tp-1)->type]))) {
158 			tp->wslen = 0;
159 			return;
160 		}
161 		tp->t[-1] = ' ';
162 		return;
163 	}
164 	if (wstab[tp->type] || (trp->tp>trp->bp && wstab[(tp-1)->type]))
165 		return;
166 	tt = newstring(tp->t, tp->len, 1);
167 	*tt++ = ' ';
168 	tp->t = tt;
169 	tp->wslen = 1;
170 	tp->flag |= XPWS;
171 }
172 
173 /*
174  * Copy an entire tokenrow into another, at tp.
175  * It is assumed that there is enough space.
176  *  Not strictly conforming.
177  */
178 void
movetokenrow(Tokenrow * dtr,Tokenrow * str)179 movetokenrow(Tokenrow *dtr, Tokenrow *str)
180 {
181 	int nby;
182 
183 	/* nby = sizeof(Token) * (str->lp - str->bp); */
184 	nby = (char *)str->lp - (char *)str->bp;
185 	memmove(dtr->tp, str->bp, nby);
186 }
187 
188 /*
189  * Move the tokens in a row, starting at tr->tp, rightward by nt tokens;
190  * nt may be negative (left move).
191  * The row may need to be grown.
192  * Non-strictly conforming because of the (char *), but easily fixed
193  */
194 void
adjustrow(Tokenrow * trp,int nt)195 adjustrow(Tokenrow *trp, int nt)
196 {
197 	int nby, size;
198 
199 	if (nt==0)
200 		return;
201 	size = (trp->lp - trp->bp) + nt;
202 	while (size > trp->max)
203 		growtokenrow(trp);
204 	/* nby = sizeof(Token) * (trp->lp - trp->tp); */
205 	nby = (char *)trp->lp - (char *)trp->tp;
206 	if (nby)
207 		memmove(trp->tp+nt, trp->tp, nby);
208 	trp->lp += nt;
209 }
210 
211 /*
212  * Copy a row of tokens into the destination holder, allocating
213  * the space for the contents.  Return the destination.
214  */
215 Tokenrow *
copytokenrow(Tokenrow * dtr,Tokenrow * str)216 copytokenrow(Tokenrow *dtr, Tokenrow *str)
217 {
218 	int len = rowlen(str);
219 
220 	maketokenrow(len, dtr);
221 	movetokenrow(dtr, str);
222 	dtr->lp += len;
223 	return dtr;
224 }
225 
226 /*
227  * Produce a copy of a row of tokens.  Start at trp->tp.
228  * The value strings are copied as well.  The first token
229  * has WS available.
230  */
231 Tokenrow *
normtokenrow(Tokenrow * trp)232 normtokenrow(Tokenrow *trp)
233 {
234 	Token *tp;
235 	Tokenrow *ntrp = new(Tokenrow);
236 	int len;
237 
238 	len = trp->lp - trp->tp;
239 	if (len<=0)
240 		len = 1;
241 	maketokenrow(len, ntrp);
242 	for (tp=trp->tp; tp < trp->lp; tp++) {
243 		*ntrp->lp = *tp;
244 		if (tp->len) {
245 			ntrp->lp->t = newstring(tp->t, tp->len, 1);
246 			*ntrp->lp->t++ = ' ';
247 			if (tp->wslen)
248 				ntrp->lp->wslen = 1;
249 		}
250 		ntrp->lp++;
251 	}
252 	if (ntrp->lp > ntrp->bp)
253 		ntrp->bp->wslen = 0;
254 	return ntrp;
255 }
256 
257 /*
258  * Debugging
259  */
260 void
peektokens(Tokenrow * trp,char * str)261 peektokens(Tokenrow *trp, char *str)
262 {
263 	Token *tp;
264 
265 	tp = trp->tp;
266 	flushout();
267 	if (str)
268 		fprintf(stderr, "%s ", str);
269 	if (tp<trp->bp || tp>trp->lp)
270 		fprintf(stderr, "(tp offset %ld) ", (long int) (tp - trp->bp));
271 	for (tp=trp->bp; tp<trp->lp && tp<trp->bp+32; tp++) {
272 		if (tp->type!=NL) {
273 			int c = tp->t[tp->len];
274 			tp->t[tp->len] = 0;
275 			fprintf(stderr, "%s", tp->t);
276 			tp->t[tp->len] = c;
277 		}
278 		if (tp->type==NAME) {
279 			fprintf(stderr, tp==trp->tp?"{*":"{");
280 			prhideset(tp->hideset);
281 			fprintf(stderr, "} ");
282 		} else
283 			fprintf(stderr, tp==trp->tp?"{%x*} ":"{%x} ", tp->type);
284 	}
285 	fprintf(stderr, "\n");
286 	fflush(stderr);
287 }
288 
289 void
puttokens(Tokenrow * trp)290 puttokens(Tokenrow *trp)
291 {
292 	Token *tp;
293 	int len;
294 	uchar *p;
295 
296 	if (verbose)
297 		peektokens(trp, "");
298 	tp = trp->bp;
299 	for (; tp<trp->lp; tp++) {
300 		len = tp->len+tp->wslen;
301 		p = tp->t-tp->wslen;
302 		while (tp<trp->lp-1 && p+len == (tp+1)->t - (tp+1)->wslen) {
303 			tp++;
304 			len += tp->wslen+tp->len;
305 		}
306 		if (len>OBS/2) {		/* handle giant token */
307 			if (wbp > wbuf)
308 				write(1, wbuf, wbp-wbuf);
309 			write(1, (char *)p, len);
310 			wbp = wbuf;
311 		} else {
312 			memcpy(wbp, p, len);
313 			wbp += len;
314 		}
315 		if (wbp >= &wbuf[OBS]) {
316 			write(1, wbuf, OBS);
317 			if (wbp > &wbuf[OBS])
318 				memmove(wbuf, wbuf+OBS, wbp - &wbuf[OBS]);
319 			wbp -= OBS;
320 		}
321 	}
322 	trp->tp = tp;
323 	if (cursource->fd==0)
324 		flushout();
325 }
326 
327 void
flushout(void)328 flushout(void)
329 {
330 	if (wbp>wbuf) {
331 		write(1, wbuf, wbp-wbuf);
332 		wbp = wbuf;
333 	}
334 }
335 
336 /*
337  * turn a row into just a newline
338  */
339 void
setempty(Tokenrow * trp)340 setempty(Tokenrow *trp)
341 {
342 	trp->tp = trp->bp;
343 	trp->lp = trp->bp+1;
344 	*trp->bp = nltoken;
345 }
346 
347 /*
348  * generate a number
349  */
350 char *
outnum(char * p,int n)351 outnum(char *p, int n)
352 {
353 	if (n>=10)
354 		p = outnum(p, n/10);
355 	*p++ = n%10 + '0';
356 	return p;
357 }
358 
359 /*
360  * allocate and initialize a new string from s, of length l, at offset o
361  * Null terminated.
362  */
363 uchar *
newstring(uchar * s,int l,int o)364 newstring(uchar *s, int l, int o)
365 {
366 	uchar *ns = (uchar *)domalloc(l+o+1);
367 
368 	ns[l+o] = '\0';
369 	return (uchar*)strncpy((char*)ns+o, (char*)s, l) - o;
370 }
371