view output.c @ 27:01c3a2088ab4

fix some more bugs
author David A. Holland
date Mon, 20 Dec 2010 05:01:18 -0500
parents daa801fe719e
children 76c114899f63
line wrap: on
line source

#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <err.h>

#include "utils.h"
#include "mode.h"
#include "place.h"
#include "output.h"

static int outputfd = -1;
static bool incomment = false;
static char *linebuf;
static size_t linebufpos, linebufmax;
static struct place linebufplace;

static
void
output_open(void)
{
	if (mode.output_file == NULL) {
		outputfd = STDOUT_FILENO;
	} else {
		outputfd = open(mode.output_file, O_WRONLY|O_CREAT|O_TRUNC,
				0664);
		if (outputfd < 0) {
			warn("%s", mode.output_file);
			die();
		}
	}
}

static
void
dowrite(const char *buf, size_t len)
{
	size_t done;
	ssize_t result;
	static unsigned write_errors = 0;

	if (!mode.do_output) {
		return;
	}

	if (outputfd < 0) {
		output_open();
	}

	done = 0;
	while (done < len) {
		result = write(outputfd, buf+done, len-done);
		if (result == -1) {
			warn("%s: write", mode.output_file);
			complain_failed();
			write_errors++;
			if (write_errors > 5) {
				warnx("%s: giving up", mode.output_file);
				die();
			}
			/* XXX is this really a good idea? */
			sleep(1);
		}
		done += (size_t)result;
	}
}


static
void
filter_output(const struct place *p, const char *buf, size_t len)
{
	size_t pos, start;
	struct place p2;

	start = 0;
	for (pos = 0; pos < len - 1; pos++) {
		if (buf[pos] == '/' && buf[pos+1] == '*') {
			if (incomment && warns.nestcomment) {
				p2 = *p;
				p2.column += pos;
				complain(p, "Warning: %c%c within comment",
					 '/', '*');
				if (mode.werror) {
					complain_failed();
				}
			} else if (!incomment) {
				if (pos > start) {
					dowrite(buf + start, pos - start);
				}
				start = pos;
				pos += 2;
				incomment = true;
				/* cancel out the loop's pos++ */
				pos--;
				continue;
			}
		} else if (buf[pos] == '*' && buf[pos+1] == '/') {
			if (incomment) {
				pos += 2;
				if (mode.output_retain_comments) {
					dowrite(buf + start, pos - start);
				}
				start = pos;
				incomment = false;
				/* cancel out the loop's pos++ */
				pos--;
				continue;
			}
		}
	}
	pos++;

	if (pos > start) {
		if (!incomment || mode.output_retain_comments) {
			dowrite(buf + start, pos - start);
		}
	}
}

void
output(const struct place *p, const char *buf, size_t len)
{
	if (linebufpos + len > linebufmax) {
		if (linebufmax == 0) {
			linebufmax = 64;
		}
		while (linebufpos + len > linebufmax) {
			linebufmax *= 2;
		}
		linebuf = dorealloc(linebuf, linebufmax);
	}
	if (linebufpos == 0) {
		linebufplace = *p;
	}
	memcpy(linebuf + linebufpos, buf, len);
	linebufpos += len;

	if (len == 1 && buf[0] == '\n') {
		filter_output(&linebufplace, linebuf, linebufpos);
		linebufpos = 0;
	}
}

void
output_eof(void)
{
	if (mode.output_file != NULL && outputfd >= 0) {
		close(outputfd);
	}
	outputfd = -1;
}