Stdio addition for string I/O

Richard O'Keefe ok at edai.UUCP
Tue Apr 17 06:11:45 AEST 1984


I have often wanted to do something like this:

	int   bufsiz = 4*100+1;
	char *buffer = malloc(bufsiz);
	FILE *fs = fsopen(buffer, bufsiz, 'w'); 

	for (n = 0; n < Nmax /* <= 100 */; n++)
	    fprintf(fs, "%3d ", thingy[n]);
	putc('\0', fs);
	fclose(fs);

which of course you cannot with sprintf (useful though it is).
If you can do it in Fortran, why not C?

Here is an addition to the 4.1bsd stdio package which lets you
open memory areas as streams.  The files are

	fsopen.3s	- manual page
	fsopen.c	- source file
	fstest.c	- trivial test driver

cat >fsopen.3s <<'EOF'
.TH FSOPEN 3S local
.SH NAME
fsopen \- open a string as a stream
.SH SYNOPSIS
.B #include <stdio.h>
.PP
.SM
.B FILE
.B *fopen(area, size, type)
.br
.B char *area;
.br
.B int size;
.br
.B char *type;
.PP
.SH DESCRIPTION
.I Fsopen
is similar to fopen(3), except that the stream it returns will
read from or write into the memory area identified by its first
argument.
.I Fsopen
returns a pointer to be used to identify
the stream in subsequent operations.
.PP
.I Type
is a character string having one of the following values:
.TP 5
"r"
open for reading
.ns
.TP 5
"w"
open for writing
.ns
.TP 5
"a"
append: open for writing, but start at the first NUL
character in the area instead of at the beginning.
.PP
Unlike fopen(3),
.I type
may not be followed by a '+'.
.PP
.I Size
is the number of bytes in the area.  When reading, getc(3s) will
return EOF as soon as this many characters have been read.
When writing, putc(3s) will stop writing as soon as this many
characters have been written and will indicate end of file.
.I Size
may be negative.  This means that strlen(area) is to be used.
This is useful with type 'r'.  It does not make sense with
type 'a', as no further characters could then be written.
.SH PURPOSE
sscanf(3s) and sprintf(3s) can only be used to read or write
a fixed number of items from/to a string.
.I Fsopen
makes the memory area appear exactly like any other file, so
multiple, repeated, and conditional reads and writes can be done.
.SH "SEE ALSO"
open(2),
fopen(3s),
fclose(3s),
sscanf(3s),
sprintf(3s)
.SH DIAGNOSTICS
.I Fsopen
returns the pointer
.SM
.B NULL
if all the stream descriptors are in use, or if
.I type
is ill-formed.
.SH BUGS
.I Fsopen
is only known to work under 4.1bsd UNIX.
.I Fclose
does not know about in-memory streams, and
will not add a closing NUL character to a 'w' stream.
You must call
.PP
	putc(fs, '\0');
.PP
or
.PP
	fprintf(fs, '%c', '\0');
.PP
yourself before calling fclose(fs).
'EOF'
cat >fsopen.c <<'EOF'
#include <stdio.h>

extern FILE *_lastbuf;

FILE *fsopen(area, size, mode)
    char *area;		/* the memory area to be read/written */
    int   size;		/* the size of the area in bytes      */
    char *mode;		/* "r", "w", or "a"		      */
    {
	register FILE *iop = &_iob[3];

	while (iop->_flag&(_IOREAD|_IOWRT|_IORW)) 
	    if (iop++ >= _lastbuf) return NULL;

	if (size < 0) {
	    register char *t = area;
	    register int n = 0;
	    while (*t++) n++;
	    size = n;
	}

	switch (*mode) {
	    case 'a':
		while (*area && size > 0) area++, size--;
	    case 'w':
		iop->_flag = _IOWRT|_IOSTRG;
		break;
	    case 'r':
		iop->_flag = _IOREAD|_IOSTRG;
		break;
	    default:
		return NULL;
	}

	iop->_ptr = iop->_base = area,
	iop->_cnt = size;
	return iop;
    }


'EOF'
cat >fstest.c <<'EOF'
#include <stdio.h>
extern FILE *fsopen();

main()		/*  This is a test driver for fsopen  */
    {
	static char string[] =
"This is line 1.\n\
This is line 2.\n\
Here is a NUL:\n\0\
But there is more after that!\n";
	FILE *fs;
	int c;
	int n;

	fs = fsopen(string, -1, "r");
	while ((c = getc(fs)) != EOF) putchar(c);
	fclose(fs);
	fs = fsopen(string, sizeof string - 1, "r");
	n = 0;
	while ((c = getc(fs)) != EOF) putchar(c), n++;
	fclose(fs);
	printf("%d %d\n", n, sizeof string);
	fs = fsopen(string, sizeof string, "w");
	for (n = 33; n < 48; n++) fprintf(fs, " %c", n);
	fprintf(fs, "\n%c", 0);
	fclose(fs);	/* it'd be nice if this added the NUL character */
	printf("%s", string);
    }


'EOF'

Please don't tell me about bugs or how to make it run under System 3.
Just send a better version to net.sources.  If Berkeley and/or AT&T
filled this gaping hole in stdio themselves that'd be better yet.



More information about the Comp.sources.unix mailing list