1/* $OpenBSD: misc.c,v 1.47 2017/06/15 13:48:42 bcallah 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 36#include <sys/cdefs.h> 37__FBSDID("$FreeBSD: stable/11/usr.bin/m4/misc.c 352281 2019-09-13 07:22:09Z bapt $"); 38 39#include <sys/types.h> 40#include <errno.h> 41#include <unistd.h> 42#include <stdarg.h> 43#include <stdio.h> 44#include <stdint.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 55char *ep; /* first free char in strspace */ 56static char *strspace; /* string space for evaluation */ 57char *endest; /* end of string space */ 58static size_t strsize = STRSPMAX; 59static size_t bufsize = BUFSIZE; 60 61unsigned char *buf; /* push-back buffer */ 62unsigned char *bufbase; /* the base for current ilevel */ 63unsigned char *bbase[MAXINP]; /* the base for each ilevel */ 64unsigned char *bp; /* first available character */ 65unsigned char *endpbb; /* end of push-back buffer */ 66 67 68/* 69 * find the index of second str in the first str. 70 */ 71ptrdiff_t 72indx(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 */ 85void 86pushback(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 */ 100void 101pbstr(const char *s) 102{ 103 size_t n; 104 105 n = strlen(s); 106 while (endpbb - bp <= (long)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 */ 115void 116pbnum(int n) 117{ 118 pbnumbase(n, 10, 0); 119} 120 121void 122pbnumbase(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 */ 153void 154pbunsigned(unsigned long n) 155{ 156 do { 157 pushback(n % 10 + '0'); 158 } 159 while ((n /= 10) > 0); 160} 161 162void 163initspaces(void) 164{ 165 int i; 166 167 strspace = xalloc(strsize+1, NULL); 168 ep = strspace; 169 endest = strspace+strsize; 170 buf = 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 178void 179enlarge_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] == STORAGE_STRSPACE) 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 199void 200enlarge_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 */ 218void 219chrsave(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 */ 229void 230getdiv(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 243void 244onintr(int signo __unused) 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 */ 254void 255killdiv(void) 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 265extern char *__progname; 266 267void 268m4errx(int eval, const char *fmt, ...) 269{ 270 fprintf(stderr, "%s: ", __progname); 271 fprintf(stderr, "%s at line %lu: ", CURRENT_NAME, CURRENT_LINE); 272 if (fmt != NULL) { 273 va_list ap; 274 275 va_start(ap, fmt); 276 vfprintf(stderr, fmt, ap); 277 va_end(ap); 278 } 279 fprintf(stderr, "\n"); 280 exit(eval); 281} 282 283/* 284 * resizedivs: allocate more diversion files */ 285void 286resizedivs(int n) 287{ 288 int i; 289 290 outfile = xreallocarray(outfile, n, sizeof(FILE *), 291 "too many diverts %d", n); 292 for (i = maxout; i < n; i++) 293 outfile[i] = NULL; 294 maxout = n; 295} 296 297void * 298xalloc(size_t n, const char *fmt, ...) 299{ 300 void *p = malloc(n); 301 302 if (p == NULL) { 303 if (fmt == NULL) 304 err(1, "malloc"); 305 else { 306 va_list va; 307 308 va_start(va, fmt); 309 verr(1, fmt, va); 310 va_end(va); 311 } 312 } 313 return p; 314} 315 316void * 317xcalloc(size_t n, size_t s, const char *fmt, ...) 318{ 319 void *p = calloc(n, s); 320 321 if (p == NULL) { 322 if (fmt == NULL) 323 err(1, "calloc"); 324 else { 325 va_list va; 326 327 va_start(va, fmt); 328 verr(1, fmt, va); 329 va_end(va); 330 } 331 } 332 return p; 333} 334 335void * 336xrealloc(void *old, size_t n, const char *fmt, ...) 337{ 338 char *p = realloc(old, n); 339 340 if (p == NULL) { 341 free(old); 342 if (fmt == NULL) 343 err(1, "realloc"); 344 else { 345 va_list va; 346 347 va_start(va, fmt); 348 verr(1, fmt, va); 349 va_end(va); 350 } 351 } 352 return p; 353} 354 355void * 356xreallocarray(void *old, size_t s1, size_t s2, const char *fmt, ...) 357{ 358 void *p = reallocarray(old, s1, s2); 359 360 if (p == NULL) { 361 free(old); 362 if (fmt == NULL) 363 err(1, "reallocarray"); 364 else { 365 va_list va; 366 367 va_start(va, fmt); 368 verr(1, fmt, va); 369 va_end(va); 370 } 371 } 372 return p; 373} 374 375char * 376xstrdup(const char *s) 377{ 378 char *p = strdup(s); 379 if (p == NULL) 380 err(1, "strdup"); 381 return p; 382} 383 384void 385usage(void) 386{ 387 fprintf(stderr, "usage: m4 [-EgPs] [-Dname[=value]] [-d flags] " 388 "[-I dirname] [-o filename]\n" 389 "\t[-t macro] [-Uname] [file ...]\n"); 390 exit(1); 391} 392 393int 394obtain_char(struct input_file *f) 395{ 396 if (f->c == EOF) 397 return EOF; 398 399 f->c = fgetc(f->file); 400 if (f->c == '\n') 401 f->lineno++; 402 403 return f->c; 404} 405 406void 407set_input(struct input_file *f, FILE *real, const char *name) 408{ 409 f->file = real; 410 f->lineno = 1; 411 f->c = 0; 412 f->name = xstrdup(name); 413 emit_synchline(); 414} 415 416void 417do_emit_synchline(void) 418{ 419 fprintf(active, "#line %lu \"%s\"\n", 420 infile[ilevel].lineno, infile[ilevel].name); 421 infile[ilevel].synch_lineno = infile[ilevel].lineno; 422} 423 424void 425release_input(struct input_file *f) 426{ 427 if (ferror(f->file)) 428 errx(1, "Fatal error reading from %s\n", f->name); 429 if (f->file != stdin) 430 fclose(f->file); 431 f->c = EOF; 432 /* 433 * XXX can't free filename, as there might still be 434 * error information pointing to it. 435 */ 436} 437 438void 439doprintlineno(struct input_file *f) 440{ 441 pbunsigned(f->lineno); 442} 443 444void 445doprintfilename(struct input_file *f) 446{ 447 pbstr(rquote); 448 pbstr(f->name); 449 pbstr(lquote); 450} 451 452/* 453 * buffer_mark/dump_buffer: allows one to save a mark in a buffer, 454 * and later dump everything that was added since then to a file. 455 */ 456size_t 457buffer_mark(void) 458{ 459 return bp - buf; 460} 461 462 463void 464dump_buffer(FILE *f, size_t m) 465{ 466 unsigned char *s; 467 468 for (s = bp; s-buf > (long)m;) 469 fputc(*--s, f); 470} 471