]> git.sur5r.net Git - bacula/bacula/blob - bacula/patches/testing/breg.c
ebl fix regexp separator
[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    static int _start[RE_NREGS];
56    static int _end[RE_NREGS];
57
58    self->result = get_pool_memory(PM_FNAME);
59    self->result[0] = '\0';
60
61 #ifdef HAVE_REGEX_H
62    /* TODO: que devient cette memoire... */
63    self->_regs_match = (int *) malloc (2*RE_NREGS * sizeof(int));
64
65    self->regs.num_regs = RE_NREGS;
66    self->regs.start = self->_regs_match;
67    self->regs.end   = self->_regs_match+(RE_NREGS * sizeof(int));
68 #endif 
69
70    return self;
71 }
72
73 void free_bregexp(BREGEXP *self)
74 {
75    Dmsg0(500, "bregexp: freeing BREGEXP object\n");
76
77    if (self->expr) {
78       free(self->expr);
79    }
80    if (self->result) {
81       free_pool_memory(self->result);
82    }
83    if (self->_regs_match) {
84       free(self->_regs_match);
85    }
86
87    regfree(&self->preg);
88    free(self);
89 }
90
91 void free_bregexps(alist *bregexps)
92 {
93    Dmsg0(500, "bregexp: freeing all BREGEXP object\n");
94
95    BREGEXP *elt;
96    foreach_alist(elt, bregexps) {
97       free_bregexp(elt);
98    }
99 }
100
101 char *apply_bregexps(const char *fname, alist *bregexps)
102 {
103    BREGEXP *elt;
104    char *ret = (char *) fname;
105    foreach_alist(elt, bregexps) {
106       ret = elt->replace(ret);
107    }
108    return ret;
109 }
110
111 /* return an alist of BREGEXP or return NULL if it's not a 
112  * where=!tmp!opt!ig,!temp!opt!i
113  */
114 alist *get_bregexps(const char *where)
115 {
116    char *p = (char *)where;
117    alist *list = New(alist(10, not_owned_by_alist));
118    BREGEXP *reg;
119
120    reg = new_bregexp(p);
121
122    while(reg) {
123       p = reg->eor;
124       list->append(reg);
125       reg = new_bregexp(p);
126    }
127
128    if (list->size()) {
129       return list;      
130    } else {
131       delete list;
132       return NULL;
133    }
134 }
135
136 bool BREGEXP::extract_regexp(const char *motif)
137 {
138    if ( !motif ) {
139       return false;
140    }
141    
142    char sep = motif[0];
143
144    if (!(sep == '!' || 
145          sep == ':' || 
146          sep == ';' || 
147          sep == '§' || 
148          sep == ',' || 
149          sep == '&' || 
150          sep == '%' || 
151          sep == '=' || 
152          sep == '~' ||
153          sep == '#'   )) 
154    {
155       return false;
156    }
157
158    char *search = (char *) motif + 1;
159    char *replace;
160    int options = REG_EXTENDED | REG_NEWLINE;
161    bool ok = false;
162    bool found_motif = false;
163
164    /* extract 1st part */
165    char *dest = expr = bstrdup(motif);
166
167    while (*search && !ok) {
168       if (search[0] == '\\' && search[1] == sep) {
169          *dest++ = *++search;       /* we skip separator */ 
170
171       } else if (*search == sep) {  /* we found end of expression */
172          *dest++ = '\0';
173
174          if (subst) {           /* already have found motif */
175             ok = true;
176
177          } else {
178             *dest++ = *++search; /* we skip separator */ 
179             subst = dest;        /* get replaced string */
180          }
181
182       } else {
183          *dest++ = *search++;
184       }
185    }
186    *dest = '\0';                /* in case of */
187    
188    if (!ok || !subst) {
189       /* bad regexp */
190       return false;
191    }
192
193    ok = false;
194    /* find options */
195    while (*search && !ok) {
196       if (*search == 'i') {
197          options |= REG_ICASE;
198
199       } else if (*search == 'g') {
200               /* recherche multiple*/
201
202       } else if (*search == sep) {
203          /* skip separator */
204
205       } else {                  /* end of options */
206          ok = true;
207       }
208       search++;
209    }
210
211    int rc = regcomp(&preg, expr, options);
212    if (rc != 0) {
213       char prbuf[500];
214       regerror(rc, &preg, prbuf, sizeof(prbuf));
215       Dmsg1(100, "bregexp: compile error: %s\n", prbuf);
216       return false;
217    }
218
219    eor = search;                /* useful to find the next regexp in where */
220
221    return true;
222 }
223
224 #ifndef HAVE_REGEX_H
225  #define BREGEX_CAST unsigned
226 #else
227  #define BREGEX_CAST const
228 #endif
229
230 /* return regexp->result */
231 char *BREGEXP::replace(const char *fname)
232 {
233    int flen = strlen(fname);
234    int rc = re_search(&preg, (BREGEX_CAST char*) fname, flen, 0, flen, &regs);
235
236    if (rc < 0) {
237       Dmsg0(100, "E: regex mismatch\n");
238       return return_fname(fname, flen);
239    }
240
241    int len = compute_dest_len(fname, &regs);
242
243    if (len) {
244       result = check_pool_memory_size(result, len);
245       edit_subst(fname, &regs);
246
247    } else {                     /* error in substitution */
248       Dmsg0(100, "E: error in substitution\n");
249       return return_fname(fname, flen);
250    }
251
252    return result;
253
254
255 char *BREGEXP::return_fname(const char *fname, int len)
256 {
257    result = check_pool_memory_size(result, len+1);
258    strcpy(result,fname);
259    return result;
260 }
261
262 int BREGEXP::compute_dest_len(const char *fname, struct re_registers *regs)
263 {
264    int len=0;
265    char *p;
266    char *psubst = subst;
267    int no;
268
269    if (!fname || !regs) {
270       return 0;
271    }
272
273    /* match failed ? */
274    if (regs->start[0] < 0) {
275       return 0;
276    }
277
278    for (p = psubst++; *p ; p = psubst++) {
279       /* match $1 \1 back references */
280       if ((*p == '$' || *p == '\\') && ('0' <= *psubst && *psubst <= '9')) {
281          no = *psubst++ - '0';
282
283          /* we check if the back reference exists */
284          /* references can not match if we are using (..)? */
285
286          if (regs->start[no] >= 0 && regs->end[no] >= 0) { 
287             len += regs->end[no] - regs->start[no];
288          }
289          
290       } else {
291          len++;
292       }
293    }
294
295    /* $0 is replaced by subst */
296    len -= regs->end[0] - regs->start[0];
297    len += strlen(fname) + 1;
298
299    return len;
300 }
301
302 char *BREGEXP::edit_subst(const char *fname, struct re_registers *regs)
303 {
304    int i;
305    char *p;
306    char *psubst = subst;
307    int no;
308    int len;
309
310    /* il faut recopier fname dans dest
311     *  on recopie le debut fname -> regs->start[0]
312     */
313    
314    for (i = 0; i < regs->start[0] ; i++) {
315       result[i] = fname[i];
316    }
317
318    /* on recopie le motif de remplacement (avec tous les $x) */
319
320    for (p = psubst++; *p ; p = psubst++) {
321       /* match $1 \1 back references */
322       if ((*p == '$' || *p == '\\') && ('0' <= *psubst && *psubst <= '9')) {
323          no = *psubst++ - '0';
324
325          /* have a back reference ? */
326          if (regs->start[no] >= 0 && regs->end[no] >= 0) {
327             len = regs->end[no] - regs->start[no];
328             bstrncpy(result + i, fname + regs->start[no], len + 1);
329             i += len ;
330          }
331
332       } else {
333          result[i++] = *p;
334       }
335    }
336
337    /* we copy what is out of the match */
338    strcpy(result + i, fname + regs->end[0]);
339
340    return result;
341 }
342
343 void BREGEXP::debug()
344 {
345    printf("expr=[%s]\n", expr);
346    printf("subst=[%s]\n", subst);
347    printf("result=%s\n", result?result:"(null)");
348 }