[comp.sources.misc] v03i018: getline -- get a long line

daveb@geac.UUCP (David Collier-Brown) (05/16/88)

comp.sources.misc: Volume 3, Issue 18
Submitted-By: "David Collier-Brown" <daveb@geac.UUCP>
Archive-Name: getline

 The following is a function to get a long (possibly arbitrarily
long) line from a stream.  I've written it twice, so I guess it may
be useful to others.
  Tested ONLY on a Vax-Ultrix machine, so beware of machine
dependencies that got by my jaundiced eye.

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  getline.c Makefile getline.1
# Wrapped by daveb@geac on Mon May 16 11:00:49 1988
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f getline.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"getline.c\"
else
echo shar: Extracting \"getline.c\" \(1777 characters\)
sed "s/^X//" >getline.c <<'END_OF_getline.c'
X/*
X * getline.c -- get a line into a variable-size cache. Otherwise the
X *	behavior is identical to fgets.
X */
X#include <stdio.h>
X
X#define BADEXIT 3	/* Nonzero is sufficent. 3 implies badness. */
X#define INITIAL_CHUNK 60  /* Purely a heuristic value. */
X#define CHUNKSIZE 10
X
X/* 
X * getline -- actually get the line. Behaves as expected on an eof
X *	at the beginning of a line or at end of file.  Dependant on
X *	the behavior of fgets as to what happens when an EOF is entered 
X *	from a terminal in the middle of a line.  Under Ultrix/Berkley
X *	TTY handling, the ^D seems to disappear... 
X */ 
X char *
Xgetline(fp) FILE *fp; {
X	extern char *realloc(), *malloc();
X	extern char *lastCharacter();
X	extern void exit();
X	static char *cache = NULL;
X	static int cacheSize = 0;
X
X	if (cache == NULL) {
X		/* Its the first time... */
X		if ((cache= malloc(INITIAL_CHUNK)) == NULL) {
X			(void) fprintf(stderr,"getline ran out of space (can't happen)\n");
X			exit(BADEXIT);
X		}
X		cacheSize = INITIAL_CHUNK;
X	}
X
X	/* For all cases... */
X	if (fgets(cache,cacheSize,fp) == NULL) {
X		/* We hit an eof in the last line. */
X		return NULL;
X	}
X	while (*lastCharacter(cache) != '\n') {
X		/* We have to read some more... */
X		if ((cache= realloc(cache,(unsigned)cacheSize+CHUNKSIZE)) == NULL) {
X			(void) fprintf(stderr,"getline ran out of space: line longer than available memory\n");
X			exit(BADEXIT);
X		}
X		if (fgets(&cache[cacheSize-1],CHUNKSIZE+1,fp) == NULL) {
X			cacheSize += CHUNKSIZE;
X			return cache;
X		}
X		else {
X			cacheSize += CHUNKSIZE;
X		}
X	}
X	/* We've got a line ending in \n... */
X	return cache;
X}
X
X
X static char *
XlastCharacter(p) char *p; {
X	while (p[1] != '\0')
X		p++;
X	return p;
X }
X
X#ifdef TEST
Xmain() {
X	char	*p;
X
X	while ((p=getline(stdin)) != NULL)
X		fputs(p,stdout);
X}
X#endif
X
END_OF_getline.c
if test 1777 -ne `wc -c <getline.c`; then
    echo shar: \"getline.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f Makefile -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"Makefile\"
else
echo shar: Extracting \"Makefile\" \(864 characters\)
sed "s/^X//" >Makefile <<'END_OF_Makefile'
X# 
X# getline -- a getline to go with fgets
X# 
X# BINDIR is where to put the executable.
X# MANDIR is where the manual pages go, and MANEXT is the extension.
X# for the man pages, e.g., getline.1 or getline.l or getline.m.
X
XBINDIR = /usr/local   -- watch out!
XMANDIR = /usr/man/manl
XMANEXT = l
X
X# These should all just be right if the above ones are.
XDIRNAME = $(BINDIR)/getline
XDIRNAME_M = $(MANDIR)/getline.$(MANEXT)
XLDFLAGS =
XCFLAGS = -g -DTEST
X
Xgetline: getline.c
X	$(CC) $(CFLAGS) $(LDFLAGS) -o getline getline.c
X	@-size getline
X
Xinstall: $(DIRNAME_M)
X
X$(DIRNAME): getline.c
X	$(CC) $(LDFLAGS) -o getline getline.c
X	install -c -m 755 getline $(DIRNAME)
X
X$(DIRNAME_M): getline.1
X	cp getline.1 $(DIRNAME_M)
X	chmod 644 $(DIRNAME_M)
X
X
X
Xlint:
X	lint getline.c
Xtags:
X	ctags -w getline.c
Xgetline.shar:
X	shar getline.c Makefile getline.1 > getline.shar
Xclean:
X	rm -f a.out core *.o getline
END_OF_Makefile
if test 864 -ne `wc -c <Makefile`; then
    echo shar: \"Makefile\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f getline.1 -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"getline.1\"
else
echo shar: Extracting \"getline.1\" \(873 characters\)
sed "s/^X//" >getline.1 <<'END_OF_getline.1'
X.TH getline 1,local
X.SH NAME
Xgetline \- get a line of near-arbitrary length from a stream.
X.SH SYNTAX
X.nf
X#include <stdio.h>
X
Xchar *getline(stream)
XFILE *stream;
X.fi
X
X.SH DESCRIPTION
XThe 
X.B getline 
Xroutine reads up to a newline character from the stream
Xinto an internal cache of arbitrary size.  The last character read
Xis followed by a null character.  The getline routine returns
Xits first argument or NULL on end of file or error.
X
X.SH DIAGNOSTICS
XIf a line longer than available memory is read, the program exits
Xwith a message.  This is expected to be a rare event.
X
X.SH "SEE ALSO"
Xferror(3s), fread(3s), getc(3s), puts(3s), scanf(3s), fgets(3).
X
X.SH BUGS
XStrictly dependant on the behavior of fgets: treats a ^D (eof) in
Xmid-stream from a terminal as does fgets (ie, it disappears silently
Xunder Ultrix/Berzerkley)
X.PP
XWritten by Dave (instakludge) Collier-Brown.
END_OF_getline.1
if test 873 -ne `wc -c <getline.1`; then
    echo shar: \"getline.1\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of shell archive.
exit 0
-- 
 David Collier-Brown.  {mnetor yunexus utgpu}!geac!daveb
 Geac Computers Ltd.,  | "His Majesty made you a major 
 350 Steelcase Road,   |  because he believed you would 
 Markham, Ontario.     |  know when not to obey his orders"