1 1.19 christos /* $OpenBSD: misc.c,v 1.41 2009/10/14 17:19:47 sthen Exp $ */ 2 1.25 rillig /* $NetBSD: misc.c,v 1.25 2024/10/06 19:31:26 rillig Exp $ */ 3 1.6 tls 4 1.5 glass /* 5 1.5 glass * Copyright (c) 1989, 1993 6 1.5 glass * The Regents of the University of California. All rights reserved. 7 1.5 glass * 8 1.5 glass * This code is derived from software contributed to Berkeley by 9 1.5 glass * Ozan Yigit at York University. 10 1.5 glass * 11 1.5 glass * Redistribution and use in source and binary forms, with or without 12 1.5 glass * modification, are permitted provided that the following conditions 13 1.5 glass * are met: 14 1.5 glass * 1. Redistributions of source code must retain the above copyright 15 1.5 glass * notice, this list of conditions and the following disclaimer. 16 1.5 glass * 2. Redistributions in binary form must reproduce the above copyright 17 1.5 glass * notice, this list of conditions and the following disclaimer in the 18 1.5 glass * documentation and/or other materials provided with the distribution. 19 1.16 agc * 3. Neither the name of the University nor the names of its contributors 20 1.5 glass * may be used to endorse or promote products derived from this software 21 1.5 glass * without specific prior written permission. 22 1.5 glass * 23 1.5 glass * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 1.5 glass * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 1.5 glass * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 1.5 glass * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 1.5 glass * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 1.5 glass * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 1.5 glass * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 1.5 glass * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 1.5 glass * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 1.5 glass * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 1.5 glass * SUCH DAMAGE. 34 1.5 glass */ 35 1.17 jmc #if HAVE_NBTOOL_CONFIG_H 36 1.17 jmc #include "nbtool_config.h" 37 1.17 jmc #endif 38 1.7 lukem #include <sys/cdefs.h> 39 1.25 rillig __RCSID("$NetBSD: misc.c,v 1.25 2024/10/06 19:31:26 rillig Exp $"); 40 1.5 glass #include <sys/types.h> 41 1.5 glass #include <errno.h> 42 1.19 christos #include <unistd.h> 43 1.19 christos #include <stdarg.h> 44 1.5 glass #include <stdio.h> 45 1.5 glass #include <stdlib.h> 46 1.12 tv #include <stddef.h> 47 1.5 glass #include <string.h> 48 1.19 christos #include <err.h> 49 1.1 cgd #include "mdef.h" 50 1.5 glass #include "stdd.h" 51 1.5 glass #include "extern.h" 52 1.5 glass #include "pathnames.h" 53 1.12 tv 54 1.19 christos 55 1.12 tv char *ep; /* first free char in strspace */ 56 1.12 tv static char *strspace; /* string space for evaluation */ 57 1.12 tv char *endest; /* end of string space */ 58 1.12 tv static size_t strsize = STRSPMAX; 59 1.12 tv static size_t bufsize = BUFSIZE; 60 1.12 tv 61 1.19 christos unsigned char *buf; /* push-back buffer */ 62 1.19 christos unsigned char *bufbase; /* the base for current ilevel */ 63 1.19 christos unsigned char *bbase[MAXINP]; /* the base for each ilevel */ 64 1.19 christos unsigned char *bp; /* first available character */ 65 1.19 christos unsigned char *endpbb; /* end of push-back buffer */ 66 1.12 tv 67 1.12 tv 68 1.5 glass /* 69 1.5 glass * find the index of second str in the first str. 70 1.5 glass */ 71 1.12 tv ptrdiff_t 72 1.19 christos indx(const char *s1, const char *s2) 73 1.5 glass { 74 1.25 rillig const char *t; 75 1.7 lukem 76 1.7 lukem t = strstr(s1, s2); 77 1.7 lukem if (t == NULL) 78 1.7 lukem return (-1); 79 1.19 christos else 80 1.19 christos return (t - s1); 81 1.5 glass } 82 1.5 glass /* 83 1.19 christos * pushback - push character back onto input 84 1.5 glass */ 85 1.5 glass void 86 1.19 christos pushback(int c) 87 1.5 glass { 88 1.12 tv if (c == EOF) 89 1.12 tv return; 90 1.12 tv if (bp >= endpbb) 91 1.12 tv enlarge_bufspace(); 92 1.12 tv *bp++ = c; 93 1.9 cgd } 94 1.9 cgd 95 1.9 cgd /* 96 1.5 glass * pbstr - push string back onto input 97 1.19 christos * pushback is replicated to improve 98 1.5 glass * performance. 99 1.5 glass */ 100 1.5 glass void 101 1.19 christos pbstr(const char *s) 102 1.5 glass { 103 1.12 tv size_t n; 104 1.2 glass 105 1.12 tv n = strlen(s); 106 1.19 christos while ((size_t)(endpbb - bp) <= n) 107 1.12 tv enlarge_bufspace(); 108 1.12 tv while (n > 0) 109 1.12 tv *bp++ = s[--n]; 110 1.5 glass } 111 1.5 glass 112 1.5 glass /* 113 1.5 glass * pbnum - convert number to string, push back on input. 114 1.5 glass */ 115 1.5 glass void 116 1.19 christos pbnum(int n) 117 1.19 christos { 118 1.19 christos pbnumbase(n, 10, 0); 119 1.19 christos } 120 1.19 christos 121 1.19 christos void 122 1.19 christos pbnumbase(int n, int base, int d) 123 1.5 glass { 124 1.19 christos static char digits[36] = "0123456789abcdefghijklmnopqrstuvwxyz"; 125 1.7 lukem int num; 126 1.19 christos int printed = 0; 127 1.19 christos 128 1.19 christos if (base > 36) 129 1.19 christos m4errx(1, "base %d > 36: not supported.", base); 130 1.19 christos 131 1.19 christos if (base < 2) 132 1.19 christos m4errx(1, "bad base %d for conversion.", base); 133 1.2 glass 134 1.5 glass num = (n < 0) ? -n : n; 135 1.2 glass do { 136 1.19 christos pushback(digits[num % base]); 137 1.19 christos printed++; 138 1.2 glass } 139 1.19 christos while ((num /= base) > 0); 140 1.2 glass 141 1.5 glass if (n < 0) 142 1.19 christos printed++; 143 1.19 christos while (printed++ < d) 144 1.19 christos pushback('0'); 145 1.19 christos 146 1.19 christos if (n < 0) 147 1.19 christos pushback('-'); 148 1.5 glass } 149 1.5 glass 150 1.5 glass /* 151 1.12 tv * pbunsigned - convert unsigned long to string, push back on input. 152 1.12 tv */ 153 1.12 tv void 154 1.19 christos pbunsigned(unsigned long n) 155 1.12 tv { 156 1.12 tv do { 157 1.19 christos pushback(n % 10 + '0'); 158 1.12 tv } 159 1.12 tv while ((n /= 10) > 0); 160 1.12 tv } 161 1.12 tv 162 1.12 tv void 163 1.23 matt initspaces(void) 164 1.12 tv { 165 1.12 tv int i; 166 1.12 tv 167 1.19 christos strspace = xalloc(strsize+1, NULL); 168 1.12 tv ep = strspace; 169 1.12 tv endest = strspace+strsize; 170 1.19 christos buf = (unsigned char *)xalloc(bufsize, NULL); 171 1.12 tv bufbase = buf; 172 1.12 tv bp = buf; 173 1.12 tv endpbb = buf + bufsize; 174 1.12 tv for (i = 0; i < MAXINP; i++) 175 1.12 tv bbase[i] = buf; 176 1.12 tv } 177 1.12 tv 178 1.12 tv void 179 1.23 matt enlarge_strspace(void) 180 1.12 tv { 181 1.12 tv char *newstrspace; 182 1.12 tv int i; 183 1.12 tv 184 1.12 tv strsize *= 2; 185 1.12 tv newstrspace = malloc(strsize + 1); 186 1.12 tv if (!newstrspace) 187 1.12 tv errx(1, "string space overflow"); 188 1.12 tv memcpy(newstrspace, strspace, strsize/2); 189 1.12 tv for (i = 0; i <= sp; i++) 190 1.12 tv if (sstack[i]) 191 1.12 tv mstack[i].sstr = (mstack[i].sstr - strspace) 192 1.12 tv + newstrspace; 193 1.12 tv ep = (ep-strspace) + newstrspace; 194 1.12 tv free(strspace); 195 1.12 tv strspace = newstrspace; 196 1.12 tv endest = strspace + strsize; 197 1.12 tv } 198 1.12 tv 199 1.12 tv void 200 1.23 matt enlarge_bufspace(void) 201 1.12 tv { 202 1.19 christos unsigned char *newbuf; 203 1.12 tv int i; 204 1.12 tv 205 1.19 christos bufsize += bufsize/2; 206 1.19 christos newbuf = xrealloc(buf, bufsize, "too many characters pushed back"); 207 1.12 tv for (i = 0; i < MAXINP; i++) 208 1.12 tv bbase[i] = (bbase[i]-buf)+newbuf; 209 1.12 tv bp = (bp-buf)+newbuf; 210 1.12 tv bufbase = (bufbase-buf)+newbuf; 211 1.12 tv buf = newbuf; 212 1.12 tv endpbb = buf+bufsize; 213 1.12 tv } 214 1.12 tv 215 1.12 tv /* 216 1.5 glass * chrsave - put single char on string space 217 1.5 glass */ 218 1.5 glass void 219 1.19 christos chrsave(int c) 220 1.5 glass { 221 1.12 tv if (ep >= endest) 222 1.12 tv enlarge_strspace(); 223 1.12 tv *ep++ = c; 224 1.5 glass } 225 1.5 glass 226 1.5 glass /* 227 1.5 glass * read in a diversion file, and dispose it. 228 1.5 glass */ 229 1.5 glass void 230 1.19 christos getdiv(int n) 231 1.5 glass { 232 1.7 lukem int c; 233 1.2 glass 234 1.5 glass if (active == outfile[n]) 235 1.19 christos m4errx(1, "undivert: diversion still active."); 236 1.12 tv rewind(outfile[n]); 237 1.12 tv while ((c = getc(outfile[n])) != EOF) 238 1.12 tv putc(c, active); 239 1.5 glass (void) fclose(outfile[n]); 240 1.5 glass outfile[n] = NULL; 241 1.5 glass } 242 1.2 glass 243 1.5 glass /* 244 1.5 glass * killdiv - get rid of the diversion files 245 1.5 glass */ 246 1.5 glass void 247 1.22 joerg killdiv(void) 248 1.5 glass { 249 1.7 lukem int n; 250 1.2 glass 251 1.12 tv for (n = 0; n < maxout; n++) 252 1.5 glass if (outfile[n] != NULL) { 253 1.5 glass (void) fclose(outfile[n]); 254 1.5 glass } 255 1.5 glass } 256 1.2 glass 257 1.19 christos void 258 1.19 christos m4errx(int exval, const char *fmt, ...) 259 1.19 christos { 260 1.20 joerg fprintf(stderr, "%s: ", getprogname()); 261 1.19 christos fprintf(stderr, "%s at line %lu: ", CURRENT_NAME, CURRENT_LINE); 262 1.19 christos if (fmt != NULL) { 263 1.19 christos va_list ap; 264 1.19 christos 265 1.19 christos va_start(ap, fmt); 266 1.19 christos vfprintf(stderr, fmt, ap); 267 1.19 christos va_end(ap); 268 1.19 christos } 269 1.19 christos fprintf(stderr, "\n"); 270 1.19 christos exit(exval); 271 1.19 christos } 272 1.19 christos 273 1.12 tv /* 274 1.12 tv * resizedivs: allocate more diversion files */ 275 1.12 tv void 276 1.19 christos resizedivs(int n) 277 1.12 tv { 278 1.12 tv int i; 279 1.12 tv 280 1.19 christos outfile = (FILE **)xrealloc(outfile, sizeof(FILE *) * n, 281 1.19 christos "too many diverts %d", n); 282 1.12 tv for (i = maxout; i < n; i++) 283 1.12 tv outfile[i] = NULL; 284 1.12 tv maxout = n; 285 1.12 tv } 286 1.12 tv 287 1.12 tv void * 288 1.19 christos xalloc(size_t n, const char *fmt, ...) 289 1.19 christos { 290 1.19 christos void *p = malloc(n); 291 1.19 christos 292 1.19 christos if (p == NULL) { 293 1.19 christos if (fmt == NULL) 294 1.19 christos err(1, "malloc"); 295 1.19 christos else { 296 1.19 christos va_list va; 297 1.19 christos 298 1.19 christos va_start(va, fmt); 299 1.19 christos verr(1, fmt, va); 300 1.19 christos va_end(va); 301 1.19 christos } 302 1.19 christos } 303 1.19 christos return p; 304 1.19 christos } 305 1.19 christos 306 1.19 christos void * 307 1.19 christos xrealloc(void *old, size_t n, const char *fmt, ...) 308 1.5 glass { 309 1.19 christos char *p = realloc(old, n); 310 1.2 glass 311 1.19 christos if (p == NULL) { 312 1.19 christos free(old); 313 1.19 christos if (fmt == NULL) 314 1.19 christos err(1, "realloc"); 315 1.19 christos else { 316 1.19 christos va_list va; 317 1.19 christos 318 1.19 christos va_start(va, fmt); 319 1.19 christos verr(1, fmt, va); 320 1.19 christos va_end(va); 321 1.19 christos } 322 1.19 christos } 323 1.5 glass return p; 324 1.5 glass } 325 1.2 glass 326 1.5 glass char * 327 1.19 christos xstrdup(const char *s) 328 1.5 glass { 329 1.7 lukem char *p = strdup(s); 330 1.5 glass if (p == NULL) 331 1.7 lukem err(1, "strdup"); 332 1.5 glass return p; 333 1.5 glass } 334 1.2 glass 335 1.12 tv int 336 1.19 christos obtain_char(struct input_file *f) 337 1.12 tv { 338 1.12 tv if (f->c == EOF) 339 1.12 tv return EOF; 340 1.19 christos 341 1.19 christos f->c = fgetc(f->file); 342 1.24 christos #ifndef REAL_FREEZE 343 1.24 christos if (freezef) 344 1.24 christos fputc(f->c, freezef); 345 1.24 christos #endif 346 1.19 christos if (f->c == '\n') 347 1.12 tv f->lineno++; 348 1.12 tv 349 1.12 tv return f->c; 350 1.12 tv } 351 1.12 tv 352 1.12 tv void 353 1.19 christos set_input(struct input_file *f, FILE *real, const char *name) 354 1.12 tv { 355 1.12 tv f->file = real; 356 1.12 tv f->lineno = 1; 357 1.12 tv f->c = 0; 358 1.12 tv f->name = xstrdup(name); 359 1.19 christos emit_synchline(); 360 1.19 christos } 361 1.19 christos 362 1.19 christos void 363 1.23 matt do_emit_synchline(void) 364 1.19 christos { 365 1.19 christos fprintf(active, "#line %lu \"%s\"\n", 366 1.19 christos infile[ilevel].lineno, infile[ilevel].name); 367 1.19 christos infile[ilevel].synch_lineno = infile[ilevel].lineno; 368 1.12 tv } 369 1.12 tv 370 1.12 tv void 371 1.19 christos release_input(struct input_file *f) 372 1.12 tv { 373 1.12 tv if (f->file != stdin) 374 1.12 tv fclose(f->file); 375 1.12 tv f->c = EOF; 376 1.12 tv /* 377 1.12 tv * XXX can't free filename, as there might still be 378 1.12 tv * error information pointing to it. 379 1.12 tv */ 380 1.12 tv } 381 1.12 tv 382 1.12 tv void 383 1.19 christos doprintlineno(struct input_file *f) 384 1.5 glass { 385 1.21 christos pbunsigned(TOKEN_LINE(f)); 386 1.12 tv } 387 1.2 glass 388 1.12 tv void 389 1.19 christos doprintfilename(struct input_file *f) 390 1.12 tv { 391 1.12 tv pbstr(rquote); 392 1.12 tv pbstr(f->name); 393 1.12 tv pbstr(lquote); 394 1.12 tv } 395 1.2 glass 396 1.12 tv /* 397 1.12 tv * buffer_mark/dump_buffer: allows one to save a mark in a buffer, 398 1.12 tv * and later dump everything that was added since then to a file. 399 1.12 tv */ 400 1.12 tv size_t 401 1.23 matt buffer_mark(void) 402 1.12 tv { 403 1.12 tv return bp - buf; 404 1.5 glass } 405 1.2 glass 406 1.12 tv 407 1.5 glass void 408 1.19 christos dump_buffer(FILE *f, size_t m) 409 1.5 glass { 410 1.19 christos unsigned char *s; 411 1.12 tv 412 1.19 christos for (s = bp; (size_t)(s - buf) > m;) 413 1.12 tv fputc(*--s, f); 414 1.5 glass } 415