#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <signal.h>

/* Runtil (run until)
   Richard H. Tingstad

   [firstname].[lastname]@gmail.com
   http://drop.by

   Compile like so: gcc -o runtil runtil.c

 */

int alive = 1;
pid_t pid;
int iopipe[2];
void sighandler(int);

int main(int argc, char* argv[]) {

  if (argc < 3) {
    printf("Usage: %s STOPSTRING FILE [ARG0] [ARG1]...\nExecute FILE with arguments ARG0, ARG1, ..., and kill FILE if it writes STOPSTRING to standard out.\n\nRichard H. Tingstad\n", argv[0]);
    exit(0);
  }
  int i;
  char* argarr[argc-1];
  for(i = 2; i < argc; i++) {
    argarr[i-2] = argv[i];
  }
  argarr[argc - 2] = (char *)NULL;

  if(pipe(iopipe)) {
    fprintf(stderr, "Pipe error\n");
    exit(1);
  }

  if((pid = fork()) == -1) {
    fprintf(stderr, "Fork error\n");
    exit(1);
  }
  if(pid) { /* parent process */
    signal(SIGINT, sighandler);
    signal(SIGTERM, sighandler);
    dup2(iopipe[0], 0);
    close(iopipe[1]); /* close unused side of pipe */
    /*setvbuf(stdout, (char*)NULL, _IONBF, 0); */  /* set non-buffered output on stdout */

    int len = strlen(argv[1]);
    char* s = (char*)malloc(sizeof(char) * (len + 1));
    s[len] = '\0';

    int timeout = len + len + len;
    int time = 0;
    int p = 0;
    int status;
    int retval = -1;
    while(1) {
      if (alive) {
	retval = waitpid(-1, &status, WNOHANG);
	if (retval > 0) { /* child has terminated */
	  alive = 0;
	  /*printf("%s exited with code %d\n", argv[2], status); */
	}
      }
      if (scanf("%c", &s[len - 1]) == -1) {
        if (++time > timeout && !alive) {
          printf("%s", &s[len - p - 1]);
	  p = len;
          break;
        }
      }
      else {
        time = 0;
        if (++p == len) {
          printf("%s", s);
          p = 0;
        }
        if (strncmp(s, argv[1], len) == 0) {
          printf("%s", &s[len - p]);
	  kill(pid, SIGKILL); /* kill child/program */
	  alive = 1; /* to avoid last letters to be printed again in if(!alive... (still small chance of double printing) */
          break;
        }
        for (i = 0; i < len - 1; i++)
          s[i] = s[i + 1];
      }
    }
    if (!alive && p != len && p != 0) printf("%s", &s[len - p - 1]);
    if (strncmp("\n", &s[len - 1], 1) != 0) printf("\n");
  }
  else { /* child process */
    dup2(iopipe[1], 1); /* pipe stdout to parent process */
    close(iopipe[0]); /* close unused side of pipe */
    execvp(argv[2], argarr); /* run program */
  }
  return 0;
}

void sighandler(int signum) {
  switch (signum) {
  case (SIGINT): /* ctrl+c */
    kill(pid, SIGKILL);
    exit(1);
    return;
  case (SIGTERM):
    kill(pid, SIGKILL);
    exit(1);
    return;
  default:
    alive = 0;
    return;
  }
}
