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
commit99a4f6360bf96de61fc0ff403ae2b0807ec8052d (patch)
treed581b3e6445623ed47f81e0e34c061b4445cd66b
parentf049d7a3e52768b6e59940174135f31a5580144b (diff)
downloadtxr-99a4f6360bf96de61fc0ff403ae2b0807ec8052d.tar.gz
txr-99a4f6360bf96de61fc0ff403ae2b0807ec8052d.tar.bz2
txr-99a4f6360bf96de61fc0ff403ae2b0807ec8052d.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