2 * This file is part of DisOrder
3 * Copyright (C) 2004, 2005, 2007, 20008 Richard Kettlewell
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 /** @file lib/regsub.c
19 * @brief Regexp substitution
29 #define PREMATCH (-1) /* fictitious pre-match substring */
30 #define POSTMATCH (-2) /* fictitious post-match substring */
32 static inline size_t substring_start(const char attribute((unused
)) *subject
,
33 const size_t *ovector
,
36 case PREMATCH
: return 0;
37 case POSTMATCH
: return ovector
[1];
38 default: return ovector
[2 * n
];
42 static inline size_t substring_end(const char *subject
,
43 const size_t *ovector
,
46 case PREMATCH
: return ovector
[0];
47 case POSTMATCH
: return strlen(subject
);
48 default: return ovector
[2 * n
+ 1];
52 static void transform_append(struct dynstr
*d
,
54 const size_t *ovector
,
56 int start
= substring_start(subject
, ovector
, n
);
57 int end
= substring_end(subject
, ovector
, n
);
60 dynstr_append_bytes(d
, subject
+ start
, end
- start
);
63 static void replace_core(struct dynstr
*d
,
67 const size_t *ovector
) {
74 transform_append(d
, subject
, ovector
, 0);
77 case '1': case '2': case '3':
78 case '4': case '5': case '6':
79 case '7': case '8': case '9':
80 substr
= replace
[1] - '0';
82 transform_append(d
, subject
, ovector
, substr
);
86 dynstr_append(d
, '$');
90 dynstr_append(d
, *replace
++);
94 dynstr_append(d
, *replace
++);
98 unsigned regsub_flags(const char *flags
) {
103 case 'g': f
|= REGSUB_GLOBAL
; break;
104 case 'i': f
|= REGSUB_CASE_INDEPENDENT
; break;
111 int regsub_compile_options(unsigned flags
) {
114 if(flags
& REGSUB_CASE_INDEPENDENT
)
115 options
|= RXF_CASELESS
;
119 const char *regsub(const regexp
*re
, const char *subject
,
120 const char *replace
, unsigned flags
) {
127 /* find the next match */
128 while((rc
= regexp_match(re
, subject
, strlen(subject
), 0,
129 ovector
, sizeof ovector
/ sizeof (ovector
[0]))) > 0) {
130 /* text just before the match */
131 if(!(flags
& REGSUB_REPLACE
))
132 transform_append(&d
, subject
, ovector
, PREMATCH
);
133 /* the replacement text */
134 replace_core(&d
, subject
, replace
, rc
, ovector
);
136 if(!*subject
) /* end of subject */
138 if(flags
& REGSUB_REPLACE
) /* replace subject entirely */
140 /* step over the matched substring */
141 subject
+= substring_start(subject
, ovector
, POSTMATCH
);
142 if(!(flags
& REGSUB_GLOBAL
))
145 if(rc
<= 0 && rc
!= RXERR_NOMATCH
) {
146 disorder_error(0, "regexp_match returned %d, subject '%s'", rc
, subject
);
149 if((flags
& REGSUB_MUST_MATCH
) && matches
== 0)
151 /* append the remainder of the subject */
152 if(!(flags
& REGSUB_REPLACE
))
153 dynstr_append_string(&d
, subject
);
154 dynstr_terminate(&d
);