argv ==> stdin, got it

mcvoy at uwvax.UUCP mcvoy at uwvax.UUCP
Sat Nov 22 14:11:33 AEST 1986


In article <4379 at mimsy.UUCP> chris at mimsy.UUCP (Chris Torek) writes:
>In article <2976 at rsch.WISC.EDU> mcvoy at rsch.WISC.EDU (Lawrence W. McVoy) writes:
>>/*
>> * code to fork a child and have control of the child's stdin/out
>> * from usenet.  Works.  Fast, too.  The idea is that the command line
>> * is fed to the stdin of the child.  This is so that you don't have
>> * to f*ck with the stupid code in y.tab.c or lex.yy.c.  It should work
     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>> * for anything that wants stdin.
>> */
>
>So what is so hard about making lex read argv rather than stdin?
>Here is a trivial parser that accepts only `foo bar;'.  Note that
>the semicolon must be quoted to protect it from the shell.

[ about 100 lines of code deleted, showing how to make lex take input
 from argv ]

Well,  I tried something like that.  It works fine with lex, but not with 
yacc.  Yacc must actually diddle various input buffers and just redefining
the input and unput routines was not enough to make it fly.  Now, I know
the hackers out there (such as chris) are going to say, "look, it's easy.
All you have to do is be intimately familiar with the way lex & yacc
interact.  And it's only about 20 lines of code spread over lex.yy.c,
y.tab.c, and /usr/src/usr.lib/libl/somefile."  Well, a better solution
has been suggested.  Just use a pipe and send the command line into
the pipe.  As someone pointed out, for a cl you don't even have to
fork, the pipe is big enough to buffer it up.  Here's the code,
and thanks for all the help...

# include	<stdio.h>
# define	write_end	in[1]
# define	read_end	in[0]

/*
 * code to stuff the command line into a pipe and then call a function that 
 * expects input from stdin.
 * suggested by - aweinste at diamond.bbn.com
 * Bugs - the cl had better be smaller tthan the pipe or this code
 * will hang (blocked on the write).
 */
main(argc, argv)
    char** argv;
{
    int in[2];
    int i;

    /* set it up so that stdin is the read side of pipe (in[1]) */
    pipe(in);
    close(0);
    dup(read_end);	/* stdin <-- pipe */
    close(read_end);	/* don't need this (now extra) fd */

    /* stuff the cl into the write side of the pipe */
    for (i=1; i<argc; i++) 
	write(write_end, argv[i], strlen(argv[i]));
    write(write_end, "\n", strlen("\n"));
    close(write_end);

    /* call the routine that wants input from stdin */
    return yyparse();
}

yyerror(s)
    char* s;
{
    fprintf(stderr, "%s\n");
}

-- 
Larry McVoy 	        mcvoy at rsch.wisc.edu, 
      		        {seismo, topaz, harvard, ihnp4, etc}!uwvax!mcvoy

"They're coming soon!  Quad-stated guru-gates!"



More information about the Comp.unix.questions mailing list