146111Sbostic /*- 246111Sbostic * Copyright (c) 1990 The Regents of the University of California. 346111Sbostic * All rights reserved. 446111Sbostic * 546111Sbostic * This code is derived from software contributed to Berkeley by 646111Sbostic * Chris Torek. 746111Sbostic * 846111Sbostic * %sccs.include.redist.c% 946111Sbostic */ 1046111Sbostic 1146111Sbostic #if defined(LIBC_SCCS) && !defined(lint) 12*58421Storek static char sccsid[] = "@(#)fgetln.c 5.3 (Berkeley) 03/03/93"; 1346111Sbostic #endif /* LIBC_SCCS and not lint */ 1446111Sbostic 1546111Sbostic #include <stdio.h> 1646111Sbostic #include <stdlib.h> 1746111Sbostic #include <string.h> 1846111Sbostic #include "local.h" 1946111Sbostic 2046111Sbostic /* 2146111Sbostic * Expand the line buffer. Return -1 on error. 22*58421Storek #ifdef notdef 2346111Sbostic * The `new size' does not account for a terminating '\0', 2446111Sbostic * so we add 1 here. 25*58421Storek #endif 2646111Sbostic */ 2746111Sbostic __slbexpand(fp, newsize) 2846111Sbostic FILE *fp; 2946111Sbostic size_t newsize; 3046111Sbostic { 3146111Sbostic void *p; 3246111Sbostic 33*58421Storek #ifdef notdef 34*58421Storek ++newsize; 35*58421Storek #endif 36*58421Storek if (fp->_lb._size >= newsize) 3746111Sbostic return (0); 3846111Sbostic if ((p = realloc(fp->_lb._base, newsize)) == NULL) 3946111Sbostic return (-1); 4046111Sbostic fp->_lb._base = p; 4146111Sbostic fp->_lb._size = newsize; 4246111Sbostic return (0); 4346111Sbostic } 4446111Sbostic 4546111Sbostic /* 4646111Sbostic * Get an input line. The returned pointer often (but not always) 47*58421Storek * points into a stdio buffer. Fgetline does not alter the text of 48*58421Storek * the returned line (which is thus not a C string because it will 49*58421Storek * not necessarily end with '\0'), but does allow callers to modify 50*58421Storek * it if they wish. Thus, we set __SMOD in case the caller does. 5146111Sbostic */ 5246111Sbostic char * 5346111Sbostic fgetline(fp, lenp) 5446111Sbostic register FILE *fp; 5546111Sbostic size_t *lenp; 5646111Sbostic { 5746111Sbostic register unsigned char *p; 5846111Sbostic register size_t len; 5946111Sbostic size_t off; 6046111Sbostic 6146111Sbostic /* make sure there is input */ 6246111Sbostic if (fp->_r <= 0 && __srefill(fp)) { 63*58421Storek *lenp = 0; 6446111Sbostic return (NULL); 6546111Sbostic } 6646111Sbostic 6746111Sbostic /* look for a newline in the input */ 6846111Sbostic if ((p = memchr((void *)fp->_p, '\n', fp->_r)) != NULL) { 6946111Sbostic register char *ret; 7046111Sbostic 7146111Sbostic /* 72*58421Storek * Found one. Flag buffer as modified to keep fseek from 73*58421Storek * `optimising' a backward seek, in case the user stomps on 74*58421Storek * the text. 7546111Sbostic */ 76*58421Storek p++; /* advance over it */ 7746111Sbostic ret = (char *)fp->_p; 78*58421Storek *lenp = len = p - fp->_p; 7946111Sbostic fp->_flags |= __SMOD; 80*58421Storek fp->_r -= len; 81*58421Storek fp->_p = p; 8246111Sbostic return (ret); 8346111Sbostic } 8446111Sbostic 8546111Sbostic /* 8646111Sbostic * We have to copy the current buffered data to the line buffer. 87*58421Storek * As a bonus, though, we can leave off the __SMOD. 8846111Sbostic * 89*58421Storek * OPTIMISTIC is length that we (optimistically) expect will 90*58421Storek * accomodate the `rest' of the string, on each trip through the 91*58421Storek * loop below. 9246111Sbostic */ 9346111Sbostic #define OPTIMISTIC 80 9446111Sbostic 9546111Sbostic for (len = fp->_r, off = 0;; len += fp->_r) { 9646111Sbostic register size_t diff; 9746111Sbostic 9846111Sbostic /* 99*58421Storek * Make sure there is room for more bytes. Copy data from 100*58421Storek * file buffer to line buffer, refill file and look for 101*58421Storek * newline. The loop stops only when we find a newline. 10246111Sbostic */ 10346111Sbostic if (__slbexpand(fp, len + OPTIMISTIC)) 10446111Sbostic goto error; 105*58421Storek (void)bcopy((void *)fp->_p, (void *)(fp->_lb._base + off), 10646111Sbostic len - off); 10746111Sbostic off = len; 10846111Sbostic if (__srefill(fp)) 10946111Sbostic break; /* EOF or error: return partial line */ 11046111Sbostic if ((p = memchr((void *)fp->_p, '\n', fp->_r)) == NULL) 11146111Sbostic continue; 11246111Sbostic 11346111Sbostic /* got it: finish up the line (like code above) */ 114*58421Storek p++; 11546111Sbostic diff = p - fp->_p; 11646111Sbostic len += diff; 11746111Sbostic if (__slbexpand(fp, len)) 11846111Sbostic goto error; 119*58421Storek (void)bcopy((void *)fp->_p, (void *)(fp->_lb._base + off), 12046111Sbostic diff); 121*58421Storek fp->_r -= diff; 122*58421Storek fp->_p = p; 12346111Sbostic break; 12446111Sbostic } 125*58421Storek *lenp = len; 126*58421Storek #ifdef notdef 12746111Sbostic fp->_lb._base[len] = 0; 128*58421Storek #endif 12946111Sbostic return ((char *)fp->_lb._base); 13046111Sbostic 13146111Sbostic error: 132*58421Storek *lenp = 0; /* ??? */ 13346111Sbostic return (NULL); /* ??? */ 13446111Sbostic } 135