1 /* $OpenBSD: misc.c,v 1.41 2009/10/14 17:19:47 sthen Exp $ */ 2 /* $NetBSD: misc.c,v 1.25 2024/10/06 19:31:26 rillig 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.25 2024/10/06 19:31:26 rillig Exp $"); 40 #include <sys/types.h> 41 #include <errno.h> 42 #include <unistd.h> 43 #include <stdarg.h> 44 #include <stdio.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 68 /* 69 * find the index of second str in the first str. 70 */ 71 ptrdiff_t 72 indx(const char *s1, const char *s2) 73 { 74 const char *t; 75 76 t = strstr(s1, s2); 77 if (t == NULL) 78 return (-1); 79 else 80 return (t - s1); 81 } 82 /* 83 * pushback - push character back onto input 84 */ 85 void 86 pushback(int c) 87 { 88 if (c == EOF) 89 return; 90 if (bp >= endpbb) 91 enlarge_bufspace(); 92 *bp++ = c; 93 } 94 95 /* 96 * pbstr - push string back onto input 97 * pushback is replicated to improve 98 * performance. 99 */ 100 void 101 pbstr(const char *s) 102 { 103 size_t n; 104 105 n = strlen(s); 106 while ((size_t)(endpbb - bp) <= n) 107 enlarge_bufspace(); 108 while (n > 0) 109 *bp++ = s[--n]; 110 } 111 112 /* 113 * pbnum - convert number to string, push back on input. 114 */ 115 void 116 pbnum(int n) 117 { 118 pbnumbase(n, 10, 0); 119 } 120 121 void 122 pbnumbase(int n, int base, int d) 123 { 124 static char digits[36] = "0123456789abcdefghijklmnopqrstuvwxyz"; 125 int num; 126 int printed = 0; 127 128 if (base > 36) 129 m4errx(1, "base %d > 36: not supported.", base); 130 131 if (base < 2) 132 m4errx(1, "bad base %d for conversion.", base); 133 134 num = (n < 0) ? -n : n; 135 do { 136 pushback(digits[num % base]); 137 printed++; 138 } 139 while ((num /= base) > 0); 140 141 if (n < 0) 142 printed++; 143 while (printed++ < d) 144 pushback('0'); 145 146 if (n < 0) 147 pushback('-'); 148 } 149 150 /* 151 * pbunsigned - convert unsigned long to string, push back on input. 152 */ 153 void 154 pbunsigned(unsigned long n) 155 { 156 do { 157 pushback(n % 10 + '0'); 158 } 159 while ((n /= 10) > 0); 160 } 161 162 void 163 initspaces(void) 164 { 165 int i; 166 167 strspace = xalloc(strsize+1, NULL); 168 ep = strspace; 169 endest = strspace+strsize; 170 buf = (unsigned char *)xalloc(bufsize, NULL); 171 bufbase = buf; 172 bp = buf; 173 endpbb = buf + bufsize; 174 for (i = 0; i < MAXINP; i++) 175 bbase[i] = buf; 176 } 177 178 void 179 enlarge_strspace(void) 180 { 181 char *newstrspace; 182 int i; 183 184 strsize *= 2; 185 newstrspace = malloc(strsize + 1); 186 if (!newstrspace) 187 errx(1, "string space overflow"); 188 memcpy(newstrspace, strspace, strsize/2); 189 for (i = 0; i <= sp; i++) 190 if (sstack[i]) 191 mstack[i].sstr = (mstack[i].sstr - strspace) 192 + newstrspace; 193 ep = (ep-strspace) + newstrspace; 194 free(strspace); 195 strspace = newstrspace; 196 endest = strspace + strsize; 197 } 198 199 void 200 enlarge_bufspace(void) 201 { 202 unsigned char *newbuf; 203 int i; 204 205 bufsize += bufsize/2; 206 newbuf = xrealloc(buf, bufsize, "too many characters pushed back"); 207 for (i = 0; i < MAXINP; i++) 208 bbase[i] = (bbase[i]-buf)+newbuf; 209 bp = (bp-buf)+newbuf; 210 bufbase = (bufbase-buf)+newbuf; 211 buf = newbuf; 212 endpbb = buf+bufsize; 213 } 214 215 /* 216 * chrsave - put single char on string space 217 */ 218 void 219 chrsave(int c) 220 { 221 if (ep >= endest) 222 enlarge_strspace(); 223 *ep++ = c; 224 } 225 226 /* 227 * read in a diversion file, and dispose it. 228 */ 229 void 230 getdiv(int n) 231 { 232 int c; 233 234 if (active == outfile[n]) 235 m4errx(1, "undivert: diversion still active."); 236 rewind(outfile[n]); 237 while ((c = getc(outfile[n])) != EOF) 238 putc(c, active); 239 (void) fclose(outfile[n]); 240 outfile[n] = NULL; 241 } 242 243 /* 244 * killdiv - get rid of the diversion files 245 */ 246 void 247 killdiv(void) 248 { 249 int n; 250 251 for (n = 0; n < maxout; n++) 252 if (outfile[n] != NULL) { 253 (void) fclose(outfile[n]); 254 } 255 } 256 257 void 258 m4errx(int exval, const char *fmt, ...) 259 { 260 fprintf(stderr, "%s: ", getprogname()); 261 fprintf(stderr, "%s at line %lu: ", CURRENT_NAME, CURRENT_LINE); 262 if (fmt != NULL) { 263 va_list ap; 264 265 va_start(ap, fmt); 266 vfprintf(stderr, fmt, ap); 267 va_end(ap); 268 } 269 fprintf(stderr, "\n"); 270 exit(exval); 271 } 272 273 /* 274 * resizedivs: allocate more diversion files */ 275 void 276 resizedivs(int n) 277 { 278 int i; 279 280 outfile = (FILE **)xrealloc(outfile, sizeof(FILE *) * n, 281 "too many diverts %d", n); 282 for (i = maxout; i < n; i++) 283 outfile[i] = NULL; 284 maxout = n; 285 } 286 287 void * 288 xalloc(size_t n, const char *fmt, ...) 289 { 290 void *p = malloc(n); 291 292 if (p == NULL) { 293 if (fmt == NULL) 294 err(1, "malloc"); 295 else { 296 va_list va; 297 298 va_start(va, fmt); 299 verr(1, fmt, va); 300 va_end(va); 301 } 302 } 303 return p; 304 } 305 306 void * 307 xrealloc(void *old, size_t n, const char *fmt, ...) 308 { 309 char *p = realloc(old, n); 310 311 if (p == NULL) { 312 free(old); 313 if (fmt == NULL) 314 err(1, "realloc"); 315 else { 316 va_list va; 317 318 va_start(va, fmt); 319 verr(1, fmt, va); 320 va_end(va); 321 } 322 } 323 return p; 324 } 325 326 char * 327 xstrdup(const char *s) 328 { 329 char *p = strdup(s); 330 if (p == NULL) 331 err(1, "strdup"); 332 return p; 333 } 334 335 int 336 obtain_char(struct input_file *f) 337 { 338 if (f->c == EOF) 339 return EOF; 340 341 f->c = fgetc(f->file); 342 #ifndef REAL_FREEZE 343 if (freezef) 344 fputc(f->c, freezef); 345 #endif 346 if (f->c == '\n') 347 f->lineno++; 348 349 return f->c; 350 } 351 352 void 353 set_input(struct input_file *f, FILE *real, const char *name) 354 { 355 f->file = real; 356 f->lineno = 1; 357 f->c = 0; 358 f->name = xstrdup(name); 359 emit_synchline(); 360 } 361 362 void 363 do_emit_synchline(void) 364 { 365 fprintf(active, "#line %lu \"%s\"\n", 366 infile[ilevel].lineno, infile[ilevel].name); 367 infile[ilevel].synch_lineno = infile[ilevel].lineno; 368 } 369 370 void 371 release_input(struct input_file *f) 372 { 373 if (f->file != stdin) 374 fclose(f->file); 375 f->c = EOF; 376 /* 377 * XXX can't free filename, as there might still be 378 * error information pointing to it. 379 */ 380 } 381 382 void 383 doprintlineno(struct input_file *f) 384 { 385 pbunsigned(TOKEN_LINE(f)); 386 } 387 388 void 389 doprintfilename(struct input_file *f) 390 { 391 pbstr(rquote); 392 pbstr(f->name); 393 pbstr(lquote); 394 } 395 396 /* 397 * buffer_mark/dump_buffer: allows one to save a mark in a buffer, 398 * and later dump everything that was added since then to a file. 399 */ 400 size_t 401 buffer_mark(void) 402 { 403 return bp - buf; 404 } 405 406 407 void 408 dump_buffer(FILE *f, size_t m) 409 { 410 unsigned char *s; 411 412 for (s = bp; (size_t)(s - buf) > m;) 413 fputc(*--s, f); 414 } 415