output.c revision 1.1
1/*-
2 * Copyright (c) 2010 The NetBSD Foundation, Inc.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to The NetBSD Foundation
6 * by David A. Holland.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include <string.h>
31#include <unistd.h>
32#include <fcntl.h>
33#include <errno.h>
34
35#include "utils.h"
36#include "mode.h"
37#include "place.h"
38#include "output.h"
39
40static int outputfd = -1;
41static bool incomment = false;
42static char *linebuf;
43static size_t linebufpos, linebufmax;
44static struct place linebufplace;
45
46static
47void
48output_open(void)
49{
50	if (mode.output_file == NULL) {
51		outputfd = STDOUT_FILENO;
52	} else {
53		outputfd = open(mode.output_file, O_WRONLY|O_CREAT|O_TRUNC,
54				0664);
55		if (outputfd < 0) {
56			complain(NULL, "%s: %s",
57				 mode.output_file, strerror(errno));
58			die();
59		}
60	}
61}
62
63static
64void
65dowrite(const char *buf, size_t len)
66{
67	size_t done;
68	ssize_t result;
69	static unsigned write_errors = 0;
70
71	if (!mode.do_output) {
72		return;
73	}
74
75	if (outputfd < 0) {
76		output_open();
77	}
78
79	done = 0;
80	while (done < len) {
81		result = write(outputfd, buf+done, len-done);
82		if (result == -1) {
83			complain(NULL, "%s: write: %s",
84				 mode.output_file, strerror(errno));
85			complain_failed();
86			write_errors++;
87			if (write_errors > 5) {
88				complain(NULL, "%s: giving up",
89					 mode.output_file);
90				die();
91			}
92			/* XXX is this really a good idea? */
93			sleep(1);
94		}
95		done += (size_t)result;
96	}
97}
98
99
100static
101void
102filter_output(const char *buf, size_t len)
103{
104	size_t pos, start;
105	bool inesc = false;
106	bool inquote = false;
107	char quote = '\0';
108
109	start = 0;
110	for (pos = 0; pos < len - 1; pos++) {
111		if (!inquote && buf[pos] == '/' && buf[pos+1] == '*') {
112			if (!incomment) {
113				if (pos > start) {
114					dowrite(buf + start, pos - start);
115				}
116				start = pos;
117				pos += 2;
118				incomment = true;
119				/* cancel out the loop's pos++ */
120				pos--;
121				continue;
122			}
123		} else if (buf[pos] == '*' && buf[pos+1] == '/') {
124			if (incomment) {
125				pos += 2;
126				if (mode.output_retain_comments) {
127					dowrite(buf + start, pos - start);
128				}
129				start = pos;
130				incomment = false;
131				/* cancel out the loop's pos++ */
132				pos--;
133				continue;
134			}
135		}
136
137		if (incomment) {
138			/* nothing */
139		} else if (inesc) {
140			inesc = false;
141		} else if (buf[pos] == '\\') {
142			inesc = true;
143		} else if (!inquote && (buf[pos] == '"' || buf[pos] == '\'')) {
144			inquote = true;
145			quote = buf[pos];
146		} else if (inquote && buf[pos] == quote) {
147			inquote = false;
148		}
149	}
150	pos++;
151
152	if (pos > start) {
153		if (!incomment || mode.output_retain_comments) {
154			dowrite(buf + start, pos - start);
155		}
156	}
157}
158
159void
160output(const struct place *p, const char *buf, size_t len)
161{
162	size_t oldmax;
163
164	if (linebufpos + len > linebufmax) {
165		oldmax = linebufmax;
166		if (linebufmax == 0) {
167			linebufmax = 64;
168		}
169		while (linebufpos + len > linebufmax) {
170			linebufmax *= 2;
171		}
172		linebuf = dorealloc(linebuf, oldmax, linebufmax);
173	}
174	if (linebufpos == 0) {
175		linebufplace = *p;
176	}
177	memcpy(linebuf + linebufpos, buf, len);
178	linebufpos += len;
179
180	if (len == 1 && buf[0] == '\n') {
181		filter_output(linebuf, linebufpos);
182		linebufpos = 0;
183	}
184}
185
186void
187output_eof(void)
188{
189	if (mode.output_file != NULL && outputfd >= 0) {
190		close(outputfd);
191	}
192	outputfd = -1;
193}
194