1 /*
2 
3   Simple wildcard matching with pattern matching
4 
5   copyright (c) 2004 squell <squell@alumina.nl>
6 
7   use, modification, copying and distribution of this software is permitted
8   under the conditions described in the file 'COPYING'.
9 
10   Usage:
11 
12   Construct a varexp object using a wildcard specification and a test
13   string, and then access the matched variables (if any) using the
14   index operator. Example:
15 
16      varexp v("*, *", "foo, bar")
17      v[0]; // == "foo"
18      v[1]; // == "bar"
19 
20   The index operator returns a std::string. Use the cpy() member if you
21   want a copy in plain-old-C style.
22 
23   In a boolean context, a varexp object converts to a boolean value which
24   holds the results of the pattern match (failed/succeed). Thus, varexp can
25   also be used like an ordinary wildcard test:
26 
27      if( varexp("r*.txt", str) )
28          ...       // executes if str matched "r*.txt"
29 
30   Restrictions:
31 
32   The result of using operator[] or cpy() is undefined if the string used
33   to  generate the varexp object is changed. However, values returned before
34   the point of alteration will remain safe.
35 
36   operator[] performs range checking, and throws an out_of_range exception
37   if an index is not >= 0 && < size()
38 
39   cpy(), true to form, will not perform any range checking and is a
40   potential can of worms, generally. :)
41 
42   The wildcard match will fail in certain cases where filenames are in a
43   multi-byte encodings that is not filesystem-safe, like EUC-JP.
44 
45 */
46 
47 #ifndef __ZF_VAREXP
48 #define __ZF_VAREXP
49 
50 #include <cstring>
51 #include <vector>
52 #include <utility>
53 #include <string>
54 #include <stdexcept>
55 #include <iterator>
56 
57 class varexp {
58 public:
varexp(const char * mask,const char * test)59     varexp(const char* mask, const char* test) : var()
60     { result = match(mask,test); };
varexp()61     varexp() : var()
62     { result = 0; }
63 
64     operator bool() const
65     { return result; }
66 
67     std::string operator[](std::size_t i) const;
68 
size()69     std::size_t size() const
70     { return var.size(); }
71 
72     char* cpy(char* dest, std::size_t i) const;
73 
74     class iterator;
75     iterator begin() const;
76     iterator end() const;
77 
78 protected:
79     typedef std::vector< std::pair<const char*, int> > pairvec;
80     pairvec var;
81     bool result;
82 
83     bool match(const char* mask, const char* test);
84     const char* in_set(char c, const char* set);
85     friend class iterator;
86 };
87 
88 inline std::string varexp::operator[](std::size_t i) const
89 {
90     if( i >= var.size() )                     // bounds check
91         throw std::out_of_range("varexp: index out of range");
92 
93     return std::string( var[i].first, var[i].second );
94 }
95 
cpy(char * dest,std::size_t i)96 inline char* varexp::cpy(char* dest, std::size_t i) const
97 {
98     return std::strncpy(dest, var[i].first, var[i].second );
99 }
100 
101 class varexp::iterator : public std::iterator_traits<pairvec::const_iterator> {
102     friend class varexp;
103     pairvec::const_iterator p;
104 
iterator(const pairvec::const_iterator & _p)105     iterator(const pairvec::const_iterator& _p) : p(_p) { }
106 public:
107     std::string operator*() const { return std::string(p->first, p->second); }
108     iterator& operator++()        { return ++p, *this; }
109     iterator  operator++(int)     { iterator tmp(*this);
110                                     return ++p, tmp; }
111 
112     friend bool operator==(const iterator& a, const iterator& b)
113     { return a.p == b.p; }
114     friend bool operator!=(const iterator& a, const iterator& b)
115     { return a.p != b.p; }
116 
117     typedef std::input_iterator_tag iterator_category;
118     typedef std::string             value_type;
119     typedef const std::string*      pointer;
120     typedef const std::string&      reference;
121 };
122 
begin()123 inline varexp::iterator varexp::begin() const
124 {
125     return iterator(var.begin());
126 }
127 
end()128 inline varexp::iterator varexp::end() const
129 {
130     return iterator(var.end());
131 }
132 
133 #endif
134 
135