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 // FIXME Interface violation
20 #include <boost/regex.hpp>
21 #include <boost/tokenizer.hpp>
28 using std::ostringstream;
36 string const convert_brace_glob(string const & glob)
38 // Matches " *.{abc,def,ghi}", storing "*." as group 1 and
39 // "abc,def,ghi" as group 2.
40 static boost::regex const glob_re(" *([^ {]*)\\{([^ }]+)\\}");
41 // Matches "abc" and "abc,", storing "abc" as group 1.
42 static boost::regex const block_re("([^,}]+),?");
46 string::const_iterator it = glob.begin();
47 string::const_iterator const end = glob.end();
49 boost::match_results<string::const_iterator> what;
50 if (!boost::regex_search(it, end, what, glob_re)) {
51 // Ensure that no information is lost.
52 pattern += string(it, end);
56 // Everything from the start of the input to
57 // the start of the match.
58 pattern += string(what[-1].first, what[-1].second);
60 // Given " *.{abc,def}", head == "*." and tail == "abc,def".
61 string const head = string(what[1].first, what[1].second);
62 string const tail = string(what[2].first, what[2].second);
64 // Split the ','-separated chunks of tail so that
65 // $head{$chunk1,$chunk2} becomes "$head$chunk1 $head$chunk2".
66 string const fmt = " " + head + "$1";
67 pattern += boost::regex_merge(tail, block_re, fmt);
69 // Increment the iterator to the end of the match.
70 it += distance(it, what[0].second);
77 vector<string> const glob(string const & pattern, int flags)
80 glob_buffer.gl_offs = 0;
81 glob(pattern.c_str(), flags, 0, &glob_buffer);
82 vector<string> const matches(glob_buffer.gl_pathv,
83 glob_buffer.gl_pathv +
84 glob_buffer.gl_pathc);
85 globfree(&glob_buffer);
90 vector<string> const expand_globs(string const & mask,
91 string const & directory)
93 typedef boost::tokenizer<boost::char_separator<char> > Tokenizer;
94 boost::char_separator<char> const separator(" ");
96 // Given "<glob> <glob> ... *.{abc,def} <glob>", expand to
97 // "<glob> <glob> ... *.abc *.def <glob>"
98 string const converted_glob = convert_brace_glob(mask);
102 // Split into individual globs and then call 'glob' on each one.
103 vector<string> matches;
104 Tokenizer const tokens(converted_glob, separator);
105 Tokenizer::const_iterator it = tokens.begin();
106 Tokenizer::const_iterator const end = tokens.end();
107 for (; it != end; ++it) {
108 vector<string> const tmp = glob(*it);
109 matches.insert(matches.end(), tmp.begin(), tmp.end());
115 FileFilterList::FileFilterList(string const & qt_style_filter)
117 string const filter = qt_style_filter
118 + (qt_style_filter.empty() ? string() : ";;")
119 + _("All files (*)");
121 // Split data such as "TeX documents (*.tex);;LyX Documents (*.lyx)"
122 // into individual filters.
123 static boost::regex const separator_re(";;");
125 string::const_iterator it = filter.begin();
126 string::const_iterator const end = filter.end();
128 boost::match_results<string::const_iterator> what;
130 if (!boost::regex_search(it, end, what, separator_re)) {
131 parse_filter(string(it, end));
135 // Everything from the start of the input to
136 // the start of the match.
137 parse_filter(string(what[-1].first, what[-1].second));
139 // Increment the iterator to the end of the match.
140 it += distance(it, what[0].second);
145 void FileFilterList::parse_filter(string const & filter)
147 // Matches "TeX documents (*.tex)",
148 // storing "TeX documents " as group 1 and "*.tex" as group 2.
149 static boost::regex const filter_re("([^(]*)\\(([^)]+)\\) *$");
151 boost::match_results<string::const_iterator> what;
152 if (!boost::regex_search(filter, what, filter_re)) {
153 // Just a glob, no description.
154 filters_.push_back(Filter(string(), trim(filter)));
156 string const desc = string(what[1].first, what[1].second);
157 string const globs = string(what[2].first, what[2].second);
158 filters_.push_back(Filter(trim(desc), trim(globs)));
163 string const FileFilterList::str(bool expand) const
167 vector<Filter>::const_iterator const begin = filters_.begin();
168 vector<Filter>::const_iterator const end = filters_.end();
169 vector<Filter>::const_iterator it = begin;
170 for (; it != end; ++it) {
171 string const globs = expand ?
172 convert_brace_glob(it->globs()) : it->globs();
175 bool const has_description = !it->description().empty();
177 ss << it->description() << " (";
186 } // namespace support