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*58451Storek static char sccsid[] = "@(#)fgetln.c 5.4 (Berkeley) 03/04/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. 2258421Storek #ifdef notdef 2346111Sbostic * The `new size' does not account for a terminating '\0', 2446111Sbostic * so we add 1 here. 2558421Storek #endif 2646111Sbostic */ 2746111Sbostic __slbexpand(fp, newsize) 2846111Sbostic FILE *fp; 2946111Sbostic size_t newsize; 3046111Sbostic { 3146111Sbostic void *p; 3246111Sbostic 3358421Storek #ifdef notdef 3458421Storek ++newsize; 3558421Storek #endif 3658421Storek 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) 4758421Storek * points into a stdio buffer. Fgetline does not alter the text of 4858421Storek * the returned line (which is thus not a C string because it will 4958421Storek * not necessarily end with '\0'), but does allow callers to modify 5058421Storek * 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)) { 6358421Storek *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 /* 7258421Storek * Found one. Flag buffer as modified to keep fseek from 7358421Storek * `optimising' a backward seek, in case the user stomps on 7458421Storek * the text. 7546111Sbostic */ 7658421Storek p++; /* advance over it */ 7746111Sbostic ret = (char *)fp->_p; 7858421Storek *lenp = len = p - fp->_p; 7946111Sbostic fp->_flags |= __SMOD; 8058421Storek fp->_r -= len; 8158421Storek fp->_p = p; 8246111Sbostic return (ret); 8346111Sbostic } 8446111Sbostic 8546111Sbostic /* 8646111Sbostic * We have to copy the current buffered data to the line buffer. 8758421Storek * As a bonus, though, we can leave off the __SMOD. 8846111Sbostic * 8958421Storek * OPTIMISTIC is length that we (optimistically) expect will 9058421Storek * accomodate the `rest' of the string, on each trip through the 9158421Storek * 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 /* 9958421Storek * Make sure there is room for more bytes. Copy data from 10058421Storek * file buffer to line buffer, refill file and look for 10158421Storek * newline. The loop stops only when we find a newline. 10246111Sbostic */ 10346111Sbostic if (__slbexpand(fp, len + OPTIMISTIC)) 10446111Sbostic goto error; 105*58451Storek (void)memcpy((void *)(fp->_lb._base + off), (void *)fp->_p, 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) */ 11458421Storek p++; 11546111Sbostic diff = p - fp->_p; 11646111Sbostic len += diff; 11746111Sbostic if (__slbexpand(fp, len)) 11846111Sbostic goto error; 119*58451Storek (void)memcpy((void *)(fp->_lb._base + off), (void *)fp->_p, 12046111Sbostic diff); 12158421Storek fp->_r -= diff; 12258421Storek fp->_p = p; 12346111Sbostic break; 12446111Sbostic } 12558421Storek *lenp = len; 12658421Storek #ifdef notdef 12746111Sbostic fp->_lb._base[len] = 0; 12858421Storek #endif 12946111Sbostic return ((char *)fp->_lb._base); 13046111Sbostic 13146111Sbostic error: 13258421Storek *lenp = 0; /* ??? */ 13346111Sbostic return (NULL); /* ??? */ 13446111Sbostic } 135