file descriptor vs. file pointer closing

Chris Torek chris at mimsy.UUCP
Sun Aug 14 01:59:55 AEST 1988


In article <1122 at ssc-bee.ssc-vax.UUCP> lee at ssc-vax.UUCP (Lee Carver) writes:
>Why should file descriptor closing neccesarily close the file
>pointer?  Especially when there are more then one file descriptors
>associated with the file pointer.  The following is ~180 lines of
>discussion.

It does not; and the discussion is pointless, since the entire mechanism
is different.  (And boy does Lee feel silly :-) ...)

>The second execution of readtkn [where the first was from a file, not
>a terminal, and both are from the same script] finds an end of file.

The second finds EOF because the first read all the data and left the
seek pointer of the underlying file descriptor---shared between each
invocation of readtkn and the shell that starts them, since the shell
provides it and creates it only once---pointing at the end of the file.
For instance, if a.out is compiled from the program

	#include <stdio.h>
	main() {
		char buf[100];
		(void) fgets(buf, sizeof buf, stdin);
		(void) fputs(buf, stdout);
		exit(0);
	}

then running the command

	(a.out > /dev/null; a.out) < /etc/termcap

will *not* print the second line of /etc/termcap!  Instead, it will
print a (probably partial) n'th line, by reading something from 512,
1K, 2K, 4K, 8K, or 16K bytes after the first character (the number of
bytes skipped depends on your Unix variant and the block size of the
file system in which /etc/termcap resides).

What happened?  Simple: stdio read the first n kbytes of /etc/termcap,
returned the first line, the first a.out exited, and the second a.out
read the second n kbytes.

How can you work around it?  (1) Stop using stdio.  The resulting code
will be considerably less efficient.  (2) Use stdio, but use a separate
file, or reset the seek pointer, for each invocation of the program:

(1)
	a.out < /etc/termcap > /dev/null
	a.out < /etc/termcap		# prints first line

(2)
	/* seektozero: */ main() { (void)lseek(0,0L,0); exit(0); }

	(a.out >/dev/null; seektozero; a.out) </etc/termcap
					# also prints first line

(2, improved)
	(a.out.new >/dev/null; a.out) </etc/termcap
					# prints second line

The modified a.out.new has one new line before exit(0):

	/*	long ftell();	/* should be declared in stdio.h */

		(void) lseek(stdin, ftell(stdin), 0);
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris at mimsy.umd.edu	Path:	uunet!mimsy!chris



More information about the Comp.unix.wizards mailing list