1 /* $OpenBSD: misc.c,v 1.44 2014/05/12 19:11:19 espie 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$"); 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 55 char *ep; /* first free char in strspace */ 56 static char *strspace; /* string space for evaluation */ 57 char *endest; /* end of string space */ 58 static size_t strsize = STRSPMAX; 59 static size_t bufsize = BUFSIZE; 60 61 unsigned char *buf; /* push-back buffer */ 62 unsigned char *bufbase; /* the base for current ilevel */ 63 unsigned char *bbase[MAXINP]; /* the base for each ilevel */ 64 unsigned char *bp; /* first available character */ 65 unsigned char *endpbb; /* end of push-back buffer */ 66 67 static void *reallocarray(void *, size_t, size_t); 68 69 /* 70 * find the index of second str in the first str. 71 */ 72 ptrdiff_t 73 indx(const char *s1, const char *s2) 74 { 75 char *t; 76 77 t = strstr(s1, s2); 78 if (t == NULL) 79 return (-1); 80 else 81 return (t - s1); 82 } 83 /* 84 * pushback - push character back onto input 85 */ 86 void 87 pushback(int c) 88 { 89 if (c == EOF) 90 return; 91 if (bp >= endpbb) 92 enlarge_bufspace(); 93 *bp++ = c; 94 } 95 96 /* 97 * pbstr - push string back onto input 98 * pushback is replicated to improve 99 * performance. 100 */ 101 void 102 pbstr(const char *s) 103 { 104 size_t n; 105 106 n = strlen(s); 107 while (endpbb - bp <= (long)n) 108 enlarge_bufspace(); 109 while (n > 0) 110 *bp++ = s[--n]; 111 } 112 113 /* 114 * pbnum - convert number to string, push back on input. 115 */ 116 void 117 pbnum(int n) 118 { 119 pbnumbase(n, 10, 0); 120 } 121 122 void 123 pbnumbase(int n, int base, int d) 124 { 125 static char digits[36] = "0123456789abcdefghijklmnopqrstuvwxyz"; 126 int num; 127 int printed = 0; 128 129 if (base > 36) 130 m4errx(1, "base %d > 36: not supported.", base); 131 132 if (base < 2) 133 m4errx(1, "bad base %d for conversion.", base); 134 135 num = (n < 0) ? -n : n; 136 do { 137 pushback(digits[num % base]); 138 printed++; 139 } 140 while ((num /= base) > 0); 141 142 if (n < 0) 143 printed++; 144 while (printed++ < d) 145 pushback('0'); 146 147 if (n < 0) 148 pushback('-'); 149 } 150 151 /* 152 * pbunsigned - convert unsigned long to string, push back on input. 153 */ 154 void 155 pbunsigned(unsigned long n) 156 { 157 do { 158 pushback(n % 10 + '0'); 159 } 160 while ((n /= 10) > 0); 161 } 162 163 void 164 initspaces(void) 165 { 166 int i; 167 168 strspace = xalloc(strsize+1, NULL); 169 ep = strspace; 170 endest = strspace+strsize; 171 buf = xalloc(bufsize, NULL); 172 bufbase = buf; 173 bp = buf; 174 endpbb = buf + bufsize; 175 for (i = 0; i < MAXINP; i++) 176 bbase[i] = buf; 177 } 178 179 void 180 enlarge_strspace(void) 181 { 182 char *newstrspace; 183 int i; 184 185 strsize *= 2; 186 newstrspace = malloc(strsize + 1); 187 if (!newstrspace) 188 errx(1, "string space overflow"); 189 memcpy(newstrspace, strspace, strsize/2); 190 for (i = 0; i <= sp; i++) 191 if (sstack[i]) 192 mstack[i].sstr = (mstack[i].sstr - strspace) 193 + newstrspace; 194 ep = (ep-strspace) + newstrspace; 195 free(strspace); 196 strspace = newstrspace; 197 endest = strspace + strsize; 198 } 199 200 void 201 enlarge_bufspace(void) 202 { 203 unsigned char *newbuf; 204 int i; 205 206 bufsize += bufsize/2; 207 newbuf = xrealloc(buf, bufsize, "too many characters pushed back"); 208 for (i = 0; i < MAXINP; i++) 209 bbase[i] = (bbase[i]-buf)+newbuf; 210 bp = (bp-buf)+newbuf; 211 bufbase = (bufbase-buf)+newbuf; 212 buf = newbuf; 213 endpbb = buf+bufsize; 214 } 215 216 /* 217 * chrsave - put single char on string space 218 */ 219 void 220 chrsave(int c) 221 { 222 if (ep >= endest) 223 enlarge_strspace(); 224 *ep++ = c; 225 } 226 227 /* 228 * read in a diversion file, and dispose it. 229 */ 230 void 231 getdiv(int n) 232 { 233 int c; 234 235 if (active == outfile[n]) 236 m4errx(1, "undivert: diversion still active."); 237 rewind(outfile[n]); 238 while ((c = getc(outfile[n])) != EOF) 239 putc(c, active); 240 (void) fclose(outfile[n]); 241 outfile[n] = NULL; 242 } 243 244 void 245 onintr(int signo __unused) 246 { 247 #define intrmessage "m4: interrupted.\n" 248 write(STDERR_FILENO, intrmessage, sizeof(intrmessage)-1); 249 _exit(1); 250 } 251 252 /* 253 * killdiv - get rid of the diversion files 254 */ 255 void 256 killdiv(void) 257 { 258 int n; 259 260 for (n = 0; n < maxout; n++) 261 if (outfile[n] != NULL) { 262 (void) fclose(outfile[n]); 263 } 264 } 265 266 extern char *__progname; 267 268 void 269 m4errx(int exitstatus, const char *fmt, ...) 270 { 271 fprintf(stderr, "%s: ", __progname); 272 fprintf(stderr, "%s at line %lu: ", CURRENT_NAME, CURRENT_LINE); 273 if (fmt != NULL) { 274 va_list ap; 275 276 va_start(ap, fmt); 277 vfprintf(stderr, fmt, ap); 278 va_end(ap); 279 } 280 fprintf(stderr, "\n"); 281 exit(exitstatus); 282 } 283 284 /* 285 * resizedivs: allocate more diversion files */ 286 void 287 resizedivs(int n) 288 { 289 int i; 290 291 outfile = xreallocarray(outfile, n, sizeof(FILE *), 292 "too many diverts %d", n); 293 for (i = maxout; i < n; i++) 294 outfile[i] = NULL; 295 maxout = n; 296 } 297 298 void * 299 xalloc(size_t n, const char *fmt, ...) 300 { 301 void *p = malloc(n); 302 303 if (p == NULL) { 304 if (fmt == NULL) 305 err(1, "malloc"); 306 else { 307 va_list va; 308 309 va_start(va, fmt); 310 verr(1, fmt, va); 311 va_end(va); 312 } 313 } 314 return p; 315 } 316 317 void * 318 xcalloc(size_t n, size_t s, const char *fmt, ...) 319 { 320 void *p = calloc(n, s); 321 322 if (p == NULL) { 323 if (fmt == NULL) 324 err(1, "calloc"); 325 else { 326 va_list va; 327 328 va_start(va, fmt); 329 verr(1, fmt, va); 330 va_end(va); 331 } 332 } 333 return p; 334 } 335 336 void * 337 xrealloc(void *old, size_t n, const char *fmt, ...) 338 { 339 char *p = realloc(old, n); 340 341 if (p == NULL) { 342 free(old); 343 if (fmt == NULL) 344 err(1, "realloc"); 345 else { 346 va_list va; 347 348 va_start(va, fmt); 349 verr(1, fmt, va); 350 va_end(va); 351 } 352 } 353 return p; 354 } 355 356 void * 357 xreallocarray(void *old, size_t s1, size_t s2, const char *fmt, ...) 358 { 359 void *p = reallocarray(old, s1, s2); 360 361 if (p == NULL) { 362 free(old); 363 if (fmt == NULL) 364 err(1, "reallocarray"); 365 else { 366 va_list va; 367 368 va_start(va, fmt); 369 verr(1, fmt, va); 370 va_end(va); 371 } 372 } 373 return p; 374 } 375 376 char * 377 xstrdup(const char *s) 378 { 379 char *p = strdup(s); 380 if (p == NULL) 381 err(1, "strdup"); 382 return p; 383 } 384 385 void 386 usage(void) 387 { 388 fprintf(stderr, "usage: m4 [-gPs] [-Dname[=value]] [-d flags] " 389 "[-I dirname] [-o filename]\n" 390 "\t[-t macro] [-Uname] [file ...]\n"); 391 exit(1); 392 } 393 394 int 395 obtain_char(struct input_file *f) 396 { 397 if (f->c == EOF) 398 return EOF; 399 400 f->c = fgetc(f->file); 401 if (f->c == '\n') 402 f->lineno++; 403 404 return f->c; 405 } 406 407 void 408 set_input(struct input_file *f, FILE *real, const char *name) 409 { 410 f->file = real; 411 f->lineno = 1; 412 f->c = 0; 413 f->name = xstrdup(name); 414 emit_synchline(); 415 } 416 417 void 418 do_emit_synchline(void) 419 { 420 fprintf(active, "#line %lu \"%s\"\n", 421 infile[ilevel].lineno, infile[ilevel].name); 422 infile[ilevel].synch_lineno = infile[ilevel].lineno; 423 } 424 425 void 426 release_input(struct input_file *f) 427 { 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 471 /* $OpenBSD: reallocarray.c,v 1.2 2014/12/08 03:45:00 bcook Exp $ */ 472 /* 473 * Copyright (c) 2008 Otto Moerbeek <otto@drijf.net> 474 * 475 * Permission to use, copy, modify, and distribute this software for any 476 * purpose with or without fee is hereby granted, provided that the above 477 * copyright notice and this permission notice appear in all copies. 478 * 479 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 480 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 481 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 482 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 483 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 484 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 485 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 486 */ 487 488 /* 489 * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX 490 * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW 491 */ 492 #define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4)) 493 494 void * 495 reallocarray(void *optr, size_t nmemb, size_t size) 496 { 497 if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && 498 nmemb > 0 && SIZE_MAX / nmemb < size) { 499 errno = ENOMEM; 500 return NULL; 501 } 502 return realloc(optr, size * nmemb); 503 } 504