diff options
author | das <das@FreeBSD.org> | 2009-02-28 06:00:58 +0000 |
---|---|---|
committer | das <das@FreeBSD.org> | 2009-02-28 06:00:58 +0000 |
commit | a67fbaa46cbdf18a03eefb3f83e2f74f68918753 (patch) | |
tree | f258384b92d5c4bde23e95d4c44fa3547a0364cd /lib/libc/stdio | |
parent | b739b3fb48f28ef6b6e7efeeceb832d3dec3fc9c (diff) | |
download | FreeBSD-src-a67fbaa46cbdf18a03eefb3f83e2f74f68918753.zip FreeBSD-src-a67fbaa46cbdf18a03eefb3f83e2f74f68918753.tar.gz |
- Add getdelim(), getline(), stpncpy(), strnlen(), wcsnlen(),
wcscasecmp(), and wcsncasecmp().
- Make some previously non-standard extensions visible
if POSIX_VISIBLE >= 200809.
- Use restrict qualifiers in stpcpy().
- Declare off_t and size_t in stdio.h.
- Bump __FreeBSD_version in case the new symbols (particularly
getline()) cause issues with ports.
Reviewed by: standards@
Diffstat (limited to 'lib/libc/stdio')
-rw-r--r-- | lib/libc/stdio/Makefile.inc | 8 | ||||
-rw-r--r-- | lib/libc/stdio/Symbol.map | 5 | ||||
-rw-r--r-- | lib/libc/stdio/fgetln.3 | 1 | ||||
-rw-r--r-- | lib/libc/stdio/fgets.3 | 3 | ||||
-rw-r--r-- | lib/libc/stdio/getdelim.c | 158 | ||||
-rw-r--r-- | lib/libc/stdio/getline.3 | 164 | ||||
-rw-r--r-- | lib/libc/stdio/getline.c | 39 | ||||
-rw-r--r-- | lib/libc/stdio/stdio.3 | 4 |
8 files changed, 377 insertions, 5 deletions
diff --git a/lib/libc/stdio/Makefile.inc b/lib/libc/stdio/Makefile.inc index fc106db..2ed62f5 100644 --- a/lib/libc/stdio/Makefile.inc +++ b/lib/libc/stdio/Makefile.inc @@ -10,8 +10,8 @@ SRCS+= _flock_stub.c asprintf.c clrerr.c fclose.c fcloseall.c fdopen.c \ fileno.c findfp.c flags.c fopen.c fprintf.c fpurge.c fputc.c fputs.c \ fputwc.c fputws.c fread.c freopen.c fscanf.c fseek.c fsetpos.c \ ftell.c funopen.c fvwrite.c fwalk.c fwide.c fwprintf.c fwscanf.c \ - fwrite.c getc.c \ - getchar.c gets.c getw.c getwc.c getwchar.c makebuf.c mktemp.c \ + fwrite.c getc.c getchar.c getdelim.c getline.c \ + gets.c getw.c getwc.c getwchar.c makebuf.c mktemp.c \ perror.c printf.c printf-pos.c putc.c putchar.c \ puts.c putw.c putwc.c putwchar.c \ refill.c remove.c rewind.c rget.c scanf.c setbuf.c setbuffer.c \ @@ -33,7 +33,8 @@ SYM_MAPS+= ${.CURDIR}/stdio/Symbol.map MAN+= fclose.3 ferror.3 fflush.3 fgetln.3 fgets.3 fgetwln.3 fgetws.3 \ flockfile.3 \ fopen.3 fputs.3 \ - fputws.3 fread.3 fseek.3 funopen.3 fwide.3 getc.3 getwc.3 mktemp.3 \ + fputws.3 fread.3 fseek.3 funopen.3 fwide.3 getc.3 \ + getline.3 getwc.3 mktemp.3 \ printf.3 putc.3 putwc.3 remove.3 scanf.3 setbuf.3 stdio.3 tmpnam.3 \ ungetc.3 ungetwc.3 wprintf.3 wscanf.3 @@ -53,6 +54,7 @@ MLINKS+=fseek.3 fgetpos.3 fseek.3 fseeko.3 fseek.3 fsetpos.3 fseek.3 ftell.3 \ MLINKS+=funopen.3 fropen.3 funopen.3 fwopen.3 MLINKS+=getc.3 fgetc.3 getc.3 getc_unlocked.3 getc.3 getchar.3 \ getc.3 getchar_unlocked.3 getc.3 getw.3 +MLINKS+=getline.3 getdelim.3 MLINKS+=getwc.3 fgetwc.3 getwc.3 getwchar.3 MLINKS+=mktemp.3 mkdtemp.3 mktemp.3 mkstemp.3 mktemp.3 mkstemps.3 MLINKS+=printf.3 asprintf.3 printf.3 fprintf.3 \ diff --git a/lib/libc/stdio/Symbol.map b/lib/libc/stdio/Symbol.map index ac93cb2..bf054b6 100644 --- a/lib/libc/stdio/Symbol.map +++ b/lib/libc/stdio/Symbol.map @@ -110,6 +110,11 @@ FBSD_1.0 { wscanf; }; +FBSD_1.1 { + getdelim; + getline; +}; + FBSDprivate_1.0 { _flockfile; _flockfile_debug_stub; diff --git a/lib/libc/stdio/fgetln.3 b/lib/libc/stdio/fgetln.3 index b95c61e..4b83664 100644 --- a/lib/libc/stdio/fgetln.3 +++ b/lib/libc/stdio/fgetln.3 @@ -116,6 +116,7 @@ or .Xr fgets 3 , .Xr fgetwln 3 , .Xr fopen 3 , +.Xr getline 3 , .Xr putc 3 .Sh HISTORY The diff --git a/lib/libc/stdio/fgets.3 b/lib/libc/stdio/fgets.3 index cd74fcc..aa8e2ac 100644 --- a/lib/libc/stdio/fgets.3 +++ b/lib/libc/stdio/fgets.3 @@ -147,7 +147,8 @@ the FSA.) .Xr feof 3 , .Xr ferror 3 , .Xr fgetln 3 , -.Xr fgetws 3 +.Xr fgetws 3 , +.Xr getline 3 .Sh STANDARDS The functions .Fn fgets diff --git a/lib/libc/stdio/getdelim.c b/lib/libc/stdio/getdelim.c new file mode 100644 index 0000000..fb02889 --- /dev/null +++ b/lib/libc/stdio/getdelim.c @@ -0,0 +1,158 @@ +/*- + * Copyright (c) 2009 David Schultz <das@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "namespace.h" +#include <sys/param.h> +#include <errno.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "un-namespace.h" + +#include "libc_private.h" +#include "local.h" + +static inline size_t +p2roundup(size_t n) +{ + + if (!powerof2(n)) { + n--; + n |= n >> 1; + n |= n >> 2; + n |= n >> 4; + n |= n >> 8; + n |= n >> 16; +#if SIZE_T_MAX > 0xffffffffU + n |= n >> 32; +#endif + n++; + } + return (n); +} + +/* + * Expand *linep to hold len bytes (up to SSIZE_MAX + 1). + */ +static inline int +expandtofit(char ** __restrict linep, size_t len, size_t * __restrict capp) +{ + char *newline; + size_t newcap; + + if (len > (size_t)SSIZE_MAX + 1) { + errno = EOVERFLOW; + return (-1); + } + if (len > *capp) { + if (len == (size_t)SSIZE_MAX + 1) /* avoid overflow */ + newcap = (size_t)SSIZE_MAX + 1; + else + newcap = p2roundup(len); + newline = realloc(*linep, newcap); + if (newline == NULL) + return (-1); + *capp = newcap; + *linep = newline; + } + return (0); +} + +/* + * Append the src buffer to the *dstp buffer. The buffers are of + * length srclen and *dstlenp, respectively, and dst has space for + * *dstlenp bytes. After the call, *dstlenp and *dstcapp are updated + * appropriately, and *dstp is reallocated if needed. Returns 0 on + * success, -1 on allocation failure. + */ +static int +sappend(char ** __restrict dstp, size_t * __restrict dstlenp, + size_t * __restrict dstcapp, char * __restrict src, size_t srclen) +{ + + /* ensure room for srclen + dstlen + terminating NUL */ + if (expandtofit(dstp, srclen + *dstlenp + 1, dstcapp)) + return (-1); + memcpy(*dstp + *dstlenp, src, srclen); + *dstlenp += srclen; + return (0); +} + +ssize_t +getdelim(char ** __restrict linep, size_t * __restrict linecapp, int delim, + FILE * __restrict fp) +{ + u_char *endp; + size_t linelen; + + FLOCKFILE(fp); + ORIENT(fp, -1); + + if (linep == NULL || linecapp == NULL) { + errno = EINVAL; + goto error; + } + + linelen = 0; + if (*linecapp == 0) + *linep = NULL; + + if (fp->_r <= 0 && __srefill(fp)) { + /* If fp is at EOF already, we just need space for the NUL. */ + if (__sferror(fp) || expandtofit(linep, 1, linecapp)) + goto error; + goto done; + } + + while ((endp = memchr(fp->_p, delim, fp->_r)) == NULL) { + if (sappend(linep, &linelen, linecapp, fp->_p, fp->_r)) + goto error; + if (__srefill(fp)) { + if (__sferror(fp)) + goto error; + goto done; /* hit EOF */ + } + } + endp++; /* snarf the delimiter, too */ + if (sappend(linep, &linelen, linecapp, fp->_p, endp - fp->_p)) + goto error; + fp->_r -= endp - fp->_p; + fp->_p = endp; +done: + /* Invariant: *linep has space for at least linelen+1 bytes. */ + (*linep)[linelen] = '\0'; + FUNLOCKFILE(fp); + return (linelen); + +error: + fp->_flags |= __SERR; + FUNLOCKFILE(fp); + return (-1); +} diff --git a/lib/libc/stdio/getline.3 b/lib/libc/stdio/getline.3 new file mode 100644 index 0000000..096331a --- /dev/null +++ b/lib/libc/stdio/getline.3 @@ -0,0 +1,164 @@ +.\" Copyright (c) 2009 David Schultz <das@FreeBSD.org> +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd February 28, 2009 +.Dt GETLINE 3 +.Os +.Sh NAME +.Nm getdelim , +.Nm getline +.Nd get a line from a stream +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.Fd "#define _WITH_GETLINE" +.In stdio.h +.Ft ssize_t +.Fn getdelim "char ** restrict linep" "size_t * restrict linecapp" "int delimiter" " FILE * restrict stream" +.Ft ssize_t +.Fn getline "char ** restrict linep" "size_t * restrict linecapp" " FILE * restrict stream" +.Sh DESCRIPTION +The +.Fn getdelim +function reads a line from +.Fa stream , +delimited by the character +.Fa delimiter . +The +.Fn getline +function is equivalent to +.Fn getdelim +with the newline character as the delimiter. +The delimiter character is included as part of the line, unless +the end of the file is reached. +The caller may provide a pointer to a malloc buffer for the line in +.Fa *linep , +and the capacity of that buffer in +.Fa *linecapp ; +if +.Fa *linecapp +is 0, then +.Fa *linep +is treated as +.Dv NULL . +These functions may expand the buffer as needed, as if via +.Fn realloc , +and update +.Fa *linep +and +.Fa *linecapp +accordingly. +.Sh RETURN VALUES +The +.Fn getdelim +and +.Fn getline +functions return the number of characters written, excluding the +terminating +.Dv NUL . +The value \-1 is returned if an error occurs. +.Sh EXAMPLES +The following code fragment reads lines from a file and +writes them to standard output. +The +.Fn fwrite +function is used in case the line contains embedded +.Dv NUL +characters. +.Bd -literal -offset indent +char *line = NULL; +size_t linecap = 0; +ssize_t linelen; +while ((linelen = getline(&line, &linecap, fp)) > 0) + fwrite(line, linelen, 1, stdout); +.Ed +.Sh COMPATIBILITY +Many application writers used the name +.Va getline +before the +.Fn getline +function was introduced in +.St -p1003.1 , +so a prototype is not provided by default in order to avoid +compatibility problems. +Applications that wish to use the +.Fn getline +function described herein should either request a strict +.St -p1003.1-2008 +environment by defining the macro +.Dv _POSIX_C_SOURCE +to the value 200809 or greater, or by defining the macro +.Dv _WITH_GETLINE , +prior to the inclusion of +.In stdio.h . +For compatibility with GNU libc, defining either +.Dv _BSD_SOURCE +or +.Dv _GNU_SOURCE +prior to the inclusion of +.In stdio.h +will also make +.Fn getline +available. +.Sh ERRORS +These functions may fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +Either +.Fa linep +or +.Fa linecapp +is +.Dv NULL . +.It Bq Er EOVERFLOW +No delimiter was found in the first +.Dv SSIZE_MAX +characters. +.El +.Pp +These functions may also fail for any of the errors specified for +.Fn fgets +and +.Fn malloc . +.Sh SEE ALSO +.Xr fgetln 3 , +.Xr fgets 3 , +.Xr malloc 3 +.Sh STANDARDS +The +.Fn getdelim +and +.Fn getline +functions conform to +.St -p1003.1-2008 . +.Sh HISTORY +These routines first appeared in +.Fx 8.0 . +.Sh BUGS +There are no wide character versions of +.Fn getdelim +or +.Fn getline . diff --git a/lib/libc/stdio/getline.c b/lib/libc/stdio/getline.c new file mode 100644 index 0000000..3f35520 --- /dev/null +++ b/lib/libc/stdio/getline.c @@ -0,0 +1,39 @@ +/*- + * Copyright (c) 2009 David Schultz <das@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#define _WITH_GETLINE +#include <stdio.h> + +ssize_t +getline(char ** __restrict linep, size_t * __restrict linecapp, + FILE * __restrict fp) +{ + + return (getdelim(linep, linecapp, '\n', fp)); +} diff --git a/lib/libc/stdio/stdio.3 b/lib/libc/stdio/stdio.3 index 1a13ee9..a4d1eb7 100644 --- a/lib/libc/stdio/stdio.3 +++ b/lib/libc/stdio/stdio.3 @@ -28,7 +28,7 @@ .\" @(#)stdio.3 8.7 (Berkeley) 4/19/94 .\" $FreeBSD$ .\" -.Dd January 10, 2003 +.Dd February 28, 2009 .Dt STDIO 3 .Os .Sh NAME @@ -276,6 +276,8 @@ library conforms to .It "fwrite binary stream input/output" .It "getc get next character or word from input stream" .It "getchar get next character or word from input stream" +.It "getdelim get a line from a stream" +.It "getline get a line from a stream" .It "gets get a line from a stream" .It "getw get next character or word from input stream" .It "getwc get next wide character from input stream" |