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