root/rxstring/trunk/rxstring.cpp @ 672

Revision 672, 5.3 kB (checked in by tapted, 2 years ago)

Pull in documentation from daisy rxstring

  • Property svn:eol-style set to native
  • Property svn:keywords set to author date id revision url Rev Revision
RevLine 
[672]1/* $Id$ $URL$ */
[257]2#include "rxstring.h"
3
[672]4/**\file rxstring.cpp
5 * Definition of the RxString class and helper functions.
6 * \author Trent Apted <tapted@it.usyd.edu.au>
7 * $Revision$
8 * $Date$
9 */
10
[257]11#ifdef HAVE_SYSREGEX_H
12#define my_regerror regerror
13#define my_regcomp regcomp
14#define my_regfree regfree
15#define my_regexec regexec
16#endif
17
[398]18/** returns !isspace(c), and is a function (not a macro) */
[257]19static bool nonspace(char c) {
20    return !std::isspace(c);
21}
22
[398]23/** fill \a buf with a string describing the regex error */
[257]24static void fill_error(RxString &buf, int err_code, regex_t *rxbuf) {
25    size_t buf_sz = my_regerror(err_code, rxbuf, 0, 0);
26    char *errbuf = new char[buf_sz];
27    my_regerror(err_code, rxbuf, errbuf, buf_sz);
28    buf = errbuf;
29    delete[] errbuf;
30}
31
32const RxString RxString::NO_MATCH = "";
33
[672]34RxString::Regex::Regex(const RxString& regstr, RxString *err_string, int cflags) {
35    if (!RxString::compile(*this, regstr, err_string, cflags)) {
36        /* fail -- throw? */
37    }
38}
39
[257]40RxString &RxString::trim() {
41    erase(begin(), find_if(&nonspace));
42    erase(find_last_not_if(&nonspace), end());
43    return *this;
44}
45
[398]46RxString RxString::matchn(const RxString &regex,
47                          unsigned n,
48                          RxString *err_string,
49                          int cflags,
50                          int eflags) const {
51    match_vec_type matches;
52    match(regex, &matches, err_string, cflags, eflags);
53    if (n < matches.size())
54        return matches[n];
55    else if (!matches.empty())
56        return matches[0];
57    else
58        return NO_MATCH;
59}
60
61
62RxString RxString::matchn(const my_regex_t  &regex, unsigned n, RxString *err_string, int eflags) const {
63    match_vec_type matches;
64    match(regex, &matches, err_string, eflags);
65    if (n < matches.size())
66        return matches[n];
67    else if (!matches.empty())
68        return matches[0];
69    else
70        return NO_MATCH;
71}
72
73bool RxString::compile(my_regex_t &regex,
74                       const RxString &regstr,
75                       RxString *err_string,
76                       int cflags) {
77    int err = 0;
78    cflags |= REG_EXTENDED;
79    cflags &= ~REG_NOSUB;
80
81    /* compile */
82    if ((err = my_regcomp(&regex.rx, regstr.c_str(), cflags))) {
83        if (err_string)
84            fill_error(*err_string, err, &regex.rx);
85        my_regfree(&regex.rx);
86        return 0;
87    }
88    regex.nmatch = regstr.count_char('(') + 1;
89    return true;
90}
91
[257]92size_t RxString::match(const RxString &regex,
93                       match_vec_type *matches /*=0*/,
94                       RxString *err_string /*= 0*/,
95                       int cflags /*=REG_EXTENDED*/,
96                       int eflags /*=0*/
97                      ) const {
[398]98    my_regex_t preg;
[257]99    int err = 0;
100    if (matches) {
101        cflags |= REG_EXTENDED;
102        cflags &= ~REG_NOSUB;
103    }
104    /* compile */
[398]105    if ((err = my_regcomp(&preg.rx, regex.c_str(), cflags))) {
[257]106        if (err_string)
[398]107            fill_error(*err_string, err, &preg.rx);
108        my_regfree(&preg.rx);
[257]109        return 0;
110    }
[398]111    preg.nmatch = regex.count_char('(') + 1;
112    size_t ret = match(preg, matches, err_string, eflags);
113    my_regfree(&preg.rx);
114    return ret;
115}
[257]116
[398]117size_t RxString::match(const my_regex_t &preg,
118                       match_vec_type *matches,
119                       RxString *err_string,
120                       int eflags
121                      ) const {
122
[257]123    /* execute */
124    const char *strbuf = c_str();
[398]125    int err = 0;
126    unsigned nmatch = preg.nmatch;
[257]127    regmatch_t *pmatch = 0;
128    if (nmatch)
129        pmatch = new regmatch_t[nmatch];
[398]130    if ((err = my_regexec(&preg.rx, strbuf, nmatch, pmatch, eflags))) {
[257]131        if (nmatch)
132            delete[] pmatch;
133        if (err_string)
134            *err_string = "<<NO_MATCH>>";
135        return 0;
136    }
137
138    /* fill matches */
139    size_t nmatches = 0;
140    if (matches) {
141        for (size_t i = 0; i < nmatch; ++i) {
142            if (pmatch[i].rm_so >= 0) {
[398]143                matches->push_back(RxString(substr(pmatch[i].rm_so, pmatch[i].rm_eo-pmatch[i].rm_so)));
[257]144                ++nmatches;
145            } else {
146                matches->push_back(NO_MATCH);
147            }
148        }
149    } else {
150        nmatches = 1;
151    }
152
153    /* cleanup */
154    if (nmatch)
155        delete[] pmatch;
156    return nmatches;
157}
158
159RxString &RxString::append_line(std::istream& in /*=cin*/, const char eol /*='\n'*/) {
160    char c;
161    while (in && in.get(c) && c != eol)
162        *this += c;
163    return *this;
164}
165
166
167std::string::size_type RxString::count_char(value_type val) const {
168    return std::count(begin(), end(), val);
169}
170
171RxString &RxString::toTitleCase() {
172    iterator b = begin();
173    iterator e = end();
174    bool sp = true;
175    for (; b != e; ++b) {
176        if (sp)
177            *b = std::toupper(*b);
178//        else
179//            *b = std::tolower(*b);
180        sp = std::isspace(*b);
181    }
182    return *this;
183}
184
[398]185/** toupper is a macro, so we need this function for std::transform */
[257]186static inline char my_toupper(char c) {
187    return toupper(c);
188}
189
[398]190/** tolower is a macro, so we need this function for std::transform */
[257]191static inline char my_tolower(char c) {
192    return tolower(c);
193}
194
195RxString &RxString::toUpper() {
196    std::transform(begin(), end(), begin(), &my_toupper);
197    return *this;
198}
199RxString &RxString::toLower() {
200    std::transform(begin(), end(), begin(), &my_tolower);
201    return *this;
202}
Note: See TracBrowser for help on using the browser.