view output.c @ 24:daa801fe719e

fix some bugs
author David A. Holland
date Mon, 20 Dec 2010 04:30:02 -0500
parents cef2dc916269
children 01c3a2088ab4
line wrap: on
line source

#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
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();
	}

	/* XXX this will often come by ones and twos, should buffer */

	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;
	}
}

void
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;
				pos += 2;
				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_eof(void)
{
	if (mode.output_file != NULL && outputfd >= 0) {
		close(outputfd);
	}
	outputfd = -1;
}