Add getdelim(3) and getline(3) to bionic

Some userspace programs (e.g. perf) need getline.

Changes:
() add getdelim.c, getline.c from NetBSD (http://netbsd.org/) under the
NetBSD Foundation's (TNF) license ("2 clause" Berkeley-style license).
() add stub for reentrant.h header that is needed by getdelim.c
() add tests for getdelim(3) and getline(3).
() update NOTICE file.

Change-Id: I22ed82dd5904b9d7a3695535c04f502be3c27c5d
Signed-off-by: Irina Tirdea <irina.tirdea@intel.com>
diff --git a/libc/Android.mk b/libc/Android.mk
index 45dadd2..13d2647 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -340,6 +340,8 @@
 	upstream-netbsd/libc/regex/regerror.c \
 	upstream-netbsd/libc/regex/regexec.c \
 	upstream-netbsd/libc/regex/regfree.c \
+	upstream-netbsd/libc/stdio/getdelim.c \
+	upstream-netbsd/libc/stdio/getline.c \
 	upstream-netbsd/libc/stdlib/tdelete.c \
 	upstream-netbsd/libc/stdlib/tfind.c \
 	upstream-netbsd/libc/stdlib/tsearch.c \
diff --git a/libc/NOTICE b/libc/NOTICE
index 299f672..36d9449 100644
--- a/libc/NOTICE
+++ b/libc/NOTICE
@@ -438,6 +438,40 @@
 
 -------------------------------------------------------------------
 
+Copyright (c) 1982, 1986, 1993
+   The Regents of the University of California.  All rights reserved.
+(c) UNIX System Laboratories, Inc.
+All or some portions of this file are derived from material licensed
+to the University of California by American Telephone and Telegraph
+Co. or Unix System Laboratories, Inc. and are reproduced herein with
+the permission of UNIX System Laboratories, Inc.
+
+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.
+3. Neither the name of the University nor the names of its contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+
+-------------------------------------------------------------------
+
 Copyright (c) 1983, 1987, 1989
    The Regents of the University of California.  All rights reserved.
 
@@ -3833,6 +3867,33 @@
 
 -------------------------------------------------------------------
 
+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.
+
+-------------------------------------------------------------------
+
 Copyright (c) 2010 MIPS Technologies, Inc.
 
 All rights reserved.
diff --git a/libc/include/stdio.h b/libc/include/stdio.h
index 8b95663..d0121c6 100644
--- a/libc/include/stdio.h
+++ b/libc/include/stdio.h
@@ -249,6 +249,9 @@
 size_t	 fwrite(const void *, size_t, size_t, FILE *);
 int	 getc(FILE *);
 int	 getchar(void);
+ssize_t	 getdelim(char ** __restrict, size_t * __restrict, int,
+	    FILE * __restrict);
+ssize_t	 getline(char ** __restrict, size_t * __restrict, FILE * __restrict);
 char	*gets(char *);
 #if __BSD_VISIBLE && !defined(__SYS_ERRLIST)
 #define __SYS_ERRLIST
diff --git a/libc/include/sys/param.h b/libc/include/sys/param.h
index 3a815cb..0bfdc5d 100644
--- a/libc/include/sys/param.h
+++ b/libc/include/sys/param.h
@@ -37,4 +37,6 @@
 #define ALIGNBYTES  3
 #define ALIGN(p)    (((unsigned int)(p) + ALIGNBYTES) &~ ALIGNBYTES)
 
+#define powerof2(x) ((((x)-1)&(x))==0)
+
 #endif /* _SYS_PARAM_H_ */
diff --git a/libc/upstream-netbsd/libc/stdio/getdelim.c b/libc/upstream-netbsd/libc/stdio/getdelim.c
new file mode 100644
index 0000000..acce376
--- /dev/null
+++ b/libc/upstream-netbsd/libc/stdio/getdelim.c
@@ -0,0 +1,154 @@
+/* $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 <sys/cdefs.h>
+__RCSID("$NetBSD: getdelim.c,v 1.13 2011/07/22 23:12:30 joerg Exp $");
+
+#include "namespace.h"
+
+#include <sys/param.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "reentrant.h"
+#include "local.h"
+
+#ifdef __weak_alias
+__weak_alias(getdelim, _getdelim)
+#endif
+
+/* 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;
+
+	_DIAGASSERT(fp != NULL);
+
+	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;
+			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);
+
+	/* POSIX demands we return -1 on EOF. */
+	if (off == 0) 
+		return -1;
+
+	if (*buf != NULL)
+		*(*buf + off) = '\0';
+	return off;
+
+error:
+	fp->_flags |= __SERR;
+	return -1;
+}
+
+ssize_t
+getdelim(char **__restrict buf, size_t *__restrict buflen,
+    int sep, FILE *__restrict fp)
+{
+	ssize_t n;
+
+	FLOCKFILE(fp);
+	n = __getdelim(buf, buflen, sep, fp);
+	FUNLOCKFILE(fp);
+	return n;
+}
diff --git a/libc/upstream-netbsd/libc/stdio/getline.c b/libc/upstream-netbsd/libc/stdio/getline.c
new file mode 100644
index 0000000..e5d4bab
--- /dev/null
+++ b/libc/upstream-netbsd/libc/stdio/getline.c
@@ -0,0 +1,45 @@
+/* $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 <sys/cdefs.h>
+__RCSID("$NetBSD: getline.c,v 1.3 2009/12/02 08:46:33 roy Exp $");
+
+#include "namespace.h"
+
+#include <stdio.h>
+
+#ifdef __weak_alias
+__weak_alias(getline, _getline)
+#endif
+
+ssize_t
+getline(char **__restrict buf, size_t *__restrict buflen, FILE *__restrict fp)
+{
+	return getdelim(buf, buflen, '\n', fp);
+}
diff --git a/libc/upstream-netbsd/reentrant.h b/libc/upstream-netbsd/reentrant.h
new file mode 100644
index 0000000..a4381d4
--- /dev/null
+++ b/libc/upstream-netbsd/reentrant.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _BIONIC_NETBSD_REENTRANT_H_included
+#define _BIONIC_NETBSD_REENTRANT_H_included
+
+#include <pthread.h>
+#include <signal.h>
+
+// Placeholder.
+
+#endif
diff --git a/tests/stdio_test.cpp b/tests/stdio_test.cpp
index 72af796..39f9b0f 100644
--- a/tests/stdio_test.cpp
+++ b/tests/stdio_test.cpp
@@ -46,3 +46,126 @@
 
   fclose(fp);
 }
+
+TEST(stdio, getdelim) {
+  FILE* fp = tmpfile();
+  ASSERT_TRUE(fp != NULL);
+
+  const char* line_written = "This  is a test";
+  int rc = fprintf(fp, "%s", line_written);
+  ASSERT_EQ(rc, static_cast<int>(strlen(line_written)));
+
+  rewind(fp);
+
+  char* word_read = NULL;
+  size_t allocated_length = 0;
+
+  const char* expected[] = { "This ", " ", "is ", "a ", "test" };
+  for (size_t i = 0; i < 5; ++i) {
+    ASSERT_FALSE(feof(fp));
+    ASSERT_EQ(getdelim(&word_read, &allocated_length, ' ', fp), static_cast<int>(strlen(expected[i])));
+    ASSERT_GE(allocated_length, strlen(expected[i]));
+    ASSERT_STREQ(word_read, expected[i]);
+  }
+  // The last read should have set the end-of-file indicator for the stream.
+  ASSERT_TRUE(feof(fp));
+  clearerr(fp);
+
+  // getdelim returns -1 but doesn't set errno if we're already at EOF.
+  // It should set the end-of-file indicator for the stream, though.
+  errno = 0;
+  ASSERT_EQ(getdelim(&word_read, &allocated_length, ' ', fp), -1);
+  ASSERT_EQ(errno, 0);
+  ASSERT_TRUE(feof(fp));
+
+  free(word_read);
+  fclose(fp);
+}
+
+TEST(stdio, getdelim_invalid) {
+  FILE* fp = tmpfile();
+
+  char* buffer = NULL;
+  size_t buffer_length = 0;
+
+  // The first argument can't be NULL.
+  errno = 0;
+  ASSERT_EQ(getdelim(NULL, &buffer_length, ' ', fp), -1);
+  ASSERT_EQ(errno, EINVAL);
+
+  // The second argument can't be NULL.
+  errno = 0;
+  ASSERT_EQ(getdelim(&buffer, NULL, ' ', fp), -1);
+  ASSERT_EQ(errno, EINVAL);
+
+  // The stream can't be closed.
+  fclose(fp);
+  errno = 0;
+  ASSERT_EQ(getdelim(&buffer, &buffer_length, ' ', fp), -1);
+  ASSERT_EQ(errno, EBADF);
+}
+
+TEST(stdio, getline) {
+  FILE* fp = tmpfile();
+  ASSERT_TRUE(fp != NULL);
+
+  const char* line_written = "This is a test for getline\n";
+  const size_t line_count = 5;
+
+  for (size_t i = 0; i < line_count; ++i) {
+    int rc = fprintf(fp, "%s", line_written);
+    ASSERT_EQ(rc, static_cast<int>(strlen(line_written)));
+  }
+
+  rewind(fp);
+
+  char* line_read = NULL;
+  size_t allocated_length = 0;
+
+  size_t read_line_count = 0;
+  ssize_t read_char_count;
+  while ((read_char_count = getline(&line_read, &allocated_length, fp)) != -1) {
+    ASSERT_EQ(read_char_count, static_cast<int>(strlen(line_written)));
+    ASSERT_GE(allocated_length, strlen(line_written));
+    ASSERT_STREQ(line_read, line_written);
+    ++read_line_count;
+  }
+  ASSERT_EQ(read_line_count, line_count);
+
+  // The last read should have set the end-of-file indicator for the stream.
+  ASSERT_TRUE(feof(fp));
+  clearerr(fp);
+
+  // getline returns -1 but doesn't set errno if we're already at EOF.
+  // It should set the end-of-file indicator for the stream, though.
+  errno = 0;
+  ASSERT_EQ(getline(&line_read, &allocated_length, fp), -1);
+  ASSERT_EQ(errno, 0);
+  ASSERT_TRUE(feof(fp));
+
+  free(line_read);
+  fclose(fp);
+}
+
+TEST(stdio, getline_invalid) {
+  FILE* fp = tmpfile();
+
+  char* buffer = NULL;
+  size_t buffer_length = 0;
+
+  // The first argument can't be NULL.
+  errno = 0;
+  ASSERT_EQ(getline(NULL, &buffer_length, fp), -1);
+  ASSERT_EQ(errno, EINVAL);
+
+  // The second argument can't be NULL.
+  errno = 0;
+  ASSERT_EQ(getline(&buffer, NULL, fp), -1);
+  ASSERT_EQ(errno, EINVAL);
+
+  // The stream can't be closed.
+  fclose(fp);
+  errno = 0;
+  ASSERT_EQ(getline(&buffer, &buffer_length, fp), -1);
+  ASSERT_EQ(errno, EBADF);
+}