Friday, June 20, 2008

Birthday... (and what good is a fifo?)

I've been a professional software engineer for almost 20 years and a net junkie for even longer, and I've never blogged.

Until now, that is.

I plan on posting about my history and MO as a programmer, and about some of the things I've come up with along the way to make my job easier and/or more fun.

Also, I'm a total geek who loves movies, tech gadgets, politics, cars, etc. etc. etc... I'm sure I'll fold thoughts and observations completely unrelated to programming here as well.

Here's a little morsel to kick things off...


#include <stdio.h>

#define MAXCMDLINE 1024
int simple_cli(char *filename,int (*parser)(char *cmdline),int count)
{
FILE *ifile = NULL;
char cmdline[MAXCMDLINE];
int status = 0;

for (cmdline[0]=0;count-- && !status && (ifile = fopen(filename,"r")) != NULL;fclose(ifile),cmdline[0]=0)
while (fgets(cmdline,sizeof(cmdline)-1,ifile) && (!(status=parser(cmdline))));

return status;
}

int parser(char *cmdline)
{
printf(">> %s",cmdline);
return 0;
}

main(int argc, char *argv[])
{
char *filename=argc>1?argv[1]:"/tmp/test.in";
simple_cli(filename,parser,1);
}



(Note: My preferred environment is GNU/Linux, that's what I'll target in this blog.)

This little program should compile with gcc into an executable with no problem...
The meat of it is the function "simple_cli". All it does is:

  • Given
  1. a filename,
  2. a pointer to a function that takes a char* and returns an int (the line-processor),
  3. and a repetition count,
  • it opens the file,
  • reads it line-by-line, executing the line-processor on each line,
  • until it reaches either
  1. end-of-file, or
  2. the line-processor returns a non-zero value,
  • whereupon it closes the file, and
  • returns the last return value of the line-processor.
Simple, right? I know, you're asking yourself why you're wasting your time reading this.

Well, the magic isn't really in this program, but in the environment it runs in, in the file it reads from to be precise;
A simple invocation could look like this:

bash-3.2$ echo Hello, world\! > infile
bash-3.2$ cat infile
Hello, world!
bash-3.2$ a.out infile
>> Hello, world!
But here's a trickier one:

bash-3.2$ mkfifo infifo
bash-3.2$ a.out infifo &
[2] 29875
bash-3.2$ cat > infifo
Hello world!
>> Hello world!
Hello again!
>> Hello again!
[2]+ Done a.out infifo
(Just before that last line, I hit , i.e. EOF, ending the "cat" process and subsequently the "a.out" process.)

In the second example, the simple_cli function opens whatever filename you passed in, and in this case it's a special file known as a fifo, a.k.a. a "named pipe." The cool thing about fifos is that fifo readers and writers block (by default) until the peer attaches to the fifo; in that second run of a.out above, the program was sitting there waiting for me to type in "Hello world!" and "Hello again!", and used the "parser" function to immediately spit them back out.

So, depending upon how smart your "parser" routine is, and where you call "simple_cli", you can do all kinds of neat tricks; Smart "asserts," simple config-file readers, embedded CLIs or extension languages... These are things I'll get into down the road.