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