Source

pcw / cwd.c

Full commit
#include <unistd.h>
#include <signal.h>
#include <sys/inotify.h>
#include <sys/wait.h>
#include <stdio.h>
#include <ftw.h>
#include <string.h>

#define PATH_MAX    1024
#define MAX_OPENFD  4
#define MAX_WATCH   512

int evq, init;
char paths[MAX_WATCH][PATH_MAX] = {0};
int wins[MAX_WATCH] = {0};

void win(int wd)
{
    char in[PATH_MAX], out[PATH_MAX];

    if (wins[wd])
	return;

    strcpy(in,  paths[wd]);
    strcpy(out, paths[wd]);
    strcat(in , "/in" );
    strcat(out, "/out");

    printf("about to run urxvt -title %s -e cw %s %s\n", paths[wd], out, in);

    if ((wins[wd] = fork()) == 0) {
	execlp("urxvt", "urxvt", "-title", paths[wd], "-e", "rlwrap", "cw", out, in, NULL);
	err(1, "failed on execlp cw");
    } else {
	printf("child has pid %d\n", wins[wd]);
    }
}

int add_dir(const char *fpath, const struct stat *sb, int typeflag)
{
    int wd;
    char out[PATH_MAX];
    struct stat st;

    if (!(typeflag & FTW_D))
	return;

    if ((wd = inotify_add_watch(evq, fpath, IN_CREATE | IN_MODIFY)) < 0)
	warn("failed on inotify_add_watch on %s", fpath);

    if (paths[wd][0] == '\0') {
	strcpy(paths[wd], fpath);
	printf("added %s\n", paths[wd]);
	strcpy(out, fpath);
	strcat(out, "/out");
	if (!init && stat(out, &st) == 0)
	    win(wd);
    } else {
	printf("existed %s\n", paths[wd]);
    }

    return 0;
}

int find(int *haystack, int needle, int len)
{
    int i;

    for (i = 0; i < len; i++)
	if (haystack[i] == needle)
	    return i;

    return -1;
}

void sigchld(int unused) {
    pid_t pid;
    int wd;

    if(signal(SIGCHLD, sigchld) == SIG_ERR)
	err("failed installing SIGCHLD handler");

    while((pid = waitpid(-1, NULL, WNOHANG)) > 0) {
	printf("killed child with pid %d ", pid);
	if ((wd = find(wins, pid, MAX_WATCH)) > -1) {
	    printf("wd %d path %s\n", wd, paths[wd]);
	    wins[wd] = 0;
	} else {
	    printf("no wd...\n");
	}
    }
}

int main(int argc, char **argv)
{
    char buf[4096];
    int i, len;
    struct inotify_event *cur;

    sigchld(0);

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

    init = 1;
    ftw(argv[1], add_dir, MAX_OPENFD);
    init = 0;

    for (;;) {
	if ((len = read(evq, buf, sizeof(buf))) < 0)
	    warn("failed to read from inotify event queue");
	for (cur = (struct inotify_event *)buf; (char *)cur - buf < len; cur += sizeof(struct inotify_event) + cur->len) {
	    if (cur->mask & (IN_CREATE | IN_ISDIR))
		ftw(argv[1], add_dir, MAX_OPENFD);
	    if (cur->mask & (IN_CREATE | IN_MODIFY) && !strcmp(cur->name, "out"))
		win(cur->wd);
	}
    }

    return 0;
}