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