1228063Sbapt/* $OpenBSD: misc.c,v 1.42 2010/09/07 19:58:09 marco Exp $ */ 295060Sjmallett/* $NetBSD: misc.c,v 1.6 1995/09/28 05:37:41 tls Exp $ */ 395060Sjmallett 41590Srgrimes/* 51590Srgrimes * Copyright (c) 1989, 1993 61590Srgrimes * The Regents of the University of California. All rights reserved. 71590Srgrimes * 81590Srgrimes * This code is derived from software contributed to Berkeley by 91590Srgrimes * Ozan Yigit at York University. 101590Srgrimes * 111590Srgrimes * Redistribution and use in source and binary forms, with or without 121590Srgrimes * modification, are permitted provided that the following conditions 131590Srgrimes * are met: 141590Srgrimes * 1. Redistributions of source code must retain the above copyright 151590Srgrimes * notice, this list of conditions and the following disclaimer. 161590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 171590Srgrimes * notice, this list of conditions and the following disclaimer in the 181590Srgrimes * documentation and/or other materials provided with the distribution. 19228063Sbapt * 3. Neither the name of the University nor the names of its contributors 201590Srgrimes * may be used to endorse or promote products derived from this software 211590Srgrimes * without specific prior written permission. 221590Srgrimes * 231590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 241590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 251590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 261590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 271590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 281590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 291590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 301590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 311590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 321590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 331590Srgrimes * SUCH DAMAGE. 341590Srgrimes */ 3595060Sjmallett#include <sys/cdefs.h> 3695060Sjmallett__FBSDID("$FreeBSD$"); 371590Srgrimes 381590Srgrimes#include <sys/types.h> 3995060Sjmallett#include <errno.h> 4095060Sjmallett#include <unistd.h> 41228063Sbapt#include <stdarg.h> 421590Srgrimes#include <stdio.h> 431590Srgrimes#include <stdlib.h> 4495060Sjmallett#include <stddef.h> 451590Srgrimes#include <string.h> 4695060Sjmallett#include <err.h> 471590Srgrimes#include "mdef.h" 481590Srgrimes#include "stdd.h" 491590Srgrimes#include "extern.h" 501590Srgrimes#include "pathnames.h" 511590Srgrimes 5295060Sjmallett 5395060Sjmallettchar *ep; /* first free char in strspace */ 5495060Sjmallettstatic char *strspace; /* string space for evaluation */ 5595060Sjmallettchar *endest; /* end of string space */ 5695060Sjmallettstatic size_t strsize = STRSPMAX; 5795060Sjmallettstatic size_t bufsize = BUFSIZE; 5895060Sjmallett 59228063Sbaptunsigned char *buf; /* push-back buffer */ 60228063Sbaptunsigned char *bufbase; /* the base for current ilevel */ 61228063Sbaptunsigned char *bbase[MAXINP]; /* the base for each ilevel */ 62228063Sbaptunsigned char *bp; /* first available character */ 63228063Sbaptunsigned char *endpbb; /* end of push-back buffer */ 6495060Sjmallett 6595060Sjmallett 661590Srgrimes/* 671590Srgrimes * find the index of second str in the first str. 681590Srgrimes */ 6995060Sjmallettptrdiff_t 7095887Sjmallettindx(const char *s1, const char *s2) 711590Srgrimes{ 7295060Sjmallett char *t; 731590Srgrimes 7495060Sjmallett t = strstr(s1, s2); 7595060Sjmallett if (t == NULL) 7695060Sjmallett return (-1); 7795060Sjmallett else 7895060Sjmallett return (t - s1); 791590Srgrimes} 801590Srgrimes/* 81228063Sbapt * pushback - push character back onto input 821590Srgrimes */ 831590Srgrimesvoid 84228063Sbaptpushback(int c) 851590Srgrimes{ 865165Sache if (c == EOF) 875167Sache return; 8895060Sjmallett if (bp >= endpbb) 8995060Sjmallett enlarge_bufspace(); 9095060Sjmallett *bp++ = c; 911590Srgrimes} 921590Srgrimes 931590Srgrimes/* 941590Srgrimes * pbstr - push string back onto input 95228063Sbapt * pushback is replicated to improve 961590Srgrimes * performance. 971590Srgrimes */ 981590Srgrimesvoid 9995887Sjmallettpbstr(const char *s) 1001590Srgrimes{ 10195060Sjmallett size_t n; 1021590Srgrimes 10395060Sjmallett n = strlen(s); 104228063Sbapt while (endpbb - bp <= (long)n) 10595060Sjmallett enlarge_bufspace(); 10695060Sjmallett while (n > 0) 10795060Sjmallett *bp++ = s[--n]; 1081590Srgrimes} 1091590Srgrimes 1101590Srgrimes/* 1111590Srgrimes * pbnum - convert number to string, push back on input. 1121590Srgrimes */ 1131590Srgrimesvoid 11495887Sjmallettpbnum(int n) 1151590Srgrimes{ 116228063Sbapt pbnumbase(n, 10, 0); 117228063Sbapt} 118228063Sbapt 119228063Sbaptvoid 120228063Sbaptpbnumbase(int n, int base, int d) 121228063Sbapt{ 122228063Sbapt static char digits[36] = "0123456789abcdefghijklmnopqrstuvwxyz"; 12395060Sjmallett int num; 124228063Sbapt int printed = 0; 1251590Srgrimes 126228063Sbapt if (base > 36) 127228063Sbapt m4errx(1, "base %d > 36: not supported.", base); 128228063Sbapt 129228063Sbapt if (base < 2) 130228063Sbapt m4errx(1, "bad base %d for conversion.", base); 131228063Sbapt 1321590Srgrimes num = (n < 0) ? -n : n; 1331590Srgrimes do { 134228063Sbapt pushback(digits[num % base]); 135228063Sbapt printed++; 1361590Srgrimes } 137228063Sbapt while ((num /= base) > 0); 1381590Srgrimes 1391590Srgrimes if (n < 0) 140228063Sbapt printed++; 141228063Sbapt while (printed++ < d) 142228063Sbapt pushback('0'); 143228063Sbapt 144228063Sbapt if (n < 0) 145228063Sbapt pushback('-'); 1461590Srgrimes} 1471590Srgrimes 1481590Srgrimes/* 14995060Sjmallett * pbunsigned - convert unsigned long to string, push back on input. 15095060Sjmallett */ 15195060Sjmallettvoid 15295887Sjmallettpbunsigned(unsigned long n) 15395060Sjmallett{ 15495060Sjmallett do { 155228063Sbapt pushback(n % 10 + '0'); 15695060Sjmallett } 15795060Sjmallett while ((n /= 10) > 0); 15895060Sjmallett} 15995060Sjmallett 160100014Sjmallettvoid 16199939Sjmallettinitspaces(void) 16295060Sjmallett{ 16395060Sjmallett int i; 16495060Sjmallett 165228063Sbapt strspace = xalloc(strsize+1, NULL); 16695060Sjmallett ep = strspace; 16795060Sjmallett endest = strspace+strsize; 168228063Sbapt buf = (unsigned char *)xalloc(bufsize, NULL); 16995060Sjmallett bufbase = buf; 17095060Sjmallett bp = buf; 17195060Sjmallett endpbb = buf + bufsize; 17295060Sjmallett for (i = 0; i < MAXINP; i++) 17395060Sjmallett bbase[i] = buf; 17495060Sjmallett} 17595060Sjmallett 176100014Sjmallettvoid 17799939Sjmallettenlarge_strspace(void) 17895060Sjmallett{ 17995060Sjmallett char *newstrspace; 18095060Sjmallett int i; 18195060Sjmallett 18295060Sjmallett strsize *= 2; 18395060Sjmallett newstrspace = malloc(strsize + 1); 18495060Sjmallett if (!newstrspace) 18595060Sjmallett errx(1, "string space overflow"); 18695060Sjmallett memcpy(newstrspace, strspace, strsize/2); 187100014Sjmallett for (i = 0; i <= sp; i++) 18895060Sjmallett if (sstack[i]) 189100014Sjmallett mstack[i].sstr = (mstack[i].sstr - strspace) 19095060Sjmallett + newstrspace; 19195060Sjmallett ep = (ep-strspace) + newstrspace; 19295060Sjmallett free(strspace); 19395060Sjmallett strspace = newstrspace; 19495060Sjmallett endest = strspace + strsize; 19595060Sjmallett} 19695060Sjmallett 19795060Sjmallettvoid 19899939Sjmallettenlarge_bufspace(void) 19995060Sjmallett{ 200228063Sbapt unsigned char *newbuf; 20195060Sjmallett int i; 20295060Sjmallett 203228063Sbapt bufsize += bufsize/2; 204228063Sbapt newbuf = xrealloc(buf, bufsize, "too many characters pushed back"); 20595060Sjmallett for (i = 0; i < MAXINP; i++) 20695060Sjmallett bbase[i] = (bbase[i]-buf)+newbuf; 20795060Sjmallett bp = (bp-buf)+newbuf; 20895060Sjmallett bufbase = (bufbase-buf)+newbuf; 20995060Sjmallett buf = newbuf; 21095060Sjmallett endpbb = buf+bufsize; 21195060Sjmallett} 21295060Sjmallett 21395060Sjmallett/* 2141590Srgrimes * chrsave - put single char on string space 2151590Srgrimes */ 2161590Srgrimesvoid 21795887Sjmallettchrsave(int c) 2181590Srgrimes{ 219100014Sjmallett if (ep >= endest) 22095060Sjmallett enlarge_strspace(); 22195060Sjmallett *ep++ = c; 2221590Srgrimes} 2231590Srgrimes 2241590Srgrimes/* 2251590Srgrimes * read in a diversion file, and dispose it. 2261590Srgrimes */ 2271590Srgrimesvoid 22895887Sjmallettgetdiv(int n) 2291590Srgrimes{ 23095060Sjmallett int c; 2311590Srgrimes 2321590Srgrimes if (active == outfile[n]) 233228063Sbapt m4errx(1, "undivert: diversion still active."); 23495060Sjmallett rewind(outfile[n]); 23595060Sjmallett while ((c = getc(outfile[n])) != EOF) 23695060Sjmallett putc(c, active); 2371590Srgrimes (void) fclose(outfile[n]); 2381590Srgrimes outfile[n] = NULL; 2391590Srgrimes} 2401590Srgrimes 2411590Srgrimesvoid 242228063Sbaptonintr(__unused int signo) 2431590Srgrimes{ 24495060Sjmallett#define intrmessage "m4: interrupted.\n" 24595060Sjmallett write(STDERR_FILENO, intrmessage, sizeof(intrmessage)-1); 24695060Sjmallett _exit(1); 2471590Srgrimes} 2481590Srgrimes 2491590Srgrimes/* 2501590Srgrimes * killdiv - get rid of the diversion files 2511590Srgrimes */ 2521590Srgrimesvoid 25399939Sjmallettkilldiv(void) 2541590Srgrimes{ 25595060Sjmallett int n; 2561590Srgrimes 25795060Sjmallett for (n = 0; n < maxout; n++) 2581590Srgrimes if (outfile[n] != NULL) { 2591590Srgrimes (void) fclose(outfile[n]); 2601590Srgrimes } 2611590Srgrimes} 2621590Srgrimes 263228063Sbaptextern char *__progname; 264228063Sbapt 265228063Sbaptvoid 266228063Sbaptm4errx(int evaluation, const char *fmt, ...) 267228063Sbapt{ 268228063Sbapt fprintf(stderr, "%s: ", __progname); 269228063Sbapt fprintf(stderr, "%s at line %lu: ", CURRENT_NAME, CURRENT_LINE); 270228063Sbapt if (fmt != NULL) { 271228063Sbapt va_list ap; 272228063Sbapt 273228063Sbapt va_start(ap, fmt); 274228063Sbapt vfprintf(stderr, fmt, ap); 275228063Sbapt va_end(ap); 276228063Sbapt } 277228063Sbapt fprintf(stderr, "\n"); 278228063Sbapt exit(evaluation); 279228063Sbapt} 280228063Sbapt 28195060Sjmallett/* 28295060Sjmallett * resizedivs: allocate more diversion files */ 2831590Srgrimesvoid 28495887Sjmallettresizedivs(int n) 28575551Sgshapiro{ 28695060Sjmallett int i; 28795060Sjmallett 288228063Sbapt outfile = (FILE **)xrealloc(outfile, sizeof(FILE *) * n, 289228063Sbapt "too many diverts %d", n); 29095060Sjmallett for (i = maxout; i < n; i++) 29195060Sjmallett outfile[i] = NULL; 29295060Sjmallett maxout = n; 29375551Sgshapiro} 29475551Sgshapiro 29595060Sjmallettvoid * 296228063Sbaptxalloc(size_t n, const char *fmt, ...) 29795060Sjmallett{ 298228063Sbapt void *p = malloc(n); 29995060Sjmallett 300228063Sbapt if (p == NULL) { 301228063Sbapt if (fmt == NULL) 302228063Sbapt err(1, "malloc"); 303228063Sbapt else { 304228063Sbapt va_list va; 305228063Sbapt 306228063Sbapt va_start(va, fmt); 307228063Sbapt verr(1, fmt, va); 308228063Sbapt va_end(va); 309228063Sbapt } 310228063Sbapt } 31195060Sjmallett return p; 31295060Sjmallett} 31395060Sjmallett 314228063Sbaptvoid * 315228063Sbaptxrealloc(void *old, size_t n, const char *fmt, ...) 316228063Sbapt{ 317228063Sbapt char *p = realloc(old, n); 318228063Sbapt 319228063Sbapt if (p == NULL) { 320228063Sbapt free(old); 321228063Sbapt if (fmt == NULL) 322228063Sbapt err(1, "realloc"); 323228063Sbapt else { 324228063Sbapt va_list va; 325228063Sbapt 326228063Sbapt va_start(va, fmt); 327228063Sbapt verr(1, fmt, va); 328228063Sbapt va_end(va); 329228063Sbapt } 330228063Sbapt } 331228063Sbapt return p; 332228063Sbapt} 333228063Sbapt 33495060Sjmallettchar * 33595887Sjmallettxstrdup(const char *s) 33695060Sjmallett{ 33795060Sjmallett char *p = strdup(s); 33895060Sjmallett if (p == NULL) 33995060Sjmallett err(1, "strdup"); 34095060Sjmallett return p; 34195060Sjmallett} 34295060Sjmallett 34375551Sgshapirovoid 34499939Sjmallettusage(void) 3451590Srgrimes{ 346228063Sbapt fprintf(stderr, "usage: m4 [-gPs] [-Dname[=value]] [-d flags] " 347228063Sbapt "[-I dirname] [-o filename]\n" 348228063Sbapt "\t[-t macro] [-Uname] [file ...]\n"); 3491590Srgrimes exit(1); 3501590Srgrimes} 35195060Sjmallett 352100014Sjmallettint 35395887Sjmallettobtain_char(struct input_file *f) 35495060Sjmallett{ 35595060Sjmallett if (f->c == EOF) 35695060Sjmallett return EOF; 357228063Sbapt 358228063Sbapt f->c = fgetc(f->file); 359228063Sbapt if (f->c == '\n') 36095060Sjmallett f->lineno++; 36195060Sjmallett 36295060Sjmallett return f->c; 36395060Sjmallett} 36495060Sjmallett 365100014Sjmallettvoid 36695887Sjmallettset_input(struct input_file *f, FILE *real, const char *name) 36795060Sjmallett{ 36895060Sjmallett f->file = real; 36995060Sjmallett f->lineno = 1; 37095060Sjmallett f->c = 0; 37195060Sjmallett f->name = xstrdup(name); 372228063Sbapt emit_synchline(); 37395060Sjmallett} 37495060Sjmallett 375100014Sjmallettvoid 376228063Sbaptdo_emit_synchline(void) 377228063Sbapt{ 378228063Sbapt fprintf(active, "#line %lu \"%s\"\n", 379228063Sbapt infile[ilevel].lineno, infile[ilevel].name); 380228063Sbapt infile[ilevel].synch_lineno = infile[ilevel].lineno; 381228063Sbapt} 382228063Sbapt 383228063Sbaptvoid 38495887Sjmallettrelease_input(struct input_file *f) 38595060Sjmallett{ 38695060Sjmallett if (f->file != stdin) 38795060Sjmallett fclose(f->file); 38895060Sjmallett f->c = EOF; 38995060Sjmallett /* 390100014Sjmallett * XXX can't free filename, as there might still be 39195060Sjmallett * error information pointing to it. 39295060Sjmallett */ 39395060Sjmallett} 39495060Sjmallett 39595060Sjmallettvoid 39695887Sjmallettdoprintlineno(struct input_file *f) 39795060Sjmallett{ 39895060Sjmallett pbunsigned(f->lineno); 39995060Sjmallett} 40095060Sjmallett 40195060Sjmallettvoid 40295887Sjmallettdoprintfilename(struct input_file *f) 40395060Sjmallett{ 40495060Sjmallett pbstr(rquote); 40595060Sjmallett pbstr(f->name); 40695060Sjmallett pbstr(lquote); 40795060Sjmallett} 40895060Sjmallett 409100014Sjmallett/* 41095060Sjmallett * buffer_mark/dump_buffer: allows one to save a mark in a buffer, 41195060Sjmallett * and later dump everything that was added since then to a file. 41295060Sjmallett */ 41395060Sjmallettsize_t 41499939Sjmallettbuffer_mark(void) 41595060Sjmallett{ 41695060Sjmallett return bp - buf; 41795060Sjmallett} 41895060Sjmallett 41995060Sjmallett 42095060Sjmallettvoid 42195887Sjmallettdump_buffer(FILE *f, size_t m) 42295060Sjmallett{ 423228063Sbapt unsigned char *s; 42495060Sjmallett 425228063Sbapt for (s = bp; s-buf > (long)m;) 42695060Sjmallett fputc(*--s, f); 42795060Sjmallett} 428