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