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 * SPDX-License-Identifier: BSD-3-Clause 6 * 7 * Copyright (c) 1989, 1993 8 * The Regents of the University of California. All rights reserved. 9 * 10 * This code is derived from software contributed to Berkeley by 11 * Ozan Yigit at York University. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 3. Neither the name of the University nor the names of its contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 */ 37 38#include <sys/cdefs.h> 39__FBSDID("$FreeBSD$"); 40 41#include <sys/types.h> 42#include <errno.h> 43#include <unistd.h> 44#include <stdarg.h> 45#include <stdio.h> 46#include <stdint.h> 47#include <stdlib.h> 48#include <stddef.h> 49#include <string.h> 50#include <err.h> 51#include "mdef.h" 52#include "stdd.h" 53#include "extern.h" 54#include "pathnames.h" 55 56 57char *ep; /* first free char in strspace */ 58static char *strspace; /* string space for evaluation */ 59char *endest; /* end of string space */ 60static size_t strsize = STRSPMAX; 61static size_t bufsize = BUFSIZE; 62 63unsigned char *buf; /* push-back buffer */ 64unsigned char *bufbase; /* the base for current ilevel */ 65unsigned char *bbase[MAXINP]; /* the base for each ilevel */ 66unsigned char *bp; /* first available character */ 67unsigned char *endpbb; /* end of push-back buffer */ 68 69 70/* 71 * find the index of second str in the first str. 72 */ 73ptrdiff_t 74indx(const char *s1, const char *s2) 75{ 76 char *t; 77 78 t = strstr(s1, s2); 79 if (t == NULL) 80 return (-1); 81 else 82 return (t - s1); 83} 84/* 85 * pushback - push character back onto input 86 */ 87void 88pushback(int c) 89{ 90 if (c == EOF) 91 return; 92 if (bp >= endpbb) 93 enlarge_bufspace(); 94 *bp++ = c; 95} 96 97/* 98 * pbstr - push string back onto input 99 * pushback is replicated to improve 100 * performance. 101 */ 102void 103pbstr(const char *s) 104{ 105 size_t n; 106 107 n = strlen(s); 108 while (endpbb - bp <= (long)n) 109 enlarge_bufspace(); 110 while (n > 0) 111 *bp++ = s[--n]; 112} 113 114/* 115 * pbnum - convert number to string, push back on input. 116 */ 117void 118pbnum(int n) 119{ 120 pbnumbase(n, 10, 0); 121} 122 123void 124pbnumbase(int n, int base, int d) 125{ 126 static char digits[36] = "0123456789abcdefghijklmnopqrstuvwxyz"; 127 int num; 128 int printed = 0; 129 130 if (base > 36) 131 m4errx(1, "base %d > 36: not supported.", base); 132 133 if (base < 2) 134 m4errx(1, "bad base %d for conversion.", base); 135 136 num = (n < 0) ? -n : n; 137 do { 138 pushback(digits[num % base]); 139 printed++; 140 } 141 while ((num /= base) > 0); 142 143 if (n < 0) 144 printed++; 145 while (printed++ < d) 146 pushback('0'); 147 148 if (n < 0) 149 pushback('-'); 150} 151 152/* 153 * pbunsigned - convert unsigned long to string, push back on input. 154 */ 155void 156pbunsigned(unsigned long n) 157{ 158 do { 159 pushback(n % 10 + '0'); 160 } 161 while ((n /= 10) > 0); 162} 163 164void 165initspaces(void) 166{ 167 int i; 168 169 strspace = xalloc(strsize+1, NULL); 170 ep = strspace; 171 endest = strspace+strsize; 172 buf = xalloc(bufsize, NULL); 173 bufbase = buf; 174 bp = buf; 175 endpbb = buf + bufsize; 176 for (i = 0; i < MAXINP; i++) 177 bbase[i] = buf; 178} 179 180void 181enlarge_strspace(void) 182{ 183 char *newstrspace; 184 int i; 185 186 strsize *= 2; 187 newstrspace = malloc(strsize + 1); 188 if (!newstrspace) 189 errx(1, "string space overflow"); 190 memcpy(newstrspace, strspace, strsize/2); 191 for (i = 0; i <= sp; i++) 192 if (sstack[i] == STORAGE_STRSPACE) 193 mstack[i].sstr = (mstack[i].sstr - strspace) 194 + newstrspace; 195 ep = (ep-strspace) + newstrspace; 196 free(strspace); 197 strspace = newstrspace; 198 endest = strspace + strsize; 199} 200 201void 202enlarge_bufspace(void) 203{ 204 unsigned char *newbuf; 205 int i; 206 207 bufsize += bufsize/2; 208 newbuf = xrealloc(buf, bufsize, "too many characters pushed back"); 209 for (i = 0; i < MAXINP; i++) 210 bbase[i] = (bbase[i]-buf)+newbuf; 211 bp = (bp-buf)+newbuf; 212 bufbase = (bufbase-buf)+newbuf; 213 buf = newbuf; 214 endpbb = buf+bufsize; 215} 216 217/* 218 * chrsave - put single char on string space 219 */ 220void 221chrsave(int c) 222{ 223 if (ep >= endest) 224 enlarge_strspace(); 225 *ep++ = c; 226} 227 228/* 229 * read in a diversion file, and dispose it. 230 */ 231void 232getdiv(int n) 233{ 234 int c; 235 236 if (active == outfile[n]) 237 m4errx(1, "undivert: diversion still active."); 238 rewind(outfile[n]); 239 while ((c = getc(outfile[n])) != EOF) 240 putc(c, active); 241 (void) fclose(outfile[n]); 242 outfile[n] = NULL; 243} 244 245void 246onintr(int signo __unused) 247{ 248#define intrmessage "m4: interrupted.\n" 249 write(STDERR_FILENO, intrmessage, sizeof(intrmessage)-1); 250 _exit(1); 251} 252 253/* 254 * killdiv - get rid of the diversion files 255 */ 256void 257killdiv(void) 258{ 259 int n; 260 261 for (n = 0; n < maxout; n++) 262 if (outfile[n] != NULL) { 263 (void) fclose(outfile[n]); 264 } 265} 266 267extern char *__progname; 268 269void 270m4errx(int eval, const char *fmt, ...) 271{ 272 fprintf(stderr, "%s: ", __progname); 273 fprintf(stderr, "%s at line %lu: ", CURRENT_NAME, CURRENT_LINE); 274 if (fmt != NULL) { 275 va_list ap; 276 277 va_start(ap, fmt); 278 vfprintf(stderr, fmt, ap); 279 va_end(ap); 280 } 281 fprintf(stderr, "\n"); 282 exit(eval); 283} 284 285/* 286 * resizedivs: allocate more diversion files */ 287void 288resizedivs(int n) 289{ 290 int i; 291 292 outfile = xreallocarray(outfile, n, sizeof(FILE *), 293 "too many diverts %d", n); 294 for (i = maxout; i < n; i++) 295 outfile[i] = NULL; 296 maxout = n; 297} 298 299void * 300xalloc(size_t n, const char *fmt, ...) 301{ 302 void *p = malloc(n); 303 304 if (p == NULL) { 305 if (fmt == NULL) 306 err(1, "malloc"); 307 else { 308 va_list va; 309 310 va_start(va, fmt); 311 verr(1, fmt, va); 312 va_end(va); 313 } 314 } 315 return p; 316} 317 318void * 319xcalloc(size_t n, size_t s, const char *fmt, ...) 320{ 321 void *p = calloc(n, s); 322 323 if (p == NULL) { 324 if (fmt == NULL) 325 err(1, "calloc"); 326 else { 327 va_list va; 328 329 va_start(va, fmt); 330 verr(1, fmt, va); 331 va_end(va); 332 } 333 } 334 return p; 335} 336 337void * 338xrealloc(void *old, size_t n, const char *fmt, ...) 339{ 340 char *p = realloc(old, n); 341 342 if (p == NULL) { 343 free(old); 344 if (fmt == NULL) 345 err(1, "realloc"); 346 else { 347 va_list va; 348 349 va_start(va, fmt); 350 verr(1, fmt, va); 351 va_end(va); 352 } 353 } 354 return p; 355} 356 357void * 358xreallocarray(void *old, size_t s1, size_t s2, const char *fmt, ...) 359{ 360 void *p = reallocarray(old, s1, s2); 361 362 if (p == NULL) { 363 free(old); 364 if (fmt == NULL) 365 err(1, "reallocarray"); 366 else { 367 va_list va; 368 369 va_start(va, fmt); 370 verr(1, fmt, va); 371 va_end(va); 372 } 373 } 374 return p; 375} 376 377char * 378xstrdup(const char *s) 379{ 380 char *p = strdup(s); 381 if (p == NULL) 382 err(1, "strdup"); 383 return p; 384} 385 386void 387usage(void) 388{ 389 fprintf(stderr, "usage: m4 [-EgPs] [-Dname[=value]] [-d flags] " 390 "[-I dirname] [-o filename]\n" 391 "\t[-t macro] [-Uname] [file ...]\n"); 392 exit(1); 393} 394 395int 396obtain_char(struct input_file *f) 397{ 398 if (f->c == EOF) 399 return EOF; 400 401 f->c = fgetc(f->file); 402 if (f->c == '\n') 403 f->lineno++; 404 405 return f->c; 406} 407 408void 409set_input(struct input_file *f, FILE *real, const char *name) 410{ 411 f->file = real; 412 f->lineno = 1; 413 f->c = 0; 414 f->name = xstrdup(name); 415 emit_synchline(); 416} 417 418void 419do_emit_synchline(void) 420{ 421 fprintf(active, "#line %lu \"%s\"\n", 422 infile[ilevel].lineno, infile[ilevel].name); 423 infile[ilevel].synch_lineno = infile[ilevel].lineno; 424} 425 426void 427release_input(struct input_file *f) 428{ 429 if (ferror(f->file)) 430 errx(1, "Fatal error reading from %s\n", f->name); 431 if (f->file != stdin) 432 fclose(f->file); 433 f->c = EOF; 434 /* 435 * XXX can't free filename, as there might still be 436 * error information pointing to it. 437 */ 438} 439 440void 441doprintlineno(struct input_file *f) 442{ 443 pbunsigned(f->lineno); 444} 445 446void 447doprintfilename(struct input_file *f) 448{ 449 pbstr(rquote); 450 pbstr(f->name); 451 pbstr(lquote); 452} 453 454/* 455 * buffer_mark/dump_buffer: allows one to save a mark in a buffer, 456 * and later dump everything that was added since then to a file. 457 */ 458size_t 459buffer_mark(void) 460{ 461 return bp - buf; 462} 463 464 465void 466dump_buffer(FILE *f, size_t m) 467{ 468 unsigned char *s; 469 470 for (s = bp; s-buf > (long)m;) 471 fputc(*--s, f); 472} 473