]> git.decadent.org.uk Git - dak.git/blob - tools/dsync-0.0/libdsync/filefilter.cc
Added another tool used in dak (and placed nowhere else), dsync
[dak.git] / tools / dsync-0.0 / libdsync / filefilter.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description                                                          /*{{{*/
3 // $Id: filefilter.cc,v 1.4 1999/08/05 03:22:55 jgg Exp $
4 /* ######################################################################
5
6    File Filter - Regular Expression maching filter
7    
8    The idea for this was stolen shamelessly from rsync.
9
10    Doesn't work:
11     dsync-flist -e binary-alpha -i binary-all -i binary-i386 generate /tmp/listing
12    
13    And various other incantations like that.
14    
15    ##################################################################### */
16                                                                         /*}}}*/
17 // Include files                                                        /*{{{*/
18 #ifdef __GNUG__
19 #pragma implementation "dsync/filefilter.h"
20 #endif
21
22 #include <dsync/filefilter.h>
23 #include <dsync/error.h>
24
25 #include <fnmatch.h>
26 using namespace std;
27                                                                         /*}}}*/
28
29 // FileFilter::dsFileFilter - Constructor                               /*{{{*/
30 // ---------------------------------------------------------------------
31 /* */
32 dsFileFilter::dsFileFilter() : List(0)
33 {
34 }
35                                                                         /*}}}*/
36 // FileFilter::~dsFileFilter - Destructor                               /*{{{*/
37 // ---------------------------------------------------------------------
38 /* */
39 dsFileFilter::~dsFileFilter()
40 {
41    while (List != 0)
42    {
43       Item *Tmp = List;
44       List = Tmp->Next;
45       delete Tmp;
46    }
47 }
48                                                                         /*}}}*/
49 // FileFilter::Test - Test a directory and file                         /*{{{*/
50 // ---------------------------------------------------------------------
51 /* This will return true if the named entity is included by the filter, false
52    otherwise. By default all entries are included. */
53 bool dsFileFilter::Test(const char *Directory,const char *File)
54 {
55    for (Item *I = List; I != 0; I = I->Next)
56    {
57       bool Res = I->Test(Directory,File);
58       if (Res == false)
59          continue;
60       
61       if (I->Type == Item::Include)
62          return true;
63       
64       if (I->Type == Item::Exclude)
65          return false;
66    }
67    
68    return true;
69 }
70                                                                         /*}}}*/
71 // FileFilter::LoadFilter - Load the filter list from the configuration /*{{{*/
72 // ---------------------------------------------------------------------
73 /* When given the root of a configuration tree this will parse that sub-tree
74    as an ordered list of include/exclude directives. Each value in the list
75    must be prefixed with a + or a - indicating include/exclude */
76 bool dsFileFilter::LoadFilter(Configuration::Item const *Top)
77 {
78    if (Top != 0)
79       Top = Top->Child;
80    
81    // Advance to the end of the list
82    Item **End = &List;
83    for (; *End != 0; End = &(*End)->Next);
84       
85    for (; Top != 0;)
86    {
87       Item *New = new Item;
88       
89       // Decode the type
90       if (Top->Value[0] == '+')
91          New->Type = Item::Include;
92       else
93       {
94          if (Top->Value[0] == '-')
95             New->Type = Item::Exclude;
96          else
97          {
98             delete New;
99             return _error->Error("Malformed filter directive %s",Top->Tag.c_str());
100          }
101       }
102
103       // Strip off the +/- indicator
104       unsigned int Count = 1;
105       for (const char *I = Top->Value.c_str() + 1; I < Top->Value.c_str() + strlen(Top->Value.c_str()) &&
106              isspace(*I); I++)
107          Count++;
108       New->Pattern = string(Top->Value,Count);
109       
110       // Set flags
111       New->Flags = 0;
112       if (New->Pattern == "*")
113          New->Flags |= Item::MatchAll;
114       if (New->Pattern.find('/') != string::npos)
115          New->Flags |= Item::MatchPath;
116       
117       // Link it into the list
118       New->Next = 0;
119       *End = New;
120       End = &New->Next;
121       
122       Top = Top->Next;
123    }
124    return true;
125 }
126                                                                         /*}}}*/
127 // FileFilter::Item::Test - Test a single item                          /*{{{*/
128 // ---------------------------------------------------------------------
129 /* */
130 bool dsFileFilter::Item::Test(const char *Directory,const char *File)
131 {
132    // Catch all
133    if ((Flags & MatchAll) == MatchAll)
134       return true;
135  
136    // Append the direcotry
137    if ((Flags & MatchPath) == MatchPath)
138    {
139       char S[1024];
140       if (strlen(Directory) + strlen(File) > sizeof(S))
141           return _error->Error("File field overflow");
142       strcpy(S,Directory);
143       strcat(S,File);
144       
145       return fnmatch(Pattern.c_str(),S,FNM_PATHNAME) == 0;
146    }
147    
148    return fnmatch(Pattern.c_str(),File,FNM_PATHNAME) == 0;
149 }
150                                                                         /*}}}*/