diff options
author | Federico G. Schwindt <fgsch@cvs.openbsd.org> | 2012-03-21 23:44:36 +0000 |
---|---|---|
committer | Federico G. Schwindt <fgsch@cvs.openbsd.org> | 2012-03-21 23:44:36 +0000 |
commit | 6c8fdab4473fb1ea0bc0189a8c11a1f581ba4b3e (patch) | |
tree | d5516719feedfb8dac881ff3b48f5064434f6590 /lib/libc | |
parent | bec4c79143a9a3b2a6b939a4e009faeb84e68413 (diff) |
Implement getdelim(3) and getline(3).
Prompted in a mail to tech@ by Jan Klemkow (j-dot-klemkow-at-wemelug-dot-de)
but this is based on NetBSD's implementation instead with some tweaks by me.
Further improvements would happen in tree.
ok millert@; discussed with many others
ports cleanup by naddy@, sthen@. Antti Harri, Gonzalo L. R. and myself.
Diffstat (limited to 'lib/libc')
-rw-r--r-- | lib/libc/stdio/Makefile.inc | 9 | ||||
-rw-r--r-- | lib/libc/stdio/getdelim.3 | 155 | ||||
-rw-r--r-- | lib/libc/stdio/getdelim.c | 134 | ||||
-rw-r--r-- | lib/libc/stdio/getline.c | 37 |
4 files changed, 332 insertions, 3 deletions
diff --git a/lib/libc/stdio/Makefile.inc b/lib/libc/stdio/Makefile.inc index 14e391690b8..bf8cd0e38f5 100644 --- a/lib/libc/stdio/Makefile.inc +++ b/lib/libc/stdio/Makefile.inc @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile.inc,v 1.21 2012/01/18 14:01:38 stsp Exp $ +# $OpenBSD: Makefile.inc,v 1.22 2012/03/21 23:44:35 fgsch Exp $ # stdio sources .PATH: ${LIBCSRCDIR}/stdio @@ -18,12 +18,14 @@ SRCS+= asprintf.c clrerr.c fclose.c fdopen.c feof.c ferror.c fflush.c fgetc.c \ fgetwc.c fgetws.c fputwc.c fputws.c fwide.c getwc.c getwchar.c \ putwc.c putwchar.c ungetwc.c \ fwprintf.c swprintf.c vfwprintf.c vswprintf.c vwprintf.c wprintf.c \ - fwscanf.c swscanf.c vfwscanf.c vswscanf.c vwscanf.c wscanf.c + fwscanf.c swscanf.c vfwscanf.c vswscanf.c vwscanf.c wscanf.c \ + getdelim.c getline.c MAN+= fclose.3 ferror.3 fflush.3 fgetln.3 fgets.3 fopen.3 fputs.3 \ fread.3 fseek.3 funopen.3 getc.3 mktemp.3 perror.3 printf.3 putc.3 \ remove.3 scanf.3 setbuf.3 stdio.3 tmpnam.3 ungetc.3 \ - fgetws.3 fputws.3 fwide.3 getwc.3 putwc.3 ungetwc.3 wprintf.3 wscanf.3 + fgetws.3 fputws.3 fwide.3 getwc.3 putwc.3 ungetwc.3 wprintf.3 wscanf.3 \ + getdelim.3 MLINKS+=ferror.3 clearerr.3 ferror.3 feof.3 ferror.3 fileno.3 MLINKS+=fflush.3 fpurge.3 @@ -35,6 +37,7 @@ MLINKS+=fseek.3 fgetpos.3 fseek.3 fsetpos.3 fseek.3 ftell.3 fseek.3 rewind.3 MLINKS+=fseek.3 fseeko.3 fseek.3 ftello.3 MLINKS+=funopen.3 fropen.3 funopen.3 fwopen.3 MLINKS+=getc.3 fgetc.3 getc.3 getchar.3 getc.3 getw.3 +MLINKS+=getdelim.3 getline.3 MLINKS+=mktemp.3 mkstemp.3 MLINKS+=mktemp.3 mkdtemp.3 MLINKS+=mktemp.3 mkstemps.3 diff --git a/lib/libc/stdio/getdelim.3 b/lib/libc/stdio/getdelim.3 new file mode 100644 index 00000000000..c1c0a31432c --- /dev/null +++ b/lib/libc/stdio/getdelim.3 @@ -0,0 +1,155 @@ +.\" $OpenBSD: getdelim.3,v 1.1 2012/03/21 23:44:35 fgsch Exp $ +.\" $NetBSD: getdelim.3,v 1.9 2011/04/20 23:37:51 enami Exp $ +.\" +.\" Copyright (c) 2009 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to The NetBSD Foundation +.\" by Roy Marples. +.\" +.\" 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. +.\" +.Dd June 30, 2010 +.Dt GETDELIM 3 +.Os +.Sh NAME +.Nm getdelim , +.Nm getline +.Nd read a delimited record from a stream +.\" .Sh LIBRARY +.\" .Lb libc +.Sh SYNOPSIS +.In stdio.h +.Ft ssize_t +.Fn getdelim "char ** restrict lineptr" "size_t * restrict n" "int delimiter" "FILE * restrict stream" +.Ft ssize_t +.Fn getline "char ** restrict lineptr" "size_t * restrict n" "FILE * restrict stream" +.Sh DESCRIPTION +The +.Fn getdelim +function reads from the +.Fa stream +until it encounters a character matching +.Fa delimiter , +storing the input in +.Fa *lineptr . +The buffer is +.Dv NUL Ns No -terminated +and includes the delimiter. +The +.Fa delimiter +character must be representable as an unsigned char. +.Pp +If +.Fa *n +is non-zero, then +.Fa *lineptr +must be pre-allocated to at least +.Fa *n +bytes. +The buffer should be allocated dynamically; +it must be possible to +.Xr free 3 +.Fa *lineptr . +.Fn getdelim +ensures that +.Fa *lineptr +is large enough to hold the input, updating +.Fa *n +to reflect the new size. +.Pp +The +.Fn getline +function is equivalent to +.Fn getdelim +with +.Fa delimiter +set to the newline character. +.Sh RETURN VALUES +The +.Fn getdelim +and +.Fn getline +functions return the number of characters read, including the delimiter. +If no characters were read and the stream is at end-of-file, the functions +return \-1. +If an error occurs, the functions return \-1 and the global variable +.Va errno +is set to indicate the error. +.Pp +The functions do not distinguish between end-of-file and error, +and callers must use +.Xr feof 3 +and +.Xr ferror 3 +to determine which occurred. +.Sh EXAMPLES +The following code fragment reads lines from a file and writes them to +standard output. +.Bd -literal -offset indent +char *line = NULL; +size_t linesize = 0; +ssize_t linelen; + +while ((linelen = getline(\*[Am]line, \*[Am]linesize, fp)) != -1) + fwrite(line, linelen, 1, stdout); + +if (ferror(fp)) + perror("getline"); +.Ed +.Sh ERRORS +.Bl -tag -width [EOVERFLOW] +.It Bq Er EINVAL +.Fa lineptr +or +.Fa n +is a +.Dv NULL +pointer. +.It Bq Er EOVERFLOW +More than SSIZE_MAX characters were read without encountering the delimiter. +.El +.Pp +The +.Fn getdelim +and +.Fn getline +functions may also fail and set +.Va errno +for any of the errors specified in the routines +.Xr fflush 3 , +.Xr malloc 3 , +.Xr read 2 , +.Xr stat 2 , +or +.Xr realloc 3 . +.Sh SEE ALSO +.Xr ferror 3 , +.Xr fgets 3 , +.Xr fopen 3 +.Sh STANDARDS +The +.Fn getdelim +and +.Fn getline +functions conform to +.St -p1003.1-2008 . diff --git a/lib/libc/stdio/getdelim.c b/lib/libc/stdio/getdelim.c new file mode 100644 index 00000000000..dcde0c34e61 --- /dev/null +++ b/lib/libc/stdio/getdelim.c @@ -0,0 +1,134 @@ +/* $OpenBSD: getdelim.c,v 1.1 2012/03/21 23:44:35 fgsch Exp $ */ +/* $NetBSD: getdelim.c,v 1.13 2011/07/22 23:12:30 joerg Exp $ */ + +/* + * Copyright (c) 2009 The NetBSD Foundation, Inc. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Roy Marples. + * + * 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 ``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 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 <errno.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "local.h" + +/* Minimum buffer size we create. + * This should allow config files to fit into our power of 2 buffer growth + * without the need for a realloc. */ +#define MINBUF 128 + +ssize_t +getdelim(char **__restrict buf, size_t *__restrict buflen, + int sep, FILE *__restrict fp) +{ + unsigned char *p; + size_t len, newlen, off; + char *newb; + + FLOCKFILE(fp); + + if (buf == NULL || buflen == NULL) { + errno = EINVAL; + goto error; + } + + /* If buf is NULL, we have to assume a size of zero */ + if (*buf == NULL) + *buflen = 0; + + _SET_ORIENTATION(fp, -1); + off = 0; + do { + /* If the input buffer is empty, refill it */ + if (fp->_r <= 0 && __srefill(fp)) { + if (__sferror(fp)) + goto error; + /* No error, so EOF. */ + break; + } + + /* Scan through looking for the separator */ + p = memchr(fp->_p, sep, (size_t)fp->_r); + if (p == NULL) + len = fp->_r; + else + len = (p - fp->_p) + 1; + + newlen = off + len; + /* Ensure we can handle it */ + if (newlen < off || newlen > SSIZE_MAX) { + errno = EOVERFLOW; + goto error; + } + newlen++; /* reserve space for the NULL terminator */ + if (newlen > *buflen) { + if (newlen < MINBUF) + newlen = MINBUF; +#define powerof2(x) ((((x)-1)&(x))==0) + if (!powerof2(newlen)) { + /* Grow the buffer to the next power of 2 */ + newlen--; + newlen |= newlen >> 1; + newlen |= newlen >> 2; + newlen |= newlen >> 4; + newlen |= newlen >> 8; + newlen |= newlen >> 16; +#if SIZE_T_MAX > 0xffffffffU + newlen |= newlen >> 32; +#endif + newlen++; + } + + newb = realloc(*buf, newlen); + if (newb == NULL) + goto error; + *buf = newb; + *buflen = newlen; + } + + (void)memcpy((*buf + off), fp->_p, len); + /* Safe, len is never greater than what fp->_r can fit. */ + fp->_r -= (int)len; + fp->_p += (int)len; + off += len; + } while (p == NULL); + + FUNLOCKFILE(fp); + + /* POSIX demands we return -1 on EOF. */ + if (off == 0) + return -1; + + if (*buf != NULL) + *(*buf + off) = '\0'; + return off; + +error: + fp->_flags |= __SERR; + FUNLOCKFILE(fp); + return -1; +} diff --git a/lib/libc/stdio/getline.c b/lib/libc/stdio/getline.c new file mode 100644 index 00000000000..55ad39675b9 --- /dev/null +++ b/lib/libc/stdio/getline.c @@ -0,0 +1,37 @@ +/* $OpenBSD: getline.c,v 1.1 2012/03/21 23:44:35 fgsch Exp $ */ +/* $NetBSD: getline.c,v 1.3 2009/12/02 08:46:33 roy Exp $ */ + +/* + * Copyright (c) 2009 The NetBSD Foundation, Inc. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Roy Marples. + * + * 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 ``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 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 <stdio.h> + +ssize_t +getline(char **__restrict buf, size_t *__restrict buflen, FILE *__restrict fp) +{ + return getdelim(buf, buflen, '\n', fp); +} |