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/types.h> 39 #include <errno.h> 40 #include <unistd.h> 41 #include <stdarg.h> 42 #include <stdio.h> 43 #include <stdint.h> 44 #include <stdlib.h> 45 #include <stddef.h> 46 #include <string.h> 47 #include <err.h> 48 #include "mdef.h" 49 #include "stdd.h" 50 #include "extern.h" 51 #include "pathnames.h" 52 53 54 char *ep; /* first free char in strspace */ 55 static char *strspace; /* string space for evaluation */ 56 char *endest; /* end of string space */ 57 static size_t strsize = STRSPMAX; 58 static size_t bufsize = BUFSIZE; 59 60 unsigned char *buf; /* push-back buffer */ 61 unsigned char *bufbase; /* the base for current ilevel */ 62 unsigned char *bbase[MAXINP]; /* the base for each ilevel */ 63 unsigned char *bp; /* first available character */ 64 unsigned char *endpbb; /* end of push-back buffer */ 65 66 67 /* 68 * find the index of second str in the first str. 69 */ 70 ptrdiff_t 71 indx(const char *s1, const char *s2) 72 { 73 char *t; 74 75 t = strstr(s1, s2); 76 if (t == NULL) 77 return (-1); 78 else 79 return (t - s1); 80 } 81 /* 82 * pushback - push character back onto input 83 */ 84 void 85 pushback(int c) 86 { 87 if (c == EOF) 88 return; 89 if (bp >= endpbb) 90 enlarge_bufspace(); 91 *bp++ = c; 92 } 93 94 /* 95 * pbstr - push string back onto input 96 * pushback is replicated to improve 97 * performance. 98 */ 99 void 100 pbstr(const char *s) 101 { 102 size_t n; 103 104 n = strlen(s); 105 while (endpbb - bp <= (long)n) 106 enlarge_bufspace(); 107 while (n > 0) 108 *bp++ = s[--n]; 109 } 110 111 /* 112 * pbnum - convert number to string, push back on input. 113 */ 114 void 115 pbnum(int n) 116 { 117 pbnumbase(n, 10, 0); 118 } 119 120 void 121 pbnumbase(int n, int base, int d) 122 { 123 static char digits[36] = "0123456789abcdefghijklmnopqrstuvwxyz"; 124 int num; 125 int printed = 0; 126 127 if (base > 36) 128 m4errx(1, "base %d > 36: not supported.", base); 129 130 if (base < 2) 131 m4errx(1, "bad base %d for conversion.", base); 132 133 num = (n < 0) ? -n : n; 134 do { 135 pushback(digits[num % base]); 136 printed++; 137 } 138 while ((num /= base) > 0); 139 140 if (n < 0) 141 printed++; 142 while (printed++ < d) 143 pushback('0'); 144 145 if (n < 0) 146 pushback('-'); 147 } 148 149 /* 150 * pbunsigned - convert unsigned long to string, push back on input. 151 */ 152 void 153 pbunsigned(unsigned long n) 154 { 155 do { 156 pushback(n % 10 + '0'); 157 } 158 while ((n /= 10) > 0); 159 } 160 161 void 162 initspaces(void) 163 { 164 int i; 165 166 strspace = xalloc(strsize+1, NULL); 167 ep = strspace; 168 endest = strspace+strsize; 169 buf = xalloc(bufsize, NULL); 170 bufbase = buf; 171 bp = buf; 172 endpbb = buf + bufsize; 173 for (i = 0; i < MAXINP; i++) 174 bbase[i] = buf; 175 } 176 177 void 178 enlarge_strspace(void) 179 { 180 char *newstrspace; 181 int i; 182 183 strsize *= 2; 184 newstrspace = malloc(strsize + 1); 185 if (!newstrspace) 186 errx(1, "string space overflow"); 187 memcpy(newstrspace, strspace, strsize/2); 188 for (i = 0; i <= sp; i++) 189 if (sstack[i] == STORAGE_STRSPACE) 190 mstack[i].sstr = (mstack[i].sstr - strspace) 191 + newstrspace; 192 ep = (ep-strspace) + newstrspace; 193 free(strspace); 194 strspace = newstrspace; 195 endest = strspace + strsize; 196 } 197 198 void 199 enlarge_bufspace(void) 200 { 201 unsigned char *newbuf; 202 int i; 203 204 bufsize += bufsize/2; 205 newbuf = xrealloc(buf, bufsize, "too many characters pushed back"); 206 for (i = 0; i < MAXINP; i++) 207 bbase[i] = (bbase[i]-buf)+newbuf; 208 bp = (bp-buf)+newbuf; 209 bufbase = (bufbase-buf)+newbuf; 210 buf = newbuf; 211 endpbb = buf+bufsize; 212 } 213 214 /* 215 * chrsave - put single char on string space 216 */ 217 void 218 chrsave(int c) 219 { 220 if (ep >= endest) 221 enlarge_strspace(); 222 *ep++ = c; 223 } 224 225 /* 226 * read in a diversion file, and dispose it. 227 */ 228 void 229 getdiv(int n) 230 { 231 int c; 232 233 if (active == outfile[n]) 234 m4errx(1, "undivert: diversion still active."); 235 rewind(outfile[n]); 236 while ((c = getc(outfile[n])) != EOF) 237 putc(c, active); 238 (void) fclose(outfile[n]); 239 outfile[n] = NULL; 240 } 241 242 void 243 onintr(int signo __unused) 244 { 245 #define intrmessage "m4: interrupted.\n" 246 write(STDERR_FILENO, intrmessage, sizeof(intrmessage)-1); 247 _exit(1); 248 } 249 250 /* 251 * killdiv - get rid of the diversion files 252 */ 253 void 254 killdiv(void) 255 { 256 int n; 257 258 for (n = 0; n < maxout; n++) 259 if (outfile[n] != NULL) { 260 (void) fclose(outfile[n]); 261 } 262 } 263 264 extern char *__progname; 265 266 void 267 m4errx(int eval, const char *fmt, ...) 268 { 269 fprintf(stderr, "%s: ", __progname); 270 fprintf(stderr, "%s at line %lu: ", CURRENT_NAME, CURRENT_LINE); 271 if (fmt != NULL) { 272 va_list ap; 273 274 va_start(ap, fmt); 275 vfprintf(stderr, fmt, ap); 276 va_end(ap); 277 } 278 fprintf(stderr, "\n"); 279 exit(eval); 280 } 281 282 /* 283 * resizedivs: allocate more diversion files */ 284 void 285 resizedivs(int n) 286 { 287 int i; 288 289 outfile = xreallocarray(outfile, n, sizeof(FILE *), 290 "too many diverts %d", n); 291 for (i = maxout; i < n; i++) 292 outfile[i] = NULL; 293 maxout = n; 294 } 295 296 void * 297 xalloc(size_t n, const char *fmt, ...) 298 { 299 void *p = malloc(n); 300 301 if (p == NULL) { 302 if (fmt == NULL) 303 err(1, "malloc"); 304 else { 305 va_list va; 306 307 va_start(va, fmt); 308 verr(1, fmt, va); 309 va_end(va); 310 } 311 } 312 return p; 313 } 314 315 void * 316 xcalloc(size_t n, size_t s, const char *fmt, ...) 317 { 318 void *p = calloc(n, s); 319 320 if (p == NULL) { 321 if (fmt == NULL) 322 err(1, "calloc"); 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 334 void * 335 xrealloc(void *old, size_t n, const char *fmt, ...) 336 { 337 char *p = realloc(old, n); 338 339 if (p == NULL) { 340 free(old); 341 if (fmt == NULL) 342 err(1, "realloc"); 343 else { 344 va_list va; 345 346 va_start(va, fmt); 347 verr(1, fmt, va); 348 va_end(va); 349 } 350 } 351 return p; 352 } 353 354 void * 355 xreallocarray(void *old, size_t s1, size_t s2, const char *fmt, ...) 356 { 357 void *p = reallocarray(old, s1, s2); 358 359 if (p == NULL) { 360 free(old); 361 if (fmt == NULL) 362 err(1, "reallocarray"); 363 else { 364 va_list va; 365 366 va_start(va, fmt); 367 verr(1, fmt, va); 368 va_end(va); 369 } 370 } 371 return p; 372 } 373 374 char * 375 xstrdup(const char *s) 376 { 377 char *p = strdup(s); 378 if (p == NULL) 379 err(1, "strdup"); 380 return p; 381 } 382 383 void 384 usage(void) 385 { 386 fprintf(stderr, "usage: m4 [-EgPs] [-Dname[=value]] [-d flags] " 387 "[-I dirname] [-o filename]\n" 388 "\t[-t macro] [-Uname] [file ...]\n"); 389 exit(1); 390 } 391 392 int 393 obtain_char(struct input_file *f) 394 { 395 if (f->c == EOF) 396 return EOF; 397 398 f->c = fgetc(f->file); 399 if (f->c == '\n') 400 f->lineno++; 401 402 return f->c; 403 } 404 405 void 406 set_input(struct input_file *f, FILE *real, const char *name) 407 { 408 f->file = real; 409 f->lineno = 1; 410 f->c = 0; 411 f->name = xstrdup(name); 412 emit_synchline(); 413 } 414 415 void 416 do_emit_synchline(void) 417 { 418 fprintf(active, "#line %lu \"%s\"\n", 419 infile[ilevel].lineno, infile[ilevel].name); 420 infile[ilevel].synch_lineno = infile[ilevel].lineno; 421 } 422 423 void 424 release_input(struct input_file *f) 425 { 426 if (ferror(f->file)) 427 errx(1, "Fatal error reading from %s\n", f->name); 428 if (f->file != stdin) 429 fclose(f->file); 430 f->c = EOF; 431 /* 432 * XXX can't free filename, as there might still be 433 * error information pointing to it. 434 */ 435 } 436 437 void 438 doprintlineno(struct input_file *f) 439 { 440 pbunsigned(f->lineno); 441 } 442 443 void 444 doprintfilename(struct input_file *f) 445 { 446 pbstr(rquote); 447 pbstr(f->name); 448 pbstr(lquote); 449 } 450 451 /* 452 * buffer_mark/dump_buffer: allows one to save a mark in a buffer, 453 * and later dump everything that was added since then to a file. 454 */ 455 size_t 456 buffer_mark(void) 457 { 458 return bp - buf; 459 } 460 461 462 void 463 dump_buffer(FILE *f, size_t m) 464 { 465 unsigned char *s; 466 467 for (s = bp; s-buf > (long)m;) 468 fputc(*--s, f); 469 } 470