1/* $OpenBSD: misc.c,v 1.42 2010/09/07 19:58:09 marco Exp $ */ 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. 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#include <sys/cdefs.h> 36__FBSDID("$FreeBSD: releng/10.2/usr.bin/m4/misc.c 228063 2011-11-28 13:32:39Z bapt $"); 37 38#include <sys/types.h> 39#include <errno.h> 40#include <unistd.h> 41#include <stdarg.h> 42#include <stdio.h> 43#include <stdlib.h> 44#include <stddef.h> 45#include <string.h> 46#include <err.h> 47#include "mdef.h" 48#include "stdd.h" 49#include "extern.h" 50#include "pathnames.h" 51 52 53char *ep; /* first free char in strspace */ 54static char *strspace; /* string space for evaluation */ 55char *endest; /* end of string space */ 56static size_t strsize = STRSPMAX; 57static size_t bufsize = BUFSIZE; 58 59unsigned char *buf; /* push-back buffer */ 60unsigned char *bufbase; /* the base for current ilevel */ 61unsigned char *bbase[MAXINP]; /* the base for each ilevel */ 62unsigned char *bp; /* first available character */ 63unsigned char *endpbb; /* end of push-back buffer */ 64 65 66/* 67 * find the index of second str in the first str. 68 */ 69ptrdiff_t 70indx(const char *s1, const char *s2) 71{ 72 char *t; 73 74 t = strstr(s1, s2); 75 if (t == NULL) 76 return (-1); 77 else 78 return (t - s1); 79} 80/* 81 * pushback - push character back onto input 82 */ 83void 84pushback(int c) 85{ 86 if (c == EOF) 87 return; 88 if (bp >= endpbb) 89 enlarge_bufspace(); 90 *bp++ = c; 91} 92 93/* 94 * pbstr - push string back onto input 95 * pushback is replicated to improve 96 * performance. 97 */ 98void 99pbstr(const char *s) 100{ 101 size_t n; 102 103 n = strlen(s); 104 while (endpbb - bp <= (long)n) 105 enlarge_bufspace(); 106 while (n > 0) 107 *bp++ = s[--n]; 108} 109 110/* 111 * pbnum - convert number to string, push back on input. 112 */ 113void 114pbnum(int n) 115{ 116 pbnumbase(n, 10, 0); 117} 118 119void 120pbnumbase(int n, int base, int d) 121{ 122 static char digits[36] = "0123456789abcdefghijklmnopqrstuvwxyz"; 123 int num; 124 int printed = 0; 125 126 if (base > 36) 127 m4errx(1, "base %d > 36: not supported.", base); 128 129 if (base < 2) 130 m4errx(1, "bad base %d for conversion.", base); 131 132 num = (n < 0) ? -n : n; 133 do { 134 pushback(digits[num % base]); 135 printed++; 136 } 137 while ((num /= base) > 0); 138 139 if (n < 0) 140 printed++; 141 while (printed++ < d) 142 pushback('0'); 143 144 if (n < 0) 145 pushback('-'); 146} 147 148/* 149 * pbunsigned - convert unsigned long to string, push back on input. 150 */ 151void 152pbunsigned(unsigned long n) 153{ 154 do { 155 pushback(n % 10 + '0'); 156 } 157 while ((n /= 10) > 0); 158} 159 160void 161initspaces(void) 162{ 163 int i; 164 165 strspace = xalloc(strsize+1, NULL); 166 ep = strspace; 167 endest = strspace+strsize; 168 buf = (unsigned char *)xalloc(bufsize, NULL); 169 bufbase = buf; 170 bp = buf; 171 endpbb = buf + bufsize; 172 for (i = 0; i < MAXINP; i++) 173 bbase[i] = buf; 174} 175 176void 177enlarge_strspace(void) 178{ 179 char *newstrspace; 180 int i; 181 182 strsize *= 2; 183 newstrspace = malloc(strsize + 1); 184 if (!newstrspace) 185 errx(1, "string space overflow"); 186 memcpy(newstrspace, strspace, strsize/2); 187 for (i = 0; i <= sp; i++) 188 if (sstack[i]) 189 mstack[i].sstr = (mstack[i].sstr - strspace) 190 + newstrspace; 191 ep = (ep-strspace) + newstrspace; 192 free(strspace); 193 strspace = newstrspace; 194 endest = strspace + strsize; 195} 196 197void 198enlarge_bufspace(void) 199{ 200 unsigned char *newbuf; 201 int i; 202 203 bufsize += bufsize/2; 204 newbuf = xrealloc(buf, bufsize, "too many characters pushed back"); 205 for (i = 0; i < MAXINP; i++) 206 bbase[i] = (bbase[i]-buf)+newbuf; 207 bp = (bp-buf)+newbuf; 208 bufbase = (bufbase-buf)+newbuf; 209 buf = newbuf; 210 endpbb = buf+bufsize; 211} 212 213/* 214 * chrsave - put single char on string space 215 */ 216void 217chrsave(int c) 218{ 219 if (ep >= endest) 220 enlarge_strspace(); 221 *ep++ = c; 222} 223 224/* 225 * read in a diversion file, and dispose it. 226 */ 227void 228getdiv(int n) 229{ 230 int c; 231 232 if (active == outfile[n]) 233 m4errx(1, "undivert: diversion still active."); 234 rewind(outfile[n]); 235 while ((c = getc(outfile[n])) != EOF) 236 putc(c, active); 237 (void) fclose(outfile[n]); 238 outfile[n] = NULL; 239} 240 241void 242onintr(__unused int signo) 243{ 244#define intrmessage "m4: interrupted.\n" 245 write(STDERR_FILENO, intrmessage, sizeof(intrmessage)-1); 246 _exit(1); 247} 248 249/* 250 * killdiv - get rid of the diversion files 251 */ 252void 253killdiv(void) 254{ 255 int n; 256 257 for (n = 0; n < maxout; n++) 258 if (outfile[n] != NULL) { 259 (void) fclose(outfile[n]); 260 } 261} 262 263extern char *__progname; 264 265void 266m4errx(int evaluation, const char *fmt, ...) 267{ 268 fprintf(stderr, "%s: ", __progname); 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(evaluation); 279} 280 281/* 282 * resizedivs: allocate more diversion files */ 283void 284resizedivs(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 295void * 296xalloc(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 314void * 315xrealloc(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 334char * 335xstrdup(const char *s) 336{ 337 char *p = strdup(s); 338 if (p == NULL) 339 err(1, "strdup"); 340 return p; 341} 342 343void 344usage(void) 345{ 346 fprintf(stderr, "usage: m4 [-gPs] [-Dname[=value]] [-d flags] " 347 "[-I dirname] [-o filename]\n" 348 "\t[-t macro] [-Uname] [file ...]\n"); 349 exit(1); 350} 351 352int 353obtain_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 365void 366set_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 375void 376do_emit_synchline(void) 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 383void 384release_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 395void 396doprintlineno(struct input_file *f) 397{ 398 pbunsigned(f->lineno); 399} 400 401void 402doprintfilename(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 */ 413size_t 414buffer_mark(void) 415{ 416 return bp - buf; 417} 418 419 420void 421dump_buffer(FILE *f, size_t m) 422{ 423 unsigned char *s; 424 425 for (s = bp; s-buf > (long)m;) 426 fputc(*--s, f); 427} 428