]> git.sur5r.net Git - openldap/blob - libraries/librewrite/subst.c
a6d9fdbabf9bcfa89541c38342abc377afac60f7
[openldap] / libraries / librewrite / subst.c
1 /******************************************************************************
2  *
3  * Copyright (C) 2000 Pierangelo Masarati, <ando@sys-net.it>
4  * All rights reserved.
5  *
6  * Permission is granted to anyone to use this software for any purpose
7  * on any computer system, and to alter it and redistribute it, subject
8  * to the following restrictions:
9  *
10  * 1. The author is not responsible for the consequences of use of this
11  * software, no matter how awful, even if they arise from flaws in it.
12  *
13  * 2. The origin of this software must not be misrepresented, either by
14  * explicit claim or by omission.  Since few users ever read sources,
15  * credits should appear in the documentation.
16  *
17  * 3. Altered versions must be plainly marked as such, and must not be
18  * misrepresented as being the original software.  Since few users
19  * ever read sources, credits should appear in the documentation.
20  * 
21  * 4. This notice may not be removed or altered.
22  *
23  ******************************************************************************/
24
25 #include <portable.h>
26
27 #include "rewrite-int.h"
28
29 /*
30  * Compiles a substitution pattern
31  */
32 struct rewrite_subst *
33 rewrite_subst_compile(
34                 struct rewrite_info *info,
35                 const char *result
36 )
37 {
38         size_t subs_len;
39         struct berval **subs = NULL, **tmps;
40         struct rewrite_submatch **submatch = NULL;
41
42         struct rewrite_subst *s = NULL;
43
44         const char *begin, *p;
45         int nsub = 0, l;
46
47         assert( info != NULL );
48         assert( result != NULL );
49
50         /*
51          * Take care of substitution string
52          */
53         for ( p = begin = result, subs_len = 0; p[ 0 ] != '\0'; p++ ) {
54                 
55                 /*
56                  * Keep only single escapes '%'
57                  */
58                 if ( p[ 0 ] != REWRITE_SUBMATCH_ESCAPE ) {
59                         continue;
60                 } 
61                 if ( p[ 1 ] == REWRITE_SUBMATCH_ESCAPE ) {
62                         AC_MEMCPY((char *)p, p + 1, strlen( p ) );
63                         continue;
64                 }
65
66                 nsub++;
67                 
68                 tmps = (struct berval **)realloc( subs,
69                                 sizeof( struct berval * )*( nsub + 1 ) );
70                 if ( tmps == NULL ) {
71                         /* cleanup */
72                         return NULL;
73                 }
74                 subs = tmps;
75                 subs[ nsub ] = NULL;
76                 
77                 /*
78                  * I think an `if l > 0' at runtime is better outside than
79                  * inside a function call ...
80                  */
81                 l = p - begin;
82                 if ( l > 0 ) {
83                         subs_len += l;
84                         subs[ nsub - 1 ] =
85                                 calloc( sizeof( struct berval ), 1 );
86                         if ( subs[ nsub - 1 ] == NULL ) {
87                                 /* cleanup */
88                                 return NULL;
89                         }
90                         subs[ nsub - 1 ]->bv_len = l;
91                         subs[ nsub - 1 ]->bv_val = malloc( l + 1 );
92                         if ( subs[ nsub - 1 ]->bv_val == NULL ) {
93                                 return NULL;
94                         }
95                         AC_MEMCPY( subs[ nsub - 1 ]->bv_val, begin, l );
96                         subs[ nsub - 1 ]->bv_val[ l ] = '\0';
97                 } else {
98                         subs[ nsub - 1 ] = NULL;
99                 }
100                 
101                 /*
102                  * Substitution pattern
103                  */
104                 if ( isdigit( (unsigned char) p[ 1 ] ) ) {
105                         int d = p[ 1 ] - '0';
106                         struct rewrite_submatch **tmpsm;
107
108                         /*
109                          * Add a new value substitution scheme
110                          */
111                         tmpsm = realloc( submatch, 
112         sizeof( struct rewrite_submatch * )*( nsub + 1 ) );
113                         if ( tmpsm == NULL ) {
114                                 /* cleanup */
115                                 return NULL;
116                         }
117                         submatch = tmpsm;
118                         submatch[ nsub ] = NULL;
119                         
120                         submatch[ nsub - 1 ] = 
121         calloc( sizeof(  struct rewrite_submatch ), 1 );
122                         if ( submatch[ nsub - 1 ] == NULL ) {
123                                 /* cleanup */
124                                 return NULL;
125                         }
126                         submatch[ nsub - 1 ]->ls_submatch = d;
127
128                         /*
129                          * If there is no argument, use default
130                          * (substitute substring as is)
131                          */
132                         if ( p[ 2 ] != '{' ) {
133                                 submatch[ nsub - 1 ]->ls_type = 
134                                         REWRITE_SUBMATCH_ASIS;
135                                 begin = ++p + 1;
136                         } else {
137                                 struct rewrite_map *map;
138
139                                 submatch[ nsub - 1 ]->ls_type =
140                                         REWRITE_SUBMATCH_XMAP;
141
142                                 map = rewrite_xmap_parse( info,
143                                                 p + 3, &begin );
144                                 if ( map == NULL ) {
145                                         /* cleanup */
146                                         return NULL;
147                                 }
148                                 p = begin - 1;
149
150                                 submatch[ nsub - 1 ]->ls_map = map;
151                         }
152
153                 /*
154                  * Map with args ...
155                  */
156                 } else if ( p[ 1 ] == '{' ) {
157                         struct rewrite_map *map;
158                         struct rewrite_submatch **tmpsm;
159
160                         map = rewrite_map_parse( info, p + 2, &begin );
161                         if ( map == NULL ) {
162                                 /* cleanup */
163                                 return NULL;
164                         }
165                         p = begin - 1;
166
167                         /*
168                          * Add a new value substitution scheme
169                          */
170                         tmpsm = realloc( submatch,
171                                         sizeof( struct rewrite_submatch * )*( nsub + 1 ) );
172                         if ( tmpsm == NULL ) {
173                                 /* cleanup */
174                                 return NULL;
175                         }
176                         submatch = tmpsm;
177                         submatch[ nsub ] = NULL;
178                         submatch[ nsub - 1 ] =
179                                 calloc( sizeof(  struct rewrite_submatch ), 1 );
180                         if ( submatch[ nsub - 1 ] == NULL ) {
181                                 /* cleanup */
182                                 return NULL;
183                         }
184
185                         submatch[ nsub - 1 ]->ls_type =
186                                 REWRITE_SUBMATCH_MAP_W_ARG;
187                         
188                         submatch[ nsub - 1 ]->ls_map = map;
189                 }
190         }
191         
192         /*
193          * Last part of string
194          */
195         tmps = realloc( subs, sizeof( struct berval *)*( nsub + 2 ) );
196         if ( tmps == NULL ) {
197                 /*
198                  * XXX need to free the value subst stuff!
199                  */
200                 free( submatch );
201                 return NULL;
202         }
203
204         subs = tmps;
205         subs[ nsub + 1 ] = NULL;
206         l = p - begin;
207         if ( l > 0 ) {
208                 subs[ nsub ] = calloc( sizeof( struct berval ), 1 );
209                 subs_len += l;
210                 subs[ nsub ]->bv_len = l;
211                 subs[ nsub ]->bv_val = malloc( l + 1 );
212                 AC_MEMCPY( subs[ nsub ]->bv_val, begin, l );
213                 subs[ nsub ]->bv_val[ l ] = '\0';
214         } else {
215                 subs[ nsub ] = NULL;
216         }
217
218         s = calloc( sizeof( struct rewrite_subst ), 1 );
219         if ( s == NULL ) {
220                 /* cleanup */
221                 return NULL;
222         }
223
224         s->lt_subs_len = subs_len;
225         s->lt_subs = subs;
226         s->lt_num_submatch = nsub;
227         s->lt_submatch = submatch;
228
229         return s;
230 }
231
232 /*
233  * Copies the match referred to by submatch and fetched in string by match.
234  * Helper for rewrite_rule_apply.
235  */
236 static int
237 submatch_copy(
238                 struct rewrite_submatch *submatch,
239                 const char *string,
240                 const regmatch_t *match,
241                 struct berval *val
242 )
243 {
244         int c, l;
245         const char *s;
246
247         assert( submatch != NULL );
248         assert( submatch->ls_type == REWRITE_SUBMATCH_ASIS
249                         || submatch->ls_type == REWRITE_SUBMATCH_XMAP );
250         assert( string != NULL );
251         assert( match != NULL );
252         assert( val != NULL );
253         
254         c = submatch->ls_submatch;
255         s = string + match[ c ].rm_so;
256         l = match[ c ].rm_eo - match[ c ].rm_so;
257         
258         val->bv_val = NULL;
259         val->bv_len = l;
260         val->bv_val = calloc( sizeof( char ), l + 1 );
261         if ( val->bv_val == NULL ) {
262                 return REWRITE_ERR;
263         }
264         
265         AC_MEMCPY( val->bv_val, s, l );
266         val->bv_val[ l ] = '\0';
267         
268         return REWRITE_SUCCESS;
269 }
270
271 /*
272  * Substitutes a portion of rewritten string according to substitution
273  * pattern using submatches
274  */
275 int
276 rewrite_subst_apply(
277                 struct rewrite_info *info,
278                 struct rewrite_op *op,
279                 struct rewrite_subst *subst,
280                 const char *string,
281                 const regmatch_t *match,
282                 struct berval *val
283 )
284 {
285         struct berval *submatch = NULL;
286         char *res = NULL;
287         int n, l, cl;
288         int rc = REWRITE_REGEXEC_OK;
289
290         assert( info != NULL );
291         assert( op != NULL );
292         assert( subst != NULL );
293         assert( string != NULL );
294         assert( match != NULL );
295         assert( val != NULL );
296
297         val->bv_val = NULL;
298         val->bv_len = 0;
299
300         /*
301          * Prepare room for submatch expansion
302          */
303         if ( subst->lt_num_submatch > 0 ) {
304                 submatch = calloc( sizeof( struct berval ),
305                                 subst->lt_num_submatch );
306                 if ( submatch == NULL ) {
307                         return REWRITE_REGEXEC_ERR;
308                 }
309         }
310         
311         /*
312          * Resolve submatches (simple subst, map expansion and so).
313          */
314         for ( n = 0, l = 0; n < subst->lt_num_submatch; n++ ) {
315                 struct berval key;
316                 int rc;
317                 
318                 /*
319                  * Get key
320                  */
321                 switch( subst->lt_submatch[ n ]->ls_type ) {
322                 case REWRITE_SUBMATCH_ASIS:
323                 case REWRITE_SUBMATCH_XMAP:
324                         rc = submatch_copy( subst->lt_submatch[ n ],
325                                         string, match, &key );
326                         if ( rc != REWRITE_SUCCESS ) {
327                                 free( submatch );
328                                 return REWRITE_REGEXEC_ERR;
329                         }
330                         break;
331                         
332                 case REWRITE_SUBMATCH_MAP_W_ARG:
333                         switch ( subst->lt_submatch[ n ]->ls_map->lm_type ) {
334                         case REWRITE_MAP_GET_OP_VAR:
335                         case REWRITE_MAP_GET_SESN_VAR:
336                         case REWRITE_MAP_GET_PARAM:
337                                 rc = REWRITE_SUCCESS;
338                                 break;
339                         default:
340                                 rc = rewrite_subst_apply( info, op, 
341                                         subst->lt_submatch[ n ]->ls_map->lm_subst,
342                                         string, match, &key);
343                         }
344                         
345                         if ( rc != REWRITE_SUCCESS ) {
346                                 free( submatch );
347                                 return REWRITE_REGEXEC_ERR;
348                         }
349                         break;
350
351                 default:
352                         Debug( LDAP_DEBUG_ANY, "Not Implemented\n%s%s%s", 
353                                         "", "", "" );
354                         rc = REWRITE_ERR;
355                         break;
356                 }
357                 
358                 if ( rc != REWRITE_SUCCESS ) {
359                         free( submatch );
360                         return REWRITE_REGEXEC_ERR;
361                 }
362
363                 /*
364                  * Resolve key
365                  */
366                 switch ( subst->lt_submatch[ n ]->ls_type ) {
367                 case REWRITE_SUBMATCH_ASIS:
368                         submatch[ n ] = key;
369                         rc = REWRITE_SUCCESS;
370                         break;
371                         
372                 case REWRITE_SUBMATCH_XMAP:
373                         rc = rewrite_xmap_apply( info, op,
374                                         subst->lt_submatch[ n ]->ls_map,
375                                         &key, &submatch[ n ] );
376                         break;
377                         
378                 case REWRITE_SUBMATCH_MAP_W_ARG:
379                         rc = rewrite_map_apply( info, op,
380                                         subst->lt_submatch[ n ]->ls_map,
381                                         &key, &submatch[ n ] );
382                         break;
383                                                 
384                 default:
385                         /*
386                          * When implemented, this might return the
387                          * exit status of a rewrite context,
388                          * which may include a stop, or an
389                          * unwilling to perform
390                          */
391                         rc = REWRITE_ERR;
392                         break;
393                 }
394                 
395                 if ( rc != REWRITE_SUCCESS ) {
396                         free( submatch );
397                         return REWRITE_REGEXEC_ERR;
398                 }
399                 
400                 /*
401                  * Increment the length of the resulting string
402                  */
403                 l += submatch[ n ].bv_len;
404         }
405         
406         /*
407          * Alloc result buffer as big as the constant part 
408          * of the subst pattern and initialize it
409          */
410         l += subst->lt_subs_len;
411         res = calloc( sizeof( char ), l + 1 );
412         if ( res == NULL ) {
413                 rc = REWRITE_REGEXEC_ERR;
414                 goto cleanup;
415         }
416
417         /*
418          * Apply submatches (possibly resolved thru maps
419          */
420         for ( n = 0, cl = 0; n < subst->lt_num_submatch; n++ ) {
421                 if ( subst->lt_subs[ n ] != NULL ) {
422                         AC_MEMCPY( res + cl, subst->lt_subs[ n ]->bv_val,
423                                         subst->lt_subs[ n ]->bv_len );
424                         cl += subst->lt_subs[ n ]->bv_len;
425                 }
426                 AC_MEMCPY( res + cl, submatch[ n ].bv_val, 
427                                 submatch[ n ].bv_len );
428                 cl += submatch[ n ].bv_len;
429                 free( submatch[ n ].bv_val );
430         }
431         if ( subst->lt_subs[ n ] != NULL ) {
432                 AC_MEMCPY( res + cl, subst->lt_subs[ n ]->bv_val,
433                                 subst->lt_subs[ n ]->bv_len );
434         }
435
436         val->bv_val = res;
437         val->bv_len = l;
438
439 cleanup:;
440         if ( submatch ) {
441                 free( submatch );
442         }
443
444         return rc;
445 }
446