Annotation of src/usr.bin/m4/misc.c, Revision 1.47
1.47 ! bcallah 1: /* $OpenBSD: misc.c,v 1.46 2015/12/07 14:12:46 espie Exp $ */
1.1 deraadt 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.
1.29 millert 19: * 3. Neither the name of the University nor the names of its contributors
1.1 deraadt 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>
1.30 espie 39: #include <stdarg.h>
1.1 deraadt 40: #include <stdio.h>
1.43 espie 41: #include <stdint.h>
1.1 deraadt 42: #include <stdlib.h>
1.7 espie 43: #include <stddef.h>
1.1 deraadt 44: #include <string.h>
1.7 espie 45: #include <err.h>
1.1 deraadt 46: #include "mdef.h"
47: #include "stdd.h"
48: #include "extern.h"
49: #include "pathnames.h"
50:
1.9 espie 51:
52: char *ep; /* first free char in strspace */
53: static char *strspace; /* string space for evaluation */
1.24 espie 54: char *endest; /* end of string space */
1.9 espie 55: static size_t strsize = STRSPMAX;
56: static size_t bufsize = BUFSIZE;
57:
1.40 espie 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 */
1.42 marco 61: unsigned char *bp; /* first available character */
1.40 espie 62: unsigned char *endpbb; /* end of push-back buffer */
1.9 espie 63:
64:
1.1 deraadt 65: /*
66: * find the index of second str in the first str.
67: */
1.7 espie 68: ptrdiff_t
1.27 espie 69: indx(const char *s1, const char *s2)
1.1 deraadt 70: {
1.12 espie 71: char *t;
1.7 espie 72:
1.12 espie 73: t = strstr(s1, s2);
74: if (t == NULL)
75: return (-1);
1.7 espie 76: else
1.12 espie 77: return (t - s1);
1.1 deraadt 78: }
79: /*
1.33 espie 80: * pushback - push character back onto input
1.1 deraadt 81: */
82: void
1.33 espie 83: pushback(int c)
1.1 deraadt 84: {
1.17 espie 85: if (c == EOF)
86: return;
1.9 espie 87: if (bp >= endpbb)
88: enlarge_bufspace();
89: *bp++ = c;
1.1 deraadt 90: }
91:
92: /*
93: * pbstr - push string back onto input
1.33 espie 94: * pushback is replicated to improve
1.1 deraadt 95: * performance.
96: */
97: void
1.27 espie 98: pbstr(const char *s)
1.1 deraadt 99: {
1.9 espie 100: size_t n;
1.1 deraadt 101:
1.9 espie 102: n = strlen(s);
1.12 espie 103: while (endpbb - bp <= n)
1.9 espie 104: enlarge_bufspace();
105: while (n > 0)
106: *bp++ = s[--n];
1.1 deraadt 107: }
108:
109: /*
110: * pbnum - convert number to string, push back on input.
111: */
112: void
1.27 espie 113: pbnum(int n)
1.1 deraadt 114: {
1.31 espie 115: pbnumbase(n, 10, 0);
116: }
117:
118: void
119: pbnumbase(int n, int base, int d)
120: {
121: static char digits[36] = "0123456789abcdefghijklmnopqrstuvwxyz";
1.12 espie 122: int num;
1.31 espie 123: int printed = 0;
124:
125: if (base > 36)
1.35 espie 126: m4errx(1, "base %d > 36: not supported.", base);
1.31 espie 127:
128: if (base < 2)
1.35 espie 129: m4errx(1, "bad base %d for conversion.", base);
1.1 deraadt 130:
131: num = (n < 0) ? -n : n;
132: do {
1.33 espie 133: pushback(digits[num % base]);
1.31 espie 134: printed++;
1.1 deraadt 135: }
1.31 espie 136: while ((num /= base) > 0);
137:
138: if (n < 0)
139: printed++;
140: while (printed++ < d)
1.33 espie 141: pushback('0');
1.1 deraadt 142:
143: if (n < 0)
1.33 espie 144: pushback('-');
1.1 deraadt 145: }
146:
1.18 espie 147: /*
148: * pbunsigned - convert unsigned long to string, push back on input.
149: */
150: void
1.27 espie 151: pbunsigned(unsigned long n)
1.18 espie 152: {
153: do {
1.33 espie 154: pushback(n % 10 + '0');
1.18 espie 155: }
156: while ((n /= 10) > 0);
157: }
1.9 espie 158:
1.42 marco 159: void
1.9 espie 160: initspaces()
161: {
162: int i;
163:
1.30 espie 164: strspace = xalloc(strsize+1, NULL);
1.9 espie 165: ep = strspace;
166: endest = strspace+strsize;
1.43 espie 167: buf = xalloc(bufsize, NULL);
1.9 espie 168: bufbase = buf;
169: bp = buf;
170: endpbb = buf + bufsize;
171: for (i = 0; i < MAXINP; i++)
172: bbase[i] = buf;
173: }
174:
1.42 marco 175: void
1.17 espie 176: enlarge_strspace()
1.9 espie 177: {
178: char *newstrspace;
1.19 espie 179: int i;
1.9 espie 180:
181: strsize *= 2;
182: newstrspace = malloc(strsize + 1);
183: if (!newstrspace)
184: errx(1, "string space overflow");
185: memcpy(newstrspace, strspace, strsize/2);
1.42 marco 186: for (i = 0; i <= sp; i++)
1.45 espie 187: if (sstack[i] == STORAGE_STRSPACE)
1.42 marco 188: mstack[i].sstr = (mstack[i].sstr - strspace)
1.19 espie 189: + newstrspace;
1.9 espie 190: ep = (ep-strspace) + newstrspace;
1.19 espie 191: free(strspace);
1.9 espie 192: strspace = newstrspace;
193: endest = strspace + strsize;
194: }
195:
1.24 espie 196: void
1.17 espie 197: enlarge_bufspace()
1.9 espie 198: {
1.40 espie 199: unsigned char *newbuf;
1.9 espie 200: int i;
201:
1.30 espie 202: bufsize += bufsize/2;
203: newbuf = xrealloc(buf, bufsize, "too many characters pushed back");
1.9 espie 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;
1.10 espie 209: endpbb = buf+bufsize;
1.9 espie 210: }
211:
1.1 deraadt 212: /*
213: * chrsave - put single char on string space
214: */
215: void
1.27 espie 216: chrsave(int c)
1.1 deraadt 217: {
1.42 marco 218: if (ep >= endest)
1.9 espie 219: enlarge_strspace();
220: *ep++ = c;
1.1 deraadt 221: }
222:
223: /*
224: * read in a diversion file, and dispose it.
225: */
226: void
1.27 espie 227: getdiv(int n)
1.1 deraadt 228: {
1.12 espie 229: int c;
1.1 deraadt 230:
231: if (active == outfile[n])
1.35 espie 232: m4errx(1, "undivert: diversion still active.");
1.8 espie 233: rewind(outfile[n]);
234: while ((c = getc(outfile[n])) != EOF)
235: putc(c, active);
1.1 deraadt 236: (void) fclose(outfile[n]);
1.13 espie 237: outfile[n] = NULL;
1.1 deraadt 238: }
239:
240: void
1.27 espie 241: onintr(int signo)
1.1 deraadt 242: {
1.21 espie 243: #define intrmessage "m4: interrupted.\n"
1.26 deraadt 244: write(STDERR_FILENO, intrmessage, sizeof(intrmessage)-1);
1.21 espie 245: _exit(1);
1.1 deraadt 246: }
247:
248: /*
249: * killdiv - get rid of the diversion files
250: */
251: void
252: killdiv()
253: {
1.12 espie 254: int n;
1.1 deraadt 255:
1.20 espie 256: for (n = 0; n < maxout; n++)
1.1 deraadt 257: if (outfile[n] != NULL) {
258: (void) fclose(outfile[n]);
259: }
1.35 espie 260: }
261:
262: extern char *__progname;
263:
264: void
265: m4errx(int eval, const char *fmt, ...)
266: {
267: fprintf(stderr, "%s: ", __progname);
268: fprintf(stderr, "%s at line %lu: ", CURRENT_NAME, CURRENT_LINE);
1.37 ray 269: if (fmt != NULL) {
270: va_list ap;
271:
272: va_start(ap, fmt);
1.35 espie 273: vfprintf(stderr, fmt, ap);
1.37 ray 274: va_end(ap);
275: }
1.35 espie 276: fprintf(stderr, "\n");
277: exit(eval);
1.20 espie 278: }
279:
280: /*
281: * resizedivs: allocate more diversion files */
282: void
1.27 espie 283: resizedivs(int n)
1.20 espie 284: {
285: int i;
286:
1.43 espie 287: outfile = xreallocarray(outfile, n, sizeof(FILE *),
1.30 espie 288: "too many diverts %d", n);
1.20 espie 289: for (i = maxout; i < n; i++)
290: outfile[i] = NULL;
291: maxout = n;
1.1 deraadt 292: }
293:
1.18 espie 294: void *
1.30 espie 295: xalloc(size_t n, const char *fmt, ...)
1.1 deraadt 296: {
1.30 espie 297: void *p = malloc(n);
1.1 deraadt 298:
1.30 espie 299: if (p == NULL) {
300: if (fmt == NULL)
301: err(1, "malloc");
302: else {
303: va_list va;
1.42 marco 304:
1.30 espie 305: va_start(va, fmt);
306: verr(1, fmt, va);
307: va_end(va);
308: }
309: }
310: return p;
311: }
312:
313: void *
1.44 espie 314: xcalloc(size_t n, size_t s, const char *fmt, ...)
1.43 espie 315: {
1.44 espie 316: void *p = calloc(n, s);
1.43 espie 317:
318: if (p == NULL) {
319: if (fmt == NULL)
1.44 espie 320: err(1, "calloc");
1.43 espie 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 *
1.30 espie 333: xrealloc(void *old, size_t n, const char *fmt, ...)
334: {
335: char *p = realloc(old, n);
1.43 espie 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 *
353: xreallocarray(void *old, size_t s1, size_t s2, const char *fmt, ...)
354: {
1.44 espie 355: void *p = reallocarray(old, s1, s2);
1.30 espie 356:
357: if (p == NULL) {
358: free(old);
359: if (fmt == NULL)
1.44 espie 360: err(1, "reallocarray");
1.30 espie 361: else {
362: va_list va;
363:
364: va_start(va, fmt);
365: verr(1, fmt, va);
366: va_end(va);
1.42 marco 367: }
1.30 espie 368: }
1.1 deraadt 369: return p;
370: }
371:
372: char *
1.27 espie 373: xstrdup(const char *s)
1.1 deraadt 374: {
1.12 espie 375: char *p = strdup(s);
1.1 deraadt 376: if (p == NULL)
1.7 espie 377: err(1, "strdup");
1.1 deraadt 378: return p;
379: }
380:
381: void
1.47 ! bcallah 382: usage(void)
1.1 deraadt 383: {
1.47 ! bcallah 384: fprintf(stderr, "usage: m4 [-EgPs] [-Dname[=value]] [-d flags] "
1.36 jmc 385: "[-I dirname] [-o filename]\n"
386: "\t[-t macro] [-Uname] [file ...]\n");
1.1 deraadt 387: exit(1);
388: }
389:
1.42 marco 390: int
1.27 espie 391: obtain_char(struct input_file *f)
1.15 espie 392: {
1.17 espie 393: if (f->c == EOF)
394: return EOF;
1.33 espie 395:
396: f->c = fgetc(f->file);
397: if (f->c == '\n')
1.15 espie 398: f->lineno++;
399:
400: return f->c;
401: }
402:
1.42 marco 403: void
1.27 espie 404: set_input(struct input_file *f, FILE *real, const char *name)
1.15 espie 405: {
406: f->file = real;
407: f->lineno = 1;
408: f->c = 0;
409: f->name = xstrdup(name);
1.28 espie 410: emit_synchline();
411: }
412:
413: void
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;
1.15 espie 419: }
420:
1.42 marco 421: void
1.27 espie 422: release_input(struct input_file *f)
1.15 espie 423: {
1.46 espie 424: if (ferror(f->file))
425: errx(1, "Fatal error reading from %s\n", f->name);
1.15 espie 426: if (f->file != stdin)
427: fclose(f->file);
1.17 espie 428: f->c = EOF;
1.16 espie 429: /*
1.42 marco 430: * XXX can't free filename, as there might still be
1.16 espie 431: * error information pointing to it.
432: */
1.18 espie 433: }
434:
435: void
1.27 espie 436: doprintlineno(struct input_file *f)
1.18 espie 437: {
438: pbunsigned(f->lineno);
439: }
440:
441: void
1.27 espie 442: doprintfilename(struct input_file *f)
1.18 espie 443: {
1.25 espie 444: pbstr(rquote);
1.18 espie 445: pbstr(f->name);
1.25 espie 446: pbstr(lquote);
1.22 espie 447: }
448:
1.42 marco 449: /*
1.22 espie 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
454: buffer_mark()
455: {
456: return bp - buf;
457: }
458:
459:
460: void
1.27 espie 461: dump_buffer(FILE *f, size_t m)
1.22 espie 462: {
1.40 espie 463: unsigned char *s;
1.22 espie 464:
1.23 espie 465: for (s = bp; s-buf > m;)
1.22 espie 466: fputc(*--s, f);
1.15 espie 467: }