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"