filefilter.cc 4.0 KB

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