]> git.sur5r.net Git - bacula/bacula/blob - bacula/patches/testing/breg.c
ebl use bfree instead of free
[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 *)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    {
166       return false;
167    }
168
169    char *search = (char *) motif + 1;
170    int options = REG_EXTENDED | REG_NEWLINE;
171    bool ok = false;
172
173    /* extract 1st part */
174    char *dest = expr = bstrdup(motif);
175
176    while (*search && !ok) {
177       if (search[0] == '\\' && search[1] == sep) {
178          *dest++ = *++search;       /* we skip separator */ 
179
180       } else if (search[0] == '\\' && search[1] == '\\') {
181          *dest++ = *++search;       /* we skip the second \ */
182
183       } else if (*search == sep) {  /* we found end of expression */
184          *dest++ = '\0';
185
186          if (subst) {           /* already have found motif */
187             ok = true;
188
189          } else {
190             *dest++ = *++search; /* we skip separator */ 
191             subst = dest;        /* get replaced string */
192          }
193
194       } else {
195          *dest++ = *search++;
196       }
197    }
198    *dest = '\0';                /* in case of */
199    
200    if (!ok || !subst) {
201       /* bad regexp */
202       return false;
203    }
204
205    ok = false;
206    /* find options */
207    while (*search && !ok) {
208       if (*search == 'i') {
209          options |= REG_ICASE;
210
211       } else if (*search == 'g') {
212               /* recherche multiple*/
213
214       } else if (*search == sep) {
215          /* skip separator */
216
217       } else {                  /* end of options */
218          ok = true;
219       }
220       search++;
221    }
222
223    int rc = regcomp(&preg, expr, options);
224    if (rc != 0) {
225       char prbuf[500];
226       regerror(rc, &preg, prbuf, sizeof(prbuf));
227       Dmsg1(100, "bregexp: compile error: %s\n", prbuf);
228       return false;
229    }
230
231    eor = search;                /* useful to find the next regexp in where */
232
233    return true;
234 }
235
236 #ifndef HAVE_REGEX_H
237  #define BREGEX_CAST unsigned
238 #else
239  #define BREGEX_CAST const
240 #endif
241
242 /* return regexp->result */
243 char *BREGEXP::replace(const char *fname)
244 {
245    success = false;             /* use this.success to known if it's ok */
246    int flen = strlen(fname);
247    int rc = re_search(&preg, (BREGEX_CAST char*) fname, flen, 0, flen, &regs);
248
249    if (rc < 0) {
250       Dmsg0(500, "bregexp: regex mismatch\n");
251       return return_fname(fname, flen);
252    }
253
254    int len = compute_dest_len(fname, &regs);
255
256    if (len) {
257       result = check_pool_memory_size(result, len);
258       edit_subst(fname, &regs);
259       success = true;
260       Dmsg2(500, "bregexp: len = %i, result_len = %i\n", len, strlen(result));
261
262    } else {                     /* error in substitution */
263       Dmsg0(100, "bregexp: error in substitution\n");
264       return return_fname(fname, flen);
265    }
266
267    return result;
268
269
270 char *BREGEXP::return_fname(const char *fname, int len)
271 {
272    result = check_pool_memory_size(result, len+1);
273    strcpy(result,fname);
274    return result;
275 }
276
277 int BREGEXP::compute_dest_len(const char *fname, struct re_registers *regs)
278 {
279    int len=0;
280    char *p;
281    char *psubst = subst;
282    int no;
283
284    if (!fname || !regs) {
285       return 0;
286    }
287
288    /* match failed ? */
289    if (regs->start[0] < 0) {
290       return 0;
291    }
292
293    for (p = psubst++; *p ; p = psubst++) {
294       /* match $1 \1 back references */
295       if ((*p == '$' || *p == '\\') && ('0' <= *psubst && *psubst <= '9')) {
296          no = *psubst++ - '0';
297
298          /* we check if the back reference exists */
299          /* references can not match if we are using (..)? */
300
301          if (regs->start[no] >= 0 && regs->end[no] >= 0) { 
302             len += regs->end[no] - regs->start[no];
303          }
304          
305       } else {
306          len++;
307       }
308    }
309
310    /* $0 is replaced by subst */
311    len -= regs->end[0] - regs->start[0];
312    len += strlen(fname) + 1;
313
314    return len;
315 }
316
317 char *BREGEXP::edit_subst(const char *fname, struct re_registers *regs)
318 {
319    int i;
320    char *p;
321    char *psubst = subst;
322    int no;
323    int len;
324
325    /* il faut recopier fname dans dest
326     *  on recopie le debut fname -> regs->start[0]
327     */
328    
329    for (i = 0; i < regs->start[0] ; i++) {
330       result[i] = fname[i];
331    }
332
333    /* on recopie le motif de remplacement (avec tous les $x) */
334
335    for (p = psubst++; *p ; p = psubst++) {
336       /* match $1 \1 back references */
337       if ((*p == '$' || *p == '\\') && ('0' <= *psubst && *psubst <= '9')) {
338          no = *psubst++ - '0';
339
340          /* have a back reference ? */
341          if (regs->start[no] >= 0 && regs->end[no] >= 0) {
342             len = regs->end[no] - regs->start[no];
343             bstrncpy(result + i, fname + regs->start[no], len + 1);
344             i += len ;
345          }
346
347       } else {
348          result[i++] = *p;
349       }
350    }
351
352    /* we copy what is out of the match */
353    strcpy(result + i, fname + regs->end[0]);
354
355    return result;
356 }
357
358 /* escape sep char and \
359  * dest must be long enough (src*2+1)
360  * return end of the string */
361 char *bregexp_escape_string(char *dest, char *src, char sep)
362 {
363    char *ret = dest;
364    while (*src)
365    {
366       if (*src == sep) {
367          *dest++ = '\\';
368       } else if (*src == '\\') {
369          *dest++ = '\\';
370       }
371       *dest++ = *src++;
372    }
373    *dest = '\0';
374
375    return ret; 
376 }
377
378 int bregexp_get_build_where_size(char *strip_prefix, 
379                                  char *add_prefix, 
380                                  char *add_suffix)
381 {
382    /* strip_prefix = !strip_prefix!!i        4 bytes
383     * add_prefix   = !^!add_prefix!          5 bytes
384     * add_suffix   = !([^/])$!$1add_suffix! 13 bytes
385     */
386    int str_size = (strip_prefix?strlen(strip_prefix)+4:0 +
387                    add_prefix?strlen(add_prefix)+5:0     + /* escape + 3*, + \0 */ 
388                    add_suffix?strlen(add_suffix)+14:0     )     * 2  + 3   + 1;
389
390    return str_size;
391 }
392
393 /* build a regexp string with user arguments
394  * Usage :
395  * 
396  * int len = bregexp_get_build_where_size(a,b,c) ;
397  * char *dest = (char *) bmalloc (len * sizeof(char));
398  * bregexp_build_where(dest, len, a, b, c);
399  * free(dest);
400  * 
401  */
402 char *bregexp_build_where(char *dest, int str_size,
403                           char *strip_prefix, 
404                           char *add_prefix, 
405                           char *add_suffix)
406 {
407    int len=0;
408    char sep = '!';
409
410    POOLMEM *str_tmp = get_memory(str_size);
411
412    *str_tmp = *dest = '\0';
413    
414    if (strip_prefix) {
415       len += bsnprintf(dest, str_size - len, "!%s!!i",
416                        bregexp_escape_string(str_tmp, strip_prefix, sep));
417    }
418
419    if (add_suffix) {
420       if (len) dest[len++] = ',';
421
422       len += bsnprintf(dest + len,  str_size - len, "!([^/])$!$1%s!",
423                        bregexp_escape_string(str_tmp, add_suffix, sep));
424    }
425
426    if (add_prefix) {
427       if (len) dest[len++] = ',';
428
429       len += bsnprintf(dest + len, str_size - len, "!^!%s!", 
430                        bregexp_escape_string(str_tmp, add_prefix, sep));
431    }
432
433    free_pool_memory(str_tmp);
434
435    return ret;
436 }
437
438
439 void BREGEXP::debug()
440 {
441    printf("expr=[%s]\n", expr);
442    printf("subst=[%s]\n", subst);
443    printf("result=%s\n", result?result:"(null)");
444 }