1 /*- 2 * Copyright (c) 1990 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Chris Torek. 7 * 8 * %sccs.include.redist.c% 9 */ 10 11 #if defined(LIBC_SCCS) && !defined(lint) 12 static char sccsid[] = "@(#)fgetln.c 5.4 (Berkeley) 03/04/93"; 13 #endif /* LIBC_SCCS and not lint */ 14 15 #include <stdio.h> 16 #include <stdlib.h> 17 #include <string.h> 18 #include "local.h" 19 20 /* 21 * Expand the line buffer. Return -1 on error. 22 #ifdef notdef 23 * The `new size' does not account for a terminating '\0', 24 * so we add 1 here. 25 #endif 26 */ 27 __slbexpand(fp, newsize) 28 FILE *fp; 29 size_t newsize; 30 { 31 void *p; 32 33 #ifdef notdef 34 ++newsize; 35 #endif 36 if (fp->_lb._size >= newsize) 37 return (0); 38 if ((p = realloc(fp->_lb._base, newsize)) == NULL) 39 return (-1); 40 fp->_lb._base = p; 41 fp->_lb._size = newsize; 42 return (0); 43 } 44 45 /* 46 * Get an input line. The returned pointer often (but not always) 47 * points into a stdio buffer. Fgetline does not alter the text of 48 * the returned line (which is thus not a C string because it will 49 * not necessarily end with '\0'), but does allow callers to modify 50 * it if they wish. Thus, we set __SMOD in case the caller does. 51 */ 52 char * 53 fgetline(fp, lenp) 54 register FILE *fp; 55 size_t *lenp; 56 { 57 register unsigned char *p; 58 register size_t len; 59 size_t off; 60 61 /* make sure there is input */ 62 if (fp->_r <= 0 && __srefill(fp)) { 63 *lenp = 0; 64 return (NULL); 65 } 66 67 /* look for a newline in the input */ 68 if ((p = memchr((void *)fp->_p, '\n', fp->_r)) != NULL) { 69 register char *ret; 70 71 /* 72 * Found one. Flag buffer as modified to keep fseek from 73 * `optimising' a backward seek, in case the user stomps on 74 * the text. 75 */ 76 p++; /* advance over it */ 77 ret = (char *)fp->_p; 78 *lenp = len = p - fp->_p; 79 fp->_flags |= __SMOD; 80 fp->_r -= len; 81 fp->_p = p; 82 return (ret); 83 } 84 85 /* 86 * We have to copy the current buffered data to the line buffer. 87 * As a bonus, though, we can leave off the __SMOD. 88 * 89 * OPTIMISTIC is length that we (optimistically) expect will 90 * accomodate the `rest' of the string, on each trip through the 91 * loop below. 92 */ 93 #define OPTIMISTIC 80 94 95 for (len = fp->_r, off = 0;; len += fp->_r) { 96 register size_t diff; 97 98 /* 99 * Make sure there is room for more bytes. Copy data from 100 * file buffer to line buffer, refill file and look for 101 * newline. The loop stops only when we find a newline. 102 */ 103 if (__slbexpand(fp, len + OPTIMISTIC)) 104 goto error; 105 (void)memcpy((void *)(fp->_lb._base + off), (void *)fp->_p, 106 len - off); 107 off = len; 108 if (__srefill(fp)) 109 break; /* EOF or error: return partial line */ 110 if ((p = memchr((void *)fp->_p, '\n', fp->_r)) == NULL) 111 continue; 112 113 /* got it: finish up the line (like code above) */ 114 p++; 115 diff = p - fp->_p; 116 len += diff; 117 if (__slbexpand(fp, len)) 118 goto error; 119 (void)memcpy((void *)(fp->_lb._base + off), (void *)fp->_p, 120 diff); 121 fp->_r -= diff; 122 fp->_p = p; 123 break; 124 } 125 *lenp = len; 126 #ifdef notdef 127 fp->_lb._base[len] = 0; 128 #endif 129 return ((char *)fp->_lb._base); 130 131 error: 132 *lenp = 0; /* ??? */ 133 return (NULL); /* ??? */ 134 } 135