Home | History | Annotate | Line # | Download | only in m4
misc.c revision 1.20
      1 /*	$OpenBSD: misc.c,v 1.41 2009/10/14 17:19:47 sthen Exp $	*/
      2 /*	$NetBSD: misc.c,v 1.20 2009/11/06 15:13:27 joerg 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 #if HAVE_NBTOOL_CONFIG_H
     36 #include "nbtool_config.h"
     37 #endif
     38 #include <sys/cdefs.h>
     39 __RCSID("$NetBSD: misc.c,v 1.20 2009/11/06 15:13:27 joerg Exp $");
     40 #include <sys/types.h>
     41 #include <errno.h>
     42 #include <unistd.h>
     43 #include <stdarg.h>
     44 #include <stdio.h>
     45 #include <stdlib.h>
     46 #include <stddef.h>
     47 #include <string.h>
     48 #include <err.h>
     49 #include "mdef.h"
     50 #include "stdd.h"
     51 #include "extern.h"
     52 #include "pathnames.h"
     53 
     54 
     55 char *ep;		/* first free char in strspace */
     56 static char *strspace;	/* string space for evaluation */
     57 char *endest;		/* end of string space	       */
     58 static size_t strsize = STRSPMAX;
     59 static size_t bufsize = BUFSIZE;
     60 
     61 unsigned char *buf;			/* push-back buffer	       */
     62 unsigned char *bufbase;			/* the base for current ilevel */
     63 unsigned char *bbase[MAXINP];		/* the base for each ilevel    */
     64 unsigned char *bp; 			/* first available character   */
     65 unsigned char *endpbb;			/* end of push-back buffer     */
     66 
     67 
     68 /*
     69  * find the index of second str in the first str.
     70  */
     71 ptrdiff_t
     72 indx(const char *s1, const char *s2)
     73 {
     74 	char *t;
     75 
     76 	t = strstr(s1, s2);
     77 	if (t == NULL)
     78 		return (-1);
     79 	else
     80 		return (t - s1);
     81 }
     82 /*
     83  *  pushback - push character back onto input
     84  */
     85 void
     86 pushback(int c)
     87 {
     88 	if (c == EOF)
     89 		return;
     90 	if (bp >= endpbb)
     91 		enlarge_bufspace();
     92 	*bp++ = c;
     93 }
     94 
     95 /*
     96  *  pbstr - push string back onto input
     97  *          pushback is replicated to improve
     98  *          performance.
     99  */
    100 void
    101 pbstr(const char *s)
    102 {
    103 	size_t n;
    104 
    105 	n = strlen(s);
    106 	while ((size_t)(endpbb - bp) <= n)
    107 		enlarge_bufspace();
    108 	while (n > 0)
    109 		*bp++ = s[--n];
    110 }
    111 
    112 /*
    113  *  pbnum - convert number to string, push back on input.
    114  */
    115 void
    116 pbnum(int n)
    117 {
    118 	pbnumbase(n, 10, 0);
    119 }
    120 
    121 void
    122 pbnumbase(int n, int base, int d)
    123 {
    124 	static char digits[36] = "0123456789abcdefghijklmnopqrstuvwxyz";
    125 	int num;
    126 	int printed = 0;
    127 
    128 	if (base > 36)
    129 		m4errx(1, "base %d > 36: not supported.", base);
    130 
    131 	if (base < 2)
    132 		m4errx(1, "bad base %d for conversion.", base);
    133 
    134 	num = (n < 0) ? -n : n;
    135 	do {
    136 		pushback(digits[num % base]);
    137 		printed++;
    138 	}
    139 	while ((num /= base) > 0);
    140 
    141 	if (n < 0)
    142 		printed++;
    143 	while (printed++ < d)
    144 		pushback('0');
    145 
    146 	if (n < 0)
    147 		pushback('-');
    148 }
    149 
    150 /*
    151  *  pbunsigned - convert unsigned long to string, push back on input.
    152  */
    153 void
    154 pbunsigned(unsigned long n)
    155 {
    156 	do {
    157 		pushback(n % 10 + '0');
    158 	}
    159 	while ((n /= 10) > 0);
    160 }
    161 
    162 void
    163 initspaces()
    164 {
    165 	int i;
    166 
    167 	strspace = xalloc(strsize+1, NULL);
    168 	ep = strspace;
    169 	endest = strspace+strsize;
    170 	buf = (unsigned char *)xalloc(bufsize, NULL);
    171 	bufbase = buf;
    172 	bp = buf;
    173 	endpbb = buf + bufsize;
    174 	for (i = 0; i < MAXINP; i++)
    175 		bbase[i] = buf;
    176 }
    177 
    178 void
    179 enlarge_strspace()
    180 {
    181 	char *newstrspace;
    182 	int i;
    183 
    184 	strsize *= 2;
    185 	newstrspace = malloc(strsize + 1);
    186 	if (!newstrspace)
    187 		errx(1, "string space overflow");
    188 	memcpy(newstrspace, strspace, strsize/2);
    189 	for (i = 0; i <= sp; i++)
    190 		if (sstack[i])
    191 			mstack[i].sstr = (mstack[i].sstr - strspace)
    192 			    + newstrspace;
    193 	ep = (ep-strspace) + newstrspace;
    194 	free(strspace);
    195 	strspace = newstrspace;
    196 	endest = strspace + strsize;
    197 }
    198 
    199 void
    200 enlarge_bufspace()
    201 {
    202 	unsigned char *newbuf;
    203 	int i;
    204 
    205 	bufsize += bufsize/2;
    206 	newbuf = xrealloc(buf, bufsize, "too many characters pushed back");
    207 	for (i = 0; i < MAXINP; i++)
    208 		bbase[i] = (bbase[i]-buf)+newbuf;
    209 	bp = (bp-buf)+newbuf;
    210 	bufbase = (bufbase-buf)+newbuf;
    211 	buf = newbuf;
    212 	endpbb = buf+bufsize;
    213 }
    214 
    215 /*
    216  *  chrsave - put single char on string space
    217  */
    218 void
    219 chrsave(int c)
    220 {
    221 	if (ep >= endest)
    222 		enlarge_strspace();
    223 	*ep++ = c;
    224 }
    225 
    226 /*
    227  * read in a diversion file, and dispose it.
    228  */
    229 void
    230 getdiv(int n)
    231 {
    232 	int c;
    233 
    234 	if (active == outfile[n])
    235 		m4errx(1, "undivert: diversion still active.");
    236 	rewind(outfile[n]);
    237 	while ((c = getc(outfile[n])) != EOF)
    238 		putc(c, active);
    239 	(void) fclose(outfile[n]);
    240 	outfile[n] = NULL;
    241 }
    242 
    243 void
    244 onintr(int signo)
    245 {
    246 #define intrmessage	"m4: interrupted.\n"
    247 	write(STDERR_FILENO, intrmessage, sizeof(intrmessage)-1);
    248 	_exit(1);
    249 }
    250 
    251 /*
    252  * killdiv - get rid of the diversion files
    253  */
    254 void
    255 killdiv()
    256 {
    257 	int n;
    258 
    259 	for (n = 0; n < maxout; n++)
    260 		if (outfile[n] != NULL) {
    261 			(void) fclose(outfile[n]);
    262 		}
    263 }
    264 
    265 void
    266 m4errx(int exval, const char *fmt, ...)
    267 {
    268 	fprintf(stderr, "%s: ", getprogname());
    269 	fprintf(stderr, "%s at line %lu: ", CURRENT_NAME, CURRENT_LINE);
    270 	if (fmt != NULL) {
    271 		va_list ap;
    272 
    273 		va_start(ap, fmt);
    274 		vfprintf(stderr, fmt, ap);
    275 		va_end(ap);
    276 	}
    277 	fprintf(stderr, "\n");
    278 	exit(exval);
    279 }
    280 
    281 /*
    282  * resizedivs: allocate more diversion files */
    283 void
    284 resizedivs(int n)
    285 {
    286 	int i;
    287 
    288 	outfile = (FILE **)xrealloc(outfile, sizeof(FILE *) * n,
    289 	    "too many diverts %d", n);
    290 	for (i = maxout; i < n; i++)
    291 		outfile[i] = NULL;
    292 	maxout = n;
    293 }
    294 
    295 void *
    296 xalloc(size_t n, const char *fmt, ...)
    297 {
    298 	void *p = malloc(n);
    299 
    300 	if (p == NULL) {
    301 		if (fmt == NULL)
    302 			err(1, "malloc");
    303 		else {
    304 			va_list va;
    305 
    306 			va_start(va, fmt);
    307 			verr(1, fmt, va);
    308 			va_end(va);
    309 		}
    310 	}
    311 	return p;
    312 }
    313 
    314 void *
    315 xrealloc(void *old, size_t n, const char *fmt, ...)
    316 {
    317 	char *p = realloc(old, n);
    318 
    319 	if (p == NULL) {
    320 		free(old);
    321 		if (fmt == NULL)
    322 			err(1, "realloc");
    323 		else {
    324 			va_list va;
    325 
    326 			va_start(va, fmt);
    327 			verr(1, fmt, va);
    328 			va_end(va);
    329 	    	}
    330 	}
    331 	return p;
    332 }
    333 
    334 char *
    335 xstrdup(const char *s)
    336 {
    337 	char *p = strdup(s);
    338 	if (p == NULL)
    339 		err(1, "strdup");
    340 	return p;
    341 }
    342 
    343 void
    344 usage(void)
    345 {
    346 	fprintf(stderr, "usage: %s [-gPs] [-Dname[=value]] [-d flags] "
    347 			"[-I dirname] [-o filename]\n"
    348 			"\t[-t macro] [-Uname] [file ...]\n", getprogname());
    349 	exit(1);
    350 }
    351 
    352 int
    353 obtain_char(struct input_file *f)
    354 {
    355 	if (f->c == EOF)
    356 		return EOF;
    357 
    358 	f->c = fgetc(f->file);
    359 	if (f->c == '\n')
    360 		f->lineno++;
    361 
    362 	return f->c;
    363 }
    364 
    365 void
    366 set_input(struct input_file *f, FILE *real, const char *name)
    367 {
    368 	f->file = real;
    369 	f->lineno = 1;
    370 	f->c = 0;
    371 	f->name = xstrdup(name);
    372 	emit_synchline();
    373 }
    374 
    375 void
    376 do_emit_synchline()
    377 {
    378 	fprintf(active, "#line %lu \"%s\"\n",
    379 	    infile[ilevel].lineno, infile[ilevel].name);
    380 	infile[ilevel].synch_lineno = infile[ilevel].lineno;
    381 }
    382 
    383 void
    384 release_input(struct input_file *f)
    385 {
    386 	if (f->file != stdin)
    387 	    fclose(f->file);
    388 	f->c = EOF;
    389 	/*
    390 	 * XXX can't free filename, as there might still be
    391 	 * error information pointing to it.
    392 	 */
    393 }
    394 
    395 void
    396 doprintlineno(struct input_file *f)
    397 {
    398 	pbunsigned(f->lineno);
    399 }
    400 
    401 void
    402 doprintfilename(struct input_file *f)
    403 {
    404 	pbstr(rquote);
    405 	pbstr(f->name);
    406 	pbstr(lquote);
    407 }
    408 
    409 /*
    410  * buffer_mark/dump_buffer: allows one to save a mark in a buffer,
    411  * and later dump everything that was added since then to a file.
    412  */
    413 size_t
    414 buffer_mark()
    415 {
    416 	return bp - buf;
    417 }
    418 
    419 
    420 void
    421 dump_buffer(FILE *f, size_t m)
    422 {
    423 	unsigned char *s;
    424 
    425 	for (s = bp; (size_t)(s - buf) > m;)
    426 		fputc(*--s, f);
    427 }
    428