<pre style='margin:0'>
Rainer Müller (raimue) pushed a commit to branch vcs-fetch
in repository macports-base.

</pre>
<p><a href="https://github.com/macports/macports-base/commit/37e40f2ac471d1aa2ff09c04a6c1a4aef6f20856">https://github.com/macports/macports-base/commit/37e40f2ac471d1aa2ff09c04a6c1a4aef6f20856</a></p>
<pre style="white-space: pre; background: #F8F8F8"><span style='display:block; white-space:pre;color:#808000;'>commit 37e40f2ac471d1aa2ff09c04a6c1a4aef6f20856
</span>Author: Rainer Müller <raimue@macports.org>
AuthorDate: Mon Apr 2 01:45:07 2018 +0200

<span style='display:block; white-space:pre;color:#404040;'>    fs-traverse: Add -exclude option
</span>---
 src/pextlib1.0/fs-traverse.c         | 68 +++++++++++++++++++++++++++++++++---
 src/pextlib1.0/tests/fs-traverse.tcl | 56 +++++++++++++++++++++++++++++
 2 files changed, 119 insertions(+), 5 deletions(-)

<span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/pextlib1.0/fs-traverse.c b/src/pextlib1.0/fs-traverse.c
</span><span style='display:block; white-space:pre;color:#808080;'>index a0e0e20..c8db16d 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/src/pextlib1.0/fs-traverse.c
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/pextlib1.0/fs-traverse.c
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -49,18 +49,19 @@
</span> #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
<span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <fnmatch.h>
</span> 
 #include <tcl.h>
 
 #include "fs-traverse.h"
 
<span style='display:block; white-space:pre;background:#ffe0e0;'>-static int do_traverse(Tcl_Interp *interp, int flags, char * const *targets, Tcl_Obj *varname, Tcl_Obj *body);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int do_traverse(Tcl_Interp *interp, int flags, const char * const *excludes, char * const *targets, Tcl_Obj *varname, Tcl_Obj *body);
</span> 
 #define F_DEPTH 0x1
 #define F_IGNORE_ERRORS 0x2
 #define F_TAILS 0x4
 
