Safe coding practices (was Re: Bug in users command)

D'Arcy J.M. Cain darcy at druid.uucp
Thu Feb 7 04:00:55 AEST 1991


In article <1991Feb03.181937.9090 at convex.com> Tom Christiansen writes:
>From the keyboard of chip at tct.uucp (Chip Salzenberg):
>:Each site (or programmer) needs to write fgetline() or its moral
>:equivalent using getc(), malloc() and realloc(), and use it every time
>:gets() or fgets() would have been used.
>
>Ug.  If it's written once, published, and made available for use free
>of charge *and* without viral strings attached, each site or programmer
>won't have to re-invent the wheel.  Of course, sites without source are
>still largely at the mercy of vendors.

OK, I have made a stab at it.  Of course the first thing to do is define
it.  I have whipped up a man page for the way I think this function
should work and it is included here.  While I am at it the code to implement
it is also included.  (Yah, source but it's so small.)

Anybody want to use this as a starting point?  I have made it completely
free so that no one has to worry about licensing restrictions.  Besides,
it's so trivial who couldn't duplicate it in 20 minutes anyway?

----------------------------- cut here --------------------------------
/*
NAME
	fgetline

SYNOPSIS
	char *fgetline(FILE *fp, int exclusive);

DESCRIPTION
	Reads a line from the stream given by fp and returns a pointer to
	the string.  There is no length restiction on the returned string.
	Space is dynamically allocated for the string as needed.  If the
	exclusive flag is set then the space won't be reused on the next
	call to fgetline.

RETURNS
	A pointer to the string without the terminating EOL is returned if
	successful or NULL if there was an error.

AUTHOR
	D'Arcy J.M. Cain (darcy at druid.UUCP)

CAVEATS
	This function is in the public domain.

*/

#include	<stdio.h>
#include	<malloc.h>

/* I originally was going to use 80 here as the most common case but */
/* decided that a few extra bytes to save a malloc from time to time */
/* would be a better choice.  Comments welcome.  */
#define		CHUNK	128

static char	*buf = NULL;

char	*fgetline(FILE *fp, int exclusive)
{
	size_t	sz = CHUNK;	/* this keeps track of the current size of buffer */
	size_t	i = 0;		/* index into string tracking current position */
	char	*ptr;		/* since we may set buf to NULL before returning */
	int		c;			/* to store getc() return */

	/* set buf to 128 bytes */
	if (buf == NULL)
		buf = malloc(sz);
	else
		buf = realloc(buf, sz);

	/* check for memory problem */
	if (buf == NULL)
		return(NULL);

	/* get characters from stream until EOF */
	while ((c = getc(fp)) != EOF)
	{
		/* check for end of line */
		if (c == '\n')
			goto finished;		/* cringe */

		buf[i++] = c;

		/* check for buffer overflow */
		if (i >= sz)
			if ((buf = realloc(buf, (sz += CHUNK))) == NULL)
				return(NULL);
	}

	/* see if anything read in before EOF */
	/* perhaps some code to preserve errno over free() call needed? */
	if (!i)
	{
		free(buf);
		buf = NULL;
		return(NULL);
	}

finished:
	buf[i++] = 0;

	/* the realloc may be overkill here in most cases - perhaps it */
	/* should be moved to the 'if (exclusive)' block */
	ptr = buf = realloc(buf, i);

	/* prevent reuse if necessary */
	if (exclusive)
		buf = NULL;

	return(ptr);
}
---------------------------------------------------------------------------

-- 
D'Arcy J.M. Cain (darcy at druid)     |
D'Arcy Cain Consulting             |   There's no government
West Hill, Ontario, Canada         |   like no government!
+1 416 281 6094                    |



More information about the Comp.bugs.4bsd.ucb-fixes mailing list