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