2 * Manipulation routines for BREGEXP list
4 * Eric Bollengier, March 2007
10 Bacula
\81Â
\81® - 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
\81Â
\81® 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
\81Ã
\81¼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)
170 char *search = (char *) motif + 1;
171 int options = REG_EXTENDED | REG_NEWLINE;
174 /* extract 1st part */
175 char *dest = expr = bstrdup(motif);
177 while (*search && !ok) {
178 if (search[0] == '\\' && search[1] == sep) {
179 *dest++ = *++search; /* we skip separator */
181 } else if (search[0] == '\\' && search[1] == '\\') {
182 *dest++ = *++search; /* we skip the second \ */
184 } else if (*search == sep) { /* we found end of expression */
187 if (subst) { /* already have found motif */
191 *dest++ = *++search; /* we skip separator */
192 subst = dest; /* get replaced string */
199 *dest = '\0'; /* in case of */
208 while (*search && !ok) {
209 if (*search == 'i') {
210 options |= REG_ICASE;
212 } else if (*search == 'g') {
213 /* recherche multiple*/
215 } else if (*search == sep) {
218 } else { /* end of options */
224 int rc = regcomp(&preg, expr, options);
227 regerror(rc, &preg, prbuf, sizeof(prbuf));
228 Dmsg1(100, "bregexp: compile error: %s\n", prbuf);
232 eor = search; /* useful to find the next regexp in where */
238 #define BREGEX_CAST unsigned
240 #define BREGEX_CAST const
243 /* return regexp->result */
244 char *BREGEXP::replace(const char *fname)
246 success = false; /* use this.success to known if it's ok */
247 int flen = strlen(fname);
250 check_pool_memory_size(lcase, flen);
251 for(i=0; fname[i] ; i++) {
252 lcase[i] = tolower(fname[i]);
255 int rc = re_search(&preg, (BREGEX_CAST char*) lcase, flen, 0, flen, ®s);
257 int rc = re_search(&preg, (BREGEX_CAST char*) fname, flen, 0, flen, ®s);
261 Dmsg0(500, "bregexp: regex mismatch\n");
262 return return_fname(fname, flen);
265 int len = compute_dest_len(fname, ®s);
268 result = check_pool_memory_size(result, len);
269 edit_subst(fname, ®s);
271 Dmsg2(500, "bregexp: len = %i, result_len = %i\n", len, strlen(result));
273 } else { /* error in substitution */
274 Dmsg0(100, "bregexp: error in substitution\n");
275 return return_fname(fname, flen);
281 char *BREGEXP::return_fname(const char *fname, int len)
283 result = check_pool_memory_size(result, len+1);
284 strcpy(result,fname);
288 int BREGEXP::compute_dest_len(const char *fname, struct re_registers *regs)
292 char *psubst = subst;
295 if (!fname || !regs) {
300 if (regs->start[0] < 0) {
304 for (p = psubst++; *p ; p = psubst++) {
305 /* match $1 \1 back references */
306 if ((*p == '$' || *p == '\\') && ('0' <= *psubst && *psubst <= '9')) {
307 no = *psubst++ - '0';
309 /* we check if the back reference exists */
310 /* references can not match if we are using (..)? */
312 if (regs->start[no] >= 0 && regs->end[no] >= 0) {
313 len += regs->end[no] - regs->start[no];
321 /* $0 is replaced by subst */
322 len -= regs->end[0] - regs->start[0];
323 len += strlen(fname) + 1;
328 char *BREGEXP::edit_subst(const char *fname, struct re_registers *regs)
332 char *psubst = subst;
336 /* il faut recopier fname dans dest
337 * on recopie le debut fname -> regs->start[0]
340 for (i = 0; i < regs->start[0] ; i++) {
341 result[i] = fname[i];
344 /* on recopie le motif de remplacement (avec tous les $x) */
346 for (p = psubst++; *p ; p = psubst++) {
347 /* match $1 \1 back references */
348 if ((*p == '$' || *p == '\\') && ('0' <= *psubst && *psubst <= '9')) {
349 no = *psubst++ - '0';
351 /* have a back reference ? */
352 if (regs->start[no] >= 0 && regs->end[no] >= 0) {
353 len = regs->end[no] - regs->start[no];
354 bstrncpy(result + i, fname + regs->start[no], len + 1);
363 /* we copy what is out of the match */
364 strcpy(result + i, fname + regs->end[0]);
369 /* escape sep char and \
370 * dest must be long enough (src*2+1)
371 * return end of the string */
372 char *bregexp_escape_string(char *dest, char *src, char sep)
379 } else if (*src == '\\') {
389 static char regexp_sep = '!';
390 static char *str_strip_prefix = "!%s!!i";
391 static char *str_add_prefix = "!^!%s!";
392 static char *str_add_suffix = "!([^/])$!$1%s!";
394 int bregexp_get_build_where_size(char *strip_prefix,
398 int str_size = ((strip_prefix?strlen(strip_prefix)+strlen(str_strip_prefix):0) +
399 (add_prefix?strlen(add_prefix)+strlen(str_add_prefix) :0) +
400 (add_suffix?strlen(add_suffix)+strlen(str_add_suffix) :0) )
401 /* escape + 3*, + \0 */
404 Dmsg1(1, "bregexp_get_build_where_size = %i\n", str_size);
408 /* build a regexp string with user arguments
411 * int len = bregexp_get_build_where_size(a,b,c) ;
412 * char *dest = (char *) bmalloc (len * sizeof(char));
413 * bregexp_build_where(dest, len, a, b, c);
417 char *bregexp_build_where(char *dest, int str_size,
424 POOLMEM *str_tmp = get_memory(str_size);
426 *str_tmp = *dest = '\0';
429 len += bsnprintf(dest, str_size - len, str_strip_prefix,
430 bregexp_escape_string(str_tmp, strip_prefix, regexp_sep));
434 if (len) dest[len++] = ',';
436 len += bsnprintf(dest + len, str_size - len, str_add_suffix,
437 bregexp_escape_string(str_tmp, add_suffix, regexp_sep));
441 if (len) dest[len++] = ',';
443 len += bsnprintf(dest + len, str_size - len, str_add_prefix,
444 bregexp_escape_string(str_tmp, add_prefix, regexp_sep));
447 free_pool_memory(str_tmp);
453 void BREGEXP::debug()
455 printf("expr=[%s]\n", expr);
456 printf("subst=[%s]\n", subst);
457 printf("result=%s\n", NPRT(result));