Source

pcw-bsd / cw.c

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

#include <sys/stat.h>
#include <sys/select.h>
#include <sys/inotify.h>

int quiet = 0;
mode_t type = 0;
mode_t perm = 0600;

void usage(void)
{
	printf("Usage: cw [-c|-f] [-q] [-v] infile outfile\n");
	exit(1);
}

FILE *mopen(char *path, char *mode)
{
	struct stat st;
	FILE *f;

	if (stat(path, &st) < 0 && errno == ENOENT) {
		if (!type)
			err(1, "file %s does not exist", path);
		else if (mknod(path, type | perm, 0) < 0)
			err(1, "file %s could not be created", path);
	}

	if (!quiet) warnx("Opening %s (if it's a fifo, waiting for the other side to be opened)...", path);

	if ((f = fopen(path, mode)) == NULL)
		err(1, "failed to fopen %s", path);

	if (!quiet) warnx("...OK");

	return f;
}

int main(int argc, char **argv)
{
	int evq, in_wd, i;
	FILE *in, *out;
	char buf[4096];
	fd_set rd;

	for (i = 1; i < argc; i++) {
		if (argv[i][0] != '-')
			break;
		if (argv[i][2] != '\0')
			usage();
		switch (argv[i][1]) {
			case 'c' : type = S_IFREG; break; // create regular files
			case 'f' : type = S_IFIFO; break; // create fifos
			case 'q' : quiet = 1; break;
			case 'v' : printf("cw-"VERSION" © Evan Gates\n"); exit(1);
			// is it worth doing character, block, and socket too?
			default  : usage();
		}
	}
	if (i + 1 >= argc)
		usage();

	in = mopen(argv[i], "r");

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

	out = mopen(argv[i + 1], "w");

	if (!quiet) fprintf(stderr, "-------------------- new text starts here --------------------\n");

	if ((evq = inotify_init()) < 0)
		err(1, "failed inotify_init()");

	if ((in_wd = inotify_add_watch(evq, argv[i], IN_MODIFY)) < 0)
		err(1, "failed inotify_add_watch()");

	for (;;) {
		FD_ZERO(&rd);
		FD_SET(0, &rd);
		FD_SET(evq, &rd);

		select(evq + 1, &rd, 0, 0, NULL);

		if (FD_ISSET(evq, &rd)) {
			if (read(evq, buf, sizeof(buf)) < 0)
				err(1, "failed read() on evq");

			while (fgets(buf, sizeof(buf), in))
				fputs(buf, stdout);
			fflush(stdout);
		}
		if (FD_ISSET(0, &rd)) {
			fgets(buf, sizeof(buf), stdin);
			fputs(buf, out);
			fflush(out);
		}
	}
	return 0;
}