aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/contrib/tree-1.6.0-matchdirs.patch
blob: de2cfa2820868be25c1786f7b64ea7c3986bb831 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
From 57f931a7a8564379e7b2e5c31301dcd6c0e84b50 Mon Sep 17 00:00:00 2001
From: "Jason A. Donenfeld" <Jason@zx2c4.com>
Date: Thu, 4 Apr 2013 08:43:05 -0700
Subject: [PATCH] Add --matchdirs to check patterns against directories

This causes pattern matching to include the full contents of any
directories that match the pattern, including sub-directories.
---
 doc/tree.1 | 10 +++++++++-
 tree.c     | 46 ++++++++++++++++++++++++++++++++++++++++------
 2 files changed, 49 insertions(+), 7 deletions(-)

diff --git a/doc/tree.1 b/doc/tree.1
index 4b80852..7765f34 100644
--- a/doc/tree.1
+++ b/doc/tree.1
@@ -21,7 +21,7 @@
 .SH NAME
 tree \- list contents of directories in a tree-like format.
 .SH SYNOPSIS
-\fBtree\fP [\fB-acdfghilnpqrstuvxACDFQNSUX\fP] [\fB-L\fP \fIlevel\fP [\fB-R\fP]] [\fB-H\fP \fIbaseHREF\fP] [\fB-T\fP \fItitle\fP] [\fB-o\fP \fIfilename\fP] [\fB--nolinks\fP] [\fB-P\fP \fIpattern\fP] [\fB-I\fP \fIpattern\fP] [\fB--inodes\fP] [\fB--device\fP] [\fB--noreport\fP] [\fB--dirsfirst\fP] [\fB--version\fP] [\fB--help\fP] [\fB--filelimit\fP \fI#\fP] [\fB--si\fP] [\fB--prune\fP] [\fB--du\fP] [\fB--timefmt\fP \fIformat\fP] [\fIdirectory\fP ...]
+\fBtree\fP [\fB-acdfghilnpqrstuvxACDFQNSUX\fP] [\fB-L\fP \fIlevel\fP [\fB-R\fP]] [\fB-H\fP \fIbaseHREF\fP] [\fB-T\fP \fItitle\fP] [\fB-o\fP \fIfilename\fP] [\fB--nolinks\fP] [\fB-P\fP \fIpattern\fP] [\fB-I\fP \fIpattern\fP] [\fB--inodes\fP] [\fB--device\fP] [\fB--noreport\fP] [\fB--dirsfirst\fP] [\fB--version\fP] [\fB--help\fP] [\fB--filelimit\fP \fI#\fP] [\fB--si\fP] [\fB--prune\fP] [\fB--du\fP] [\fB--timefmt\fP \fIformat\fP] [\fB--matchdirs\fP] [\fIdirectory\fP ...]
 .br
 .SH DESCRIPTION
 \fITree\fP is a recursive directory listing program that produces a depth
@@ -123,6 +123,14 @@ Prints (implies -D) and formats the date according to the format string
 which uses the \fBstrftime\fP(3) syntax.
 .PP
 .TP
+.B --matchdirs
+If a match pattern is specified by the -P option, this will cause the pattern
+to be applied to directory names (in addition to filenames).  In the event of a
+match on the directory name, matching is disabled for the directory's
+contents.If the --prune option is used, empty folders that match the pattern
+will not be pruned.
+.PP
+.TP
 .B -o \fIfilename\fP
 Send output to \fIfilename\fP.
 .PP
diff --git a/tree.c b/tree.c
index 19cf368..187613d 100644
--- a/tree.c
+++ b/tree.c
@@ -28,7 +28,7 @@ static char *hversion="\t\t tree v1.6.0 %s 1996 - 2011 by Steve Baker and Thomas
 bool dflag, lflag, pflag, sflag, Fflag, aflag, fflag, uflag, gflag;
 bool qflag, Nflag, Qflag, Dflag, inodeflag, devflag, hflag, Rflag;
 bool Hflag, siflag, cflag, Xflag, duflag, pruneflag;
-bool noindent, force_color, nocolor, xdev, noreport, nolinks, flimit, dirsfirst, nosort;
+bool noindent, force_color, nocolor, xdev, noreport, nolinks, flimit, dirsfirst, nosort, matchdirs;
 char *pattern = NULL, *ipattern = NULL, *host = NULL, *title = "Directory Tree", *sp = " ";
 char *timefmt = NULL;
 const char *charset = NULL;
@@ -75,12 +75,13 @@ int main(int argc, char **argv)
   char sizebuf[64];
   off_t size = 0;
   mode_t mt;
+  bool needfulltree;
 
   q = p = dtotal = ftotal = 0;
   aflag = dflag = fflag = lflag = pflag = sflag = Fflag = uflag = gflag = FALSE;
   Dflag = qflag = Nflag = Qflag = Rflag = hflag = Hflag = siflag = cflag = FALSE;
   noindent = force_color = nocolor = xdev = noreport = nolinks = FALSE;
-  dirsfirst = nosort = inodeflag = devflag = Xflag = FALSE;
+  matchdirs = dirsfirst = nosort = inodeflag = devflag = Xflag = FALSE;
   duflag = pruneflag = FALSE;
   flimit = 0;
   dirs = xmalloc(sizeof(int) * (maxdirs=4096));
@@ -350,6 +351,11 @@ int main(int argc, char **argv)
 	      Dflag = TRUE;
 	      break;
 	    }
+	    if (!strncmp("--matchdirs",argv[i],11)) {
+	      j = strlen(argv[i])-1;
+	      matchdirs = TRUE;
+	      break;
+	    }
 	  }
 	default:
 	  fprintf(stderr,"tree: Invalid argument -`%c'.\n",argv[i][j]);
