]> git.lyx.org Git - features.git/blob - boost/libs/regex/src/cregex.cpp
boost: update to 1.42.0
[features.git] / boost / libs / regex / src / cregex.cpp
1 /*
2  *
3  * Copyright (c) 1998-2002
4  * John Maddock
5  *
6  * Use, modification and distribution are subject to the 
7  * Boost Software License, Version 1.0. (See accompanying file 
8  * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9  *
10  */
11
12  /*
13   *   LOCATION:    see http://www.boost.org for most recent version.
14   *   FILE:        cregex.cpp
15   *   VERSION:     see <boost/version.hpp>
16   *   DESCRIPTION: Implements high level class boost::RexEx
17   */
18
19
20 #define BOOST_REGEX_SOURCE
21
22 #include <boost/regex.hpp>
23 #include <boost/cregex.hpp>
24 #if !defined(BOOST_NO_STD_STRING)
25 #include <map>
26 #include <list>
27 #include <boost/regex/v4/fileiter.hpp>
28 typedef boost::match_flag_type match_flag_type;
29 #include <cstdio>
30
31 #ifdef BOOST_MSVC
32 #pragma warning(disable:4309)
33 #endif
34
35 namespace boost{
36
37 #ifdef __BORLANDC__
38 #if __BORLANDC__ < 0x530
39 //
40 // we need to instantiate the vector classes we use
41 // since declaring a reference to type doesn't seem to
42 // do the job...
43 std::vector<std::size_t> inst1;
44 std::vector<std::string> inst2;
45 #endif
46 #endif
47
48 namespace{
49
50 template <class iterator>
51 std::string to_string(iterator i, iterator j)
52 {
53    std::string s;
54    while(i != j)
55    {
56       s.append(1, *i);
57       ++i;
58    }
59    return s;
60 }
61
62 inline std::string to_string(const char* i, const char* j)
63 {
64    return std::string(i, j);
65 }
66
67 }
68 namespace re_detail{
69
70 class RegExData
71 {
72 public:
73    enum type
74    {
75       type_pc,
76       type_pf,
77       type_copy
78    };
79    regex e;
80    cmatch m;
81 #ifndef BOOST_REGEX_NO_FILEITER
82    match_results<mapfile::iterator> fm;
83 #endif
84    type t;
85    const char* pbase;
86 #ifndef BOOST_REGEX_NO_FILEITER
87    mapfile::iterator fbase;
88 #endif
89    std::map<int, std::string, std::less<int> > strings;
90    std::map<int, std::ptrdiff_t, std::less<int> > positions;
91    void update();
92    void clean();
93    RegExData() : e(), m(),
94 #ifndef BOOST_REGEX_NO_FILEITER
95    fm(),
96 #endif
97    t(type_copy), pbase(0),
98 #ifndef BOOST_REGEX_NO_FILEITER
99    fbase(),
100 #endif
101    strings(), positions() {}
102 };
103
104 void RegExData::update()
105 {
106    strings.erase(strings.begin(), strings.end());
107    positions.erase(positions.begin(), positions.end());
108    if(t == type_pc)
109    {
110       for(unsigned int i = 0; i < m.size(); ++i)
111       {
112          if(m[i].matched) strings[i] = std::string(m[i].first, m[i].second);
113          positions[i] = m[i].matched ? m[i].first - pbase : -1;
114       }
115    }
116 #ifndef BOOST_REGEX_NO_FILEITER
117    else
118    {
119       for(unsigned int i = 0; i < fm.size(); ++i)
120       {
121          if(fm[i].matched) strings[i] = to_string(fm[i].first, fm[i].second);
122          positions[i] = fm[i].matched ? fm[i].first - fbase : -1;
123       }
124    }
125 #endif
126    t = type_copy;
127 }
128
129 void RegExData::clean()
130 {
131 #ifndef BOOST_REGEX_NO_FILEITER
132    fbase = mapfile::iterator();
133    fm = match_results<mapfile::iterator>();
134 #endif
135 }
136
137 } // namespace
138
139 RegEx::RegEx()
140 {
141    pdata = new re_detail::RegExData();
142 }
143
144 RegEx::RegEx(const RegEx& o)
145 {
146    pdata = new re_detail::RegExData(*(o.pdata));
147 }
148
149 RegEx::~RegEx()
150 {
151    delete pdata;
152 }
153
154 RegEx::RegEx(const char* c, bool icase)
155 {
156    pdata = new re_detail::RegExData();
157    SetExpression(c, icase);
158 }
159
160 RegEx::RegEx(const std::string& s, bool icase)
161 {
162    pdata = new re_detail::RegExData();
163    SetExpression(s.c_str(), icase);
164 }
165
166 RegEx& RegEx::operator=(const RegEx& o)
167 {
168    *pdata = *(o.pdata);
169    return *this;
170 }
171
172 RegEx& RegEx::operator=(const char* p)
173 {
174    SetExpression(p, false);
175    return *this;
176 }
177
178 unsigned int RegEx::SetExpression(const char* p, bool icase)
179 {
180    boost::uint_fast32_t f = icase ? regex::normal | regex::icase : regex::normal;
181    return pdata->e.set_expression(p, f);
182 }
183
184 unsigned int RegEx::error_code()const
185 {
186    return pdata->e.error_code();
187 }
188
189
190 std::string RegEx::Expression()const
191 {
192    return pdata->e.expression();
193 }
194
195 //
196 // now matching operators:
197 //
198 bool RegEx::Match(const char* p, match_flag_type flags)
199 {
200    pdata->t = re_detail::RegExData::type_pc;
201    pdata->pbase = p;
202    const char* end = p;
203    while(*end)++end;
204
205    if(regex_match(p, end, pdata->m, pdata->e, flags))
206    {
207       pdata->update();
208       return true;
209    }
210    return false;
211 }
212
213 bool RegEx::Search(const char* p, match_flag_type flags)
214 {
215    pdata->t = re_detail::RegExData::type_pc;
216    pdata->pbase = p;
217    const char* end = p;
218    while(*end)++end;
219
220    if(regex_search(p, end, pdata->m, pdata->e, flags))
221    {
222       pdata->update();
223       return true;
224    }
225    return false;
226 }
227 namespace re_detail{
228 struct pred1
229 {
230    GrepCallback cb;
231    RegEx* pe;
232    pred1(GrepCallback c, RegEx* i) : cb(c), pe(i) {}
233    bool operator()(const cmatch& m)
234    {
235       pe->pdata->m = m;
236       return cb(*pe);
237    }
238 };
239 }
240 unsigned int RegEx::Grep(GrepCallback cb, const char* p, match_flag_type flags)
241 {
242    pdata->t = re_detail::RegExData::type_pc;
243    pdata->pbase = p;
244    const char* end = p;
245    while(*end)++end;
246
247    unsigned int result = regex_grep(re_detail::pred1(cb, this), p, end, pdata->e, flags);
248    if(result)
249       pdata->update();
250    return result;
251 }
252 namespace re_detail{
253 struct pred2
254 {
255    std::vector<std::string>& v;
256    RegEx* pe;
257    pred2(std::vector<std::string>& o, RegEx* e) : v(o), pe(e) {}
258    bool operator()(const cmatch& m)
259    {
260       pe->pdata->m = m;
261       v.push_back(std::string(m[0].first, m[0].second));
262       return true;
263    }
264 private:
265    pred2& operator=(const pred2&);
266 };
267 }
268
269 unsigned int RegEx::Grep(std::vector<std::string>& v, const char* p, match_flag_type flags)
270 {
271    pdata->t = re_detail::RegExData::type_pc;
272    pdata->pbase = p;
273    const char* end = p;
274    while(*end)++end;
275
276    unsigned int result = regex_grep(re_detail::pred2(v, this), p, end, pdata->e, flags);
277    if(result)
278       pdata->update();
279    return result;
280 }
281 namespace re_detail{
282 struct pred3
283 {
284    std::vector<std::size_t>& v;
285    const char* base;
286    RegEx* pe;
287    pred3(std::vector<std::size_t>& o, const char* pb, RegEx* p) : v(o), base(pb), pe(p) {}
288    bool operator()(const cmatch& m)
289    {
290       pe->pdata->m = m;
291       v.push_back(static_cast<std::size_t>(m[0].first - base));
292       return true;
293    }
294 private:
295    pred3& operator=(const pred3&);
296 };
297 }
298 unsigned int RegEx::Grep(std::vector<std::size_t>& v, const char* p, match_flag_type flags)
299 {
300    pdata->t = re_detail::RegExData::type_pc;
301    pdata->pbase = p;
302    const char* end = p;
303    while(*end)++end;
304
305    unsigned int result = regex_grep(re_detail::pred3(v, p, this), p, end, pdata->e, flags);
306    if(result)
307       pdata->update();
308    return result;
309 }
310 #ifndef BOOST_REGEX_NO_FILEITER
311 namespace re_detail{
312 struct pred4
313 {
314    GrepFileCallback cb;
315    RegEx* pe;
316    const char* file;
317    bool ok;
318    pred4(GrepFileCallback c, RegEx* i, const char* f) : cb(c), pe(i), file(f), ok(true) {}
319    bool operator()(const match_results<mapfile::iterator>& m)
320    {
321       pe->pdata->t = RegExData::type_pf;
322       pe->pdata->fm = m;
323       pe->pdata->update();
324       ok = cb(file, *pe);
325       return ok;
326    }
327 };
328 }
329 namespace{
330 void BuildFileList(std::list<std::string>* pl, const char* files, bool recurse)
331 {
332    file_iterator start(files);
333    file_iterator end;
334    if(recurse)
335    {
336       // go through sub directories:
337       char buf[MAX_PATH];
338       re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(buf, MAX_PATH, start.root()));
339       if(*buf == 0)
340       {
341          re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(buf, MAX_PATH, "."));
342          re_detail::overflow_error_if_not_zero(re_detail::strcat_s(buf, MAX_PATH, directory_iterator::separator()));
343          re_detail::overflow_error_if_not_zero(re_detail::strcat_s(buf, MAX_PATH, "*"));
344       }
345       else
346       {
347          re_detail::overflow_error_if_not_zero(re_detail::strcat_s(buf, MAX_PATH, directory_iterator::separator()));
348          re_detail::overflow_error_if_not_zero(re_detail::strcat_s(buf, MAX_PATH, "*"));
349       }
350       directory_iterator dstart(buf);
351       directory_iterator dend;
352
353       // now get the file mask bit of "files":
354       const char* ptr = files;
355       while(*ptr) ++ptr;
356       while((ptr != files) && (*ptr != *directory_iterator::separator()) && (*ptr != '/'))--ptr;
357       if(ptr != files) ++ptr;
358
359       while(dstart != dend)
360       {
361 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) && !defined(_WIN32_WCE) && !defined(UNDER_CE)
362          (::sprintf_s)(buf, sizeof(buf), "%s%s%s", dstart.path(), directory_iterator::separator(), ptr);
363 #else
364          (std::sprintf)(buf, "%s%s%s", dstart.path(), directory_iterator::separator(), ptr);
365 #endif
366          BuildFileList(pl, buf, recurse);
367          ++dstart;
368       }
369    }
370    while(start != end)
371    {
372       pl->push_back(*start);
373       ++start;
374    }
375 }
376 }
377
378 unsigned int RegEx::GrepFiles(GrepFileCallback cb, const char* files, bool recurse, match_flag_type flags)
379 {
380    unsigned int result = 0;
381    std::list<std::string> file_list;
382    BuildFileList(&file_list, files, recurse);
383    std::list<std::string>::iterator start, end;
384    start = file_list.begin();
385    end = file_list.end();
386
387    while(start != end)
388    {
389       mapfile map((*start).c_str());
390       pdata->t = re_detail::RegExData::type_pf;
391       pdata->fbase = map.begin();
392       re_detail::pred4 pred(cb, this, (*start).c_str());
393       int r = regex_grep(pred, map.begin(), map.end(), pdata->e, flags);
394       result += r;
395       ++start;
396       pdata->clean();
397       if(pred.ok == false)
398          return result;
399    }
400
401    return result;
402 }
403
404
405 unsigned int RegEx::FindFiles(FindFilesCallback cb, const char* files, bool recurse, match_flag_type flags)
406 {
407    unsigned int result = 0;
408    std::list<std::string> file_list;
409    BuildFileList(&file_list, files, recurse);
410    std::list<std::string>::iterator start, end;
411    start = file_list.begin();
412    end = file_list.end();
413
414    while(start != end)
415    {
416       mapfile map((*start).c_str());
417       pdata->t = re_detail::RegExData::type_pf;
418       pdata->fbase = map.begin();
419
420       if(regex_search(map.begin(), map.end(), pdata->fm, pdata->e, flags))
421       {
422          ++result;
423          if(false == cb((*start).c_str()))
424             return result;
425       }
426       //pdata->update();
427       ++start;
428       //pdata->clean();
429    }
430
431    return result;
432 }
433 #endif
434
435 #ifdef BOOST_REGEX_V3
436 #define regex_replace regex_merge
437 #endif
438
439 std::string RegEx::Merge(const std::string& in, const std::string& fmt,
440                     bool copy, match_flag_type flags)
441 {
442    std::string result;
443    re_detail::string_out_iterator<std::string> i(result);
444    if(!copy) flags |= format_no_copy;
445    regex_replace(i, in.begin(), in.end(), pdata->e, fmt.c_str(), flags);
446    return result;
447 }
448
449 std::string RegEx::Merge(const char* in, const char* fmt,
450                     bool copy, match_flag_type flags)
451 {
452    std::string result;
453    if(!copy) flags |= format_no_copy;
454    re_detail::string_out_iterator<std::string> i(result);
455    regex_replace(i, in, in + std::strlen(in), pdata->e, fmt, flags);
456    return result;
457 }
458
459 std::size_t RegEx::Split(std::vector<std::string>& v, 
460                       std::string& s,
461                       match_flag_type flags,
462                       unsigned max_count)
463 {
464    return regex_split(std::back_inserter(v), s, pdata->e, flags, max_count);
465 }
466
467
468
469 //
470 // now operators for returning what matched in more detail:
471 //
472 std::size_t RegEx::Position(int i)const
473 {
474    switch(pdata->t)
475    {
476    case re_detail::RegExData::type_pc:
477       return pdata->m[i].matched ? pdata->m[i].first - pdata->pbase : RegEx::npos;
478 #ifndef BOOST_REGEX_NO_FILEITER
479    case re_detail::RegExData::type_pf:
480       return pdata->fm[i].matched ? pdata->fm[i].first - pdata->fbase : RegEx::npos;
481 #endif
482    case re_detail::RegExData::type_copy:
483       {
484       std::map<int, std::ptrdiff_t, std::less<int> >::iterator pos = pdata->positions.find(i);
485       if(pos == pdata->positions.end())
486          return RegEx::npos;
487       return (*pos).second;
488       }
489    }
490    return RegEx::npos;
491 }
492
493 std::size_t RegEx::Marks()const
494 {
495    return pdata->e.mark_count();
496 }
497
498
499 std::size_t RegEx::Length(int i)const
500 {
501    switch(pdata->t)
502    {
503    case re_detail::RegExData::type_pc:
504       return pdata->m[i].matched ? pdata->m[i].second - pdata->m[i].first : RegEx::npos;
505 #ifndef BOOST_REGEX_NO_FILEITER
506    case re_detail::RegExData::type_pf:
507       return pdata->fm[i].matched ? pdata->fm[i].second - pdata->fm[i].first : RegEx::npos;
508 #endif
509    case re_detail::RegExData::type_copy:
510       {
511       std::map<int, std::string, std::less<int> >::iterator pos = pdata->strings.find(i);
512       if(pos == pdata->strings.end())
513          return RegEx::npos;
514       return (*pos).second.size();
515       }
516    }
517    return RegEx::npos;
518 }
519
520 bool RegEx::Matched(int i)const
521 {
522    switch(pdata->t)
523    {
524    case re_detail::RegExData::type_pc:
525       return pdata->m[i].matched;
526 #ifndef BOOST_REGEX_NO_FILEITER
527    case re_detail::RegExData::type_pf:
528       return pdata->fm[i].matched;
529 #endif      
530    case re_detail::RegExData::type_copy:
531       {
532       std::map<int, std::string, std::less<int> >::iterator pos = pdata->strings.find(i);
533       if(pos == pdata->strings.end())
534          return false;
535       return true;
536       }
537    }
538    return false;
539 }
540
541
542 std::string RegEx::What(int i)const
543 {
544    std::string result;
545    switch(pdata->t)
546    {
547    case re_detail::RegExData::type_pc:
548       if(pdata->m[i].matched) 
549          result.assign(pdata->m[i].first, pdata->m[i].second);
550       break;
551    case re_detail::RegExData::type_pf:
552       if(pdata->m[i].matched) 
553          result.assign(to_string(pdata->m[i].first, pdata->m[i].second));
554       break;
555    case re_detail::RegExData::type_copy:
556       {
557       std::map<int, std::string, std::less<int> >::iterator pos = pdata->strings.find(i);
558       if(pos != pdata->strings.end())
559          result = (*pos).second;
560       break;
561       }
562    }
563    return result;
564 }
565
566 const std::size_t RegEx::npos = ~static_cast<std::size_t>(0);
567
568 } // namespace boost
569
570 #if defined(__BORLANDC__) && (__BORLANDC__ >= 0x550) && (__BORLANDC__ <= 0x551) && !defined(_RWSTD_COMPILE_INSTANTIATE)
571 //
572 // this is an ugly hack to work around an ugly problem:
573 // by default this file will produce unresolved externals during
574 // linking unless _RWSTD_COMPILE_INSTANTIATE is defined (Borland bug).
575 // However if _RWSTD_COMPILE_INSTANTIATE is defined then we get separate
576 // copies of basic_string's static data in the RTL and this DLL, this messes
577 // with basic_string's memory management and results in run-time crashes,
578 // Oh sweet joy of Catch 22....
579 //
580 namespace std{
581 template<> template<>
582 basic_string<char>& BOOST_REGEX_DECL
583 basic_string<char>::replace<const char*>(char* f1, char* f2, const char* i1, const char* i2)
584 {
585    unsigned insert_pos = f1 - begin();
586    unsigned remove_len = f2 - f1;
587    unsigned insert_len = i2 - i1;
588    unsigned org_size = size();
589    if(insert_len > remove_len)
590    {
591       append(insert_len-remove_len, ' ');
592       std::copy_backward(begin() + insert_pos + remove_len, begin() + org_size, end());
593       std::copy(i1, i2, begin() + insert_pos);
594    }
595    else
596    {
597       std::copy(begin() + insert_pos + remove_len, begin() + org_size, begin() + insert_pos + insert_len);
598       std::copy(i1, i2, begin() + insert_pos);
599       erase(size() + insert_len - remove_len);
600    }
601    return *this;
602 }
603 template<> template<>
604 basic_string<wchar_t>& BOOST_REGEX_DECL
605 basic_string<wchar_t>::replace<const wchar_t*>(wchar_t* f1, wchar_t* f2, const wchar_t* i1, const wchar_t* i2)
606 {
607    unsigned insert_pos = f1 - begin();
608    unsigned remove_len = f2 - f1;
609    unsigned insert_len = i2 - i1;
610    unsigned org_size = size();
611    if(insert_len > remove_len)
612    {
613       append(insert_len-remove_len, ' ');
614       std::copy_backward(begin() + insert_pos + remove_len, begin() + org_size, end());
615       std::copy(i1, i2, begin() + insert_pos);
616    }
617    else
618    {
619       std::copy(begin() + insert_pos + remove_len, begin() + org_size, begin() + insert_pos + insert_len);
620       std::copy(i1, i2, begin() + insert_pos);
621       erase(size() + insert_len - remove_len);
622    }
623    return *this;
624 }
625 } // namespace std
626 #endif
627
628 #endif
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644