]> git.sur5r.net Git - bacula/bacula/blob - bacula/patches/testing/breg.c
ebl update
[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 == sep) {  /* we found end of expression */
177          *dest++ = '\0';
178
179          if (subst) {           /* already have found motif */
180             ok = true;
181
182          } else {
183             *dest++ = *++search; /* we skip separator */ 
184             subst = dest;        /* get replaced string */
185          }
186
187       } else {
188          *dest++ = *search++;
189       }
190    }
191    *dest = '\0';                /* in case of */
192    
193    if (!ok || !subst) {
194       /* bad regexp */
195       return false;
196    }
197
198    ok = false;
199    /* find options */
200    while (*search && !ok) {
201       if (*search == 'i') {
202          options |= REG_ICASE;
203
204       } else if (*search == 'g') {
205               /* recherche multiple*/
206
207       } else if (*search == sep) {
208          /* skip separator */
209
210       } else {                  /* end of options */
211          ok = true;
212       }
213       search++;
214    }
215
216    int rc = regcomp(&preg, expr, options);
217    if (rc != 0) {
218       char prbuf[500];
219       regerror(rc, &preg, prbuf, sizeof(prbuf));
220       Dmsg1(100, "bregexp: compile error: %s\n", prbuf);
221       return false;
222    }
223
224    eor = search;                /* useful to find the next regexp in where */
225
226    return true;
227 }
228
229 #ifndef HAVE_REGEX_H
230  #define BREGEX_CAST unsigned
231 #else
232  #define BREGEX_CAST const
233 #endif
234
235 /* return regexp->result */
236 char *BREGEXP::replace(const char *fname)
237 {
238    success = false;             /* use this.success to known if it's ok */
239    int flen = strlen(fname);
240    int rc = re_search(&preg, (BREGEX_CAST char*) fname, flen, 0, flen, &regs);
241
242    if (rc < 0) {
243       Dmsg0(500, "bregexp: regex mismatch\n");
244       return return_fname(fname, flen);
245    }
246
247    int len = compute_dest_len(fname, &regs);
248
249    if (len) {
250       result = check_pool_memory_size(result, len);
251       edit_subst(fname, &regs);
252       success = true;
253       Dmsg2(500, "bregexp: len = %i, result_len = %i\n", len, strlen(result));
254
255    } else {                     /* error in substitution */
256       Dmsg0(100, "bregexp: error in substitution\n");
257       return return_fname(fname, flen);
258    }
259
260    return result;
261
262
263 char *BREGEXP::return_fname(const char *fname, int len)
264 {
265    result = check_pool_memory_size(result, len+1);
266    strcpy(result,fname);
267    return result;
268 }
269
270 int BREGEXP::compute_dest_len(const char *fname, struct re_registers *regs)
271 {
272    int len=0;
273    char *p;
274    char *psubst = subst;
275    int no;
276
277    if (!fname || !regs) {
278       return 0;
279    }
280
281    /* match failed ? */
282    if (regs->start[0] < 0) {
283       return 0;
284    }
285
286    for (p = psubst++; *p ; p = psubst++) {
287       /* match $1 \1 back references */
288       if ((*p == '$' || *p == '\\') && ('0' <= *psubst && *psubst <= '9')) {
289          no = *psubst++ - '0';
290
291          /* we check if the back reference exists */
292          /* references can not match if we are using (..)? */
293
294          if (regs->start[no] >= 0 && regs->end[no] >= 0) { 
295             len += regs->end[no] - regs->start[no];
296          }
297          
298       } else {
299          len++;
300       }
301    }
302
303    /* $0 is replaced by subst */
304    len -= regs->end[0] - regs->start[0];
305    len += strlen(fname) + 1;
306
307    return len;
308 }
309
310 char *BREGEXP::edit_subst(const char *fname, struct re_registers *regs)
311 {
312    int i;
313    char *p;
314    char *psubst = subst;
315    int no;
316    int len;
317
318    /* il faut recopier fname dans dest
319     *  on recopie le debut fname -> regs->start[0]
320     */
321    
322    for (i = 0; i < regs->start[0] ; i++) {
323       result[i] = fname[i];
324    }
325
326    /* on recopie le motif de remplacement (avec tous les $x) */
327
328    for (p = psubst++; *p ; p = psubst++) {
329       /* match $1 \1 back references */
330       if ((*p == '$' || *p == '\\') && ('0' <= *psubst && *psubst <= '9')) {
331          no = *psubst++ - '0';
332
333          /* have a back reference ? */
334          if (regs->start[no] >= 0 && regs->end[no] >= 0) {
335             len = regs->end[no] - regs->start[no];
336             bstrncpy(result + i, fname + regs->start[no], len + 1);
337             i += len ;
338          }
339
340       } else {
341          result[i++] = *p;
342       }
343    }
344
345    /* we copy what is out of the match */
346    strcpy(result + i, fname + regs->end[0]);
347
348    return result;
349 }
350
351 void BREGEXP::debug()
352 {
353    printf("expr=[%s]\n", expr);
354    printf("subst=[%s]\n", subst);
355    printf("result=%s\n", result?result:"(null)");
356 }