]> git.sur5r.net Git - openldap/blob - libraries/librewrite/subst.c
Sync with HEAD
[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
62                 if ( p[ 1 ] == REWRITE_SUBMATCH_ESCAPE ) {
63                         /* Pull &p[1] over p, including the trailing '\0' */
64                         AC_MEMCPY((char *)p, &p[ 1 ], strlen( p ) );
65                         continue;
66                 }
67
68                 tmps = ( struct berval * )realloc( subs,
69                                 sizeof( struct berval )*( nsub + 1 ) );
70                 if ( tmps == NULL ) {
71                         /* FIXME: cleanup */
72                         return NULL;
73                 }
74                 subs = tmps;
75                 
76                 /*
77                  * I think an `if l > 0' at runtime is better outside than
78                  * inside a function call ...
79                  */
80                 l = p - begin;
81                 if ( l > 0 ) {
82                         subs_len += l;
83                         subs[ nsub ].bv_len = l;
84                         subs[ nsub ].bv_val = malloc( l + 1 );
85                         if ( subs[ nsub ].bv_val == NULL ) {
86                                 return NULL;
87                         }
88                         AC_MEMCPY( subs[ nsub ].bv_val, begin, l );
89                         subs[ nsub ].bv_val[ l ] = '\0';
90                 } else {
91                         subs[ nsub ].bv_val = NULL;
92                         subs[ nsub ].bv_len = 0;
93                 }
94                 
95                 /*
96                  * Substitution pattern
97                  */
98                 if ( isdigit( (unsigned char) p[ 1 ] ) ) {
99                         struct rewrite_submatch *tmpsm;
100                         int d = p[ 1 ] - '0';
101
102                         /*
103                          * Add a new value substitution scheme
104                          */
105
106                         tmpsm = ( struct rewrite_submatch * )realloc( submatch,
107                                         sizeof( struct rewrite_submatch )*( nsub + 1 ) );
108                         if ( tmpsm == NULL ) {
109                                 /* cleanup */
110                                 return NULL;
111                         }
112                         submatch = tmpsm;
113                         submatch[ nsub ].ls_submatch = d;
114
115                         /*
116                          * If there is no argument, use default
117                          * (substitute substring as is)
118                          */
119                         if ( p[ 2 ] != '{' ) {
120                                 submatch[ nsub ].ls_type = 
121                                         REWRITE_SUBMATCH_ASIS;
122                                 submatch[ nsub ].ls_map = NULL;
123                                 begin = ++p + 1;
124
125                         } else {
126                                 struct rewrite_map *map;
127
128                                 submatch[ nsub ].ls_type =
129                                         REWRITE_SUBMATCH_XMAP;
130
131                                 map = rewrite_xmap_parse( info,
132                                                 p + 3, &begin );
133                                 if ( map == NULL ) {
134                                         /* cleanup */
135                                         return NULL;
136                                 }
137                                 submatch[ nsub ].ls_map = map;
138                                 p = begin - 1;
139                         }
140
141                 /*
142                  * Map with args ...
143                  */
144                 } else if ( p[ 1 ] == '{' ) {
145                         struct rewrite_map *map;
146                         struct rewrite_submatch *tmpsm;
147
148                         map = rewrite_map_parse( info, p + 2, &begin );
149                         if ( map == NULL ) {
150                                 /* cleanup */
151                                 return NULL;
152                         }
153                         p = begin - 1;
154
155                         /*
156                          * Add a new value substitution scheme
157                          */
158                         tmpsm = ( struct rewrite_submatch * )realloc( submatch,
159                                         sizeof( struct rewrite_submatch )*( nsub + 1 ) );
160                         if ( tmpsm == NULL ) {
161                                 /* cleanup */
162                                 return NULL;
163                         }
164                         submatch = tmpsm;
165                         submatch[ nsub ].ls_type =
166                                 REWRITE_SUBMATCH_MAP_W_ARG;
167                         submatch[ nsub ].ls_map = map;
168                 }
169
170                 nsub++;
171         }
172         
173         /*
174          * Last part of string
175          */
176         tmps = (struct berval * )realloc( subs, sizeof( struct berval )*( nsub + 1 ) );
177         if ( tmps == NULL ) {
178                 /*
179                  * XXX need to free the value subst stuff!
180                  */
181                 free( subs );
182                 return NULL;
183         }
184         subs = tmps;
185         l = p - begin;
186         if ( l > 0 ) {
187                 subs_len += l;
188                 subs[ nsub ].bv_len = l;
189                 subs[ nsub ].bv_val = malloc( l + 1 );
190                 AC_MEMCPY( subs[ nsub ].bv_val, begin, l );
191                 subs[ nsub ].bv_val[ l ] = '\0';
192         } else {
193                 subs[ nsub ].bv_val = NULL;
194                 subs[ nsub ].bv_len = 0;
195         }
196
197         s = calloc( sizeof( struct rewrite_subst ), 1 );
198         if ( s == NULL ) {
199                 /* cleanup */
200                 return NULL;
201         }
202
203         s->lt_subs_len = subs_len;
204         s->lt_subs = subs;
205         s->lt_num_submatch = nsub;
206         s->lt_submatch = submatch;
207
208         return s;
209 }
210
211 /*
212  * Copies the match referred to by submatch and fetched in string by match.
213  * Helper for rewrite_rule_apply.
214  */
215 static int
216 submatch_copy(
217                 struct rewrite_submatch *submatch,
218                 const char *string,
219                 const regmatch_t *match,
220                 struct berval *val
221 )
222 {
223         int             c, l;
224         const char      *s;
225
226         assert( submatch != NULL );
227         assert( submatch->ls_type == REWRITE_SUBMATCH_ASIS
228                         || submatch->ls_type == REWRITE_SUBMATCH_XMAP );
229         assert( string != NULL );
230         assert( match != NULL );
231         assert( val != NULL );
232         assert( val->bv_val == NULL );
233         
234         c = submatch->ls_submatch;
235         s = string + match[ c ].rm_so;
236         l = match[ c ].rm_eo - match[ c ].rm_so;
237         
238         val->bv_len = l;
239         val->bv_val = malloc( l + 1 );
240         if ( val->bv_val == NULL ) {
241                 return REWRITE_ERR;
242         }
243         
244         AC_MEMCPY( val->bv_val, s, l );
245         val->bv_val[ l ] = '\0';
246         
247         return REWRITE_SUCCESS;
248 }
249
250 /*
251  * Substitutes a portion of rewritten string according to substitution
252  * pattern using submatches
253  */
254 int
255 rewrite_subst_apply(
256                 struct rewrite_info *info,
257                 struct rewrite_op *op,
258                 struct rewrite_subst *subst,
259                 const char *string,
260                 const regmatch_t *match,
261                 struct berval *val
262 )
263 {
264         struct berval *submatch = NULL;
265         char *res = NULL;
266         int n = 0, l, cl;
267         int rc = REWRITE_REGEXEC_OK;
268
269         assert( info != NULL );
270         assert( op != NULL );
271         assert( subst != NULL );
272         assert( string != NULL );
273         assert( match != NULL );
274         assert( val != NULL );
275
276         assert( val->bv_val == NULL );
277
278         val->bv_val = NULL;
279         val->bv_len = 0;
280
281         /*
282          * Prepare room for submatch expansion
283          */
284         if ( subst->lt_num_submatch > 0 ) {
285                 submatch = calloc( sizeof( struct berval ),
286                                 subst->lt_num_submatch );
287                 if ( submatch == NULL ) {
288                         return REWRITE_REGEXEC_ERR;
289                 }
290         }
291         
292         /*
293          * Resolve submatches (simple subst, map expansion and so).
294          */
295         for ( n = 0, l = 0; n < subst->lt_num_submatch; n++ ) {
296                 struct berval   key = { 0, NULL };
297
298                 submatch[ n ].bv_val = NULL;
299                 
300                 /*
301                  * Get key
302                  */
303                 switch ( subst->lt_submatch[ n ].ls_type ) {
304                 case REWRITE_SUBMATCH_ASIS:
305                 case REWRITE_SUBMATCH_XMAP:
306                         rc = submatch_copy( &subst->lt_submatch[ n ],
307                                         string, match, &key );
308                         if ( rc != REWRITE_SUCCESS ) {
309                                 rc = REWRITE_REGEXEC_ERR;
310                                 goto cleanup;
311                         }
312                         break;
313                         
314                 case REWRITE_SUBMATCH_MAP_W_ARG:
315                         switch ( subst->lt_submatch[ n ].ls_map->lm_type ) {
316                         case REWRITE_MAP_GET_OP_VAR:
317                         case REWRITE_MAP_GET_SESN_VAR:
318                         case REWRITE_MAP_GET_PARAM:
319                                 rc = REWRITE_SUCCESS;
320                                 break;
321
322                         default:
323                                 rc = rewrite_subst_apply( info, op, 
324                                         subst->lt_submatch[ n ].ls_map->lm_subst,
325                                         string, match, &key);
326                         }
327                         
328                         if ( rc != REWRITE_SUCCESS ) {
329                                 rc = REWRITE_REGEXEC_ERR;
330                                 goto cleanup;
331                         }
332                         break;
333
334                 default:
335                         Debug( LDAP_DEBUG_ANY, "Not Implemented\n", 0, 0, 0 );
336                         rc = REWRITE_ERR;
337                         break;
338                 }
339                 
340                 if ( rc != REWRITE_SUCCESS ) {
341                         rc = REWRITE_REGEXEC_ERR;
342                         goto cleanup;
343                 }
344
345                 /*
346                  * Resolve key
347                  */
348                 switch ( subst->lt_submatch[ n ].ls_type ) {
349                 case REWRITE_SUBMATCH_ASIS:
350                         submatch[ n ] = key;
351                         rc = REWRITE_SUCCESS;
352                         break;
353                         
354                 case REWRITE_SUBMATCH_XMAP:
355                         rc = rewrite_xmap_apply( info, op,
356                                         subst->lt_submatch[ n ].ls_map,
357                                         &key, &submatch[ n ] );
358                         free( key.bv_val );
359                         key.bv_val = NULL;
360                         break;
361                         
362                 case REWRITE_SUBMATCH_MAP_W_ARG:
363                         rc = rewrite_map_apply( info, op,
364                                         subst->lt_submatch[ n ].ls_map,
365                                         &key, &submatch[ n ] );
366                         free( key.bv_val );
367                         key.bv_val = NULL;
368                         break;
369
370                 default:
371                         /*
372                          * When implemented, this might return the
373                          * exit status of a rewrite context,
374                          * which may include a stop, or an
375                          * unwilling to perform
376                          */
377                         rc = REWRITE_ERR;
378                         break;
379                 }
380                 
381                 if ( rc != REWRITE_SUCCESS ) {
382                         rc = REWRITE_REGEXEC_ERR;
383                 }
384                 
385                 /*
386                  * Increment the length of the resulting string
387                  */
388                 l += submatch[ n ].bv_len;
389         }
390         
391         /*
392          * Alloc result buffer
393          */
394         l += subst->lt_subs_len;
395         res = malloc( l + 1 );
396         if ( res == NULL ) {
397                 rc = REWRITE_REGEXEC_ERR;
398                 goto cleanup;
399         }
400
401         /*
402          * Apply submatches (possibly resolved thru maps)
403          */
404         for ( n = 0, cl = 0; n < subst->lt_num_submatch; n++ ) {
405                 if ( subst->lt_subs[ n ].bv_val != NULL ) {
406                         AC_MEMCPY( res + cl, subst->lt_subs[ n ].bv_val,
407                                         subst->lt_subs[ n ].bv_len );
408                         cl += subst->lt_subs[ n ].bv_len;
409                 }
410                 AC_MEMCPY( res + cl, submatch[ n ].bv_val, 
411                                 submatch[ n ].bv_len );
412                 cl += submatch[ n ].bv_len;
413         }
414         if ( subst->lt_subs[ n ].bv_val != NULL ) {
415                 AC_MEMCPY( res + cl, subst->lt_subs[ n ].bv_val,
416                                 subst->lt_subs[ n ].bv_len );
417                 cl += subst->lt_subs[ n ].bv_len;
418         }
419         res[ cl ] = '\0';
420
421         val->bv_val = res;
422         val->bv_len = l;
423
424 cleanup:;
425         if ( submatch ) {
426                 for ( ; --n >= 0; ) {
427                         if ( submatch[ n ].bv_val ) {
428                                 free( submatch[ n ].bv_val );
429                         }
430                 }
431                 free( submatch );
432         }
433
434         return rc;
435 }
436
437 /*
438  * frees data
439  */
440 int
441 rewrite_subst_destroy(
442                 struct rewrite_subst **psubst
443 )
444 {
445         int                     n;
446         struct rewrite_subst    *subst;
447
448         assert( psubst );
449         assert( *psubst );
450
451         subst = *psubst;
452
453         for ( n = 0; n < subst->lt_num_submatch; n++ ) {
454                 if ( subst->lt_subs[ n ].bv_val ) {
455                         free( subst->lt_subs[ n ].bv_val );
456                         subst->lt_subs[ n ].bv_val = NULL;
457                 }
458
459                 switch ( subst->lt_submatch[ n ].ls_type ) {
460                 case REWRITE_SUBMATCH_ASIS:
461                         break;
462
463                 case REWRITE_SUBMATCH_XMAP:
464                         rewrite_xmap_destroy( &subst->lt_submatch[ n ].ls_map );
465                         break;
466
467                 case REWRITE_SUBMATCH_MAP_W_ARG:
468                         rewrite_map_destroy( &subst->lt_submatch[ n ].ls_map );
469                         break;
470
471                 default:
472                         break;
473                 }
474         }
475
476         free( subst->lt_submatch );
477         subst->lt_submatch = NULL;
478
479         /* last one */
480         if ( subst->lt_subs[ n ].bv_val ) {
481                 free( subst->lt_subs[ n ].bv_val );
482                 subst->lt_subs[ n ].bv_val = NULL;
483         }
484
485         free( subst->lt_subs );
486         subst->lt_subs = NULL;
487
488         free( subst );
489         *psubst = NULL;
490
491         return 0;
492 }
493