]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/breg.c
Working directory pane in restore. Will get this into the stack next.
[bacula/bacula] / bacula / src / lib / breg.c
1 /*
2  * Manipulation routines for BREGEXP list
3  *
4  *  Eric Bollengier, March 2007
5  *
6  *  Version $Id$
7  *
8  */
9 /*
10    Bacula\81Â\81® - 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\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.
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 *)bmalloc(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 *) bmalloc (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) {
75       return;
76    }
77
78    if (self->expr) {
79       bfree(self->expr);
80    }
81    if (self->result) {
82       free_pool_memory(self->result);
83    }
84    if (self->_regs_match) {
85       bfree(self->_regs_match);
86    }
87
88    regfree(&self->preg);
89    bfree(self);
90 }
91
92 /* Free a bregexps alist
93  */
94 void free_bregexps(alist *bregexps)
95 {
96    Dmsg0(500, "bregexp: freeing all BREGEXP object\n");
97
98    BREGEXP *elt;
99    foreach_alist(elt, bregexps) {
100       free_bregexp(elt);
101    }
102 }
103
104 /* Apply all regexps to fname
105  */
106 bool apply_bregexps(const char *fname, alist *bregexps, char **result)
107 {
108    BREGEXP *elt;
109    bool ok=false;
110
111    char *ret = (char *) fname;
112    foreach_alist(elt, bregexps) {
113       ret = elt->replace(ret);
114       ok = ok || elt->success;
115    }
116    Dmsg2(500, "bregexp: fname=%s ret=%s\n", fname, ret);
117
118    *result = ret;
119    return ok;
120 }
121
122 /* return an alist of BREGEXP or return NULL if it's not a 
123  * where=!tmp!opt!ig,!temp!opt!i
124  */
125 alist *get_bregexps(const char *where)
126 {
127    char *p = (char *)where;
128    alist *list = New(alist(10, not_owned_by_alist));
129    BREGEXP *reg;
130
131    reg = new_bregexp(p);
132
133    while(reg) {
134       p = reg->eor;
135       list->append(reg);
136       reg = new_bregexp(p);
137    }
138
139    if (list->size()) {
140       return list;      
141    } else {
142       delete list;
143       return NULL;
144    }
145 }
146
147 bool BREGEXP::extract_regexp(const char *motif)
148 {
149    if ( !motif ) {
150       return false;
151    }
152    
153    char sep = motif[0];
154
155    if (!(sep == '!' || 
156          sep == ':' || 
157          sep == ';' || 
158          sep == '|' || 
159          sep == ',' || 
160          sep == '&' || 
161          sep == '%' || 
162          sep == '=' || 
163          sep == '~' ||
164          sep == '/' ||
165          sep == '#'   )) 
166    {
167       return false;
168    }
169
170    char *search = (char *) motif + 1;
171    int options = REG_EXTENDED | REG_NEWLINE;
172    bool ok = false;
173
174    /* extract 1st part */
175    char *dest = expr = bstrdup(motif);
176
177    while (*search && !ok) {
178       if (search[0] == '\\' && search[1] == sep) {
179          *dest++ = *++search;       /* we skip separator */ 
180
181       } else if (search[0] == '\\' && search[1] == '\\') {
182          *dest++ = *++search;       /* we skip the second \ */
183
184       } else if (*search == sep) {  /* we found end of expression */
185          *dest++ = '\0';
186
187          if (subst) {           /* already have found motif */
188             ok = true;
189
190          } else {
191             *dest++ = *++search; /* we skip separator */ 
192             subst = dest;        /* get replaced string */
193          }
194
195       } else {
196          *dest++ = *search++;
197       }
198    }
199    *dest = '\0';                /* in case of */
200    
201    if (!ok || !subst) {
202       /* bad regexp */
203       return false;
204    }
205
206    ok = false;
207    /* find options */
208    while (*search && !ok) {
209       if (*search == 'i') {
210          options |= REG_ICASE;
211
212       } else if (*search == 'g') {
213               /* recherche multiple*/
214
215       } else if (*search == sep) {
216          /* skip separator */
217
218       } else {                  /* end of options */
219          ok = true;
220       }
221       search++;
222    }
223
224    int rc = regcomp(&preg, expr, options);
225    if (rc != 0) {
226       char prbuf[500];
227       regerror(rc, &preg, prbuf, sizeof(prbuf));
228       Dmsg1(100, "bregexp: compile error: %s\n", prbuf);
229       return false;
230    }
231
232    eor = search;                /* useful to find the next regexp in where */
233
234    return true;
235 }
236
237 #ifndef HAVE_REGEX_H
238  #define BREGEX_CAST unsigned
239 #else
240  #define BREGEX_CAST const
241 #endif
242
243 /* return regexp->result */
244 char *BREGEXP::replace(const char *fname)
245 {
246    success = false;             /* use this.success to known if it's ok */
247    int flen = strlen(fname);
248    int rc = re_search(&preg, (BREGEX_CAST char*) fname, flen, 0, flen, &regs);
249
250    if (rc < 0) {
251       Dmsg0(500, "bregexp: regex mismatch\n");
252       return return_fname(fname, flen);
253    }
254
255    int len = compute_dest_len(fname, &regs);
256
257    if (len) {
258       result = check_pool_memory_size(result, len);
259       edit_subst(fname, &regs);
260       success = true;
261       Dmsg2(500, "bregexp: len = %i, result_len = %i\n", len, strlen(result));
262
263    } else {                     /* error in substitution */
264       Dmsg0(100, "bregexp: error in substitution\n");
265       return return_fname(fname, flen);
266    }
267
268    return result;
269
270
271 char *BREGEXP::return_fname(const char *fname, int len)
272 {
273    result = check_pool_memory_size(result, len+1);
274    strcpy(result,fname);
275    return result;
276 }
277
278 int BREGEXP::compute_dest_len(const char *fname, struct re_registers *regs)
279 {
280    int len=0;
281    char *p;
282    char *psubst = subst;
283    int no;
284
285    if (!fname || !regs) {
286       return 0;
287    }
288
289    /* match failed ? */
290    if (regs->start[0] < 0) {
291       return 0;
292    }
293
294    for (p = psubst++; *p ; p = psubst++) {
295       /* match $1 \1 back references */
296       if ((*p == '$' || *p == '\\') && ('0' <= *psubst && *psubst <= '9')) {
297          no = *psubst++ - '0';
298
299          /* we check if the back reference exists */
300          /* references can not match if we are using (..)? */
301
302          if (regs->start[no] >= 0 && regs->end[no] >= 0) { 
303             len += regs->end[no] - regs->start[no];
304          }
305          
306       } else {
307          len++;
308       }
309    }
310
311    /* $0 is replaced by subst */
312    len -= regs->end[0] - regs->start[0];
313    len += strlen(fname) + 1;
314
315    return len;
316 }
317
318 char *BREGEXP::edit_subst(const char *fname, struct re_registers *regs)
319 {
320    int i;
321    char *p;
322    char *psubst = subst;
323    int no;
324    int len;
325
326    /* il faut recopier fname dans dest
327     *  on recopie le debut fname -> regs->start[0]
328     */
329    
330    for (i = 0; i < regs->start[0] ; i++) {
331       result[i] = fname[i];
332    }
333
334    /* on recopie le motif de remplacement (avec tous les $x) */
335
336    for (p = psubst++; *p ; p = psubst++) {
337       /* match $1 \1 back references */
338       if ((*p == '$' || *p == '\\') && ('0' <= *psubst && *psubst <= '9')) {
339          no = *psubst++ - '0';
340
341          /* have a back reference ? */
342          if (regs->start[no] >= 0 && regs->end[no] >= 0) {
343             len = regs->end[no] - regs->start[no];
344             bstrncpy(result + i, fname + regs->start[no], len + 1);
345             i += len ;
346          }
347
348       } else {
349          result[i++] = *p;
350       }
351    }
352
353    /* we copy what is out of the match */
354    strcpy(result + i, fname + regs->end[0]);
355
356    return result;
357 }
358
359 /* escape sep char and \
360  * dest must be long enough (src*2+1)
361  * return end of the string */
362 char *bregexp_escape_string(char *dest, char *src, char sep)
363 {
364    char *ret = dest;
365    while (*src)
366    {
367       if (*src == sep) {
368          *dest++ = '\\';
369       } else if (*src == '\\') {
370          *dest++ = '\\';
371       }
372       *dest++ = *src++;
373    }
374    *dest = '\0';
375
376    return ret; 
377 }
378
379 static char regexp_sep = '!';
380 static char *str_strip_prefix = "!%s!!i";
381 static char *str_add_prefix   = "!^!%s!";
382 static char *str_add_suffix   = "!([^/])$!$1%s!";
383
384 int bregexp_get_build_where_size(char *strip_prefix, 
385                                  char *add_prefix, 
386                                  char *add_suffix)
387 {
388    int str_size = ((strip_prefix?strlen(strip_prefix)+strlen(str_strip_prefix):0) +
389                    (add_prefix?strlen(add_prefix)+strlen(str_add_prefix)      :0) +  
390                    (add_suffix?strlen(add_suffix)+strlen(str_add_suffix)      :0) )
391          /* escape + 3*, + \0 */
392             * 2    + 3   + 1;
393
394    Dmsg1(1, "bregexp_get_build_where_size = %i\n", str_size);
395    return str_size;
396 }
397
398 /* build a regexp string with user arguments
399  * Usage :
400  * 
401  * int len = bregexp_get_build_where_size(a,b,c) ;
402  * char *dest = (char *) bmalloc (len * sizeof(char));
403  * bregexp_build_where(dest, len, a, b, c);
404  * bfree(dest);
405  * 
406  */
407 char *bregexp_build_where(char *dest, int str_size,
408                           char *strip_prefix, 
409                           char *add_prefix, 
410                           char *add_suffix)
411 {
412    int len=0;
413
414    POOLMEM *str_tmp = get_memory(str_size);
415
416    *str_tmp = *dest = '\0';
417    
418    if (strip_prefix) {
419       len += bsnprintf(dest, str_size - len, str_strip_prefix,
420                        bregexp_escape_string(str_tmp, strip_prefix, regexp_sep));
421    }
422
423    if (add_suffix) {
424       if (len) dest[len++] = ',';
425
426       len += bsnprintf(dest + len,  str_size - len, str_add_suffix,
427                        bregexp_escape_string(str_tmp, add_suffix, regexp_sep));
428    }
429
430    if (add_prefix) {
431       if (len) dest[len++] = ',';
432
433       len += bsnprintf(dest + len, str_size - len, str_add_prefix, 
434                        bregexp_escape_string(str_tmp, add_prefix, regexp_sep));
435    }
436
437    free_pool_memory(str_tmp);
438
439    return dest;
440 }
441
442
443 void BREGEXP::debug()
444 {
445    printf("expr=[%s]\n", expr);
446    printf("subst=[%s]\n", subst);
447    printf("result=%s\n", NPRT(result));
448 }