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