From 99a4f6360bf96de61fc0ff403ae2b0807ec8052d Mon Sep 17 00:00:00 2001 From: Kaz Kylheku Date: Wed, 22 Nov 2023 13:35:55 -0800 Subject: 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. --- glob.c | 33 ++++++++++++++++++++++----------- tests/018/glob.tl | 2 +- 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 -- cgit v1.2.3