]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/breg.c
ebl Commit file relocation
[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 #ifndef HAVE_REGEX_H
249    int i;
250    check_pool_memory_size(lcase, flen);
251    for(i=0; fname[i] ; i++) {
252       lcase[i] = tolower(fname[i]);
253    }
254    lcase[i] = '\0';
255    int rc = re_search(&preg, (BREGEX_CAST char*) lcase, flen, 0, flen, &regs);
256 #else
257    int rc = re_search(&preg, (BREGEX_CAST char*) fname, flen, 0, flen, &regs);
258 #endif
259
260    if (rc < 0) {
261       Dmsg0(500, "bregexp: regex mismatch\n");
262       return return_fname(fname, flen);
263    }
264
265    int len = compute_dest_len(fname, &regs);
266
267    if (len) {
268       result = check_pool_memory_size(result, len);
269       edit_subst(fname, &regs);
270       success = true;
271       Dmsg2(500, "bregexp: len = %i, result_len = %i\n", len, strlen(result));
272
273    } else {                     /* error in substitution */
274       Dmsg0(100, "bregexp: error in substitution\n");
275       return return_fname(fname, flen);
276    }
277
278    return result;
279
280
281 char *BREGEXP::return_fname(const char *fname, int len)
282 {
283    result = check_pool_memory_size(result, len+1);
284    strcpy(result,fname);
285    return result;
286 }
287
288 int BREGEXP::compute_dest_len(const char *fname, struct re_registers *regs)
289 {
290    int len=0;
291    char *p;
292    char *psubst = subst;
293    int no;
294
295    if (!fname || !regs) {
296       return 0;
297    }
298
299    /* match failed ? */
300    if (regs->start[0] < 0) {
301       return 0;
302    }
303
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';
308
309          /* we check if the back reference exists */
310          /* references can not match if we are using (..)? */
311
312          if (regs->start[no] >= 0 && regs->end[no] >= 0) { 
313             len += regs->end[no] - regs->start[no];
314          }
315          
316       } else {
317          len++;
318       }
319    }
320
321    /* $0 is replaced by subst */
322    len -= regs->end[0] - regs->start[0];
323    len += strlen(fname) + 1;
324
325    return len;
326 }
327
328 char *BREGEXP::edit_subst(const char *fname, struct re_registers *regs)
329 {
330    int i;
331    char *p;
332    char *psubst = subst;
333    int no;
334    int len;
335
336    /* il faut recopier fname dans dest
337     *  on recopie le debut fname -> regs->start[0]
338     */
339    
340    for (i = 0; i < regs->start[0] ; i++) {
341       result[i] = fname[i];
342    }
343
344    /* on recopie le motif de remplacement (avec tous les $x) */
345
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';
350
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);
355             i += len ;
356          }
357
358       } else {
359          result[i++] = *p;
360       }
361    }
362
363    /* we copy what is out of the match */
364    strcpy(result + i, fname + regs->end[0]);
365
366    return result;
367 }
368
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)
373 {
374    char *ret = dest;
375    while (*src)
376    {
377       if (*src == sep) {
378          *dest++ = '\\';
379       } else if (*src == '\\') {
380          *dest++ = '\\';
381       }
382       *dest++ = *src++;
383    }
384    *dest = '\0';
385
386    return ret; 
387 }
388
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!";
393
394 int bregexp_get_build_where_size(char *strip_prefix, 
395                                  char *add_prefix, 
396                                  char *add_suffix)
397 {
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 */
402             * 2    + 3   + 1;
403
404    Dmsg1(1, "bregexp_get_build_where_size = %i\n", str_size);
405    return str_size;
406 }
407
408 /* build a regexp string with user arguments
409  * Usage :
410  * 
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);
414  * bfree(dest);
415  * 
416  */
417 char *bregexp_build_where(char *dest, int str_size,
418                           char *strip_prefix, 
419                           char *add_prefix, 
420                           char *add_suffix)
421 {
422    int len=0;
423
424    POOLMEM *str_tmp = get_memory(str_size);
425
426    *str_tmp = *dest = '\0';
427    
428    if (strip_prefix) {
429       len += bsnprintf(dest, str_size - len, str_strip_prefix,
430                        bregexp_escape_string(str_tmp, strip_prefix, regexp_sep));
431    }
432
433    if (add_suffix) {
434       if (len) dest[len++] = ',';
435
436       len += bsnprintf(dest + len,  str_size - len, str_add_suffix,
437                        bregexp_escape_string(str_tmp, add_suffix, regexp_sep));
438    }
439
440    if (add_prefix) {
441       if (len) dest[len++] = ',';
442
443       len += bsnprintf(dest + len, str_size - len, str_add_prefix, 
444                        bregexp_escape_string(str_tmp, add_prefix, regexp_sep));
445    }
446
447    free_pool_memory(str_tmp);
448
449    return dest;
450 }
451
452
453 void BREGEXP::debug()
454 {
455    printf("expr=[%s]\n", expr);
456    printf("subst=[%s]\n", subst);
457    printf("result=%s\n", NPRT(result));
458 }