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