1 /* $OpenBSD: misc.c,v 1.50 2026/02/25 05:37:25 op Exp $ */ 2 /* $NetBSD: misc.c,v 1.27 2026/06/12 00:35:01 christos 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 #if HAVE_NBTOOL_CONFIG_H 36 #include "nbtool_config.h" 37 #endif 38 #include <sys/cdefs.h> 39 __RCSID("$NetBSD: misc.c,v 1.27 2026/06/12 00:35:01 christos Exp $"); 40 #include <sys/types.h> 41 #include <errno.h> 42 #include <unistd.h> 43 #include <stdarg.h> 44 #include <stdio.h> 45 #include <stdint.h> 46 #include <stdlib.h> 47 #include <stddef.h> 48 #include <string.h> 49 #include <err.h> 50 #include "mdef.h" 51 #include "stdd.h" 52 #include "extern.h" 53 #include "pathnames.h" 54 55 56 char *ep; /* first free char in strspace */ 57 static char *strspace; /* string space for evaluation */ 58 char *endest; /* end of string space */ 59 static size_t strsize = STRSPMAX; 60 static size_t bufsize = BUFSIZE; 61 62 unsigned char *buf; /* push-back buffer */ 63 unsigned char *bufbase; /* the base for current ilevel */ 64 unsigned char *bbase[MAXINP]; /* the base for each ilevel */ 65 unsigned char *bp; /* first available character */ 66 unsigned char *endpbb; /* end of push-back buffer */ 67 68 69 /* 70 * find the index of second str in the first str. 71 */ 72 ptrdiff_t 73 doindex(const char *s1, const char *s2) 74 { 75 const 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 ((size_t)(endpbb - bp) <= 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] == STORAGE_STRSPACE) 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 /* 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 void 268 m4errx(int exval, const char *fmt, ...) 269 { 270 fprintf(stderr, "%s: ", getprogname()); 271 fprintf(stderr, "%s at line %lu: ", CURRENT_NAME, CURRENT_LINE); 272 if (fmt != NULL) { 273 va_list ap; 274 275 va_start(ap, fmt); 276 vfprintf(stderr, fmt, ap); 277 va_end(ap); 278 } 279 fprintf(stderr, "\n"); 280 exit(exval); 281 } 282 283 /* 284 * resizedivs: allocate more diversion files */ 285 void 286 resizedivs(int n) 287 { 288 int i; 289 290 outfile = xreallocarray(outfile, n, sizeof(FILE *), 291 "too many diverts %d", n); 292 for (i = maxout; i < n; i++) 293 outfile[i] = NULL; 294 maxout = n; 295 } 296 297 void * 298 xalloc(size_t n, const char *fmt, ...) 299 { 300 void *p = malloc(n); 301 302 if (p == NULL) { 303 if (fmt == NULL) 304 err(1, "malloc"); 305 else { 306 va_list va; 307 308 va_start(va, fmt); 309 verr(1, fmt, va); 310 va_end(va); 311 } 312 } 313 return p; 314 } 315 316 void * 317 xcalloc(size_t n, size_t s, const char *fmt, ...) 318 { 319 void *p = calloc(n, s); 320 321 if (p == NULL) { 322 if (fmt == NULL) 323 err(1, "calloc"); 324 else { 325 va_list va; 326 327 va_start(va, fmt); 328 verr(1, fmt, va); 329 va_end(va); 330 } 331 } 332 return p; 333 } 334 335 void * 336 xrealloc(void *old, size_t n, const char *fmt, ...) 337 { 338 char *p = realloc(old, n); 339 340 if (p == NULL) { 341 free(old); 342 if (fmt == NULL) 343 err(1, "realloc"); 344 else { 345 va_list va; 346 347 va_start(va, fmt); 348 verr(1, fmt, va); 349 va_end(va); 350 } 351 } 352 return p; 353 } 354 355 void * 356 xreallocarray(void *old, size_t s1, size_t s2, const char *fmt, ...) 357 { 358 void *p = reallocarray(old, s1, s2); 359 360 if (p == NULL) { 361 free(old); 362 if (fmt == NULL) 363 err(1, "reallocarray"); 364 else { 365 va_list va; 366 367 va_start(va, fmt); 368 verr(1, fmt, va); 369 va_end(va); 370 } 371 } 372 return p; 373 } 374 375 char * 376 xstrdup(const char *s) 377 { 378 char *p = strdup(s); 379 if (p == NULL) 380 err(1, "strdup"); 381 return p; 382 } 383 384 void 385 usage(FILE *f) 386 { 387 fprintf(f, "Usage: %s [-EGgiPQsv] [-Dname[=value]] [-d flags] " 388 "[-I dirname] [-o filename] [-L limit]\n" 389 "\t[-t macro] [-Uname] [file ...]\n", getprogname()); 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 #ifndef REAL_FREEZE 400 if (freezef) 401 fputc(f->c, freezef); 402 #endif 403 if (f->c == '\n') 404 f->lineno++; 405 406 return f->c; 407 } 408 409 void 410 set_input(struct input_file *f, FILE *real, const char *name) 411 { 412 f->file = real; 413 f->lineno = 1; 414 f->c = 0; 415 f->name = xstrdup(name); 416 emit_synchline(); 417 } 418 419 void 420 do_emit_synchline(void) 421 { 422 fprintf(active, "#line %lu \"%s\"\n", 423 TOKEN_LINE(&infile[ilevel]), infile[ilevel].name); 424 infile[ilevel].synch_lineno = infile[ilevel].lineno; 425 } 426 427 void 428 release_input(struct input_file *f) 429 { 430 if (ferror(f->file)) 431 errx(1, "Fatal error reading from %s\n", f->name); 432 if (f->file != stdin) 433 fclose(f->file); 434 f->c = EOF; 435 /* 436 * XXX can't free filename, as there might still be 437 * error information pointing to it. 438 */ 439 } 440 441 void 442 doprintlineno(struct input_file *f) 443 { 444 pbunsigned(TOKEN_LINE(f)); 445 } 446 447 void 448 doprintfilename(struct input_file *f) 449 { 450 pbstr(rquote); 451 pbstr(f->name); 452 pbstr(lquote); 453 } 454 455 /* 456 * buffer_mark/dump_buffer: allows one to save a mark in a buffer, 457 * and later dump everything that was added since then to a file. 458 */ 459 size_t 460 buffer_mark(void) 461 { 462 return bp - buf; 463 } 464 465 466 void 467 dump_buffer(FILE *f, size_t m) 468 { 469 unsigned char *s; 470 471 for (s = bp; (size_t)(s - buf) > m;) 472 fputc(*--s, f); 473 } 474