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 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 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 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 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 197 output_eof(void) 198 { 199 if (mode.output_file != NULL && outputfd >= 0) { 200 close(outputfd); 201 } 202 outputfd = -1; 203 } 204