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