about summary refs log tree commit diff
path: root/src/regex
diff options
context:
space:
mode:
authorIsmael Luceno <ismael@iodev.co.uk>2019-07-25 23:50:48 +0200
committerRich Felker <dalias@aerifal.cx>2019-08-06 14:03:31 -0400
commit49eacf29d29fa704b2feda879978ae64a825358c (patch)
tree9197460fce02c8e15a59f65fa60ecd7098db2cb0 /src/regex
parentf522de81ac88dddb58266c15bcfaa044c4065e19 (diff)
downloadmusl-49eacf29d29fa704b2feda879978ae64a825358c.tar.gz
musl-49eacf29d29fa704b2feda879978ae64a825358c.tar.xz
musl-49eacf29d29fa704b2feda879978ae64a825358c.zip
glob: implement GLOB_TILDE and GLOB_TILDE_CHECK
Diffstat (limited to 'src/regex')
-rw-r--r--src/regex/glob.c42
1 files changed, 41 insertions, 1 deletions
diff --git a/src/regex/glob.c b/src/regex/glob.c
index aa1c6a44..58248675 100644
--- a/src/regex/glob.c
+++ b/src/regex/glob.c
@@ -8,6 +8,8 @@
 #include <stdlib.h>
 #include <errno.h>
 #include <stddef.h>
+#include <unistd.h>
+#include <pwd.h>
 
 struct match
 {
@@ -182,6 +184,39 @@ static int sort(const void *a, const void *b)
 	return strcmp(*(const char **)a, *(const char **)b);
 }
 
+static int expand_tilde(char **pat, char *buf, size_t *pos)
+{
+	char *p = *pat + 1;
+	size_t i = 0;
+
+	char delim, *name_end = __strchrnul(p, '/');
+	if ((delim = *name_end)) *name_end++ = 0;
+	*pat = name_end;
+
+	char *home = *p ? NULL : getenv("HOME");
+	if (!home) {
+		struct passwd pw, *res;
+		switch (*p ? getpwnam_r(p, &pw, buf, PATH_MAX, &res)
+			   : getpwuid_r(getuid(), &pw, buf, PATH_MAX, &res)) {
+		case ENOMEM:
+			return GLOB_NOSPACE;
+		case 0:
+			if (!res)
+		default:
+				return GLOB_NOMATCH;
+		}
+		home = pw.pw_dir;
+	}
+	while (i < PATH_MAX - 2 && *home)
+		buf[i++] = *home++;
+	if (*home)
+		return GLOB_NOMATCH;
+	if ((buf[i] = delim))
+		buf[++i] = 0;
+	*pos = i;
+	return 0;
+}
+
 int glob(const char *restrict pat, int flags, int (*errfunc)(const char *path, int err), glob_t *restrict g)
 {
 	struct match head = { .next = NULL }, *tail = &head;
@@ -202,7 +237,12 @@ int glob(const char *restrict pat, int flags, int (*errfunc)(const char *path, i
 		char *p = strdup(pat);
 		if (!p) return GLOB_NOSPACE;
 		buf[0] = 0;
-		error = do_glob(buf, 0, 0, p, flags, errfunc, &tail);
+		size_t pos = 0;
+		char *s = p;
+		if ((flags & (GLOB_TILDE | GLOB_TILDE_CHECK)) && *p == '~')
+			error = expand_tilde(&s, buf, &pos);
+		if (!error)
+			error = do_glob(buf, pos, 0, s, flags, errfunc, &tail);
 		free(p);
 	}