Source

pcw-bsd / cw.c

Full commit
#include <err.h>
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include <sys/ioctl.h>
#include <sys/select.h>
#include <sys/param.h>

#ifdef __linux__
#define HAVE_INOTIFY
#include <sys/inotify.h>
#else 
#define HAVE_KQUEUE
#include <sys/types.h>
#include <sys/event.h>
#include <sys/time.h>
#endif

FILE *in, *out;
char buf[4096];

void sigwinch(int unused)
{
	rewind(in);

	while (fgets(buf, sizeof(buf), in))
		fputs(buf, stdout);
	fflush(stdout);
}

#ifdef HAVE_INOTIFY
void run_inotify(char *infile)
{
	int evq, in_wd;
	fd_set rd;

	if ((evq = inotify_init()) < 0)
		err(1, "failed inotify_init()");
	if ((in_wd = inotify_add_watch(evq, infile, IN_MODIFY)) < 0)
		err(1, "failed inotify_add_watch()");

	for(;;) {
		FD_ZERO(&rd);
		FD_SET(evq, &rd);
		FD_SET(fileno(stdin), &rd);
		if (select(evq + 1, &rd, 0, 0, NULL) < 0) {
		    if (errno == EINTR)
			continue;
		    else
			warn("error on select");
		}
		if (FD_ISSET(evq, &rd)) {
			if (read(evq, buf, sizeof(buf)) < 0 && errno != EINTR)
				err(1, "failed read() on evq");

			while (fgets(buf, sizeof(buf), in))
				fputs(buf, stdout);
			fflush(stdout);
		}
		if (FD_ISSET(fileno(stdin), &rd)) {
			if (fgets(buf, sizeof(buf), stdin))
				fputs(buf, out);
			fflush(out);
		}
	}
}
#endif // HAVE_INOTIFY

#ifdef HAVE_KQUEUE
void run_kqueue() 
{
	int kq, i;
	struct kevent change;
	struct kevent event;
	int len;

	if ((kq = kqueue()) == -1)
		perror("kqueue failed");

	EV_SET(&change, fileno(in), EVFILT_READ, 
		EV_ADD | EV_ENABLE, NULL, 0, 0);
	if (kevent(kq, &change, 1, NULL, 0, NULL) == -1)
		err(1, "kevent set EVFILT_READ");

 	EV_SET(&change, fileno(stdin), EVFILT_READ,
		EV_ADD | EV_ENABLE, NULL, 0, 0);
	if (kevent(kq, &change, 1, NULL, 0, NULL) == -1)
		err(1, "kevent set EVFILT_READ");

	for (;;) {
		i = kevent(kq, NULL, 0, &event, 1, NULL);
		if (i == -1) {
			/* don't quit on interrupts (ie. SIGWINCH */
			if (errno == EINTR)
				continue;
			else
				err(1, "kevent read"); 
		}

		if (event.filter == EVFILT_READ) {
			if(event.ident == fileno(stdin)) {
				len = read(fileno(stdin),buf,sizeof(buf));
					write(fileno(out),buf,len);
				fflush(out);
			}
			if(event.ident == fileno(in)) {
				len = read(fileno(in),buf,sizeof(buf));
					write(fileno(stdout),buf,len);
				fflush(stdout);
			}
		}
	}
}
#endif // HAVE_KQUEUE

int main(int argc, char **argv)
{
	if (argc != 3) {
		printf("Usage: cw infile outfile\n");
		printf("cw-"VERSION" © Evan Gates\n");
		exit(1);
	}

	if (signal(SIGWINCH, sigwinch) == SIG_ERR)
		err(1, "failed to install sigwinch handler");

	if ((in = fopen(argv[1], "r")) == NULL)
		err(1, "failed to fopen %s", argv[1]);

	while (fgets(buf, sizeof(buf), in))
		fputs(buf, stdout);
	fflush(stdout);

	if ((out = fopen(argv[2], "w")) == NULL)
		err(1, "failed to fopen %s", argv[2]);

#ifdef HAVE_INOTIFY
	run_inotify(argv[1]);
#else
	run_kqueue();
#endif

	return 0;
}