]> git.sur5r.net Git - openldap/blob - libraries/librewrite/subst.c
In ldap_extended_operation_s, check for NULL retoidp and retdatap
[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         submatch = calloc( sizeof( struct berval ),
304                         subst->lt_num_submatch );
305         if ( submatch == NULL ) {
306                 return REWRITE_REGEXEC_ERR;
307         }
308         
309         /*
310          * Resolve submatches (simple subst, map expansion and so).
311          */
312         for ( n = 0, l = 0; n < subst->lt_num_submatch; n++ ) {
313                 struct berval key;
314                 int rc;
315                 
316                 /*
317                  * Get key
318                  */
319                 switch( subst->lt_submatch[ n ]->ls_type ) {
320                 case REWRITE_SUBMATCH_ASIS:
321                 case REWRITE_SUBMATCH_XMAP:
322                         rc = submatch_copy( subst->lt_submatch[ n ],
323                                         string, match, &key );
324                         if ( rc != REWRITE_SUCCESS ) {
325                                 free( submatch );
326                                 return REWRITE_REGEXEC_ERR;
327                         }
328                         break;
329                         
330                 case REWRITE_SUBMATCH_MAP_W_ARG:
331                         switch ( subst->lt_submatch[ n ]->ls_map->lm_type ) {
332                         case REWRITE_MAP_GET_OP_VAR:
333                         case REWRITE_MAP_GET_SESN_VAR:
334                         case REWRITE_MAP_GET_PARAM:
335                                 rc = REWRITE_SUCCESS;
336                                 break;
337                         default:
338                                 rc = rewrite_subst_apply( info, op, 
339                                         subst->lt_submatch[ n ]->ls_map->lm_subst,
340                                         string, match, &key);
341                         }
342                         
343                         if ( rc != REWRITE_SUCCESS ) {
344                                 free( submatch );
345                                 return REWRITE_REGEXEC_ERR;
346                         }
347                         break;
348
349                 default:
350                         Debug( LDAP_DEBUG_ANY, "Not Implemented\n%s%s%s", 
351                                         "", "", "" );
352                         rc = REWRITE_ERR;
353                         break;
354                 }
355                 
356                 if ( rc != REWRITE_SUCCESS ) {
357                         free( submatch );
358                         return REWRITE_REGEXEC_ERR;
359                 }
360
361                 /*
362                  * Resolve key
363                  */
364                 switch ( subst->lt_submatch[ n ]->ls_type ) {
365                 case REWRITE_SUBMATCH_ASIS:
366                         submatch[ n ] = key;
367                         rc = REWRITE_SUCCESS;
368                         break;
369                         
370                 case REWRITE_SUBMATCH_XMAP:
371                         rc = rewrite_xmap_apply( info, op,
372                                         subst->lt_submatch[ n ]->ls_map,
373                                         &key, &submatch[ n ] );
374                         break;
375                         
376                 case REWRITE_SUBMATCH_MAP_W_ARG:
377                         rc = rewrite_map_apply( info, op,
378                                         subst->lt_submatch[ n ]->ls_map,
379                                         &key, &submatch[ n ] );
380                         break;
381                                                 
382                 default:
383                         /*
384                          * When implemented, this might return the
385                          * exit status of a rewrite context,
386                          * which may include a stop, or an
387                          * unwilling to perform
388                          */
389                         rc = REWRITE_ERR;
390                         break;
391                 }
392                 
393                 if ( rc != REWRITE_SUCCESS ) {
394                         free( submatch );
395                         return REWRITE_REGEXEC_ERR;
396                 }
397                 
398                 /*
399                  * Increment the length of the resulting string
400                  */
401                 l += submatch[ n ].bv_len;
402         }
403         
404         /*
405          * Alloc result buffer as big as the constant part 
406          * of the subst pattern and initialize it
407          */
408         l += subst->lt_subs_len;
409         res = calloc( sizeof( char ), l + 1 );
410         if ( res == NULL ) {
411                 free( submatch );
412                 return REWRITE_REGEXEC_ERR;
413         }
414
415         /*
416          * Apply submatches (possibly resolved thru maps
417          */
418         for ( n = 0, cl = 0; n < subst->lt_num_submatch; n++ ) {
419                 if ( subst->lt_subs[ n ] != NULL ) {
420                         AC_MEMCPY( res + cl, subst->lt_subs[ n ]->bv_val,
421                                         subst->lt_subs[ n ]->bv_len );
422                         cl += subst->lt_subs[ n ]->bv_len;
423                 }
424                 AC_MEMCPY( res + cl, submatch[ n ].bv_val, 
425                                 submatch[ n ].bv_len );
426                 cl += submatch[ n ].bv_len;
427                 free( submatch[ n ].bv_val );
428         }
429         if ( subst->lt_subs[ n ] != NULL ) {
430                 AC_MEMCPY( res + cl, subst->lt_subs[ n ]->bv_val,
431                                 subst->lt_subs[ n ]->bv_len );
432         }
433
434         val->bv_val = res;
435         val->bv_len = l;
436         
437         return rc;
438 }
439