Home | History | Annotate | Line # | Download | only in m4
      1 /*	$OpenBSD: misc.c,v 1.41 2009/10/14 17:19:47 sthen Exp $	*/
      2 /*	$NetBSD: misc.c,v 1.25 2024/10/06 19:31:26 rillig 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.25 2024/10/06 19:31:26 rillig 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 	const 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(void)
    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(void)
    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(void)
    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 /*
    244  * killdiv - get rid of the diversion files
    245  */
    246 void
    247 killdiv(void)
    248 {
    249 	int n;
    250 
    251 	for (n = 0; n < maxout; n++)
    252 		if (outfile[n] != NULL) {
    253 			(void) fclose(outfile[n]);
    254 		}
    255 }
    256 
    257 void
    258 m4errx(int exval, const char *fmt, ...)
    259 {
    260 	fprintf(stderr, "%s: ", getprogname());
    261 	fprintf(stderr, "%s at line %lu: ", CURRENT_NAME, CURRENT_LINE);
    262 	if (fmt != NULL) {
    263 		va_list ap;
    264 
    265 		va_start(ap, fmt);
    266 		vfprintf(stderr, fmt, ap);
    267 		va_end(ap);
    268 	}
    269 	fprintf(stderr, "\n");
    270 	exit(exval);
    271 }
    272 
    273 /*
    274  * resizedivs: allocate more diversion files */
    275 void
    276 resizedivs(int n)
    277 {
    278 	int i;
    279 
    280 	outfile = (FILE **)xrealloc(outfile, sizeof(FILE *) * n,
    281 	    "too many diverts %d", n);
    282 	for (i = maxout; i < n; i++)
    283 		outfile[i] = NULL;
    284 	maxout = n;
    285 }
    286 
    287 void *
    288 xalloc(size_t n, const char *fmt, ...)
    289 {
    290 	void *p = malloc(n);
    291 
    292 	if (p == NULL) {
    293 		if (fmt == NULL)
    294 			err(1, "malloc");
    295 		else {
    296 			va_list va;
    297 
    298 			va_start(va, fmt);
    299 			verr(1, fmt, va);
    300 			va_end(va);
    301 		}
    302 	}
    303 	return p;
    304 }
    305 
    306 void *
    307 xrealloc(void *old, size_t n, const char *fmt, ...)
    308 {
    309 	char *p = realloc(old, n);
    310 
    311 	if (p == NULL) {
    312 		free(old);
    313 		if (fmt == NULL)
    314 			err(1, "realloc");
    315 		else {
    316 			va_list va;
    317 
    318 			va_start(va, fmt);
    319 			verr(1, fmt, va);
    320 			va_end(va);
    321 	    	}
    322 	}
    323 	return p;
    324 }
    325 
    326 char *
    327 xstrdup(const char *s)
    328 {
    329 	char *p = strdup(s);
    330 	if (p == NULL)
    331 		err(1, "strdup");
    332 	return p;
    333 }
    334 
    335 int
    336 obtain_char(struct input_file *f)
    337 {
    338 	if (f->c == EOF)
    339 		return EOF;
    340 
    341 	f->c = fgetc(f->file);
    342 #ifndef REAL_FREEZE
    343 	if (freezef)
    344 		fputc(f->c, freezef);
    345 #endif
    346 	if (f->c == '\n')
    347 		f->lineno++;
    348 
    349 	return f->c;
    350 }
    351 
    352 void
    353 set_input(struct input_file *f, FILE *real, const char *name)
    354 {
    355 	f->file = real;
    356 	f->lineno = 1;
    357 	f->c = 0;
    358 	f->name = xstrdup(name);
    359 	emit_synchline();
    360 }
    361 
    362 void
    363 do_emit_synchline(void)
    364 {
    365 	fprintf(active, "#line %lu \"%s\"\n",
    366 	    infile[ilevel].lineno, infile[ilevel].name);
    367 	infile[ilevel].synch_lineno = infile[ilevel].lineno;
    368 }
    369 
    370 void
    371 release_input(struct input_file *f)
    372 {
    373 	if (f->file != stdin)
    374 	    fclose(f->file);
    375 	f->c = EOF;
    376 	/*
    377 	 * XXX can't free filename, as there might still be
    378 	 * error information pointing to it.
    379 	 */
    380 }
    381 
    382 void
    383 doprintlineno(struct input_file *f)
    384 {
    385 	pbunsigned(TOKEN_LINE(f));
    386 }
    387 
    388 void
    389 doprintfilename(struct input_file *f)
    390 {
    391 	pbstr(rquote);
    392 	pbstr(f->name);
    393 	pbstr(lquote);
    394 }
    395 
    396 /*
    397  * buffer_mark/dump_buffer: allows one to save a mark in a buffer,
    398  * and later dump everything that was added since then to a file.
    399  */
    400 size_t
    401 buffer_mark(void)
    402 {
    403 	return bp - buf;
    404 }
    405 
    406 
    407 void
    408 dump_buffer(FILE *f, size_t m)
    409 {
    410 	unsigned char *s;
    411 
    412 	for (s = bp; (size_t)(s - buf) > m;)
    413 		fputc(*--s, f);
    414 }
    415