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