Merge branch 'vendor/GCC44'
[dragonfly.git] / usr.bin / m4 / misc.c
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  * 3. All advertising materials mentioning features or use of this software
20  *    must display the following acknowledgement:
21  *      This product includes software developed by the University of
22  *      California, Berkeley and its contributors.
23  * 4. Neither the name of the University nor the names of its contributors
24  *    may be used to endorse or promote products derived from this software
25  *    without specific prior written permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37  * SUCH DAMAGE.
38  *
39  * @(#)misc.c   8.1 (Berkeley) 6/6/93
40  * $OpenBSD: misc.c,v 1.27 2002/04/26 16:15:16 espie Exp $
41  * $FreeBSD: src/usr.bin/m4/misc.c,v 1.15 2002/07/15 02:15:12 jmallett Exp $
42  * $DragonFly: src/usr.bin/m4/misc.c,v 1.3 2006/12/27 21:29:02 pavalos Exp $
43  */
44
45 #include <sys/types.h>
46 #include <errno.h>
47 #include <unistd.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 ((size_t)(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(void)
148 {
149         int i;
150
151         strspace = xalloc(strsize+1);
152         ep = strspace;
153         endest = strspace+strsize;
154         buf = (char *)xalloc(bufsize);
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(void)
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(void)
185 {
186         char *newbuf;
187         int i;
188
189         bufsize *= 2;
190         newbuf = realloc(buf, bufsize);
191         if (!newbuf)
192                 errx(1, "too many characters pushed back");
193         for (i = 0; i < MAXINP; i++)
194                 bbase[i] = (bbase[i]-buf)+newbuf;
195         bp = (bp-buf)+newbuf;
196         bufbase = (bufbase-buf)+newbuf;
197         buf = newbuf;
198         endpbb = buf+bufsize;
199 }
200
201 /*
202  *  chrsave - put single char on string space
203  */
204 void
205 chrsave(int c)
206 {
207         if (ep >= endest)
208                 enlarge_strspace();
209         *ep++ = c;
210 }
211
212 /*
213  * read in a diversion file, and dispose it.
214  */
215 void
216 getdiv(int n)
217 {
218         int c;
219
220         if (active == outfile[n])
221                 errx(1, "undivert: diversion still active");
222         rewind(outfile[n]);
223         while ((c = getc(outfile[n])) != EOF)
224                 putc(c, active);
225         (void) fclose(outfile[n]);
226         outfile[n] = NULL;
227 }
228
229 void
230 onintr(int signo __unused)
231 {
232 #define intrmessage     "m4: interrupted.\n"
233         write(STDERR_FILENO, intrmessage, sizeof(intrmessage)-1);
234         _exit(1);
235 }
236
237 /*
238  * killdiv - get rid of the diversion files
239  */
240 void
241 killdiv(void)
242 {
243         int n;
244
245         for (n = 0; n < maxout; n++)
246                 if (outfile[n] != NULL) {
247                         (void) fclose(outfile[n]);
248                 }
249 }
250
251 /*
252  * resizedivs: allocate more diversion files */
253 void
254 resizedivs(int n)
255 {
256         int i;
257
258         outfile = (FILE **)realloc(outfile, sizeof(FILE *) * n);
259         if (outfile == NULL)
260                     errx(1, "too many diverts %d", n);
261         for (i = maxout; i < n; i++)
262                 outfile[i] = NULL;
263         maxout = n;
264 }
265
266 void *
267 xalloc(size_t n)
268 {
269         char *p = malloc(n);
270
271         if (p == NULL)
272                 err(1, "malloc");
273         return p;
274 }
275
276 char *
277 xstrdup(const char *s)
278 {
279         char *p = strdup(s);
280         if (p == NULL)
281                 err(1, "strdup");
282         return p;
283 }
284
285 void
286 usage(void)
287 {
288         fprintf(stderr,
289 "usage: m4 [-d flags] [-t name] [-gs] [-D name[=value]]...\n"
290 "          [-U name]... [-I dirname]... file...\n");
291         exit(1);
292 }
293
294 int
295 obtain_char(struct input_file *f)
296 {
297         if (f->c == EOF)
298                 return EOF;
299         else if (f->c == '\n')
300                 f->lineno++;
301
302         f->c = fgetc(f->file);
303         return f->c;
304 }
305
306 void
307 set_input(struct input_file *f, FILE *real, const char *name)
308 {
309         f->file = real;
310         f->lineno = 1;
311         f->c = 0;
312         f->name = xstrdup(name);
313 }
314
315 void
316 release_input(struct input_file *f)
317 {
318         if (f->file != stdin)
319             fclose(f->file);
320         f->c = EOF;
321         /*
322          * XXX can't free filename, as there might still be
323          * error information pointing to it.
324          */
325 }
326
327 void
328 doprintlineno(struct input_file *f)
329 {
330         pbunsigned(f->lineno);
331 }
332
333 void
334 doprintfilename(struct input_file *f)
335 {
336         pbstr(rquote);
337         pbstr(f->name);
338         pbstr(lquote);
339 }
340
341 /*
342  * buffer_mark/dump_buffer: allows one to save a mark in a buffer,
343  * and later dump everything that was added since then to a file.
344  */
345 size_t
346 buffer_mark(void)
347 {
348         return bp - buf;
349 }
350
351
352 void
353 dump_buffer(FILE *f, size_t m)
354 {
355         char *s;
356
357         for (s = bp; s - buf > (int)m;)
358                 fputc(*--s, f);
359 }