From 05521dc5c5a6b571016fde335e5a91e00e48ab1b Mon Sep 17 00:00:00 2001
From: Christoph Hellwig <hch@cloudius-systems.com>
Date: Thu, 17 Jan 2013 19:55:05 +0100
Subject: [PATCH] add misc routines from musl

---
 libc/build.mak                   | 16 +++++--
 libc/misc/a64l.c                 | 26 ++++++++++++
 libc/misc/basename.c             | 14 +++++++
 libc/misc/dirname.c              | 14 +++++++
 libc/misc/ffs.c                  |  7 ++++
 libc/misc/get_current_dir_name.c | 16 +++++++
 libc/misc/gethostid.c            |  4 ++
 libc/misc/getopt.c               | 72 ++++++++++++++++++++++++++++++++
 libc/misc/getopt_long.c          | 59 ++++++++++++++++++++++++++
 libc/misc/getresgid.c            |  8 ++++
 libc/misc/getresuid.c            |  8 ++++
 libc/misc/getsubopt.c            | 23 ++++++++++
 libc/misc/setdomainname.c        |  8 ++++
 13 files changed, 272 insertions(+), 3 deletions(-)
 create mode 100644 libc/misc/a64l.c
 create mode 100644 libc/misc/basename.c
 create mode 100644 libc/misc/dirname.c
 create mode 100644 libc/misc/ffs.c
 create mode 100644 libc/misc/get_current_dir_name.c
 create mode 100644 libc/misc/gethostid.c
 create mode 100644 libc/misc/getopt.c
 create mode 100644 libc/misc/getopt_long.c
 create mode 100644 libc/misc/getresgid.c
 create mode 100644 libc/misc/getresuid.c
 create mode 100644 libc/misc/getsubopt.c
 create mode 100644 libc/misc/setdomainname.c

diff --git a/libc/build.mak b/libc/build.mak
index 926cdbaf2..d1bf4dd08 100644
--- a/libc/build.mak
+++ b/libc/build.mak
@@ -1,7 +1,5 @@
 libc :=
 
-libc += getopt.o
-
 libc += ctype/__ctype_b_loc.o
 libc += ctype/__ctype_get_mb_cur_max.o
 libc += ctype/__ctype_tolower_loc.o
@@ -99,6 +97,19 @@ libc += locale/wcsxfrm_l.o
 libc += locale/wctrans_l.o
 libc += locale/wctype_l.o
 
+libc += misc/a64l.o
+libc += misc/basename.o
+libc += misc/dirname.o
+libc += misc/ffs.o
+libc += misc/get_current_dir_name.o
+libc += misc/gethostid.o
+libc += misc/getopt.o
+libc += misc/getopt_long.o
+libc += misc/getresuid.o
+libc += misc/getresgid.o
+libc += misc/getsubopt.o
+libc += misc/setdomainname.o
+
 libc += multibyte/btowc.o
 libc += multibyte/internal.o
 libc += multibyte/mblen.o
@@ -224,4 +235,3 @@ libc += time.o
 libc += signal.o
 libc += mman.o
 libc += qsort.o
