3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Angus Leeming
8 * Full author contact details are available in file CREDITS.
13 #include "support/globbing.h"
14 #include "support/lstrings.h"
15 #include "support/path.h"
17 #include <boost/regex.hpp>
18 #include <boost/tokenizer.hpp>
30 string const convert_brace_glob(string const & glob)
32 // Matches " *.{abc,def,ghi}", storing "*." as group 1 and
33 // "abc,def,ghi" as group 2.
34 static boost::regex const glob_re(" *([^ {]*)\\{([^ }]+)\\}");
35 // Matches "abc" and "abc,", storing "abc" as group 1.
36 static boost::regex const block_re("([^,}]+),?");
40 string::const_iterator it = glob.begin();
41 string::const_iterator const end = glob.end();
43 boost::match_results<string::const_iterator> what;
44 if (!boost::regex_search(it, end, what, glob_re)) {
45 // Ensure that no information is lost.
46 pattern += string(it, end);
50 // Everything from the start of the input to
51 // the start of the match.
52 pattern += string(what[-1].first, what[-1].second);
54 // Given " *.{abc,def}", head == "*." and tail == "abc,def".
55 string const head = string(what[1].first, what[1].second);
56 string const tail = string(what[2].first, what[2].second);
58 // Split the ','-separated chunks of tail so that
59 // $head{$chunk1,$chunk2} becomes "$head$chunk1 $head$chunk2".
60 string const fmt = " " + head + "$1";
61 pattern += boost::regex_merge(tail, block_re, fmt);
63 // Increment the iterator to the end of the match.
64 it += distance(it, what[0].second);
71 vector<string> const glob(string const & pattern, int flags)
74 glob_buffer.gl_offs = 0;
75 glob(pattern.c_str(), flags, 0, &glob_buffer);
76 vector<string> const matches(glob_buffer.gl_pathv,
77 glob_buffer.gl_pathv +
78 glob_buffer.gl_pathc);
79 globfree(&glob_buffer);
84 vector<string> const expand_globs(string const & mask,
85 string const & directory)
87 typedef boost::tokenizer<boost::char_separator<char> > Tokenizer;
88 boost::char_separator<char> const separator(" ");
90 // Given "<glob> <glob> ... *.{abc,def} <glob>", expand to
91 // "<glob> <glob> ... *.abc *.def <glob>"
92 string const converted_glob = convert_brace_glob(mask);
96 // Split into individual globs and then call 'glob' on each one.
97 vector<string> matches;
98 Tokenizer const tokens(converted_glob, separator);
99 Tokenizer::const_iterator it = tokens.begin();
100 Tokenizer::const_iterator const end = tokens.end();
101 for (; it != end; ++it) {
102 vector<string> const tmp = glob(*it);
103 matches.insert(matches.end(), tmp.begin(), tmp.end());
108 } // namespace support