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