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