2 * Manipulation routines for BREGEXP list
4 * Eric Bollengier, March 2007
10 Bacula® - The Network Backup Solution
12 Copyright (C) 2006-2006 Free Software Foundation Europe e.V.
14 The main author of Bacula is Kern Sibbald, with contributions from
15 many others, a complete list can be found in the file AUTHORS.
16 This program is Free Software; you can redistribute it and/or
17 modify it under the terms of version two of the GNU General Public
18 License as published by the Free Software Foundation plus additions
19 that are listed in the file LICENSE.
21 This program is distributed in the hope that it will be useful, but
22 WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 General Public License for more details.
26 You should have received a copy of the GNU General Public License
27 along with this program; if not, write to the Free Software
28 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
31 Bacula® is a registered trademark of John Walker.
32 The licensor of Bacula is the Free Software Foundation Europe
33 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
34 Switzerland, email:ftf@fsfeurope.org.
43 BREGEXP *new_bregexp(const char *motif)
45 Dmsg0(500, "bregexp: creating new bregexp object\n");
46 BREGEXP *self = (BREGEXP *)bmalloc(sizeof(BREGEXP));
47 memset(self, 0, sizeof(BREGEXP));
49 if (!self->extract_regexp(motif)) {
50 Dmsg0(100, "bregexp: extract_regexp error\n");
55 self->result = get_pool_memory(PM_FNAME);
56 self->result[0] = '\0';
59 /* TODO: que devient cette memoire... */
60 self->_regs_match = (int *) bmalloc (2*RE_NREGS * sizeof(int));
62 self->regs.num_regs = RE_NREGS;
63 self->regs.start = self->_regs_match;
64 self->regs.end = self->_regs_match+(RE_NREGS * sizeof(int));
70 void free_bregexp(BREGEXP *self)
72 Dmsg0(500, "bregexp: freeing BREGEXP object\n");
82 free_pool_memory(self->result);
84 if (self->_regs_match) {
85 bfree(self->_regs_match);
92 /* Free a bregexps alist
94 void free_bregexps(alist *bregexps)
96 Dmsg0(500, "bregexp: freeing all BREGEXP object\n");
99 foreach_alist(elt, bregexps) {
104 /* Apply all regexps to fname
106 bool apply_bregexps(const char *fname, alist *bregexps, char **result)
111 char *ret = (char *) fname;
112 foreach_alist(elt, bregexps) {
113 ret = elt->replace(ret);
114 ok = ok || elt->success;
116 Dmsg2(500, "bregexp: fname=%s ret=%s\n", fname, ret);
122 /* return an alist of BREGEXP or return NULL if it's not a
123 * where=!tmp!opt!ig,!temp!opt!i
125 alist *get_bregexps(const char *where)
127 char *p = (char *)where;
128 alist *list = New(alist(10, not_owned_by_alist));
131 reg = new_bregexp(p);
136 reg = new_bregexp(p);
147 bool BREGEXP::extract_regexp(const char *motif)
169 char *search = (char *) motif + 1;
170 int options = REG_EXTENDED | REG_NEWLINE;
173 /* extract 1st part */
174 char *dest = expr = bstrdup(motif);
176 while (*search && !ok) {
177 if (search[0] == '\\' && search[1] == sep) {
178 *dest++ = *++search; /* we skip separator */
180 } else if (search[0] == '\\' && search[1] == '\\') {
181 *dest++ = *++search; /* we skip the second \ */
183 } else if (*search == sep) { /* we found end of expression */
186 if (subst) { /* already have found motif */
190 *dest++ = *++search; /* we skip separator */
191 subst = dest; /* get replaced string */
198 *dest = '\0'; /* in case of */
207 while (*search && !ok) {
208 if (*search == 'i') {
209 options |= REG_ICASE;
211 } else if (*search == 'g') {
212 /* recherche multiple*/
214 } else if (*search == sep) {
217 } else { /* end of options */
223 int rc = regcomp(&preg, expr, options);
226 regerror(rc, &preg, prbuf, sizeof(prbuf));
227 Dmsg1(100, "bregexp: compile error: %s\n", prbuf);
231 eor = search; /* useful to find the next regexp in where */
237 #define BREGEX_CAST unsigned
239 #define BREGEX_CAST const
242 /* return regexp->result */
243 char *BREGEXP::replace(const char *fname)
245 success = false; /* use this.success to known if it's ok */
246 int flen = strlen(fname);
247 int rc = re_search(&preg, (BREGEX_CAST char*) fname, flen, 0, flen, ®s);
250 Dmsg0(500, "bregexp: regex mismatch\n");
251 return return_fname(fname, flen);
254 int len = compute_dest_len(fname, ®s);
257 result = check_pool_memory_size(result, len);
258 edit_subst(fname, ®s);
260 Dmsg2(500, "bregexp: len = %i, result_len = %i\n", len, strlen(result));
262 } else { /* error in substitution */
263 Dmsg0(100, "bregexp: error in substitution\n");
264 return return_fname(fname, flen);
270 char *BREGEXP::return_fname(const char *fname, int len)
272 result = check_pool_memory_size(result, len+1);
273 strcpy(result,fname);
277 int BREGEXP::compute_dest_len(const char *fname, struct re_registers *regs)
281 char *psubst = subst;
284 if (!fname || !regs) {
289 if (regs->start[0] < 0) {
293 for (p = psubst++; *p ; p = psubst++) {
294 /* match $1 \1 back references */
295 if ((*p == '$' || *p == '\\') && ('0' <= *psubst && *psubst <= '9')) {
296 no = *psubst++ - '0';
298 /* we check if the back reference exists */
299 /* references can not match if we are using (..)? */
301 if (regs->start[no] >= 0 && regs->end[no] >= 0) {
302 len += regs->end[no] - regs->start[no];
310 /* $0 is replaced by subst */
311 len -= regs->end[0] - regs->start[0];
312 len += strlen(fname) + 1;
317 char *BREGEXP::edit_subst(const char *fname, struct re_registers *regs)
321 char *psubst = subst;
325 /* il faut recopier fname dans dest
326 * on recopie le debut fname -> regs->start[0]
329 for (i = 0; i < regs->start[0] ; i++) {
330 result[i] = fname[i];
333 /* on recopie le motif de remplacement (avec tous les $x) */
335 for (p = psubst++; *p ; p = psubst++) {
336 /* match $1 \1 back references */
337 if ((*p == '$' || *p == '\\') && ('0' <= *psubst && *psubst <= '9')) {
338 no = *psubst++ - '0';
340 /* have a back reference ? */
341 if (regs->start[no] >= 0 && regs->end[no] >= 0) {
342 len = regs->end[no] - regs->start[no];
343 bstrncpy(result + i, fname + regs->start[no], len + 1);
352 /* we copy what is out of the match */
353 strcpy(result + i, fname + regs->end[0]);
358 /* escape sep char and \
359 * dest must be long enough (src*2+1)
360 * return end of the string */
361 char *bregexp_escape_string(char *dest, char *src, char sep)
368 } else if (*src == '\\') {
378 int bregexp_get_build_where_size(char *strip_prefix,
382 /* strip_prefix = !strip_prefix!!i 4 bytes
383 * add_prefix = !^!add_prefix! 5 bytes
384 * add_suffix = !([^/])$!$1add_suffix! 13 bytes
386 int str_size = (strip_prefix?strlen(strip_prefix)+4:0 +
387 add_prefix?strlen(add_prefix)+5:0 + /* escape + 3*, + \0 */
388 add_suffix?strlen(add_suffix)+14:0 ) * 2 + 3 + 1;
393 /* build a regexp string with user arguments
396 * int len = bregexp_get_build_where_size(a,b,c) ;
397 * char *dest = (char *) bmalloc (len * sizeof(char));
398 * bregexp_build_where(dest, len, a, b, c);
402 char *bregexp_build_where(char *dest, int str_size,
410 POOLMEM *str_tmp = get_memory(str_size);
412 *str_tmp = *dest = '\0';
415 len += bsnprintf(dest, str_size - len, "!%s!!i",
416 bregexp_escape_string(str_tmp, strip_prefix, sep));
420 if (len) dest[len++] = ',';
422 len += bsnprintf(dest + len, str_size - len, "!([^/])$!$1%s!",
423 bregexp_escape_string(str_tmp, add_suffix, sep));
427 if (len) dest[len++] = ',';
429 len += bsnprintf(dest + len, str_size - len, "!^!%s!",
430 bregexp_escape_string(str_tmp, add_prefix, sep));
433 free_pool_memory(str_tmp);
439 void BREGEXP::debug()
441 printf("expr=[%s]\n", expr);
442 printf("subst=[%s]\n", subst);
443 printf("result=%s\n", result?result:"(null)");