xref: /netbsd-src/usr.bin/m4/misc.c (revision 4b30c543a0b21e3ba94f2c569e9a82b4fdb2075f)
1 /*  File   : misc.c
2     Author : Ozan Yigit
3     Updated: 26-Mar-1993
4     Purpose: Miscellaneous support code for PD M4.
5 */
6 
7 #ifndef lint
8 static char rcsid[] = "$Id: misc.c,v 1.3 1993/08/02 17:54:45 mycroft Exp $";
9 #endif /* not lint */
10 
11 #include "mdef.h"
12 #include "extr.h"
13 #include "ourlims.h"
14 
15 #ifdef	DUFFCP
16 
17 /*  This version of the ANSI standard function memcpy()
18     uses Duff's Device (tm Tom Duff)  to unroll the copying loop:
19 	while (count-- > 0) *to++ = *from++;
20 */
21 void memcpy(to, from, count)
22     register char *from, *to;
23     register int count;
24     {
25 	if (count > 0) {
26 	    register int loops = (count+8-1) >> 3;	/* div 8 round up */
27 
28 	    switch (count & (8-1)) {	/* mod 8 */
29 	        case 0: do {	*to++ = *from++;
30 		case 7:		*to++ = *from++;
31 		case 6:		*to++ = *from++;
32 		case 5:		*to++ = *from++;
33 		case 4:		*to++ = *from++;
34 		case 3:		*to++ = *from++;
35 		case 2:		*to++ = *from++;
36 		case 1:		*to++ = *from++;
37 			} while (--loops > 0);
38 	    }
39 	}
40     }
41 
42 #endif
43 
44 
45 /*  strsave(s)
46     return a new malloc()ed copy of s -- same as V.3's strdup().
47 */
48 char *strsave(s)
49     char *s;
50     {
51 	register int n = strlen(s)+1;
52 	char *p = malloc(n);
53 
54 	if (p) memcpy(p, s, n);
55 	return p;
56     }
57 
58 
59 /*  indx(s1, s2)
60     if s1 can be decomposed as alpha || s2 || omega, return the length
61     of the shortest such alpha, otherwise return -1.
62 */
63 int indx(s1, s2)
64     char *s1;
65     char *s2;
66     {
67 	register char *t;
68 	register char *m;
69 	register char *p;
70 
71 	for (p = s1; *p; p++) {
72 	    for (t = p, m = s2; *m && *m == *t; m++, t++);
73 	    if (!*m) return p-s1;
74 	}
75 	return -1;
76     }
77 
78 
79 char pbmsg[] = "m4: too many characters pushed back";
80 
81 /*  Xputback(c)
82     push character c back onto the input stream.
83     This is now macro putback() in misc.h
84 */
85 void Xputback(c)
86     char c;
87     {
88 	if (bp < endpbb) *bp++ = c; else error(pbmsg);
89     }
90 
91 
92 /*  pbstr(s)
93     push string s back onto the input stream.
94     putback() has been unfolded here to improve performance.
95     Example:
96 	s = <ABC>
97 	bp = <more stuff>
98     After the call:
99 	bp = <more stuffCBA>
100     It would be more efficient if we ran the pushback buffer in the
101     opposite direction
102 */
103 void pbstr(s)
104     register char *s;
105     {
106 	register char *es;
107 	register char *zp;
108 
109 	zp = bp;
110 	for (es = s; *es; ) es++;	/* now es points to terminating NUL */
111 	bp += es-s;			/* advance bp as far as it should go */
112 	if (bp >= endpbb) error("m4: too many characters to push back");
113 	while (es > s) *zp++ = *--es;
114     }
115 
116 
117 /*  pbqtd(s)
118     pushes string s back "quoted", doing whatever has to be done to it to
119     make sure that the result will evaluate to the original value.  As it
120     happens, we have only to add lquote and rquote.
121 */
122 void pbqtd(s)
123     register char *s;
124     {
125 	register char *es;
126 	register char *zp;
127 
128 	zp = bp;
129 	for (es = s; *es; ) es++;	/* now es points to terminating NUL */
130 	bp += 2+es-s;			/* advance bp as far as it should go */
131 	if (bp >= endpbb) error("m4: too many characters to push back");
132 	*zp++ = rquote;
133 	while (es > s) *zp++ = *--es;
134 	*zp++ = lquote;
135     }
136 
137 
138 /*  pbnum(n)
139     convert a number to a (decimal) string and push it back.
140     The original definition did not work for MININT; this does.
141 */
142 void pbnum(n)
143     int n;
144     {
145 	register int num;
146 
147 	num = n > 0 ? -n : n;	/* MININT <= num <= 0 */
148 	do {
149 	    putback('0' - (num % 10));
150 	} while ((num /= 10) < 0);
151 	if (n < 0) putback('-');
152     }
153 
154 
155 /*  pbrad(n, r, m)
156     converts a number n to base r ([-36..-2] U [2..36]), with at least
157     m digits.  If r == 10 and m == 1, this is exactly the same as pbnum.
158     However, this uses the function int2str() from R.A.O'Keefe's public
159     domain string library, and puts the results of that back.
160     The Unix System V Release 3 version of m4 accepts radix 1;
161     THIS VERSION OF M4 DOES NOT ACCEPT RADIX 1 OR -1,
162     nor do we accept radix < -36 or radix > 36.  At the moment such bad
163     radices quietly produce nothing.  The V.3 treatment of radix 1 is
164 	push back abs(n) "1"s, then
165 	if n < 0, push back one "-".
166     Until I come across something which uses it, I can't bring myself to
167     implement this.
168 
169     I have, however, found a use for radix 0.  Unsurprisingly, it is
170     related to radix 0 in Edinburgh Prolog.
171 	eval('c1c2...cn', 0, m)
172     pushes back max(m-n,0) blanks and the characters c1...cn.  This can
173     adjust to any byte size as long as UCHAR_MAX = (1 << CHAR_BIT) - 1.
174     In particular, eval(c, 0) where 0 < c <= UCHAR_MAX, pushes back the
175     character with code c.  Note that this has to agree with eval(); so
176     both of them have to use the same byte ordering.
177 */
178 void pbrad(n, r, m)
179     long int n;
180     int r, m;
181     {
182 	char buffer[34];
183 	char *p;
184 	int L;
185 
186 	if (r == 0) {
187 	    unsigned long int x = (unsigned long)n;
188 	    int n;
189 
190 	    for (n = 0; x; x >>= CHAR_BIT, n++) buffer[n] = x & UCHAR_MAX;
191 	    for (L = n; --L >= 0; ) putback(buffer[L]);
192 	    for (L = m-n; --L >= 0; ) putback(' ');
193 	    return;
194 	}
195 	L = m - (int2str(p = buffer, -r, n)-buffer);
196 	if (buffer[0] == '-') L++, p++;
197 	if (L > 0) {
198 	    pbstr(p);
199 	    while (--L >= 0) putback('0');
200 	    if (p != buffer) putback('-');
201 	} else {
202 	    pbstr(buffer);
203 	}
204     }
205 
206 
207 char csmsg[] = "m4: string space overflow";
208 
209 /*  chrsave(c)
210     put the character c in the string space.
211 */
212 void Xchrsave(c)
213     char c;
214     {
215 #if 0
216 	if (sp < 0) putc(c, active); else
217 #endif
218 	if (ep < endest) *ep++ = c; else
219 	error(csmsg);
220     }
221 
222 
223 /*  getdiv(ind)
224     read in a diversion file and then delete it.
225 */
226 void getdiv(ind)
227     int ind;
228     {
229 	register int c;
230 	register FILE *dfil;
231 	register FILE *afil;
232 
233 	afil = active;
234 	if (outfile[ind] == afil)
235 	    error("m4: undivert: diversion still active.");
236 	(void) fclose(outfile[ind]);
237 	outfile[ind] = NULL;
238 	m4temp[UNIQUE] = '0' + ind;
239 	if ((dfil = fopen(m4temp, "r")) == NULL)
240 	    error("m4: cannot undivert.");
241 	while ((c = getc(dfil)) != EOF) putc(c, afil);
242 	(void) fclose(dfil);
243 
244 #if vms
245 	if (remove(m4temp)) error("m4: cannot unlink.");
246 #else
247 	if (unlink(m4temp) == -1) error("m4: cannot unlink.");
248 #endif
249     }
250 
251 
252 /*  killdiv()
253     delete all the diversion files which have been created.
254 */
255 void killdiv()
256     {
257 	register int n;
258 
259 	for (n = 0; n < MAXOUT; n++) {
260 	    if (outfile[n] != NULL) {
261 		(void) fclose(outfile[n]);
262 		m4temp[UNIQUE] = '0' + n;
263 #if unix
264 		(void) unlink(m4temp);
265 #else
266 		(void) remove(m4temp);
267 #endif
268 	    }
269 	}
270     }
271 
272 
273 /*  error(s)
274     close all files, report a fatal error, and quit, letting the caller know.
275 */
276 void error(s)
277     char *s;
278     {
279 	killdiv();
280 	fprintf(stderr, "%s\n", s);
281 	exit(1);
282     }
283 
284 
285 /*  Interrupt handling
286 */
287 static char *msg = "\ninterrupted.";
288 
289 #ifdef	__STDC__
290 void onintr(int signo)
291 #else
292 onintr()
293 #endif
294     {
295 	error(msg);
296     }
297 
298 
299 void usage()
300     {
301 	fprintf(stderr, "Usage: m4 [-e] [-[BHST]int] [-Dname[=val]] [-Uname]\n");
302 	exit(1);
303     }
304 
305 #ifdef GETOPT
306 /* Henry Spencer's getopt() - get option letter from argv */
307 
308 char *optarg;			/* Global argument pointer. */
309 int optind = 0;			/* Global argv index. */
310 
311 static char *scan = NULL;	/* Private scan pointer. */
312 
313 #ifndef	__STDC__
314 extern	char *index();
315 #define strchr index
316 #endif
317 
318 int getopt(argc, argv, optstring)
319     int argc;
320     char **argv;
321     char *optstring;
322     {
323 	register char c;
324 	register char *place;
325 
326 	optarg = NULL;
327 
328 	if (scan == NULL || *scan == '\0') {
329 	    if (optind == 0) optind++;
330 	    if (optind >= argc
331 	     || argv[optind][0] != '-'
332 	     || argv[optind][1] == '\0')
333 		return EOF;
334 	    if (strcmp(argv[optind], "--") == 0) {
335 		optind++;
336 		return EOF;
337 	    }
338 	    scan = argv[optind]+1;
339 	    optind++;
340 	}
341 	c = *scan++;
342 	place = strchr(optstring, c);
343 
344 	if (place == NULL || c == ':') {
345 	    fprintf(stderr, "%s: unknown option -%c\n", argv[0], c);
346 	    return '?';
347 	}
348 	place++;
349 	if (*place == ':') {
350 	    if (*scan != '\0') {
351 		optarg = scan;
352 		scan = NULL;
353 	    } else {
354 		optarg = argv[optind];
355 		optind++;
356 	    }
357 	}
358 	return c;
359     }
360 #endif
361 
362