pipe flushing

Joseph S. D. Yao jsdy at hadron.UUCP
Fri Jan 2 21:46:10 AEST 1987


I am not the Throop, but here's how:

In article <658 at bath63.ux63.bath.ac.uk> ma6nrr at ux63.bath.ac.uk (Rashbrook) writes (to Wayne Throop):
>a) mail me the fflush manual (I can't find it anywhere)

Try 'man 3 fclose'.

>b) show me what to do:

In the below, some of what I say is flagged by '*' in the LHC.
These lines have to do with style.  This is not irrelevant,
however anyone who wishes to flame those lines should be
deprecated as a crashing boor.  Style helps improve programming
performance; but by its very name one should assume that there
is more than one way to do each of these things.

Some mangling of the program text bbelow has occured, in an
attempt to convince inews (the real culprit) that more
information is going out than came in.

...
>#define lenu (unsigned)len
>char buffer[128];			/* read/write buffer
>					   arbitrary length */
* Should be local to parent() [see note on stop()].
>int pipe0[2],pipe1[2],tty,outfile,len;
* Should be local as appropriate, and passed as parameters.
>void exit();	/* this is for lint */
* Should be local to main() [see note on stop()].
>main(argc,argv,envp)
...
>{
>  if (argc!=3)
>  {	/* bad no. of args */
... What about programs with arguments?
>    fprintf(stderr,"Usage: %s file program\n",*argv);
>    exit(2);
>  }
>  if (outfile=creat(*++argv,0666),outfile==EOF)
*/2:
    I would have made the outfile = ... and if (...) two
    separate statements, to eschew confusion.  Also, I never
    make files 0666: that way lies lack of data integrity.
>  {	/* attempt to open file */
>    fprintf(stderr,"%s: cannot open\n",*argv);
>    exit(1);
>  }
>  pipe(pipe0);	/* pipe for i/p to program   */
>  pipe(pipe1);	/* pipe for o/p from program */
... MUST test these pipe()s for correct return!  Either < 0
    or == ERROR (if defined) to test for error.
>  if (fork()) parent(); else child(++argv,envp);
... Same.  best is switch(fork()) ...
>		/* now execute required program */
>  exit(0);	/* this is for lint */
... System 5 lint requires that these exit()s be return()s;
    I was unaware that any lint required exit()s.
>}
>stop()
>{
... (*/2) The only reliable thing to do in an interrupt
    handler is to set a flag.  Best to set a flag here,
    and have parent() take notice of it and return to
    main(), which then exit()s [or return()s, per above].
>  while ((len=read(pipe1[0],buffer,128))>0)
>  {	/* clear output buffer */ ...  >  } >exit(0);
>}
>parent()	/* parent writes to outfile */
>{
>  int (*signal())();	/* this is for lint */
>  close(pipe0[0]);		/* enable read from pipe without waiting */
... close(pipe1[1]);
>  fcntl(pipe1[0],F_SETFL,fcntl(pipe1[0],F_GETFL,0)|O_NDELAY);
... (*sigh*)  Yes, this works for pipes, even though the docs
    say it only works for tty's.  But (just because of the way
    it's defined) I'd rather have a real int than 0 as the arg.
    (man 2 fcntl)  Also, O_NDELAY is for open() or ioctl();
    FNDELAY is for fcntl().  (Yes, one is defined as the other
    in your include file.  So what?  Say What You Mean is the
    whole of the law!)
>  tty=open("/dev/tty",O_RDWR | O_NDELAY);	/* open to console */
... MUST check return values.
>  signal(18,stop);	/* trap program's death */
... Do you perchance mean SIGCHLD?  Which is  n o t  18!
    Always use symbolic constants.  That way, you don't make
    silly mistakes like this.  Also, if you should try to
    compile this on a machine which does not have SIGCHLD
    in its <signal.h>, you immediately know.
>  for (;;)
>  {	/* transfer i/o until program dies */
>    len=read(tty,buffer,128);
... Don't do the next two if lenu == 0 !
>    write(pipe0[1],buffer,lenu);
>    write(outfile,buffer,lenu);
... This code seems to assume lockstep read-from-tty / write-to-tty
    performance on the part of the child.  If that's the way
    it actually works (and if no message is >128 chars), fine.
    Otherwise, you should fork one process to funnel in each
    direction, OR use Berkeley's SIGIO (assuming BSD, but so
    do you) to sample reads, and read each one 'til dry; OR
    ...  (The problem here is getting out of sync.)
>    len=read(pipe1[0],buffer,128);
>    if (len==EOF) stop();	/* so it's messy,but it's the
>				   only way with O_NDELAY    */
... EOF is a stdio concept.  It happens to be equal to what read()
    returns on error.  Partly coincidence.  This same value also
    happens to be what is returned on a possible delay!
... Again, don't do these if lenu == 0 .
>    write(tty,buffer,lenu);
>    write(outfile,buffer,lenu);
>  }
>}
>child(argv,envp)
...
>{
>  close(0);	/* these aren't needed any more */
>  close(1);
>  if (dup(pipe0[0])!=0 || dup(pipe1[1])!=1)
>  {	/* connect pipes to stdin/out */
>    fprintf(stderr,"error in pipes\n");
>    exit(1);
>  }
>  close(pipe0[1]); >  close(pipe1[0]);
... Also, close(pipe0[0]); close(pipe1[1]); since they're dup'd.
>  close(outfile);
... Should never have been opened before the fork().
>  setbuf(stdout,(char *)0);
... Unfortunately, this does  n o t  affect any future exec'd program.
    (See below)
>/* test lines */ >printf("Hit return:\n"); >while (getchar()!='\n');
>/* this correctly prints up prompt,
>   waits for return,then acts as
>   program options |tee file */
>  if (execve(*argv,argv+1,envp)==EOF) fprintf(stderr,"%s: cannot execute\n",*argv);	/* finally execute program (hopefully!) */
>}	/* so I don't need an if,so what?	*/

An EOF is  n o t  the all-purpose error return.  Stdio only.

The setbuf() changes flags and elements in the iobuf structure
in the current process image (program memory).  When you exec
a new program, that reads in new program memory.  The structure
would have to be re-initialised from within that program; or
fflush() would have to be called every time you write: stdout
is always buffered if it isn't hooked up to a tty.  I think
that's what you were asking about.

There's more wrong with this, but I'm not sure what.
-- 

	Joe Yao		hadron!jsdy at seismo.{CSS.GOV,ARPA,UUCP}
			jsdy at hadron.COM (not yet domainised)



More information about the Comp.lang.c mailing list