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