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