Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Redirect stdin in C program to another process

Tags:

c

unix

stdin

I have a C program, and I'd like to have it filter all its input with tr. So, I'd like to start up tr as a child process, redirect my stdin to it, then capture tr's stdout and read from that.

Edit: here's the code I have so far, which doesn't work. It segfaults instantly, but I don't understand why:

#include <stdlib.h>
#include <stdio.h>

int main(int argc, char** argv){
  int ch;
  int fd = stripNewlines();

  while((ch = getc(fd)) != EOF){
    putc(ch, stdout);
  }

  return 0;
}

int stripNewlines(){
  int fd[2], ch;
  pipe(fd);

  if(!fork()){
    close(fd[0]);

    while((ch = getc(stdin)) != EOF){
      if(ch == '\n'){ continue; }
      putc(ch, fd[1]);
    }

    exit(0);
  }else{
    close(fd[1]);

    return fd[0];
  }
}

Edit: Turns out this was two things: one was that my header didn't define stdin and stdout as 0 and 1, so I was actually reading/writing to totally random pipes. The other is that for some reason getc and putc don't work how I'd expect, so I had to use read() and write() instead. If I do that, it's perfect:

#include <stdlib.h>
#include <stdio.h>

int main(int argc, char** argv){
  int ch;
  int fd = stripNewlines();

  while(read(fd, &ch, 1) == 1){
    write(1, &ch, 1);
  }

  return 0;
}

int stripNewlines(){
  int fd[2];
  int ch;
  pipe(fd);

  if(!fork()){
    close(fd[0]);

    while(read(0, &ch, 1) == 1){
      if(ch == '\n'){ continue; }
      write(fd[1], &ch, 1);
    }

    exit(0);
  }else{
    close(fd[1]);
    return fd[0];
  }
}
like image 725
Ross Andrews Avatar asked Apr 21 '10 03:04

Ross Andrews


2 Answers

Reading it from stdin makes life more difficult. If you can live with reading from another FILE *, it's pretty easy to use popen() to spawn tr, and read from the FILE * it returns.

Edit: if you can't do that, then you need to get into a bit of ugliness. Start with using popen to spawn tr with its output redirected. Then use fileno to get the file numbers associated with that FILE * and with stdin. Finally, use dup2 to associate stdin's file descriptor with the pipe from tr.

like image 76
Jerry Coffin Avatar answered Oct 18 '22 19:10

Jerry Coffin


See popen(3). Basically all you need to do is

FILE *in = popen("tr <args>", "r");

and then read from in.

like image 32
Chris Dodd Avatar answered Oct 18 '22 21:10

Chris Dodd