No empty .Rs/.Re
[netbsd-mini2440.git] / external / bsd / openldap / dist / libraries / librewrite / subst.c
blobb16819b728284c7966c74e42718e7fcd8b3cee5b
1 /* $OpenLDAP: pkg/ldap/libraries/librewrite/subst.c,v 1.22.2.3 2008/02/11 23:26:42 kurt Exp $ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 2000-2008 The OpenLDAP Foundation.
5 * All rights reserved.
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.
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>.
15 /* ACKNOWLEDGEMENT:
16 * This work was initially developed by Pierangelo Masarati for
17 * inclusion in OpenLDAP Software.
20 #include <portable.h>
22 #include "rewrite-int.h"
25 * Compiles a substitution pattern
27 struct rewrite_subst *
28 rewrite_subst_compile(
29 struct rewrite_info *info,
30 const char *str
33 size_t subs_len;
34 struct berval *subs = NULL, *tmps;
35 struct rewrite_submatch *submatch = NULL;
37 struct rewrite_subst *s = NULL;
39 char *result, *begin, *p;
40 int nsub = 0, l;
42 assert( info != NULL );
43 assert( str != NULL );
45 result = strdup( str );
46 if ( result == NULL ) {
47 return NULL;
51 * Take care of substitution string
53 for ( p = begin = result, subs_len = 0; p[ 0 ] != '\0'; p++ ) {
56 * Keep only single escapes '%'
58 if ( !IS_REWRITE_SUBMATCH_ESCAPE( p[ 0 ] ) ) {
59 continue;
62 if ( IS_REWRITE_SUBMATCH_ESCAPE( p[ 1 ] ) ) {
63 /* Pull &p[1] over p, including the trailing '\0' */
64 AC_MEMCPY((char *)p, &p[ 1 ], strlen( p ) );
65 continue;
68 tmps = ( struct berval * )realloc( subs,
69 sizeof( struct berval )*( nsub + 1 ) );
70 if ( tmps == NULL ) {
71 goto cleanup;
73 subs = tmps;
76 * I think an `if l > 0' at runtime is better outside than
77 * inside a function call ...
79 l = p - begin;
80 if ( l > 0 ) {
81 subs_len += l;
82 subs[ nsub ].bv_len = l;
83 subs[ nsub ].bv_val = malloc( l + 1 );
84 if ( subs[ nsub ].bv_val == NULL ) {
85 goto cleanup;
87 AC_MEMCPY( subs[ nsub ].bv_val, begin, l );
88 subs[ nsub ].bv_val[ l ] = '\0';
89 } else {
90 subs[ nsub ].bv_val = NULL;
91 subs[ nsub ].bv_len = 0;
95 * Substitution pattern
97 if ( isdigit( (unsigned char) p[ 1 ] ) ) {
98 struct rewrite_submatch *tmpsm;
99 int d = p[ 1 ] - '0';
102 * Add a new value substitution scheme
105 tmpsm = ( struct rewrite_submatch * )realloc( submatch,
106 sizeof( struct rewrite_submatch )*( nsub + 1 ) );
107 if ( tmpsm == NULL ) {
108 goto cleanup;
110 submatch = tmpsm;
111 submatch[ nsub ].ls_submatch = d;
114 * If there is no argument, use default
115 * (substitute substring as is)
117 if ( p[ 2 ] != '{' ) {
118 submatch[ nsub ].ls_type =
119 REWRITE_SUBMATCH_ASIS;
120 submatch[ nsub ].ls_map = NULL;
121 begin = ++p + 1;
123 } else {
124 struct rewrite_map *map;
126 submatch[ nsub ].ls_type =
127 REWRITE_SUBMATCH_XMAP;
129 map = rewrite_xmap_parse( info,
130 p + 3, (const char **)&begin );
131 if ( map == NULL ) {
132 goto cleanup;
134 submatch[ nsub ].ls_map = map;
135 p = begin - 1;
139 * Map with args ...
141 } else if ( p[ 1 ] == '{' ) {
142 struct rewrite_map *map;
143 struct rewrite_submatch *tmpsm;
145 map = rewrite_map_parse( info, p + 2,
146 (const char **)&begin );
147 if ( map == NULL ) {
148 goto cleanup;
150 p = begin - 1;
153 * Add a new value substitution scheme
155 tmpsm = ( struct rewrite_submatch * )realloc( submatch,
156 sizeof( struct rewrite_submatch )*( nsub + 1 ) );
157 if ( tmpsm == NULL ) {
158 goto cleanup;
160 submatch = tmpsm;
161 submatch[ nsub ].ls_type =
162 REWRITE_SUBMATCH_MAP_W_ARG;
163 submatch[ nsub ].ls_map = map;
166 * Escape '%' ...
168 } else if ( p[ 1 ] == '%' ) {
169 AC_MEMCPY( &p[ 1 ], &p[ 2 ], strlen( &p[ 1 ] ) );
170 continue;
172 } else {
173 goto cleanup;
176 nsub++;
180 * Last part of string
182 tmps = (struct berval * )realloc( subs, sizeof( struct berval )*( nsub + 1 ) );
183 if ( tmps == NULL ) {
185 * XXX need to free the value subst stuff!
187 free( subs );
188 goto cleanup;
190 subs = tmps;
191 l = p - begin;
192 if ( l > 0 ) {
193 subs_len += l;
194 subs[ nsub ].bv_len = l;
195 subs[ nsub ].bv_val = malloc( l + 1 );
196 AC_MEMCPY( subs[ nsub ].bv_val, begin, l );
197 subs[ nsub ].bv_val[ l ] = '\0';
198 } else {
199 subs[ nsub ].bv_val = NULL;
200 subs[ nsub ].bv_len = 0;
203 s = calloc( sizeof( struct rewrite_subst ), 1 );
204 if ( s == NULL ) {
205 goto cleanup;
208 s->lt_subs_len = subs_len;
209 s->lt_subs = subs;
210 s->lt_num_submatch = nsub;
211 s->lt_submatch = submatch;
213 cleanup:;
214 free( result );
216 return s;
220 * Copies the match referred to by submatch and fetched in string by match.
221 * Helper for rewrite_rule_apply.
223 static int
224 submatch_copy(
225 struct rewrite_submatch *submatch,
226 const char *string,
227 const regmatch_t *match,
228 struct berval *val
231 int c, l;
232 const char *s;
234 assert( submatch != NULL );
235 assert( submatch->ls_type == REWRITE_SUBMATCH_ASIS
236 || submatch->ls_type == REWRITE_SUBMATCH_XMAP );
237 assert( string != NULL );
238 assert( match != NULL );
239 assert( val != NULL );
240 assert( val->bv_val == NULL );
242 c = submatch->ls_submatch;
243 s = string + match[ c ].rm_so;
244 l = match[ c ].rm_eo - match[ c ].rm_so;
246 val->bv_len = l;
247 val->bv_val = malloc( l + 1 );
248 if ( val->bv_val == NULL ) {
249 return REWRITE_ERR;
252 AC_MEMCPY( val->bv_val, s, l );
253 val->bv_val[ l ] = '\0';
255 return REWRITE_SUCCESS;
259 * Substitutes a portion of rewritten string according to substitution
260 * pattern using submatches
263 rewrite_subst_apply(
264 struct rewrite_info *info,
265 struct rewrite_op *op,
266 struct rewrite_subst *subst,
267 const char *string,
268 const regmatch_t *match,
269 struct berval *val
272 struct berval *submatch = NULL;
273 char *res = NULL;
274 int n = 0, l, cl;
275 int rc = REWRITE_REGEXEC_OK;
277 assert( info != NULL );
278 assert( op != NULL );
279 assert( subst != NULL );
280 assert( string != NULL );
281 assert( match != NULL );
282 assert( val != NULL );
284 assert( val->bv_val == NULL );
286 val->bv_val = NULL;
287 val->bv_len = 0;
290 * Prepare room for submatch expansion
292 if ( subst->lt_num_submatch > 0 ) {
293 submatch = calloc( sizeof( struct berval ),
294 subst->lt_num_submatch );
295 if ( submatch == NULL ) {
296 return REWRITE_REGEXEC_ERR;
301 * Resolve submatches (simple subst, map expansion and so).
303 for ( n = 0, l = 0; n < subst->lt_num_submatch; n++ ) {
304 struct berval key = { 0, NULL };
306 submatch[ n ].bv_val = NULL;
309 * Get key
311 switch ( subst->lt_submatch[ n ].ls_type ) {
312 case REWRITE_SUBMATCH_ASIS:
313 case REWRITE_SUBMATCH_XMAP:
314 rc = submatch_copy( &subst->lt_submatch[ n ],
315 string, match, &key );
316 if ( rc != REWRITE_SUCCESS ) {
317 rc = REWRITE_REGEXEC_ERR;
318 goto cleanup;
320 break;
322 case REWRITE_SUBMATCH_MAP_W_ARG:
323 switch ( subst->lt_submatch[ n ].ls_map->lm_type ) {
324 case REWRITE_MAP_GET_OP_VAR:
325 case REWRITE_MAP_GET_SESN_VAR:
326 case REWRITE_MAP_GET_PARAM:
327 rc = REWRITE_SUCCESS;
328 break;
330 default:
331 rc = rewrite_subst_apply( info, op,
332 subst->lt_submatch[ n ].ls_map->lm_subst,
333 string, match, &key);
336 if ( rc != REWRITE_SUCCESS ) {
337 goto cleanup;
339 break;
341 default:
342 Debug( LDAP_DEBUG_ANY, "Not Implemented\n", 0, 0, 0 );
343 rc = REWRITE_ERR;
344 break;
347 if ( rc != REWRITE_SUCCESS ) {
348 rc = REWRITE_REGEXEC_ERR;
349 goto cleanup;
353 * Resolve key
355 switch ( subst->lt_submatch[ n ].ls_type ) {
356 case REWRITE_SUBMATCH_ASIS:
357 submatch[ n ] = key;
358 rc = REWRITE_SUCCESS;
359 break;
361 case REWRITE_SUBMATCH_XMAP:
362 rc = rewrite_xmap_apply( info, op,
363 subst->lt_submatch[ n ].ls_map,
364 &key, &submatch[ n ] );
365 free( key.bv_val );
366 key.bv_val = NULL;
367 break;
369 case REWRITE_SUBMATCH_MAP_W_ARG:
370 rc = rewrite_map_apply( info, op,
371 subst->lt_submatch[ n ].ls_map,
372 &key, &submatch[ n ] );
373 free( key.bv_val );
374 key.bv_val = NULL;
375 break;
377 default:
379 * When implemented, this might return the
380 * exit status of a rewrite context,
381 * which may include a stop, or an
382 * unwilling to perform
384 rc = REWRITE_ERR;
385 break;
388 if ( rc != REWRITE_SUCCESS ) {
389 rc = REWRITE_REGEXEC_ERR;
390 goto cleanup;
394 * Increment the length of the resulting string
396 l += submatch[ n ].bv_len;
400 * Alloc result buffer
402 l += subst->lt_subs_len;
403 res = malloc( l + 1 );
404 if ( res == NULL ) {
405 rc = REWRITE_REGEXEC_ERR;
406 goto cleanup;
410 * Apply submatches (possibly resolved thru maps)
412 for ( n = 0, cl = 0; n < subst->lt_num_submatch; n++ ) {
413 if ( subst->lt_subs[ n ].bv_val != NULL ) {
414 AC_MEMCPY( res + cl, subst->lt_subs[ n ].bv_val,
415 subst->lt_subs[ n ].bv_len );
416 cl += subst->lt_subs[ n ].bv_len;
418 AC_MEMCPY( res + cl, submatch[ n ].bv_val,
419 submatch[ n ].bv_len );
420 cl += submatch[ n ].bv_len;
422 if ( subst->lt_subs[ n ].bv_val != NULL ) {
423 AC_MEMCPY( res + cl, subst->lt_subs[ n ].bv_val,
424 subst->lt_subs[ n ].bv_len );
425 cl += subst->lt_subs[ n ].bv_len;
427 res[ cl ] = '\0';
429 val->bv_val = res;
430 val->bv_len = l;
432 cleanup:;
433 if ( submatch ) {
434 for ( ; --n >= 0; ) {
435 if ( submatch[ n ].bv_val ) {
436 free( submatch[ n ].bv_val );
439 free( submatch );
442 return rc;
446 * frees data
449 rewrite_subst_destroy(
450 struct rewrite_subst **psubst
453 int n;
454 struct rewrite_subst *subst;
456 assert( psubst != NULL );
457 assert( *psubst != NULL );
459 subst = *psubst;
461 for ( n = 0; n < subst->lt_num_submatch; n++ ) {
462 if ( subst->lt_subs[ n ].bv_val ) {
463 free( subst->lt_subs[ n ].bv_val );
464 subst->lt_subs[ n ].bv_val = NULL;
467 switch ( subst->lt_submatch[ n ].ls_type ) {
468 case REWRITE_SUBMATCH_ASIS:
469 break;
471 case REWRITE_SUBMATCH_XMAP:
472 rewrite_xmap_destroy( &subst->lt_submatch[ n ].ls_map );
473 break;
475 case REWRITE_SUBMATCH_MAP_W_ARG:
476 rewrite_map_destroy( &subst->lt_submatch[ n ].ls_map );
477 break;
479 default:
480 break;
484 free( subst->lt_submatch );
485 subst->lt_submatch = NULL;
487 /* last one */
488 if ( subst->lt_subs[ n ].bv_val ) {
489 free( subst->lt_subs[ n ].bv_val );
490 subst->lt_subs[ n ].bv_val = NULL;
493 free( subst->lt_subs );
494 subst->lt_subs = NULL;
496 free( subst );
497 *psubst = NULL;
499 return 0;