-
diff --git a/libc/misc/a64l.c b/libc/misc/a64l.c
new file mode 100644
index 000000000..86aeefe0d
--- /dev/null
+++ b/libc/misc/a64l.c
@@ -0,0 +1,26 @@
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+
+static const char digits[] =
+	"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+long a64l(const char *s)
+{
+	int e;
+	uint32_t x = 0;
+	for (e=0; e<36 && *s; e+=6, s++)
+		x |= (strchr(digits, *s)-digits)<<e;
+	return x;
+}
+
+char *l64a(long x0)
+{
+	static char s[7];
+	char *p;
+	uint32_t x = x0;
+	for (p=s; x; p++, x>>=6)
+		*p = digits[x&63];
+	*p = 0;
+	return s;
+}
diff --git a/libc/misc/basename.c b/libc/misc/basename.c
new file mode 100644
index 000000000..5713598a2
--- /dev/null
+++ b/libc/misc/basename.c
@@ -0,0 +1,14 @@
+#include <string.h>
+#include "libc.h"
+
+char *basename(char *s)
+{
+	size_t i;
+	if (!s || !*s) return ".";
+	i = strlen(s)-1;
+	for (; i&&s[i]=='/'; i--) s[i] = 0;
+	for (; i&&s[i-1]!='/'; i--);
+	return s+i;
+}
+
+weak_alias(basename, __xpg_basename);
diff --git a/libc/misc/dirname.c b/libc/misc/dirname.c
new file mode 100644
index 000000000..dd570883d
--- /dev/null
+++ b/libc/misc/dirname.c
@@ -0,0 +1,14 @@
+#include <string.h>
+#include <libgen.h>
+
+char *dirname(char *s)
+{
+	size_t i;
+	if (!s || !*s) return ".";
+	i = strlen(s)-1;
+	for (; s[i]=='/'; i--) if (!i) return "/";
+	for (; s[i]!='/'; i--) if (!i) return ".";
+	for (; s[i]=='/'; i--) if (!i) return "/";
+	s[i+1] = 0;
+	return s;
+}
diff --git a/libc/misc/ffs.c b/libc/misc/ffs.c
new file mode 100644
index 000000000..673ce5a97
--- /dev/null
+++ b/libc/misc/ffs.c
@@ -0,0 +1,7 @@
+#include <strings.h>
+#include "atomic.h"
+
+int ffs(int i)
+{
+	return i ? a_ctz_l(i)+1 : 0;
+}
diff --git a/libc/misc/get_current_dir_name.c b/libc/misc/get_current_dir_name.c
new file mode 100644
index 000000000..e0f463b5c
--- /dev/null
+++ b/libc/misc/get_current_dir_name.c
@@ -0,0 +1,16 @@
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+char *get_current_dir_name(void) {
+	struct stat a, b;
+	char buf[PATH_MAX];
+	char *res = getenv("PWD");
+	if (res && *res && !stat(res, &a) && !stat(".", &b)
+	    && (a.st_dev == b.st_dev) && (a.st_ino == b.st_ino))
+		return strdup(res);
+	if(!getcwd(buf, sizeof(buf))) return NULL;
+	return strdup(buf);
+}
diff --git a/libc/misc/gethostid.c b/libc/misc/gethostid.c
new file mode 100644
index 000000000..ea65611ab
--- /dev/null
+++ b/libc/misc/gethostid.c
@@ -0,0 +1,4 @@
+long gethostid()
+{
+	return 0;
+}
diff --git a/libc/misc/getopt.c b/libc/misc/getopt.c
new file mode 100644
index 000000000..35880a090
--- /dev/null
+++ b/libc/misc/getopt.c
@@ -0,0 +1,72 @@
+#include <unistd.h>
+#include <wchar.h>
+#include <string.h>
+#include <limits.h>
+#include <stdlib.h>
+#include "libc.h"
+
+char *optarg;
+int optind=1, opterr=1, optopt, __optpos, __optreset=0;
+
+#define optpos __optpos
+weak_alias(__optreset, optreset);
+
+int getopt(int argc, char * const argv[], const char *optstring)
+{
+	int i;
+	wchar_t c, d;
+	int k, l;
+	char *optchar;
+
+	if (!optind || __optreset) {
+		__optreset = 0;
+		__optpos = 0;
+		optind = 1;
+	}
+
+	if (optind >= argc || !argv[optind] || argv[optind][0] != '-' || !argv[optind][1])
+		return -1;
+	if (argv[optind][1] == '-' && !argv[optind][2])
+		return optind++, -1;
+
+	if (!optpos) optpos++;
+	if ((k = mbtowc(&c, argv[optind]+optpos, MB_LEN_MAX)) < 0) {
+		k = 1;
+		c = 0xfffd; /* replacement char */
+	}
+	optchar = argv[optind]+optpos;
+	optopt = c;
+	optpos += k;
+
+	if (!argv[optind][optpos]) {
+		optind++;
+		optpos = 0;
+	}
+
+	for (i=0; (l = mbtowc(&d, optstring+i, MB_LEN_MAX)) && d!=c; i+=l>0?l:1);
+
+	if (d != c) {
+		if (optstring[0] != ':' && opterr) {
+			write(2, argv[0], strlen(argv[0]));
+			write(2, ": illegal option: ", 18);
+			write(2, optchar, k);
+			write(2, "\n", 1);
+		}
+		return '?';
+	}
+	if (optstring[i+1] == ':') {
+		if (optind >= argc) {
+			if (optstring[0] == ':') return ':';
+			if (opterr) {
+				write(2, argv[0], strlen(argv[0]));
+				write(2, ": option requires an argument: ", 31);
+				write(2, optchar, k);
+				write(2, "\n", 1);
+			}
+			return '?';
+		}
+		optarg = argv[optind++] + optpos;
+		optpos = 0;
+	}
+	return c;
+}
diff --git a/libc/misc/getopt_long.c b/libc/misc/getopt_long.c
new file mode 100644
index 000000000..4ef5a5c7a
--- /dev/null
+++ b/libc/misc/getopt_long.c
@@ -0,0 +1,59 @@
+#define _GNU_SOURCE
+#include <stddef.h>
+#include <getopt.h>
+#include <stdio.h>
+
+extern int __optpos, __optreset;
+
+static int __getopt_long(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx, int longonly)
+{
+	if (!optind || __optreset) {
+		__optreset = 0;
+		__optpos = 0;
+		optind = 1;
+	}
+	if (optind >= argc || !argv[optind] || argv[optind][0] != '-') return -1;
+	if ((longonly && argv[optind][1]) ||
+		(argv[optind][1] == '-' && argv[optind][2]))
+	{
+		int i;
+		for (i=0; longopts[i].name; i++) {
+			const char *name = longopts[i].name;
+			char *opt = argv[optind]+1;
+			if (*opt == '-') opt++;
+			for (; *name && *name == *opt; name++, opt++);
+			if (*name || (*opt && *opt != '=')) continue;
+			if (*opt == '=') {
+				if (!longopts[i].has_arg) continue;
+				optarg = opt+1;
+			} else {
+				if (longopts[i].has_arg == required_argument) {
+					if (!(optarg = argv[++optind]))
+						return ':';
+				} else optarg = NULL;
+			}
+			optind++;
+			if (idx) *idx = i;
+			if (longopts[i].flag) {
+				*longopts[i].flag = longopts[i].val;
+				return 0;
+			}
+			return longopts[i].val;
+		}
+		if (argv[optind][1] == '-') {
+			optind++;
+			return '?';
+		}
+	}
+	return getopt(argc, argv, optstring);
+}
+
+int getopt_long(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx)
+{
+	return __getopt_long(argc, argv, optstring, longopts, idx, 0);
+}
+
+int getopt_long_only(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx)
+{
+	return __getopt_long(argc, argv, optstring, longopts, idx, 1);
+}
diff --git a/libc/misc/getresgid.c b/libc/misc/getresgid.c
new file mode 100644
index 000000000..d00d9a99d
--- /dev/null
+++ b/libc/misc/getresgid.c
@@ -0,0 +1,8 @@
+#define _GNU_SOURCE
+#include <unistd.h>
+#include "syscall.h"
+
+int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid)
+{
+	return syscall(SYS_getresgid, rgid, egid, sgid);
+}
diff --git a/libc/misc/getresuid.c b/libc/misc/getresuid.c
new file mode 100644
index 000000000..d75d5d408
--- /dev/null
+++ b/libc/misc/getresuid.c
@@ -0,0 +1,8 @@
+#define _GNU_SOURCE
+#include <unistd.h>
+#include "syscall.h"
+
+int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
+{
+	return syscall(SYS_getresuid, ruid, euid, suid);
+}
diff --git a/libc/misc/getsubopt.c b/libc/misc/getsubopt.c
new file mode 100644
index 000000000..dac9bf9ea
--- /dev/null
+++ b/libc/misc/getsubopt.c
@@ -0,0 +1,23 @@
+#include <stdlib.h>
+#include <string.h>
+
+int getsubopt(char **opt, char *const *keys, char **val)
+{
+	char *s = *opt;
+	int i;
+
+	*val = NULL;
+	*opt = strchr(s, ',');
+	if (*opt) *(*opt)++ = 0;
+	else *opt = s + strlen(s);
+
+	for (i=0; keys[i]; i++) {
+		size_t l = strlen(keys[i]);
+		if (strncmp(keys[i], s, l)) continue;
+		if (s[l] == '=')
+			*val = s + l;
+		else if (s[l]) continue;
+		return i;
+	}
+	return -1;
+}
diff --git a/libc/misc/setdomainname.c b/libc/misc/setdomainname.c
new file mode 100644
index 000000000..22d3f7463
--- /dev/null
+++ b/libc/misc/setdomainname.c
@@ -0,0 +1,8 @@
+#define _GNU_SOURCE
+#include <unistd.h>
+#include "syscall.h"
+
+int setdomainname(const char *name, size_t len)
+{
+	return syscall(SYS_setdomainname, name, len);
+}
-- 
GitLab