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 <stdio.h>
31 #include <string.h>
32 #include <unistd.h>
33 #include <fcntl.h>
34 #include <errno.h>
35
36 #include "utils.h"
37 #include "mode.h"
38 #include "place.h"
39 #include "output.h"
40
41 static int outputfd = -1;
42 static bool incomment = false;
43 static char *linebuf;
44 static size_t linebufpos, linebufmax;
45 static struct place linebufplace;
46
47 static
48 void
output_open(void)49 output_open(void)
50 {
51 if (mode.output_file == NULL) {
52 outputfd = STDOUT_FILENO;
53 } else {
54 outputfd = open(mode.output_file, O_WRONLY|O_CREAT|O_TRUNC,
55 0664);
56 if (outputfd < 0) {
57 complain(NULL, "%s: %s",
58 mode.output_file, strerror(errno));
59 die();
60 }
61 }
62 }
63
64 static
65 void
dowrite(const char * buf,size_t len)66 dowrite(const char *buf, size_t len)
67 {
68 size_t done;
69 ssize_t result;
70 static unsigned write_errors = 0;
71
72 if (!mode.do_output) {
73 return;
74 }
75
76 if (outputfd < 0) {
77 output_open();
78 }
79
80 done = 0;
81 while (done < len) {
82 result = write(outputfd, buf+done, len-done);
83 if (result == -1) {
84 complain(NULL, "%s: write: %s",
85 mode.output_file, strerror(errno));
86 complain_failed();
87 write_errors++;
88 if (write_errors > 5) {
89 complain(NULL, "%s: giving up",
90 mode.output_file);
91 die();
92 }
93 /* XXX is this really a good idea? */
94 sleep(1);
95 }
96 done += (size_t)result;
97 }
98 }
99
100
101 static
102 void
filter_output(const char * buf,size_t len)103 filter_output(const char *buf, size_t len)
104 {
105 size_t pos, start;
106 bool inesc = false;
107 bool inquote = false;
108 char quote = '\0';
109
110 start = 0;
111 for (pos = 0; pos < len - 1; pos++) {
112 if (!inquote && buf[pos] == '/' && buf[pos+1] == '*') {
113 if (!incomment) {
114 if (pos > start) {
115 dowrite(buf + start, pos - start);
116 }
117 start = pos;
118 pos += 2;
119 incomment = true;
120 /* cancel out the loop's pos++ */
121 pos--;
122 continue;
123 }
124 } else if (buf[pos] == '*' && buf[pos+1] == '/') {
125 if (incomment) {
126 pos += 2;
127 if (mode.output_retain_comments) {
128 dowrite(buf + start, pos - start);
129 }
130 start = pos;
131 incomment = false;
132 /* cancel out the loop's pos++ */
133 pos--;
134 continue;
135 }
136 }
137
138 if (incomment) {
139 /* nothing */
140 } else if (inesc) {
141 inesc = false;
142 } else if (buf[pos] == '\\') {
143 inesc = true;
144 } else if (!inquote && (buf[pos] == '"' || buf[pos] == '\'')) {
145 inquote = true;
146 quote = buf[pos];
147 } else if (inquote && buf[pos] == quote) {
148 inquote = false;
149 }
150 }
151 pos++;
152
153 if (pos > start) {
154 if (!incomment || mode.output_retain_comments) {
155 dowrite(buf + start, pos - start);
156 }
157 }
158 }
159
160 void
output(const struct place * p,const char * buf,size_t len)161 output(const struct place *p, const char *buf, size_t len)
162 {
163 size_t oldmax;
164
165 if (linebufpos + len > linebufmax) {
166 oldmax = linebufmax;
167 if (linebufmax == 0) {
168 linebufmax = 64;
169 }
170 while (linebufpos + len > linebufmax) {
171 linebufmax *= 2;
172 }
173 linebuf = dorealloc(linebuf, oldmax, linebufmax);
174 }
175 if (linebufpos == 0) {
176 if (!place_samefile(&linebufplace, p)) {
177 if (mode.output_cheaplinenumbers) {
178 char str[256];
179
180 snprintf(str, sizeof(str), "# %u \"%s\"\n",
181 p->line, place_getname(p));
182 dowrite(str, strlen(str));
183 }
184 }
185 linebufplace = *p;
186 }
187 memcpy(linebuf + linebufpos, buf, len);
188 linebufpos += len;
189
190 if (len == 1 && buf[0] == '\n') {
191 filter_output(linebuf, linebufpos);
192 linebufpos = 0;
193 }
194 }
195
196 void
output_eof(void)197 output_eof(void)
198 {
199 if (mode.output_file != NULL && outputfd >= 0) {
200 close(outputfd);
201 }
202 outputfd = -1;
203 }
204