Add POSIX getsubopt(3).
Bug: http://b/27952303
Change-Id: I8a816477545dadcbd5c055714e76263574446b6f
diff --git a/libc/Android.mk b/libc/Android.mk
index e9ee7fc..6d358cc 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -491,6 +491,7 @@
upstream-openbsd/lib/libc/stdlib/atol.c \
upstream-openbsd/lib/libc/stdlib/atoll.c \
upstream-openbsd/lib/libc/stdlib/getenv.c \
+ upstream-openbsd/lib/libc/stdlib/getsubopt.c \
upstream-openbsd/lib/libc/stdlib/insque.c \
upstream-openbsd/lib/libc/stdlib/imaxabs.c \
upstream-openbsd/lib/libc/stdlib/imaxdiv.c \
diff --git a/libc/include/stdlib.h b/libc/include/stdlib.h
index d9d277a..88930b1 100644
--- a/libc/include/stdlib.h
+++ b/libc/include/stdlib.h
@@ -135,6 +135,8 @@
int ptsname_r(int, char*, size_t);
int unlockpt(int);
+int getsubopt(char**, char* const*, char**);
+
typedef struct {
int quot;
int rem;
diff --git a/libc/libc.arm.brillo.map b/libc/libc.arm.brillo.map
index b8cdd3c..f631ad9 100644
--- a/libc/libc.arm.brillo.map
+++ b/libc/libc.arm.brillo.map
@@ -1274,6 +1274,7 @@
LIBC_O {
global:
getdomainname;
+ getsubopt;
hasmntopt;
pthread_getname_np;
setdomainname;
diff --git a/libc/libc.arm.map b/libc/libc.arm.map
index 57060ae..4c2a272 100644
--- a/libc/libc.arm.map
+++ b/libc/libc.arm.map
@@ -1274,6 +1274,7 @@
LIBC_O {
global:
getdomainname;
+ getsubopt;
hasmntopt;
pthread_getname_np;
setdomainname;
diff --git a/libc/libc.arm64.map b/libc/libc.arm64.map
index ac9d009..c42d1b6 100644
--- a/libc/libc.arm64.map
+++ b/libc/libc.arm64.map
@@ -1196,6 +1196,7 @@
LIBC_O {
global:
getdomainname;
+ getsubopt;
hasmntopt;
pthread_getname_np;
setdomainname;
diff --git a/libc/libc.map.txt b/libc/libc.map.txt
index 9d51b8d..25f647d 100644
--- a/libc/libc.map.txt
+++ b/libc/libc.map.txt
@@ -1300,6 +1300,7 @@
LIBC_O {
global:
getdomainname;
+ getsubopt;
hasmntopt;
pthread_getname_np;
setdomainname;
diff --git a/libc/libc.mips.brillo.map b/libc/libc.mips.brillo.map
index 7133f4b..d55f32d 100644
--- a/libc/libc.mips.brillo.map
+++ b/libc/libc.mips.brillo.map
@@ -1258,6 +1258,7 @@
LIBC_O {
global:
getdomainname;
+ getsubopt;
hasmntopt;
pthread_getname_np;
setdomainname;
diff --git a/libc/libc.mips.map b/libc/libc.mips.map
index e9b15c3..44d7d81 100644
--- a/libc/libc.mips.map
+++ b/libc/libc.mips.map
@@ -1258,6 +1258,7 @@
LIBC_O {
global:
getdomainname;
+ getsubopt;
hasmntopt;
pthread_getname_np;
setdomainname;
diff --git a/libc/libc.mips64.map b/libc/libc.mips64.map
index ac9d009..c42d1b6 100644
--- a/libc/libc.mips64.map
+++ b/libc/libc.mips64.map
@@ -1196,6 +1196,7 @@
LIBC_O {
global:
getdomainname;
+ getsubopt;
hasmntopt;
pthread_getname_np;
setdomainname;
diff --git a/libc/libc.x86.brillo.map b/libc/libc.x86.brillo.map
index c67f533..9c0b2ec 100644
--- a/libc/libc.x86.brillo.map
+++ b/libc/libc.x86.brillo.map
@@ -1257,6 +1257,7 @@
LIBC_O {
global:
getdomainname;
+ getsubopt;
hasmntopt;
pthread_getname_np;
setdomainname;
diff --git a/libc/libc.x86.map b/libc/libc.x86.map
index 6838184..980322a 100644
--- a/libc/libc.x86.map
+++ b/libc/libc.x86.map
@@ -1257,6 +1257,7 @@
LIBC_O {
global:
getdomainname;
+ getsubopt;
hasmntopt;
pthread_getname_np;
setdomainname;
diff --git a/libc/libc.x86_64.map b/libc/libc.x86_64.map
index ac9d009..c42d1b6 100644
--- a/libc/libc.x86_64.map
+++ b/libc/libc.x86_64.map
@@ -1196,6 +1196,7 @@
LIBC_O {
global:
getdomainname;
+ getsubopt;
hasmntopt;
pthread_getname_np;
setdomainname;
diff --git a/libc/upstream-openbsd/lib/libc/stdlib/getsubopt.c b/libc/upstream-openbsd/lib/libc/stdlib/getsubopt.c
new file mode 100644
index 0000000..735c85b
--- /dev/null
+++ b/libc/upstream-openbsd/lib/libc/stdlib/getsubopt.c
@@ -0,0 +1,92 @@
+/* $OpenBSD: getsubopt.c,v 1.4 2005/08/08 08:05:36 espie Exp $ */
+
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. 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.
+ * 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.
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * The SVID interface to getsubopt provides no way of figuring out which
+ * part of the suboptions list wasn't matched. This makes error messages
+ * tricky... The extern variable suboptarg is a pointer to the token
+ * which didn't match.
+ */
+char *suboptarg;
+
+int
+getsubopt(char **optionp, char * const *tokens, char **valuep)
+{
+ int cnt;
+ char *p;
+
+ suboptarg = *valuep = NULL;
+
+ if (!optionp || !*optionp)
+ return(-1);
+
+ /* skip leading white-space, commas */
+ for (p = *optionp; *p && (*p == ',' || *p == ' ' || *p == '\t'); ++p);
+
+ if (!*p) {
+ *optionp = p;
+ return(-1);
+ }
+
+ /* save the start of the token, and skip the rest of the token. */
+ for (suboptarg = p;
+ *++p && *p != ',' && *p != '=' && *p != ' ' && *p != '\t';);
+
+ if (*p) {
+ /*
+ * If there's an equals sign, set the value pointer, and
+ * skip over the value part of the token. Terminate the
+ * token.
+ */
+ if (*p == '=') {
+ *p = '\0';
+ for (*valuep = ++p;
+ *p && *p != ',' && *p != ' ' && *p != '\t'; ++p);
+ if (*p)
+ *p++ = '\0';
+ } else
+ *p++ = '\0';
+ /* Skip any whitespace or commas after this token. */
+ for (; *p && (*p == ',' || *p == ' ' || *p == '\t'); ++p);
+ }
+
+ /* set optionp for next round. */
+ *optionp = p;
+
+ for (cnt = 0; *tokens; ++tokens, ++cnt)
+ if (!strcmp(suboptarg, *tokens))
+ return(cnt);
+ return(-1);
+}