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 *)malloc(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 *) malloc (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");
78 free_pool_memory(self->result);
80 if (self->_regs_match) {
81 free(self->_regs_match);
88 /* Free a bregexps alist
90 void free_bregexps(alist *bregexps)
92 Dmsg0(500, "bregexp: freeing all BREGEXP object\n");
95 foreach_alist(elt, bregexps) {
100 /* Apply all regexps to fname
102 bool apply_bregexps(const char *fname, alist *bregexps, char **result)
107 char *ret = (char *) fname;
108 foreach_alist(elt, bregexps) {
109 ret = elt->replace(ret);
110 ok = ok || elt->success;
112 Dmsg2(500, "bregexp: fname=%s ret=%s\n", fname, ret);
118 /* return an alist of BREGEXP or return NULL if it's not a
119 * where=!tmp!opt!ig,!temp!opt!i
121 alist *get_bregexps(const char *where)
123 char *p = (char *)where;
124 alist *list = New(alist(10, not_owned_by_alist));
127 reg = new_bregexp(p);
132 reg = new_bregexp(p);
143 bool BREGEXP::extract_regexp(const char *motif)
165 char *search = (char *) motif + 1;
166 int options = REG_EXTENDED | REG_NEWLINE;
169 /* extract 1st part */
170 char *dest = expr = bstrdup(motif);
172 while (*search && !ok) {
173 if (search[0] == '\\' && search[1] == sep) {
174 *dest++ = *++search; /* we skip separator */
176 } else if (search[0] == '\\' && search[1] == '\\') {
177 *dest++ = *++search; /* we skip the second \ */
179 } else if (*search == sep) { /* we found end of expression */
182 if (subst) { /* already have found motif */
186 *dest++ = *++search; /* we skip separator */
187 subst = dest; /* get replaced string */
194 *dest = '\0'; /* in case of */
203 while (*search && !ok) {
204 if (*search == 'i') {
205 options |= REG_ICASE;
207 } else if (*search == 'g') {
208 /* recherche multiple*/
210 } else if (*search == sep) {
213 } else { /* end of options */
219 int rc = regcomp(&preg, expr, options);
222 regerror(rc, &preg, prbuf, sizeof(prbuf));
223 Dmsg1(100, "bregexp: compile error: %s\n", prbuf);
227 eor = search; /* useful to find the next regexp in where */
233 #define BREGEX_CAST unsigned
235 #define BREGEX_CAST const
238 /* return regexp->result */
239 char *BREGEXP::replace(const char *fname)
241 success = false; /* use this.success to known if it's ok */
242 int flen = strlen(fname);
243 int rc = re_search(&preg, (BREGEX_CAST char*) fname, flen, 0, flen, ®s);
246 Dmsg0(500, "bregexp: regex mismatch\n");
247 return return_fname(fname, flen);
250 int len = compute_dest_len(fname, ®s);
253 result = check_pool_memory_size(result, len);
254 edit_subst(fname, ®s);
256 Dmsg2(500, "bregexp: len = %i, result_len = %i\n", len, strlen(result));
258 } else { /* error in substitution */
259 Dmsg0(100, "bregexp: error in substitution\n");
260 return return_fname(fname, flen);
266 char *BREGEXP::return_fname(const char *fname, int len)
268 result = check_pool_memory_size(result, len+1);
269 strcpy(result,fname);
273 int BREGEXP::compute_dest_len(const char *fname, struct re_registers *regs)
277 char *psubst = subst;
280 if (!fname || !regs) {
285 if (regs->start[0] < 0) {
289 for (p = psubst++; *p ; p = psubst++) {
290 /* match $1 \1 back references */
291 if ((*p == '$' || *p == '\\') && ('0' <= *psubst && *psubst <= '9')) {
292 no = *psubst++ - '0';
294 /* we check if the back reference exists */
295 /* references can not match if we are using (..)? */
297 if (regs->start[no] >= 0 && regs->end[no] >= 0) {
298 len += regs->end[no] - regs->start[no];
306 /* $0 is replaced by subst */
307 len -= regs->end[0] - regs->start[0];
308 len += strlen(fname) + 1;
313 char *BREGEXP::edit_subst(const char *fname, struct re_registers *regs)
317 char *psubst = subst;
321 /* il faut recopier fname dans dest
322 * on recopie le debut fname -> regs->start[0]
325 for (i = 0; i < regs->start[0] ; i++) {
326 result[i] = fname[i];
329 /* on recopie le motif de remplacement (avec tous les $x) */
331 for (p = psubst++; *p ; p = psubst++) {
332 /* match $1 \1 back references */
333 if ((*p == '$' || *p == '\\') && ('0' <= *psubst && *psubst <= '9')) {
334 no = *psubst++ - '0';
336 /* have a back reference ? */
337 if (regs->start[no] >= 0 && regs->end[no] >= 0) {
338 len = regs->end[no] - regs->start[no];
339 bstrncpy(result + i, fname + regs->start[no], len + 1);
348 /* we copy what is out of the match */
349 strcpy(result + i, fname + regs->end[0]);
354 /* escape sep char and \
355 * dest must be long enough (src*2+1)
356 * return end of the string */
357 char *bregexp_escape_string(char *dest, char *src, char sep)
364 } else if (*src == '\\') {
374 /* build a regexp string with user arguments
375 * don't forget to free ret
377 char *bregexp_build_where(char *strip_prefix,
381 /* strip_prefix = !strip_prefix!!i 4 bytes
382 * add_prefix = !^!add_prefix! 5 bytes
383 * add_suffix = !([^/])$!$1add_suffix! 13 bytes
387 int str_size = (strip_prefix?strlen(strip_prefix)+4:0 +
388 add_prefix?strlen(add_prefix)+5:0 + /* escape + 3*, + \0 */
389 add_suffix?strlen(add_suffix)+14:0 ) * 2 + 3 + 1;
391 POOLMEM *ret = get_memory(str_size);
392 POOLMEM *str_tmp = get_memory(str_size);
394 *str_tmp = *ret = '\0';
397 len += bsnprintf(ret, str_size - len, "!%s!!i",
398 bregexp_escape_string(str_tmp, strip_prefix, sep));
402 if (len) ret[len++] = ',';
404 len += bsnprintf(ret + len, str_size - len, "!([^/])$!$1%s!",
405 bregexp_escape_string(str_tmp, add_suffix, sep));
409 if (len) ret[len++] = ',';
411 len += bsnprintf(ret + len, str_size - len, "!^!%s!",
412 bregexp_escape_string(str_tmp, add_prefix, sep));
415 free_pool_memory(str_tmp);
421 void BREGEXP::debug()
423 printf("expr=[%s]\n", expr);
424 printf("subst=[%s]\n", subst);
425 printf("result=%s\n", result?result:"(null)");