[comp.lang.c] Assigning an array to a FILE structure

tomr@ashtate (Tom Rombouts) (10/11/90)

They say the only stupid question is the one that isn't asked, so:

Is it possible using the ANSI stream I/O functions to assign an
array to a FILE structure so that fgetc() etc. will work on it?

To wit, I want to create code like this:


FILE * input_source;
char mybuffer[] = "This is text that I sometimes want to parse";

if( read_input_from_disk )
  input_source = fopen("somefile", "rb");
else
  input_source = make_virtual_file( mybuffer, strlen(mybuffer) );

ch = fgetc( input_source );


After RTFM'ing, it seems like this might be possible.  Perhaps one
can explicitly assign the FILE structure members.  Or, maybe there is
a way to attach the buffer to stdaux or stdin.  (If it matters I am
using MSC 5.1 in MS-DOS, but want to stay portable if I can.)  This
would seem like a common trick.  Netland, I seek your guidance....


Tom Rombouts  Torrance Techie  tomr@ashtate.A-T.com  V:(213) 538-7108

chris@mimsy.umd.edu (Chris Torek) (10/11/90)

In article <1389@ashton.UUCP> tomr@ashtate (Tom Rombouts) writes:
>Is it possible using the ANSI stream I/O functions to assign an
>array to a FILE structure so that fgetc() etc. will work on it?

No, not in ANSI C.  On some systems you can open arbitrary functions,
however, and you could thus write your own `read' function that returns
more of the string.

The nice thing about opening `functions' for I/O is that the functions
themselves can open other streams.  For instance:

	struct lzwdata {
		FILE	*l_input;	/* compressed input stream */
		... more stuff needed to implement LZW ...
	};

	/* Refill the given buffer by doing LZW decompression. */
	size_t lzwread(void *cookie, char *buf, size_t n) {
		struct lzwdata *l = cookie;

		... loop reading bytes from l_input ...
		return (count);
	}

	struct ar_data {
		FILE	*ar_input;	/* input data stream */
		long	ar_bytesleft;	/* bytes left in current input */
		... more stuff needed to handle several `files' per file ...
	};
	/* Refill the given archive input stream */
	size_t ar_read(void *cookie, char *buf, size_t n) {
		struct ar_data *ar = cookie;
		size_t ret;

		if (ar->ar_bytesleft == 0)
			return (0);	/* EOF */
		if (ar->ar_bytesleft < n)
			n = cookie->ar_bytesleft;
		ret = fread(buf, 1, n, ar);
		ar->ar_bytesleft -= ret;
		return (ret);
	}

Now if you open an archive and then wrap the lzw decompresser around
it, you get a stream that reads the next compressed subfile from the
archive, while if you open the lzw decompresser and wrap the archive
reader around it, you get a stream that reads the next subfile from
the compressed archive.

Programmers in other languages will recognize this as equivalent to
coroutines.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 405 2750)
Domain:	chris@cs.umd.edu	Path:	uunet!mimsy!chris

steve@taumet.com (Stephen Clamage) (10/11/90)

tomr@ashtate (Tom Rombouts) writes:

>They say the only stupid question is the one that isn't asked, so:

>Is it possible using the ANSI stream I/O functions to assign an
>array to a FILE structure so that fgetc() etc. will work on it?

There is no portable way to do this in ANSI C.  You could assign
your own buffer to the FILE structure, and figure out how to set the
related pointer and size fields of the structure to correspond.  But the
stdio library is still going to assume an open file somewhere, and try to
use low-level read calls to get more data -- this won't work, of course.

You can do this easily in C++, since the stream (and iostream) library
explicitly supports using a character array as if it were a file --
all the I/O and EOF operations work correctly with no attention
from the programmer.
-- 

Steve Clamage, TauMetric Corp, steve@taumet.com