<span style='display:block; white-space:pre;background:#ffe0e0;'>-/* fs-traverse ?-depth? ?-ignoreErrors? ?-tails? ?--? varname target-list body */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* fs-traverse ?-depth? ?-ignoreErrors? ?-tails? ?-exclude path-list? ?--? varname target-list body */
</span> int
 FsTraverseCmd(ClientData clientData UNUSED, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
 {
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -70,6 +71,7 @@ FsTraverseCmd(ClientData clientData UNUSED, Tcl_Interp *interp, int objc, Tcl_Ob
</span>     int rval = TCL_OK;
     Tcl_Obj *listPtr;
     Tcl_Obj *CONST *objv_orig = objv;
<span style='display:block; white-space:pre;background:#e0ffe0;'>+    const char **excludes = NULL;
</span>     int lobjc;
     Tcl_Obj **lobjv;
 
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -94,6 +96,41 @@ FsTraverseCmd(ClientData clientData UNUSED, Tcl_Interp *interp, int objc, Tcl_Ob
</span>             ++objv, --objc;
             continue;
         }
<span style='display:block; white-space:pre;background:#e0ffe0;'>+        if (!strcmp(arg, "-exclude")) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            /* free previous list, can happen if specified multiple times */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            free(excludes);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            excludes = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            ++objv, --objc;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            if (objc == 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                Tcl_WrongNumArgs(interp, 1, objv, "-exclude path-list");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                return TCL_ERROR;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            int lexcc = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            Tcl_Obj **lexcv = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            const char **iter;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            if ((rval = Tcl_ListObjGetElements(interp, *objv, &lexcc, &lexcv)) != TCL_OK) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                return rval;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            ++objv, --objc;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            excludes = calloc(lexcc + 1, sizeof(char *));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            if (excludes == NULL) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                Tcl_SetErrno(errno);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                Tcl_ResetResult(interp);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                Tcl_AppendResult(interp, "malloc: ", (char *) Tcl_PosixError(interp), NULL);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                return TCL_ERROR;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            iter = excludes;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            while (lexcc > 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                *iter++ = Tcl_GetString(*lexcv);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                --lexcc, ++lexcv;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            *iter = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            continue;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        }
</span>         if (!strcmp(arg, "--")) {
             ++objv, --objc;
             break;
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -103,7 +140,8 @@ FsTraverseCmd(ClientData clientData UNUSED, Tcl_Interp *interp, int objc, Tcl_Ob
</span>     
     /* Parse remaining args */
     if (objc != 3) {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        Tcl_WrongNumArgs(interp, 1, objv_orig, "?-depth? ?-ignoreErrors? ?-tails? ?--? varname target-list body");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        Tcl_WrongNumArgs(interp, 1, objv_orig, "?-depth? ?-ignoreErrors? ?-tails? ?-exclude path-list? ?--? varname target-list body");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        free(excludes);
</span>         return TCL_ERROR;
     }
     
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -122,6 +160,8 @@ FsTraverseCmd(ClientData clientData UNUSED, Tcl_Interp *interp, int objc, Tcl_Ob
</span>         if (flags & F_TAILS && lobjc > 1) {
             /* result would be ambiguous with multiple paths, so we do not allow this */
             Tcl_SetResult(interp, "-tails cannot be used with multiple paths", TCL_STATIC);
<span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            free(excludes);
</span>             return TCL_ERROR;
         }
 
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -138,9 +178,11 @@ FsTraverseCmd(ClientData clientData UNUSED, Tcl_Interp *interp, int objc, Tcl_Ob
</span>             --lobjc, ++lobjv;
         }
         *iter = NULL;
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        rval = do_traverse(interp, flags, entries, varname, body);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        rval = do_traverse(interp, flags, excludes, entries, varname, body);
</span>         free(entries);
     }
<span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    free(excludes);
</span>     return rval;
 }
 
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -170,7 +212,7 @@ do_compare(const FTSENT **a, const FTSENT **b)
</span> }
 
 static int
<span style='display:block; white-space:pre;background:#ffe0e0;'>-do_traverse(Tcl_Interp *interp, int flags, char * const *targets, Tcl_Obj *varname, Tcl_Obj *body)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+do_traverse(Tcl_Interp *interp, int flags, const char * const *excludes, char * const *targets, Tcl_Obj *varname, Tcl_Obj *body)
</span> {
     int rval = TCL_OK;
     FTS *root_fts;
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -179,6 +221,22 @@ do_traverse(Tcl_Interp *interp, int flags, char * const *targets, Tcl_Obj *varna
</span>     root_fts = fts_open(targets, FTS_PHYSICAL /*| FTS_COMFOLLOW */| FTS_NOCHDIR | FTS_XDEV, &do_compare);
     
     while ((ent = fts_read(root_fts)) != NULL) {
<span style='display:block; white-space:pre;background:#e0ffe0;'>+        /* match path against excludes */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        const char * const *iter = excludes;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        int is_excluded = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        while (iter != NULL && *iter != NULL) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            const char *xpath = extract_tail(targets[0], ent->fts_path);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            if (fnmatch(*iter, xpath, FNM_PATHNAME) == 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                is_excluded = 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            iter++;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        if (is_excluded) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            fts_set(root_fts, ent, FTS_SKIP);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            continue;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span>         switch (ent->fts_info) {
             case FTS_D:  /* directory in pre-order */
             case FTS_DP: /* directory in post-order*/
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/pextlib1.0/tests/fs-traverse.tcl b/src/pextlib1.0/tests/fs-traverse.tcl
</span><span style='display:block; white-space:pre;color:#808080;'>index 0030c2f..3285cc8 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/src/pextlib1.0/tests/fs-traverse.tcl
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/pextlib1.0/tests/fs-traverse.tcl
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -61,6 +61,27 @@ proc main {pextlibname} {
</span>         }
         check_output $output $trees(4)
         
<span style='display:block; white-space:pre;background:#e0ffe0;'>+        # Test -exclude (simple)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set output [list]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        fs-traverse -exclude b file $root {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            lappend output $file
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        check_output $output $trees(sub3)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        # Test -exclude (complex)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set output [list]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        fs-traverse -exclude {a/c b/a */*/b b/c/} file $root {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            lappend output $file
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        check_output $output $trees(sub4)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        # Test empty -exclude
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set output [list]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        fs-traverse -exclude {} file $root {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            lappend output $file
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        check_output $output $trees(1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        
</span>         # Error raised for traversing directory that does not exist
         if {![catch {fs-traverse file $root/does_not_exist {}}]} {
             error "fs-traverse did not raise an error for a missing directory"
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -264,6 +285,41 @@ proc setup_trees {root} {
</span>         $root/a/c/a/c   directory
         $root/a/c/a/d   file
     "
<span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    set trees(sub3) "
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        $root           directory
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        $root/a         directory
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        $root/a/a       file
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        $root/a/b       file
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        $root/a/c       directory
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        $root/a/c/a     {link ../d}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        $root/a/c/b     file
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        $root/a/c/c     directory
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        $root/a/c/d     file
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        $root/a/d       directory
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        $root/a/d/a     file
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        $root/a/d/b     {link ../../b/a}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        $root/a/d/c     directory
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        $root/a/d/d     file
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        $root/a/e       file
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    "
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    set trees(sub4) "
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        $root           directory
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        $root/a         directory
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        $root/a/a       file
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        $root/a/b       file
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        $root/a/d       directory
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        $root/a/d/a     file
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        $root/a/d/c     directory
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        $root/a/d/d     file
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        $root/a/e       file
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        $root/b         directory
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        $root/b/b       directory
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        $root/b/c       directory
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        $root/b/c/a     file
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        $root/b/c/c     file
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    "
</span>     
     set trees(2) "
         $root/a/a       file
</pre><pre style='margin:0'>

</pre>