no longer returns a C string (callers must use care)
SCCS-vsn: lib/libc/stdio/fgetln.3 5.5
SCCS-vsn: lib/libc/stdio/fgetln.c 5.3
.\"
.\" %sccs.include.redist.man%
.\"
.\"
.\" %sccs.include.redist.man%
.\"
-.\" @(#)fgetln.3 5.4 (Berkeley) %G%
+.\" @(#)fgetln.3 5.5 (Berkeley) %G%
function
returns a pointer to the next line from the stream referenced by
.Fa stream .
function
returns a pointer to the next line from the stream referenced by
.Fa stream .
-The newline character at the end of the line is replaced by a
-.Dv NUL .
-.Pp
-If
+This line is
+.Em not
+a C string as it does not end with a terminating
+.Dv NUL
+character.
+The length of the line, including the final newline,
+is stored in the memory location to which
-is non-NULL, the length of the line, not counting the terminating
-.Dv NUL ,
-is stored in the memory location it references.
+points.
+(Note, however, that if the line is the last
+in a file that does not end in a newline,
+the returned text will not contain a newline.)
.Sh RETURN VALUES
Upon successful completion a pointer is returned;
this pointer becomes invalid after the next
.Sh RETURN VALUES
Upon successful completion a pointer is returned;
this pointer becomes invalid after the next
.Xr clearerr 3 .
.Pp
The text to which the returned pointer points may be modified,
.Xr clearerr 3 .
.Pp
The text to which the returned pointer points may be modified,
-provided that no changes are made beyond the terminating
-.Dv NUL .
+provided that no changes are made beyond the returned size.
These changes are lost as soon as the pointer becomes invalid.
.Sh ERRORS
.Bl -tag -width [EBADF]
These changes are lost as soon as the pointer becomes invalid.
.Sh ERRORS
.Bl -tag -width [EBADF]
.Fn fgetline
function is
.Ud .
.Fn fgetline
function is
.Ud .
-.Sh BUGS
-It is not possible to tell whether the final line of an input file
-was terminated with a newline.
*/
#if defined(LIBC_SCCS) && !defined(lint)
*/
#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)fgetln.c 5.2 (Berkeley) %G%";
+static char sccsid[] = "@(#)fgetln.c 5.3 (Berkeley) %G%";
#endif /* LIBC_SCCS and not lint */
#include <stdio.h>
#endif /* LIBC_SCCS and not lint */
#include <stdio.h>
/*
* Expand the line buffer. Return -1 on error.
/*
* Expand the line buffer. Return -1 on error.
* The `new size' does not account for a terminating '\0',
* so we add 1 here.
* The `new size' does not account for a terminating '\0',
* so we add 1 here.
*/
__slbexpand(fp, newsize)
FILE *fp;
*/
__slbexpand(fp, newsize)
FILE *fp;
- if (fp->_lb._size >= ++newsize)
+#ifdef notdef
+ ++newsize;
+#endif
+ if (fp->_lb._size >= newsize)
return (0);
if ((p = realloc(fp->_lb._base, newsize)) == NULL)
return (-1);
return (0);
if ((p = realloc(fp->_lb._base, newsize)) == NULL)
return (-1);
/*
* Get an input line. The returned pointer often (but not always)
/*
* Get an input line. The returned pointer often (but not always)
- * points into a stdio buffer. Fgetline smashes the newline (if any)
- * in the stdio buffer; callers must not use it on streams that
- * have `magic' setvbuf() games happening.
+ * points into a stdio buffer. Fgetline does not alter the text of
+ * the returned line (which is thus not a C string because it will
+ * not necessarily end with '\0'), but does allow callers to modify
+ * it if they wish. Thus, we set __SMOD in case the caller does.
*/
char *
fgetline(fp, lenp)
*/
char *
fgetline(fp, lenp)
/* make sure there is input */
if (fp->_r <= 0 && __srefill(fp)) {
/* make sure there is input */
if (fp->_r <= 0 && __srefill(fp)) {
- if (lenp != NULL)
- *lenp = 0;
- * Found one. Flag buffer as modified to keep
- * fseek from `optimising' a backward seek, since
- * the newline is about to be trashed. (We should
- * be able to get away with doing this only if
- * p is not pointing into an ungetc buffer, since
- * fseek discards ungetc data, but this is the
- * usual case anyway.)
+ * Found one. Flag buffer as modified to keep fseek from
+ * `optimising' a backward seek, in case the user stomps on
+ * the text.
+ p++; /* advance over it */
+ *lenp = len = p - fp->_p;
- *p = 0;
- fp->_r -= len + 1;
- fp->_p = p + 1;
- if (lenp != NULL)
- *lenp = len;
+ fp->_r -= len;
+ fp->_p = p;
return (ret);
}
/*
* We have to copy the current buffered data to the line buffer.
return (ret);
}
/*
* We have to copy the current buffered data to the line buffer.
+ * As a bonus, though, we can leave off the __SMOD.
- * OPTIMISTIC is length that we (optimistically)
- * expect will accomodate the `rest' of the string,
- * on each trip through the loop below.
+ * OPTIMISTIC is length that we (optimistically) expect will
+ * accomodate the `rest' of the string, on each trip through the
+ * loop below.
- * Make sure there is room for more bytes.
- * Copy data from file buffer to line buffer,
- * refill file and look for newline. The
- * loop stops only when we find a newline.
+ * Make sure there is room for more bytes. Copy data from
+ * file buffer to line buffer, refill file and look for
+ * newline. The loop stops only when we find a newline.
*/
if (__slbexpand(fp, len + OPTIMISTIC))
goto error;
*/
if (__slbexpand(fp, len + OPTIMISTIC))
goto error;
- (void) bcopy((void *)fp->_p, (void *)(fp->_lb._base + off),
+ (void)bcopy((void *)fp->_p, (void *)(fp->_lb._base + off),
len - off);
off = len;
if (__srefill(fp))
len - off);
off = len;
if (__srefill(fp))
continue;
/* got it: finish up the line (like code above) */
continue;
/* got it: finish up the line (like code above) */
- fp->_flags |= __SMOD; /* soon */
diff = p - fp->_p;
len += diff;
if (__slbexpand(fp, len))
goto error;
diff = p - fp->_p;
len += diff;
if (__slbexpand(fp, len))
goto error;
- (void) bcopy((void *)fp->_p, (void *)(fp->_lb._base + off),
+ (void)bcopy((void *)fp->_p, (void *)(fp->_lb._base + off),
- fp->_r -= diff + 1;
- fp->_p = p + 1;
+ fp->_r -= diff;
+ fp->_p = p;
- if (lenp != NULL)
- *lenp = len;
+ *lenp = len;
+#ifdef notdef
return ((char *)fp->_lb._base);
error:
return ((char *)fp->_lb._base);
error:
- if (lenp != NULL)
- *lenp = 0; /* ??? */
return (NULL); /* ??? */
}
return (NULL); /* ??? */
}