xref: /openbsd/usr.bin/m4/misc.c (revision d2d86e25)
1 /*	$OpenBSD: misc.c,v 1.47 2017/06/15 13:48:42 bcallah Exp $	*/
2 /*	$NetBSD: misc.c,v 1.6 1995/09/28 05:37:41 tls Exp $	*/
3 
4 /*
5  * Copyright (c) 1989, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * This code is derived from software contributed to Berkeley by
9  * Ozan Yigit at York University.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 
36 #include <sys/types.h>
37 #include <errno.h>
38 #include <unistd.h>
39 #include <stdarg.h>
40 #include <stdio.h>
41 #include <stdint.h>
42 #include <stdlib.h>
43 #include <stddef.h>
44 #include <string.h>
45 #include <err.h>
46 #include "mdef.h"
47 #include "stdd.h"
48 #include "extern.h"
49 #include "pathnames.h"
50 
51 
52 char *ep;		/* first free char in strspace */
53 static char *strspace;	/* string space for evaluation */
54 char *endest;		/* end of string space	       */
55 static size_t strsize = STRSPMAX;
56 static size_t bufsize = BUFSIZE;
57 
58 unsigned char *buf;			/* push-back buffer	       */
59 unsigned char *bufbase;			/* the base for current ilevel */
60 unsigned char *bbase[MAXINP];		/* the base for each ilevel    */
61 unsigned char *bp;			/* first available character   */
62 unsigned char *endpbb;			/* end of push-back buffer     */
63 
64 
65 /*
66  * find the index of second str in the first str.
67  */
68 ptrdiff_t
indx(const char * s1,const char * s2)69 indx(const char *s1, const char *s2)
70 {
71 	char *t;
72 
73 	t = strstr(s1, s2);
74 	if (t == NULL)
75 		return (-1);
76 	else
77 		return (t - s1);
78 }
79 /*
80  *  pushback - push character back onto input
81  */
82 void
pushback(int c)83 pushback(int c)
84 {
85 	if (c == EOF)
86 		return;
87 	if (bp >= endpbb)
88 		enlarge_bufspace();
89 	*bp++ = c;
90 }
91 
92 /*
93  *  pbstr - push string back onto input
94  *          pushback is replicated to improve
95  *          performance.
96  */
97 void
pbstr(const char * s)98 pbstr(const char *s)
99 {
100 	size_t n;
101 
102 	n = strlen(s);
103 	while (endpbb - bp <= n)
104 		enlarge_bufspace();
105 	while (n > 0)
106 		*bp++ = s[--n];
107 }
108 
109 /*
110  *  pbnum - convert number to string, push back on input.
111  */
112 void
pbnum(int n)113 pbnum(int n)
114 {
115 	pbnumbase(n, 10, 0);
116 }
117 
118 void
pbnumbase(int n,int base,int d)119 pbnumbase(int n, int base, int d)
120 {
121 	static char digits[36] = "0123456789abcdefghijklmnopqrstuvwxyz";
122 	int num;
123 	int printed = 0;
124 
125 	if (base > 36)
126 		m4errx(1, "base %d > 36: not supported.", base);
127 
128 	if (base < 2)
129 		m4errx(1, "bad base %d for conversion.", base);
130 
131 	num = (n < 0) ? -n : n;
132 	do {
133 		pushback(digits[num % base]);
134 		printed++;
135 	}
136 	while ((num /= base) > 0);
137 
138 	if (n < 0)
139 		printed++;
140 	while (printed++ < d)
141 		pushback('0');
142 
143 	if (n < 0)
144 		pushback('-');
145 }
146 
147 /*
148  *  pbunsigned - convert unsigned long to string, push back on input.
149  */
150 void
pbunsigned(unsigned long n)151 pbunsigned(unsigned long n)
152 {
153 	do {
154 		pushback(n % 10 + '0');
155 	}
156 	while ((n /= 10) > 0);
157 }
158 
159 void
initspaces()160 initspaces()
161 {
162 	int i;
163 
164 	strspace = xalloc(strsize+1, NULL);
165 	ep = strspace;
166 	endest = strspace+strsize;
167 	buf = xalloc(bufsize, NULL);
168 	bufbase = buf;
169 	bp = buf;
170 	endpbb = buf + bufsize;
171 	for (i = 0; i < MAXINP; i++)
172 		bbase[i] = buf;
173 }
174 
175 void
enlarge_strspace()176 enlarge_strspace()
177 {
178 	char *newstrspace;
179 	int i;
180 
181 	strsize *= 2;
182 	newstrspace = malloc(strsize + 1);
183 	if (!newstrspace)
184 		errx(1, "string space overflow");
185 	memcpy(newstrspace, strspace, strsize/2);
186 	for (i = 0; i <= sp; i++)
187 		if (sstack[i] == STORAGE_STRSPACE)
188 			mstack[i].sstr = (mstack[i].sstr - strspace)
189 			    + newstrspace;
190 	ep = (ep-strspace) + newstrspace;
191 	free(strspace);
192 	strspace = newstrspace;
193 	endest = strspace + strsize;
194 }
195 
196 void
enlarge_bufspace()197 enlarge_bufspace()
198 {
199 	unsigned char *newbuf;
200 	int i;
201 
202 	bufsize += bufsize/2;
203 	newbuf = xrealloc(buf, bufsize, "too many characters pushed back");
204 	for (i = 0; i < MAXINP; i++)
205 		bbase[i] = (bbase[i]-buf)+newbuf;
206 	bp = (bp-buf)+newbuf;
207 	bufbase = (bufbase-buf)+newbuf;
208 	buf = newbuf;
209 	endpbb = buf+bufsize;
210 }
211 
212 /*
213  *  chrsave - put single char on string space
214  */
215 void
chrsave(int c)216 chrsave(int c)
217 {
218 	if (ep >= endest)
219 		enlarge_strspace();
220 	*ep++ = c;
221 }
222 
223 /*
224  * read in a diversion file, and dispose it.
225  */
226 void
getdiv(int n)227 getdiv(int n)
228 {
229 	int c;
230 
231 	if (active == outfile[n])
232 		m4errx(1, "undivert: diversion still active.");
233 	rewind(outfile[n]);
234 	while ((c = getc(outfile[n])) != EOF)
235 		putc(c, active);
236 	(void) fclose(outfile[n]);
237 	outfile[n] = NULL;
238 }
239 
240 void
onintr(int signo)241 onintr(int signo)
242 {
243 #define intrmessage	"m4: interrupted.\n"
244 	write(STDERR_FILENO, intrmessage, sizeof(intrmessage)-1);
245 	_exit(1);
246 }
247 
248 /*
249  * killdiv - get rid of the diversion files
250  */
251 void
killdiv()252 killdiv()
253 {
254 	int n;
255 
256 	for (n = 0; n < maxout; n++)
257 		if (outfile[n] != NULL) {
258 			(void) fclose(outfile[n]);
259 		}
260 }
261 
262 extern char *__progname;
263 
264 void
m4errx(int eval,const char * fmt,...)265 m4errx(int eval, const char *fmt, ...)
266 {
267 	fprintf(stderr, "%s: ", __progname);
268 	fprintf(stderr, "%s at line %lu: ", CURRENT_NAME, CURRENT_LINE);
269 	if (fmt != NULL) {
270 		va_list ap;
271 
272 		va_start(ap, fmt);
273 		vfprintf(stderr, fmt, ap);
274 		va_end(ap);
275 	}
276 	fprintf(stderr, "\n");
277 	exit(eval);
278 }
279 
280 /*
281  * resizedivs: allocate more diversion files */
282 void
resizedivs(int n)283 resizedivs(int n)
284 {
285 	int i;
286 
287 	outfile = xreallocarray(outfile, n, sizeof(FILE *),
288 	    "too many diverts %d", n);
289 	for (i = maxout; i < n; i++)
290 		outfile[i] = NULL;
291 	maxout = n;
292 }
293 
294 void *
xalloc(size_t n,const char * fmt,...)295 xalloc(size_t n, const char *fmt, ...)
296 {
297 	void *p = malloc(n);
298 
299 	if (p == NULL) {
300 		if (fmt == NULL)
301 			err(1, "malloc");
302 		else {
303 			va_list va;
304 
305 			va_start(va, fmt);
306 			verr(1, fmt, va);
307 			va_end(va);
308 		}
309 	}
310 	return p;
311 }
312 
313 void *
xcalloc(size_t n,size_t s,const char * fmt,...)314 xcalloc(size_t n, size_t s, const char *fmt, ...)
315 {
316 	void *p = calloc(n, s);
317 
318 	if (p == NULL) {
319 		if (fmt == NULL)
320 			err(1, "calloc");
321 		else {
322 			va_list va;
323 
324 			va_start(va, fmt);
325 			verr(1, fmt, va);
326 			va_end(va);
327 		}
328 	}
329 	return p;
330 }
331 
332 void *
xrealloc(void * old,size_t n,const char * fmt,...)333 xrealloc(void *old, size_t n, const char *fmt, ...)
334 {
335 	char *p = realloc(old, n);
336 
337 	if (p == NULL) {
338 		free(old);
339 		if (fmt == NULL)
340 			err(1, "realloc");
341 		else {
342 			va_list va;
343 
344 			va_start(va, fmt);
345 			verr(1, fmt, va);
346 			va_end(va);
347 		}
348 	}
349 	return p;
350 }
351 
352 void *
xreallocarray(void * old,size_t s1,size_t s2,const char * fmt,...)353 xreallocarray(void *old, size_t s1, size_t s2, const char *fmt, ...)
354 {
355 	void *p = reallocarray(old, s1, s2);
356 
357 	if (p == NULL) {
358 		free(old);
359 		if (fmt == NULL)
360 			err(1, "reallocarray");
361 		else {
362 			va_list va;
363 
364 			va_start(va, fmt);
365 			verr(1, fmt, va);
366 			va_end(va);
367 		}
368 	}
369 	return p;
370 }
371 
372 char *
xstrdup(const char * s)373 xstrdup(const char *s)
374 {
375 	char *p = strdup(s);
376 	if (p == NULL)
377 		err(1, "strdup");
378 	return p;
379 }
380 
381 void
usage(void)382 usage(void)
383 {
384 	fprintf(stderr, "usage: m4 [-EgPs] [-Dname[=value]] [-d flags] "
385 			"[-I dirname] [-o filename]\n"
386 			"\t[-t macro] [-Uname] [file ...]\n");
387 	exit(1);
388 }
389 
390 int
obtain_char(struct input_file * f)391 obtain_char(struct input_file *f)
392 {
393 	if (f->c == EOF)
394 		return EOF;
395 
396 	f->c = fgetc(f->file);
397 	if (f->c == '\n')
398 		f->lineno++;
399 
400 	return f->c;
401 }
402 
403 void
set_input(struct input_file * f,FILE * real,const char * name)404 set_input(struct input_file *f, FILE *real, const char *name)
405 {
406 	f->file = real;
407 	f->lineno = 1;
408 	f->c = 0;
409 	f->name = xstrdup(name);
410 	emit_synchline();
411 }
412 
413 void
do_emit_synchline()414 do_emit_synchline()
415 {
416 	fprintf(active, "#line %lu \"%s\"\n",
417 	    infile[ilevel].lineno, infile[ilevel].name);
418 	infile[ilevel].synch_lineno = infile[ilevel].lineno;
419 }
420 
421 void
release_input(struct input_file * f)422 release_input(struct input_file *f)
423 {
424 	if (ferror(f->file))
425 		errx(1, "Fatal error reading from %s\n", f->name);
426 	if (f->file != stdin)
427 	    fclose(f->file);
428 	f->c = EOF;
429 	/*
430 	 * XXX can't free filename, as there might still be
431 	 * error information pointing to it.
432 	 */
433 }
434 
435 void
doprintlineno(struct input_file * f)436 doprintlineno(struct input_file *f)
437 {
438 	pbunsigned(f->lineno);
439 }
440 
441 void
doprintfilename(struct input_file * f)442 doprintfilename(struct input_file *f)
443 {
444 	pbstr(rquote);
445 	pbstr(f->name);
446 	pbstr(lquote);
447 }
448 
449 /*
450  * buffer_mark/dump_buffer: allows one to save a mark in a buffer,
451  * and later dump everything that was added since then to a file.
452  */
453 size_t
buffer_mark()454 buffer_mark()
455 {
456 	return bp - buf;
457 }
458 
459 
460 void
dump_buffer(FILE * f,size_t m)461 dump_buffer(FILE *f, size_t m)
462 {
463 	unsigned char *s;
464 
465 	for (s = bp; s-buf > m;)
466 		fputc(*--s, f);
467 }
468