]> git.sur5r.net Git - bacula/bacula/blob - bacula/patches/testing/breg.c
ebl fix
[bacula/bacula] / bacula / patches / testing / breg.c
1 /*
2  * Manipulation routines for BREGEXP list
3  *
4  *  Eric Bollengier, March 2007
5  *
6  *  Version $Id$
7  *
8  */
9 /*
10    Bacula® - The Network Backup Solution
11
12    Copyright (C) 2006-2006 Free Software Foundation Europe e.V.
13
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.
20
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.
25
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
29    02110-1301, USA.
30
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.
35 */
36
37
38 #include "bacula.h"
39
40 #include "breg.h"
41 #include "mem_pool.h"
42
43 BREGEXP *new_bregexp(const char *motif)
44 {
45    Dmsg0(500, "bregexp: creating new bregexp object\n");
46    BREGEXP *self = (BREGEXP *)malloc(sizeof(BREGEXP));
47    memset(self, 0, sizeof(BREGEXP));
48    
49    if (!self->extract_regexp(motif)) {
50       Dmsg0(100, "bregexp: extract_regexp error\n");
51       free_bregexp(self);
52       return NULL;
53    }
54
55    self->result = get_pool_memory(PM_FNAME);
56    self->result[0] = '\0';
57
58 #ifdef HAVE_REGEX_H
59    /* TODO: que devient cette memoire... */
60    self->_regs_match = (int *) malloc (2*RE_NREGS * sizeof(int));
61
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));
65 #endif 
66
67    return self;
68 }
69
70 void free_bregexp(BREGEXP *self)
71 {
72    Dmsg0(500, "bregexp: freeing BREGEXP object\n");
73
74    if (self->expr) {
75       free(self->expr);
76    }
77    if (self->result) {
78       free_pool_memory(self->result);
79    }
80    if (self->_regs_match) {
81       free(self->_regs_match);
82    }
83
84    regfree(&self->preg);
85    free(self);
86 }
87
88 /* Free a bregexps alist
89  */
90 void free_bregexps(alist *bregexps)
91 {
92    Dmsg0(500, "bregexp: freeing all BREGEXP object\n");
93
94    BREGEXP *elt;
95    foreach_alist(elt, bregexps) {
96       free_bregexp(elt);
97    }
98 }
99
100 /* Apply all regexps to fname
101  */
102 bool apply_bregexps(const char *fname, alist *bregexps, char **result)
103 {
104    BREGEXP *elt;
105    bool ok=false;
106
107    char *ret = (char *) fname;
108    foreach_alist(elt, bregexps) {
109       ret = elt->replace(ret);
110       ok = ok || elt->success;
111    }
112    Dmsg2(500, "bregexp: fname=%s ret=%s\n", fname, ret);
113
114    *result = ret;
115    return ok;
116 }
117
118 /* return an alist of BREGEXP or return NULL if it's not a 
119  * where=!tmp!opt!ig,!temp!opt!i
120  */
121 alist *get_bregexps(const char *where)
122 {
123    char *p = (char *)where;
124    alist *list = New(alist(10, not_owned_by_alist));
125    BREGEXP *reg;
126
127    reg = new_bregexp(p);
128
129    while(reg) {
130       p = reg->eor;
131       list->append(reg);
132       reg = new_bregexp(p);
133    }
134
135    if (list->size()) {
136       return list;      
137    } else {
138       delete list;
139       return NULL;
140    }
141 }
142
143 bool BREGEXP::extract_regexp(const char *motif)
144 {
145    if ( !motif ) {
146       return false;
147    }
148    
149    char sep = motif[0];
150
151    if (!(sep == '!' || 
152          sep == ':' || 
153          sep == ';' || 
154          sep == '|' || 
155          sep == ',' || 
156          sep == '&' || 
157          sep == '%' || 
158          sep == '=' || 
159          sep == '~' ||
160          sep == '#'   )) 
161    {
162       return false;
163    }
164
165    char *search = (char *) motif + 1;
166    int options = REG_EXTENDED | REG_NEWLINE;
167    bool ok = false;
168
169    /* extract 1st part */
170    char *dest = expr = bstrdup(motif);
171
172    while (*search && !ok) {
173       if (search[0] == '\\' && search[1] == sep) {
174          *dest++ = *++search;       /* we skip separator */ 
175
176       } else if (search[0] == '\\' && search[1] == '\\') {
177          *dest++ = *++search;       /* we skip the second \ */
178
179       } else if (*search == sep) {  /* we found end of expression */
180          *dest++ = '\0';
181
182          if (subst) {           /* already have found motif */
183             ok = true;
184
185          } else {
186             *dest++ = *++search; /* we skip separator */ 
187             subst = dest;        /* get replaced string */
188          }
189
190       } else {
191          *dest++ = *search++;
192       }
193    }
194    *dest = '\0';                /* in case of */
195    
196    if (!ok || !subst) {
197       /* bad regexp */
198       return false;
199    }
200
201    ok = false;
202    /* find options */
203    while (*search && !ok) {
204       if (*search == 'i') {
205          options |= REG_ICASE;
206
207       } else if (*search == 'g') {
208               /* recherche multiple*/
209
210       } else if (*search == sep) {
211          /* skip separator */
212
213       } else {                  /* end of options */
214          ok = true;
215       }
216       search++;
217    }
218
219    int rc = regcomp(&preg, expr, options);
220    if (rc != 0) {
221       char prbuf[500];
222       regerror(rc, &preg, prbuf, sizeof(prbuf));
223       Dmsg1(100, "bregexp: compile error: %s\n", prbuf);
224       return false;
225    }
226
227    eor = search;                /* useful to find the next regexp in where */
228
229    return true;
230 }
231
232 #ifndef HAVE_REGEX_H
233  #define BREGEX_CAST unsigned
234 #else
235  #define BREGEX_CAST const
236 #endif
237
238 /* return regexp->result */
239 char *BREGEXP::replace(const char *fname)
240 {
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, &regs);
244
245    if (rc < 0) {
246       Dmsg0(500, "bregexp: regex mismatch\n");
247       return return_fname(fname, flen);
248    }
249
250    int len = compute_dest_len(fname, &regs);
251
252    if (len) {
253       result = check_pool_memory_size(result, len);
254       edit_subst(fname, &regs);
255       success = true;
256       Dmsg2(500, "bregexp: len = %i, result_len = %i\n", len, strlen(result));
257
258    } else {                     /* error in substitution */
259       Dmsg0(100, "bregexp: error in substitution\n");
260       return return_fname(fname, flen);
261    }
262
263    return result;
264
265
266 char *BREGEXP::return_fname(const char *fname, int len)
267 {
268    result = check_pool_memory_size(result, len+1);
269    strcpy(result,fname);
270    return result;
271 }
272
273 int BREGEXP::compute_dest_len(const char *fname, struct re_registers *regs)
274 {
275    int len=0;
276    char *p;
277    char *psubst = subst;
278    int no;
279
280    if (!fname || !regs) {
281       return 0;
282    }
283
284    /* match failed ? */
285    if (regs->start[0] < 0) {
286       return 0;
287    }
288
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';
293
294          /* we check if the back reference exists */
295          /* references can not match if we are using (..)? */
296
297          if (regs->start[no] >= 0 && regs->end[no] >= 0) { 
298             len += regs->end[no] - regs->start[no];
299          }
300          
301       } else {
302          len++;
303       }
304    }
305
306    /* $0 is replaced by subst */
307    len -= regs->end[0] - regs->start[0];
308    len += strlen(fname) + 1;
309
310    return len;
311 }
312
313 char *BREGEXP::edit_subst(const char *fname, struct re_registers *regs)
314 {
315    int i;
316    char *p;
317    char *psubst = subst;
318    int no;
319    int len;
320
321    /* il faut recopier fname dans dest
322     *  on recopie le debut fname -> regs->start[0]
323     */
324    
325    for (i = 0; i < regs->start[0] ; i++) {
326       result[i] = fname[i];
327    }
328
329    /* on recopie le motif de remplacement (avec tous les $x) */
330
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';
335
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);
340             i += len ;
341          }
342
343       } else {
344          result[i++] = *p;
345       }
346    }
347
348    /* we copy what is out of the match */
349    strcpy(result + i, fname + regs->end[0]);
350
351    return result;
352 }
353
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)
358 {
359    char *ret = dest;
360    while (*src)
361    {
362       if (*src == sep) {
363          *dest++ = '\\';
364       } else if (*src == '\\') {
365          *dest++ = '\\';
366       }
367       *dest++ = *src++;
368    }
369    *dest = '\0';
370
371    return ret; 
372 }
373
374 /* build a regexp string with user arguments
375  * don't forget to free ret 
376  */
377 char *bregexp_build_where(char *strip_prefix, 
378                           char *add_prefix, 
379                           char *add_suffix)
380 {
381    /* strip_prefix = !strip_prefix!!         4 bytes
382     * add_prefix   = !^!add_prefix!          5 bytes
383     * add_suffix   = !([^/])$!$1.add_suffix! 14 bytes
384     */
385    int len=0;
386    char sep = '!';
387    int str_size = (strlen(strip_prefix) + 4 +
388                    strlen(add_prefix)   + 5 +
389                    strlen(add_suffix)   + 14) * 2  + 1;
390
391    POOLMEM *ret = get_memory(str_size);
392    POOLMEM *str_tmp = get_memory(str_size);
393
394    *str_tmp = *ret = '\0';
395    
396    if (strip_prefix) {
397       len += bsnprintf(ret, str_size - len, "!%s!!",
398                        bregexp_escape_string(str_tmp, strip_prefix, sep));
399    }
400
401    if (add_suffix) {
402       if (len) ret[len++] = ',';
403
404       len += bsnprintf(ret + len,  str_size - len, "!([^/])$!$1%s!",
405                        bregexp_escape_string(str_tmp, add_suffix, sep));
406    }
407
408    if (add_prefix) {
409       if (len) ret[len++] = ',';
410
411       len += bsnprintf(ret + len, str_size - len, "!^!%s!", 
412                        bregexp_escape_string(str_tmp, add_prefix, sep));
413    }
414
415    return ret;
416 }
417
418
419 void BREGEXP::debug()
420 {
421    printf("expr=[%s]\n", expr);
422    printf("subst=[%s]\n", subst);
423    printf("result=%s\n", result?result:"(null)");
424 }