summaryrefslogtreecommitdiffstats
path: root/lib/libc/stdio/getdelim.c
diff options
context:
space:
mode:
authorfgsch <fgsch@openbsd.org>2012-03-21 23:44:35 +0000
committerfgsch <fgsch@openbsd.org>2012-03-21 23:44:35 +0000
commitdc89375155d9f94f665cd70800cb655b8fc502b7 (patch)
tree744c2f0f81b2a6580b4f6c8f9c6405c825cda475 /lib/libc/stdio/getdelim.c
parentImplement execvpe(3) and posix_spawn(3) and family. Based on (diff)
downloadwireguard-openbsd-dc89375155d9f94f665cd70800cb655b8fc502b7.tar.xz
wireguard-openbsd-dc89375155d9f94f665cd70800cb655b8fc502b7.zip
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/stdio/getdelim.c')
-rw-r--r--lib/libc/stdio/getdelim.c134
1 files changed, 134 insertions, 0 deletions
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;
+}