summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2023-11-22 13:35:55 -0800
committerKaz Kylheku <kaz@kylheku.com>2023-11-22 13:35:55 -0800
commit81fa0c0f30bb6bcd2a4d287748db6d090b0d04ea (patch)
treed581b3e6445623ed47f81e0e34c061b4445cd66b
parent0a4c8368263bf2b9258f02fea12c60825d780885 (diff)
downloadtxr-81fa0c0f30bb6bcd2a4d287748db6d090b0d04ea.tar.gz
txr-81fa0c0f30bb6bcd2a4d287748db6d090b0d04ea.tar.bz2
txr-81fa0c0f30bb6bcd2a4d287748db6d090b0d04ea.zip
glob: suppress consecutive duplicates; fix memleak.
* glob.c (glob_wrap): When converting the glob array to the returned list, suppress consecutive duplicates. This has to be done separately for each call to glob or super_glob, so we now interleave the production of the output list with the glob calls. It has to be done separately because there can be duplicates between different patterns. E.g. if (glob "?") matches one path then (glob '("?" "?")) must return two copies of it. Furthermore, the brace expansion implementation in glob* produces multiple glob calls and appends their results. Duplicates inside a single super_glob call result when there are multiple ** (double star) patterns present, which are matched by the same path in more than one way. If the results are sorted, then the duplicates appear consecutively and we will squash them. Also, a memory leak is fixed here: we must free(pat_u8) unconditionally, before testing for the early exit situation.
-rw-r--r--glob.c33
-rw-r--r--tests/018/glob.tl2
2 files changed, 23 insertions, 12 deletions
diff --git a/glob.c b/glob.c
index a2642c92..932af58d 100644
--- a/glob.c
+++ b/glob.c
@@ -82,6 +82,8 @@ val glob_wrap(val pattern, val flags, val errfun)
int (*globfn)(const char *, int,
int (*) (const char *, int),
glob_t *) = if3((c_flags & GLOB_XSTAR) != 0, super_glob, glob);
+ size_t i = 0;
+ list_collect_decl (out, ptail);
if (s_errfunc)
uw_throwf(error_s, lit("~a: glob cannot be re-entered from "
@@ -98,8 +100,16 @@ val glob_wrap(val pattern, val flags, val errfun)
if (stringp(pattern)) {
char *pat_u8 = utf8_dup_to(c_str(pattern, self));
+ const char *prev = "";
(void) globfn(pat_u8, c_flags, s_errfunc ? errfunc_thunk : 0, &gl);
free(pat_u8);
+ for (; i < gl.gl_pathc; i++) {
+ const char *path = gl.gl_pathv[i];
+ if (prev == path || strcmp(prev, path) == 0)
+ continue;
+ ptail = list_collect (ptail, string_utf8(path));
+ prev = path;
+ }
} else {
seq_iter_t iter;
val elem;
@@ -107,11 +117,20 @@ val glob_wrap(val pattern, val flags, val errfun)
while (seq_get(&iter, &elem)) {
char *pat_u8 = utf8_dup_to(c_str(elem, self));
+ const char *prev = "";
(void) globfn(pat_u8, c_flags, s_errfunc ? errfunc_thunk : 0, &gl);
+ free(pat_u8);
if (s_exit_point)
break;
c_flags |= GLOB_APPEND;
- free(pat_u8);
+
+ for (; i < gl.gl_pathc; i++) {
+ const char *path = gl.gl_pathv[i];
+ if (prev == path || strcmp(prev, path) == 0)
+ continue;
+ ptail = list_collect (ptail, string_utf8(path));
+ prev = path;
+ }
}
}
@@ -124,16 +143,8 @@ val glob_wrap(val pattern, val flags, val errfun)
uw_continue(ep);
}
- {
- size_t i;
- list_collect_decl (out, ptail);
-
- for (i = 0; i < gl.gl_pathc; i++)
- ptail = list_collect (ptail, string_utf8(gl.gl_pathv[i]));
-
- globfree(&gl);
- return out;
- }
+ globfree(&gl);
+ return out;
}
static const char *super_glob_find_inner(const char *pattern)
diff --git a/tests/018/glob.tl b/tests/018/glob.tl
index f28ec480..438e4c65 100644
--- a/tests/018/glob.tl
+++ b/tests/018/glob.tl
@@ -112,7 +112,7 @@
(glob* "**/{3,4,5}*/**" glob-xnobrace)
nil
(len (glob* "**/proc/**/**"))
- 547)
+ 366)
(if (neq (os-symbol) :solaris)
(test