misc.c revision 1.19 1 1.19 christos /* $OpenBSD: misc.c,v 1.41 2009/10/14 17:19:47 sthen Exp $ */
2 1.19 christos /* $NetBSD: misc.c,v 1.19 2009/10/26 21:11:28 christos Exp $ */
3 1.6 tls
4 1.5 glass /*
5 1.5 glass * Copyright (c) 1989, 1993
6 1.5 glass * The Regents of the University of California. All rights reserved.
7 1.5 glass *
8 1.5 glass * This code is derived from software contributed to Berkeley by
9 1.5 glass * Ozan Yigit at York University.
10 1.5 glass *
11 1.5 glass * Redistribution and use in source and binary forms, with or without
12 1.5 glass * modification, are permitted provided that the following conditions
13 1.5 glass * are met:
14 1.5 glass * 1. Redistributions of source code must retain the above copyright
15 1.5 glass * notice, this list of conditions and the following disclaimer.
16 1.5 glass * 2. Redistributions in binary form must reproduce the above copyright
17 1.5 glass * notice, this list of conditions and the following disclaimer in the
18 1.5 glass * documentation and/or other materials provided with the distribution.
19 1.16 agc * 3. Neither the name of the University nor the names of its contributors
20 1.5 glass * may be used to endorse or promote products derived from this software
21 1.5 glass * without specific prior written permission.
22 1.5 glass *
23 1.5 glass * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 1.5 glass * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 1.5 glass * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 1.5 glass * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 1.5 glass * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 1.5 glass * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 1.5 glass * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 1.5 glass * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 1.5 glass * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 1.5 glass * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 1.5 glass * SUCH DAMAGE.
34 1.5 glass */
35 1.17 jmc #if HAVE_NBTOOL_CONFIG_H
36 1.17 jmc #include "nbtool_config.h"
37 1.17 jmc #endif
38 1.7 lukem #include <sys/cdefs.h>
39 1.19 christos __RCSID("$NetBSD: misc.c,v 1.19 2009/10/26 21:11:28 christos Exp $");
40 1.5 glass #include <sys/types.h>
41 1.5 glass #include <errno.h>
42 1.19 christos #include <unistd.h>
43 1.19 christos #include <stdarg.h>
44 1.5 glass #include <stdio.h>
45 1.5 glass #include <stdlib.h>
46 1.12 tv #include <stddef.h>
47 1.5 glass #include <string.h>
48 1.19 christos #include <err.h>
49 1.1 cgd #include "mdef.h"
50 1.5 glass #include "stdd.h"
51 1.5 glass #include "extern.h"
52 1.5 glass #include "pathnames.h"
53 1.12 tv
54 1.19 christos
55 1.12 tv char *ep; /* first free char in strspace */
56 1.12 tv static char *strspace; /* string space for evaluation */
57 1.12 tv char *endest; /* end of string space */
58 1.12 tv static size_t strsize = STRSPMAX;
59 1.12 tv static size_t bufsize = BUFSIZE;
60 1.12 tv
61 1.19 christos unsigned char *buf; /* push-back buffer */
62 1.19 christos unsigned char *bufbase; /* the base for current ilevel */
63 1.19 christos unsigned char *bbase[MAXINP]; /* the base for each ilevel */
64 1.19 christos unsigned char *bp; /* first available character */
65 1.19 christos unsigned char *endpbb; /* end of push-back buffer */
66 1.12 tv
67 1.12 tv
68 1.5 glass /*
69 1.5 glass * find the index of second str in the first str.
70 1.5 glass */
71 1.12 tv ptrdiff_t
72 1.19 christos indx(const char *s1, const char *s2)
73 1.5 glass {
74 1.7 lukem char *t;
75 1.7 lukem
76 1.7 lukem t = strstr(s1, s2);
77 1.7 lukem if (t == NULL)
78 1.7 lukem return (-1);
79 1.19 christos else
80 1.19 christos return (t - s1);
81 1.5 glass }
82 1.5 glass /*
83 1.19 christos * pushback - push character back onto input
84 1.5 glass */
85 1.5 glass void
86 1.19 christos pushback(int c)
87 1.5 glass {
88 1.12 tv if (c == EOF)
89 1.12 tv return;
90 1.12 tv if (bp >= endpbb)
91 1.12 tv enlarge_bufspace();
92 1.12 tv *bp++ = c;
93 1.9 cgd }
94 1.9 cgd
95 1.9 cgd /*
96 1.5 glass * pbstr - push string back onto input
97 1.19 christos * pushback is replicated to improve
98 1.5 glass * performance.
99 1.5 glass */
100 1.5 glass void
101 1.19 christos pbstr(const char *s)
102 1.5 glass {
103 1.12 tv size_t n;
104 1.2 glass
105 1.12 tv n = strlen(s);
106 1.19 christos while ((size_t)(endpbb - bp) <= n)
107 1.12 tv enlarge_bufspace();
108 1.12 tv while (n > 0)
109 1.12 tv *bp++ = s[--n];
110 1.5 glass }
111 1.5 glass
112 1.5 glass /*
113 1.5 glass * pbnum - convert number to string, push back on input.
114 1.5 glass */
115 1.5 glass void
116 1.19 christos pbnum(int n)
117 1.19 christos {
118 1.19 christos pbnumbase(n, 10, 0);
119 1.19 christos }
120 1.19 christos
121 1.19 christos void
122 1.19 christos pbnumbase(int n, int base, int d)
123 1.5 glass {
124 1.19 christos static char digits[36] = "0123456789abcdefghijklmnopqrstuvwxyz";
125 1.7 lukem int num;
126 1.19 christos int printed = 0;
127 1.19 christos
128 1.19 christos if (base > 36)
129 1.19 christos m4errx(1, "base %d > 36: not supported.", base);
130 1.19 christos
131 1.19 christos if (base < 2)
132 1.19 christos m4errx(1, "bad base %d for conversion.", base);
133 1.2 glass
134 1.5 glass num = (n < 0) ? -n : n;
135 1.2 glass do {
136 1.19 christos pushback(digits[num % base]);
137 1.19 christos printed++;
138 1.2 glass }
139 1.19 christos while ((num /= base) > 0);
140 1.2 glass
141 1.5 glass if (n < 0)
142 1.19 christos printed++;
143 1.19 christos while (printed++ < d)
144 1.19 christos pushback('0');
145 1.19 christos
146 1.19 christos if (n < 0)
147 1.19 christos pushback('-');
148 1.5 glass }
149 1.5 glass
150 1.5 glass /*
151 1.12 tv * pbunsigned - convert unsigned long to string, push back on input.
152 1.12 tv */
153 1.12 tv void
154 1.19 christos pbunsigned(unsigned long n)
155 1.12 tv {
156 1.12 tv do {
157 1.19 christos pushback(n % 10 + '0');
158 1.12 tv }
159 1.12 tv while ((n /= 10) > 0);
160 1.12 tv }
161 1.12 tv
162 1.12 tv void
163 1.12 tv initspaces()
164 1.12 tv {
165 1.12 tv int i;
166 1.12 tv
167 1.19 christos strspace = xalloc(strsize+1, NULL);
168 1.12 tv ep = strspace;
169 1.12 tv endest = strspace+strsize;
170 1.19 christos buf = (unsigned char *)xalloc(bufsize, NULL);
171 1.12 tv bufbase = buf;
172 1.12 tv bp = buf;
173 1.12 tv endpbb = buf + bufsize;
174 1.12 tv for (i = 0; i < MAXINP; i++)
175 1.12 tv bbase[i] = buf;
176 1.12 tv }
177 1.12 tv
178 1.12 tv void
179 1.12 tv enlarge_strspace()
180 1.12 tv {
181 1.12 tv char *newstrspace;
182 1.12 tv int i;
183 1.12 tv
184 1.12 tv strsize *= 2;
185 1.12 tv newstrspace = malloc(strsize + 1);
186 1.12 tv if (!newstrspace)
187 1.12 tv errx(1, "string space overflow");
188 1.12 tv memcpy(newstrspace, strspace, strsize/2);
189 1.12 tv for (i = 0; i <= sp; i++)
190 1.12 tv if (sstack[i])
191 1.12 tv mstack[i].sstr = (mstack[i].sstr - strspace)
192 1.12 tv + newstrspace;
193 1.12 tv ep = (ep-strspace) + newstrspace;
194 1.12 tv free(strspace);
195 1.12 tv strspace = newstrspace;
196 1.12 tv endest = strspace + strsize;
197 1.12 tv }
198 1.12 tv
199 1.12 tv void
200 1.12 tv enlarge_bufspace()
201 1.12 tv {
202 1.19 christos unsigned char *newbuf;
203 1.12 tv int i;
204 1.12 tv
205 1.19 christos bufsize += bufsize/2;
206 1.19 christos newbuf = xrealloc(buf, bufsize, "too many characters pushed back");
207 1.12 tv for (i = 0; i < MAXINP; i++)
208 1.12 tv bbase[i] = (bbase[i]-buf)+newbuf;
209 1.12 tv bp = (bp-buf)+newbuf;
210 1.12 tv bufbase = (bufbase-buf)+newbuf;
211 1.12 tv buf = newbuf;
212 1.12 tv endpbb = buf+bufsize;
213 1.12 tv }
214 1.12 tv
215 1.12 tv /*
216 1.5 glass * chrsave - put single char on string space
217 1.5 glass */
218 1.5 glass void
219 1.19 christos chrsave(int c)
220 1.5 glass {
221 1.12 tv if (ep >= endest)
222 1.12 tv enlarge_strspace();
223 1.12 tv *ep++ = c;
224 1.5 glass }
225 1.5 glass
226 1.5 glass /*
227 1.5 glass * read in a diversion file, and dispose it.
228 1.5 glass */
229 1.5 glass void
230 1.19 christos getdiv(int n)
231 1.5 glass {
232 1.7 lukem int c;
233 1.2 glass
234 1.5 glass if (active == outfile[n])
235 1.19 christos m4errx(1, "undivert: diversion still active.");
236 1.12 tv rewind(outfile[n]);
237 1.12 tv while ((c = getc(outfile[n])) != EOF)
238 1.12 tv putc(c, active);
239 1.5 glass (void) fclose(outfile[n]);
240 1.5 glass outfile[n] = NULL;
241 1.5 glass }
242 1.2 glass
243 1.5 glass void
244 1.19 christos onintr(int signo)
245 1.5 glass {
246 1.12 tv #define intrmessage "m4: interrupted.\n"
247 1.19 christos write(STDERR_FILENO, intrmessage, sizeof(intrmessage)-1);
248 1.12 tv _exit(1);
249 1.5 glass }
250 1.5 glass
251 1.5 glass /*
252 1.5 glass * killdiv - get rid of the diversion files
253 1.5 glass */
254 1.5 glass void
255 1.5 glass killdiv()
256 1.5 glass {
257 1.7 lukem int n;
258 1.2 glass
259 1.12 tv for (n = 0; n < maxout; n++)
260 1.5 glass if (outfile[n] != NULL) {
261 1.5 glass (void) fclose(outfile[n]);
262 1.5 glass }
263 1.5 glass }
264 1.2 glass
265 1.19 christos extern char *__progname;
266 1.19 christos
267 1.19 christos void
268 1.19 christos m4errx(int exval, const char *fmt, ...)
269 1.19 christos {
270 1.19 christos fprintf(stderr, "%s: ", __progname);
271 1.19 christos fprintf(stderr, "%s at line %lu: ", CURRENT_NAME, CURRENT_LINE);
272 1.19 christos if (fmt != NULL) {
273 1.19 christos va_list ap;
274 1.19 christos
275 1.19 christos va_start(ap, fmt);
276 1.19 christos vfprintf(stderr, fmt, ap);
277 1.19 christos va_end(ap);
278 1.19 christos }
279 1.19 christos fprintf(stderr, "\n");
280 1.19 christos exit(exval);
281 1.19 christos }
282 1.19 christos
283 1.12 tv /*
284 1.12 tv * resizedivs: allocate more diversion files */
285 1.12 tv void
286 1.19 christos resizedivs(int n)
287 1.12 tv {
288 1.12 tv int i;
289 1.12 tv
290 1.19 christos outfile = (FILE **)xrealloc(outfile, sizeof(FILE *) * n,
291 1.19 christos "too many diverts %d", n);
292 1.12 tv for (i = maxout; i < n; i++)
293 1.12 tv outfile[i] = NULL;
294 1.12 tv maxout = n;
295 1.12 tv }
296 1.12 tv
297 1.12 tv void *
298 1.19 christos xalloc(size_t n, const char *fmt, ...)
299 1.19 christos {
300 1.19 christos void *p = malloc(n);
301 1.19 christos
302 1.19 christos if (p == NULL) {
303 1.19 christos if (fmt == NULL)
304 1.19 christos err(1, "malloc");
305 1.19 christos else {
306 1.19 christos va_list va;
307 1.19 christos
308 1.19 christos va_start(va, fmt);
309 1.19 christos verr(1, fmt, va);
310 1.19 christos va_end(va);
311 1.19 christos }
312 1.19 christos }
313 1.19 christos return p;
314 1.19 christos }
315 1.19 christos
316 1.19 christos void *
317 1.19 christos xrealloc(void *old, size_t n, const char *fmt, ...)
318 1.5 glass {
319 1.19 christos char *p = realloc(old, n);
320 1.2 glass
321 1.19 christos if (p == NULL) {
322 1.19 christos free(old);
323 1.19 christos if (fmt == NULL)
324 1.19 christos err(1, "realloc");
325 1.19 christos else {
326 1.19 christos va_list va;
327 1.19 christos
328 1.19 christos va_start(va, fmt);
329 1.19 christos verr(1, fmt, va);
330 1.19 christos va_end(va);
331 1.19 christos }
332 1.19 christos }
333 1.5 glass return p;
334 1.5 glass }
335 1.2 glass
336 1.5 glass char *
337 1.19 christos xstrdup(const char *s)
338 1.5 glass {
339 1.7 lukem char *p = strdup(s);
340 1.5 glass if (p == NULL)
341 1.7 lukem err(1, "strdup");
342 1.5 glass return p;
343 1.5 glass }
344 1.2 glass
345 1.12 tv void
346 1.19 christos usage(void)
347 1.12 tv {
348 1.19 christos fprintf(stderr, "usage: %s [-gPs] [-Dname[=value]] [-d flags] "
349 1.19 christos "[-I dirname] [-o filename]\n"
350 1.19 christos "\t[-t macro] [-Uname] [file ...]\n", getprogname());
351 1.12 tv exit(1);
352 1.12 tv }
353 1.12 tv
354 1.12 tv int
355 1.19 christos obtain_char(struct input_file *f)
356 1.12 tv {
357 1.12 tv if (f->c == EOF)
358 1.12 tv return EOF;
359 1.19 christos
360 1.19 christos f->c = fgetc(f->file);
361 1.19 christos if (f->c == '\n')
362 1.12 tv f->lineno++;
363 1.12 tv
364 1.12 tv return f->c;
365 1.12 tv }
366 1.12 tv
367 1.12 tv void
368 1.19 christos set_input(struct input_file *f, FILE *real, const char *name)
369 1.12 tv {
370 1.12 tv f->file = real;
371 1.12 tv f->lineno = 1;
372 1.12 tv f->c = 0;
373 1.12 tv f->name = xstrdup(name);
374 1.19 christos emit_synchline();
375 1.19 christos }
376 1.19 christos
377 1.19 christos void
378 1.19 christos do_emit_synchline()
379 1.19 christos {
380 1.19 christos fprintf(active, "#line %lu \"%s\"\n",
381 1.19 christos infile[ilevel].lineno, infile[ilevel].name);
382 1.19 christos infile[ilevel].synch_lineno = infile[ilevel].lineno;
383 1.12 tv }
384 1.12 tv
385 1.12 tv void
386 1.19 christos release_input(struct input_file *f)
387 1.12 tv {
388 1.12 tv if (f->file != stdin)
389 1.12 tv fclose(f->file);
390 1.12 tv f->c = EOF;
391 1.12 tv /*
392 1.12 tv * XXX can't free filename, as there might still be
393 1.12 tv * error information pointing to it.
394 1.12 tv */
395 1.12 tv }
396 1.12 tv
397 1.12 tv void
398 1.19 christos doprintlineno(struct input_file *f)
399 1.5 glass {
400 1.12 tv pbunsigned(f->lineno);
401 1.12 tv }
402 1.2 glass
403 1.12 tv void
404 1.19 christos doprintfilename(struct input_file *f)
405 1.12 tv {
406 1.12 tv pbstr(rquote);
407 1.12 tv pbstr(f->name);
408 1.12 tv pbstr(lquote);
409 1.12 tv }
410 1.2 glass
411 1.12 tv /*
412 1.12 tv * buffer_mark/dump_buffer: allows one to save a mark in a buffer,
413 1.12 tv * and later dump everything that was added since then to a file.
414 1.12 tv */
415 1.12 tv size_t
416 1.12 tv buffer_mark()
417 1.12 tv {
418 1.12 tv return bp - buf;
419 1.5 glass }
420 1.2 glass
421 1.12 tv
422 1.5 glass void
423 1.19 christos dump_buffer(FILE *f, size_t m)
424 1.5 glass {
425 1.19 christos unsigned char *s;
426 1.12 tv
427 1.19 christos for (s = bp; (size_t)(s - buf) > m;)
428 1.12 tv fputc(*--s, f);
429 1.5 glass }
430