filefilter.cc 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  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. using namespace std;
  20. /*}}}*/
  21. // FileFilter::dsFileFilter - Constructor /*{{{*/
  22. // ---------------------------------------------------------------------
  23. /* */
  24. dsFileFilter::dsFileFilter() : List(0)
  25. {
  26. }
  27. /*}}}*/
  28. // FileFilter::~dsFileFilter - Destructor /*{{{*/
  29. // ---------------------------------------------------------------------
  30. /* */
  31. dsFileFilter::~dsFileFilter()
  32. {
  33. while (List != 0)
  34. {
  35. Item *Tmp = List;
  36. List = Tmp->Next;
  37. delete Tmp;
  38. }
  39. }
  40. /*}}}*/
  41. // FileFilter::Test - Test a directory and file /*{{{*/
  42. // ---------------------------------------------------------------------
  43. /* This will return true if the named entity is included by the filter, false
  44. otherwise. By default all entries are included. */
  45. bool dsFileFilter::Test(const char *Directory,const char *File)
  46. {
  47. for (Item *I = List; I != 0; I = I->Next)
  48. {
  49. bool Res = I->Test(Directory,File);
  50. if (Res == false)
  51. continue;
  52. if (I->Type == Item::Include)
  53. return true;
  54. if (I->Type == Item::Exclude)
  55. return false;
  56. }
  57. return true;
  58. }
  59. /*}}}*/
  60. // FileFilter::LoadFilter - Load the filter list from the configuration /*{{{*/
  61. // ---------------------------------------------------------------------
  62. /* When given the root of a configuration tree this will parse that sub-tree
  63. as an ordered list of include/exclude directives. Each value in the list
  64. must be prefixed with a + or a - indicating include/exclude */
  65. bool dsFileFilter::LoadFilter(Configuration::Item const *Top)
  66. {
  67. if (Top != 0)
  68. Top = Top->Child;
  69. // Advance to the end of the list
  70. Item **End = &List;
  71. for (; *End != 0; End = &(*End)->Next);
  72. for (; Top != 0;)
  73. {
  74. Item *New = new Item;
  75. // Decode the type
  76. if (Top->Value[0] == '+')
  77. New->Type = Item::Include;
  78. else
  79. {
  80. if (Top->Value[0] == '-')
  81. New->Type = Item::Exclude;
  82. else
  83. {
  84. delete New;
  85. return _error->Error("Malformed filter directive %s",Top->Tag.c_str());
  86. }
  87. }
  88. // Strip off the +/- indicator
  89. unsigned int Count = 1;
  90. for (const char *I = Top->Value.c_str() + 1; I < Top->Value.c_str() + strlen(Top->Value.c_str()) &&
  91. isspace(*I); I++)
  92. Count++;
  93. New->Pattern = string(Top->Value,Count);
  94. // Set flags
  95. New->Flags = 0;
  96. if (New->Pattern == "*")
  97. New->Flags |= Item::MatchAll;
  98. if (New->Pattern.find('/') != string::npos)
  99. New->Flags |= Item::MatchPath;
  100. // Link it into the list
  101. New->Next = 0;
  102. *End = New;
  103. End = &New->Next;
  104. Top = Top->Next;
  105. }
  106. return true;
  107. }
  108. /*}}}*/
  109. // FileFilter::Item::Test - Test a single item /*{{{*/
  110. // ---------------------------------------------------------------------
  111. /* */
  112. bool dsFileFilter::Item::Test(const char *Directory,const char *File)
  113. {
  114. // Catch all
  115. if ((Flags & MatchAll) == MatchAll)
  116. return true;
  117. // Append the direcotry
  118. if ((Flags & MatchPath) == MatchPath)
  119. {
  120. char S[1024];
  121. if (strlen(Directory) + strlen(File) > sizeof(S))
  122. return _error->Error("File field overflow");
  123. strcpy(S,Directory);
  124. strcat(S,File);
  125. return fnmatch(Pattern.c_str(),S,FNM_PATHNAME) == 0;
  126. }
  127. return fnmatch(Pattern.c_str(),File,FNM_PATHNAME) == 0;
  128. }
  129. /*}}}*/