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 57 char *ep; /* first free char in strspace */ 58 static char *strspace; /* string space for evaluation */ 59 char *endest; /* end of string space */ 60 static size_t strsize = STRSPMAX; 61 static size_t bufsize = BUFSIZE; 62 63 unsigned char *buf; /* push-back buffer */ 64 unsigned char *bufbase; /* the base for current ilevel */ 65 unsigned char *bbase[MAXINP]; /* the base for each ilevel */ 66 unsigned char *bp; /* first available character */ 67 unsigned char *endpbb; /* end of push-back buffer */ 68 69 70 /* 71 * find the index of second str in the first str. 72 */ 73 ptrdiff_t 74 indx(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 */ 87 void 88 pushback(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 */ 102 void 103 pbstr(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 */ 117 void 118 pbnum(int n) 119 { 120 pbnumbase(n, 10, 0); 121 } 122 123 void 124 pbnumbase(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 */ 155 void 156 pbunsigned(unsigned long n) 157 { 158 do { 159 pushback(n % 10 + '0'); 160 } 161 while ((n /= 10) > 0); 162 } 163 164 void 165 initspaces(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 180 void 181 enlarge_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 201 void 202 enlarge_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 */ 220 void 221 chrsave(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 */ 231 void 232 getdiv(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 245 void 246 onintr(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 */ 256 void 257 killdiv(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 267 extern char *__progname; 268 269 void 270 m4errx(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 */ 287 void 288 resizedivs(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 299 void * 300 xalloc(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 318 void * 319 xcalloc(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 337 void * 338 xrealloc(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 357 void * 358 xreallocarray(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 377 char * 378 xstrdup(const char *s) 379 { 380 char *p = strdup(s); 381 if (p == NULL) 382 err(1, "strdup"); 383 return p; 384 } 385 386 void 387 usage(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 395 int 396 obtain_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 408 void 409 set_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 418 void 419 do_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 426 void 427 release_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 440 void 441 doprintlineno(struct input_file *f) 442 { 443 pbunsigned(f->lineno); 444 } 445 446 void 447 doprintfilename(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 */ 458 size_t 459 buffer_mark(void) 460 { 461 return bp - buf; 462 } 463 464 465 void 466 dump_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