@@ -387,16 +393,17 @@ int main(int argc, char **argv)
   parse_dir_colors();
   initlinedraw(0);
 
+  needfulltree = duflag || pruneflag || matchdirs;
   /* Set our listdir function and sanity check options. */
   if (Hflag) {
-    listdir = (duflag || pruneflag)? html_rlistdir : html_listdir;
+    listdir = needfulltree ? html_rlistdir : html_listdir;
     Xflag = FALSE;
   } else if (Xflag) {
-    listdir = (duflag || pruneflag)? xml_rlistdir : xml_listdir;
+    listdir = needfulltree ? xml_rlistdir : xml_listdir;
     colorize = FALSE;
     colored = FALSE; /* Do people want colored XML output? */
   } else {
-    listdir = (duflag || pruneflag)? unix_rlistdir : unix_listdir;
+    listdir = needfulltree ? unix_rlistdir : unix_listdir;
   }
   if (dflag) pruneflag = FALSE;	/* You'll just get nothing otherwise. */
 
@@ -534,6 +541,7 @@ void usage(int n)
 	"  --charset X   Use charset X for terminal/HTML and indentation line output.\n"
 	"  --filelimit # Do not descend dirs with more than # files in them.\n"
 	"  --timefmt <f> Print and format time according to the format <f>.\n"
+	"  --matchdirs   Include directory names in -P pattern matching.\n"
 	"  -o filename   Output to file instead of stdout.\n"
 	"  -------- File options ---------\n"
 	"  -q            Print non-printable characters as '?'.\n"
@@ -689,6 +697,8 @@ struct _info **getfulltree(char *d, u_long lev, dev_t dev, off_t *size, char **e
   struct _info **dir, **sav, **p, *sp;
   struct stat sb;
   int n;
+  u_long lev_tmp;
+  char *tmp_pattern = NULL, *start_rel_path;
   
   *err = NULL;
   if (Level >= 0 && lev > Level) return NULL;
@@ -696,7 +706,29 @@ struct _info **getfulltree(char *d, u_long lev, dev_t dev, off_t *size, char **e
     stat(d,&sb);
     dev = sb.st_dev;
   }
+
+  // if the directory name matches, turn off pattern matching for contents
+  if (matchdirs && pattern) {
+    lev_tmp = lev;
+    for (start_rel_path = d + strlen(d); start_rel_path != d; --start_rel_path) {
+      if (*start_rel_path == '/')
+        --lev_tmp;
+      if (lev_tmp <= 0) {
+        if (*start_rel_path)
+          ++start_rel_path;
+        break;
+      }
+    }
+    if (patmatch(start_rel_path,pattern) == 1) {
+      tmp_pattern = pattern;
+      pattern = NULL;
+    }
+  }
   sav = dir = read_dir(d,&n);
+  if (tmp_pattern) {
+    pattern = tmp_pattern;
+    tmp_pattern = NULL;
+  }
   if (dir == NULL) {
     *err = scopy("error opening dir");
     return NULL;
@@ -745,7 +777,9 @@ struct _info **getfulltree(char *d, u_long lev, dev_t dev, off_t *size, char **e
 	saveino((*dir)->inode, (*dir)->dev);
 	(*dir)->child = getfulltree(path,lev+1,dev,&((*dir)->size),&((*dir)->err));
       }
-      if (pruneflag && (*dir)->child == NULL) {
+      // prune empty folders, unless they match the requested pattern
+      if (pruneflag && (*dir)->child == NULL &&
+	  !(matchdirs && pattern && patmatch((*dir)->name,pattern) == 1)) {
 	sp = *dir;
 	for(p=dir;*p;p++) *p = *(p+1);
 	n--;
-- 
1.9.2