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#include <sys/cdefs.h>
36__FBSDID("$FreeBSD: releng/10.2/usr.bin/m4/misc.c 228063 2011-11-28 13:32:39Z bapt $");
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
53char *ep;		/* first free char in strspace */
54static char *strspace;	/* string space for evaluation */
55char *endest;		/* end of string space	       */
56static size_t strsize = STRSPMAX;
57static size_t bufsize = BUFSIZE;
58
59unsigned char *buf;			/* push-back buffer	       */
60unsigned char *bufbase;			/* the base for current ilevel */
61unsigned char *bbase[MAXINP];		/* the base for each ilevel    */
62unsigned char *bp;			/* first available character   */
63unsigned char *endpbb;			/* end of push-back buffer     */
64
65
66/*
67 * find the index of second str in the first str.
68 */
69ptrdiff_t
70indx(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 */
83void
84pushback(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 */
98void
99pbstr(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 */
113void
114pbnum(int n)
115{
116	pbnumbase(n, 10, 0);
117}
118
119void
120pbnumbase(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 */
151void
152pbunsigned(unsigned long n)
153{
154	do {
155		pushback(n % 10 + '0');
156	}
157	while ((n /= 10) > 0);
158}
159
160void
161initspaces(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
176void
177enlarge_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
197void
198enlarge_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 */
216void
217chrsave(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 */
227void
228getdiv(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	(void) fclose(outfile[n]);
238	outfile[n] = NULL;
239}
240
241void
242onintr(__unused int signo)
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 */
252void
253killdiv(void)
254{
255	int n;
256
257	for (n = 0; n < maxout; n++)
258		if (outfile[n] != NULL) {
259			(void) fclose(outfile[n]);
260		}
261}
262
263extern char *__progname;
264
265void
266m4errx(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 */
283void
284resizedivs(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
295void *
296xalloc(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
314void *
315xrealloc(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
334char *
335xstrdup(const char *s)
336{
337	char *p = strdup(s);
338	if (p == NULL)
339		err(1, "strdup");
340	return p;
341}
342
343void
344usage(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
352int
353obtain_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
365void
366set_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
375void
376do_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
383void
384release_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
395void
396doprintlineno(struct input_file *f)
397{
398	pbunsigned(f->lineno);
399}
400
401void
402doprintfilename(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 */
413size_t
414buffer_mark(void)
415{
416	return bp - buf;
417}
418
419
420void
421dump_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}
428