Mercurial > ~dholland > hg > tradcpp > index.cgi
annotate output.c @ 146:15f51ed08ecf
Add more tests for some degenerate cases we don't handle right.
author | David A. Holland |
---|---|
date | Sat, 13 Jul 2013 14:47:29 -0400 |
parents | ed45f2d8d3bc |
children | 16b4451e34b8 |
rev | line source |
---|---|
30 | 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 | |
27 | 30 #include <string.h> |
20 | 31 #include <unistd.h> |
32 #include <fcntl.h> | |
143 | 33 #include <errno.h> |
20 | 34 |
35 #include "utils.h" | |
36 #include "mode.h" | |
21 | 37 #include "place.h" |
20 | 38 #include "output.h" |
39 | |
40 static int outputfd = -1; | |
21 | 41 static bool incomment = false; |
27 | 42 static char *linebuf; |
43 static size_t linebufpos, linebufmax; | |
44 static struct place linebufplace; | |
20 | 45 |
46 static | |
47 void | |
48 output_open(void) | |
49 { | |
24 | 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) { | |
143 | 56 complain(NULL, "%s: %s", |
57 mode.output_file, strerror(errno)); | |
24 | 58 die(); |
59 } | |
20 | 60 } |
61 } | |
62 | |
21 | 63 static |
20 | 64 void |
21 | 65 dowrite(const char *buf, size_t len) |
20 | 66 { |
67 size_t done; | |
68 ssize_t result; | |
69 static unsigned write_errors = 0; | |
70 | |
22 | 71 if (!mode.do_output) { |
72 return; | |
73 } | |
74 | |
20 | 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) { | |
143 | 83 complain(NULL, "%s: write: %s", |
84 mode.output_file, strerror(errno)); | |
20 | 85 complain_failed(); |
86 write_errors++; | |
87 if (write_errors > 5) { | |
143 | 88 complain(NULL, "%s: giving up", |
89 mode.output_file); | |
20 | 90 die(); |
91 } | |
92 /* XXX is this really a good idea? */ | |
93 sleep(1); | |
94 } | |
95 done += (size_t)result; | |
96 } | |
97 } | |
98 | |
27 | 99 |
100 static | |
20 | 101 void |
103 | 102 filter_output(const char *buf, size_t len) |
21 | 103 { |
104 size_t pos, start; | |
81
27c9aafcaca1
Don't recognize comments within double-quote strings.
David A. Holland
parents:
78
diff
changeset
|
105 bool inesc = false; |
27c9aafcaca1
Don't recognize comments within double-quote strings.
David A. Holland
parents:
78
diff
changeset
|
106 bool inquote = false; |
128
1cda505ddc78
Don't expand macros within character constants.
David A. Holland
parents:
103
diff
changeset
|
107 char quote = '\0'; |
21 | 108 |
109 start = 0; | |
110 for (pos = 0; pos < len - 1; pos++) { | |
81
27c9aafcaca1
Don't recognize comments within double-quote strings.
David A. Holland
parents:
78
diff
changeset
|
111 if (!inquote && buf[pos] == '/' && buf[pos+1] == '*') { |
78
4cc1c575951f
No need to warn about nested comments twice.
David A. Holland
parents:
39
diff
changeset
|
112 if (!incomment) { |
21 | 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 } | |
81
27c9aafcaca1
Don't recognize comments within double-quote strings.
David A. Holland
parents:
78
diff
changeset
|
136 |
27c9aafcaca1
Don't recognize comments within double-quote strings.
David A. Holland
parents:
78
diff
changeset
|
137 if (incomment) { |
27c9aafcaca1
Don't recognize comments within double-quote strings.
David A. Holland
parents:
78
diff
changeset
|
138 /* nothing */ |
27c9aafcaca1
Don't recognize comments within double-quote strings.
David A. Holland
parents:
78
diff
changeset
|
139 } else if (inesc) { |
27c9aafcaca1
Don't recognize comments within double-quote strings.
David A. Holland
parents:
78
diff
changeset
|
140 inesc = false; |
27c9aafcaca1
Don't recognize comments within double-quote strings.
David A. Holland
parents:
78
diff
changeset
|
141 } else if (buf[pos] == '\\') { |
27c9aafcaca1
Don't recognize comments within double-quote strings.
David A. Holland
parents:
78
diff
changeset
|
142 inesc = true; |
128
1cda505ddc78
Don't expand macros within character constants.
David A. Holland
parents:
103
diff
changeset
|
143 } else if (!inquote && (buf[pos] == '"' || buf[pos] == '\'')) { |
1cda505ddc78
Don't expand macros within character constants.
David A. Holland
parents:
103
diff
changeset
|
144 inquote = true; |
1cda505ddc78
Don't expand macros within character constants.
David A. Holland
parents:
103
diff
changeset
|
145 quote = buf[pos]; |
1cda505ddc78
Don't expand macros within character constants.
David A. Holland
parents:
103
diff
changeset
|
146 } else if (inquote && buf[pos] == quote) { |
1cda505ddc78
Don't expand macros within character constants.
David A. Holland
parents:
103
diff
changeset
|
147 inquote = false; |
81
27c9aafcaca1
Don't recognize comments within double-quote strings.
David A. Holland
parents:
78
diff
changeset
|
148 } |
21 | 149 } |
24 | 150 pos++; |
151 | |
152 if (pos > start) { | |
153 if (!incomment || mode.output_retain_comments) { | |
154 dowrite(buf + start, pos - start); | |
155 } | |
156 } | |
21 | 157 } |
158 | |
159 void | |
27 | 160 output(const struct place *p, const char *buf, size_t len) |
161 { | |
39
337110e7240a
Pass the size to free; it makes debug checking easier.
David A. Holland
parents:
30
diff
changeset
|
162 size_t oldmax; |
337110e7240a
Pass the size to free; it makes debug checking easier.
David A. Holland
parents:
30
diff
changeset
|
163 |
27 | 164 if (linebufpos + len > linebufmax) { |
39
337110e7240a
Pass the size to free; it makes debug checking easier.
David A. Holland
parents:
30
diff
changeset
|
165 oldmax = linebufmax; |
27 | 166 if (linebufmax == 0) { |
167 linebufmax = 64; | |
168 } | |
169 while (linebufpos + len > linebufmax) { | |
170 linebufmax *= 2; | |
171 } | |
39
337110e7240a
Pass the size to free; it makes debug checking easier.
David A. Holland
parents:
30
diff
changeset
|
172 linebuf = dorealloc(linebuf, oldmax, linebufmax); |
27 | 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') { | |
103 | 181 filter_output(linebuf, linebufpos); |
27 | 182 linebufpos = 0; |
183 } | |
184 } | |
185 | |
186 void | |
20 | 187 output_eof(void) |
188 { | |
24 | 189 if (mode.output_file != NULL && outputfd >= 0) { |
20 | 190 close(outputfd); |
191 } | |
192 outputfd = -1; | |
193 } |