summaryrefslogtreecommitdiff
path: root/lib/libc
diff options
context:
space:
mode:
authorFederico G. Schwindt <fgsch@cvs.openbsd.org>2012-03-21 23:44:36 +0000
committerFederico G. Schwindt <fgsch@cvs.openbsd.org>2012-03-21 23:44:36 +0000
commit6c8fdab4473fb1ea0bc0189a8c11a1f581ba4b3e (patch)
treed5516719feedfb8dac881ff3b48f5064434f6590 /lib/libc
parentbec4c79143a9a3b2a6b939a4e009faeb84e68413 (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.inc9
-rw-r--r--lib/libc/stdio/getdelim.3155
-rw-r--r--lib/libc/stdio/getdelim.c134
-rw-r--r--lib/libc/stdio/getline.c37
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);
+}