2001-05-12 08:51:28 +08:00
|
|
|
/******************************************************************************
|
|
|
|
*
|
|
|
|
* Copyright (C) 2000 Pierangelo Masarati, <ando@sys-net.it>
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Permission is granted to anyone to use this software for any purpose
|
|
|
|
* on any computer system, and to alter it and redistribute it, subject
|
|
|
|
* to the following restrictions:
|
|
|
|
*
|
|
|
|
* 1. The author is not responsible for the consequences of use of this
|
|
|
|
* software, no matter how awful, even if they arise from flaws in it.
|
|
|
|
*
|
|
|
|
* 2. The origin of this software must not be misrepresented, either by
|
|
|
|
* explicit claim or by omission. Since few users ever read sources,
|
|
|
|
* credits should appear in the documentation.
|
|
|
|
*
|
|
|
|
* 3. Altered versions must be plainly marked as such, and must not be
|
|
|
|
* misrepresented as being the original software. Since few users
|
|
|
|
* ever read sources, credits should appear in the documentation.
|
|
|
|
*
|
|
|
|
* 4. This notice may not be removed or altered.
|
|
|
|
*
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
|
|
#include <portable.h>
|
|
|
|
|
|
|
|
#include "rewrite-int.h"
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Compiles a substitution pattern
|
|
|
|
*/
|
|
|
|
struct rewrite_subst *
|
|
|
|
rewrite_subst_compile(
|
|
|
|
struct rewrite_info *info,
|
|
|
|
const char *result
|
|
|
|
)
|
|
|
|
{
|
|
|
|
size_t subs_len;
|
2001-10-22 18:24:32 +08:00
|
|
|
struct berval **subs = NULL, **tmps;
|
2001-05-12 08:51:28 +08:00
|
|
|
struct rewrite_submatch **submatch = NULL;
|
|
|
|
|
|
|
|
struct rewrite_subst *s = NULL;
|
|
|
|
|
|
|
|
const char *begin, *p;
|
|
|
|
int nsub = 0, l;
|
|
|
|
|
|
|
|
assert( info != NULL );
|
|
|
|
assert( result != NULL );
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Take care of substitution string
|
|
|
|
*/
|
|
|
|
for ( p = begin = result, subs_len = 0; p[ 0 ] != '\0'; p++ ) {
|
|
|
|
|
|
|
|
/*
|
2002-04-16 02:29:39 +08:00
|
|
|
* Keep only single escapes '%'
|
2001-05-12 08:51:28 +08:00
|
|
|
*/
|
|
|
|
if ( p[ 0 ] != REWRITE_SUBMATCH_ESCAPE ) {
|
|
|
|
continue;
|
2001-08-25 23:20:16 +08:00
|
|
|
}
|
|
|
|
if ( p[ 1 ] == REWRITE_SUBMATCH_ESCAPE ) {
|
2002-01-03 01:06:56 +08:00
|
|
|
AC_MEMCPY((char *)p, p + 1, strlen( p ) );
|
2001-05-12 08:51:28 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsub++;
|
|
|
|
|
2001-10-22 18:24:32 +08:00
|
|
|
tmps = (struct berval **)realloc( subs,
|
2001-05-12 08:51:28 +08:00
|
|
|
sizeof( struct berval * )*( nsub + 1 ) );
|
2001-10-22 18:24:32 +08:00
|
|
|
if ( tmps == NULL ) {
|
2001-05-12 08:51:28 +08:00
|
|
|
/* cleanup */
|
|
|
|
return NULL;
|
|
|
|
}
|
2001-10-22 18:24:32 +08:00
|
|
|
subs = tmps;
|
2001-05-12 08:51:28 +08:00
|
|
|
subs[ nsub ] = NULL;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* I think an `if l > 0' at runtime is better outside than
|
|
|
|
* inside a function call ...
|
|
|
|
*/
|
|
|
|
l = p - begin;
|
|
|
|
if ( l > 0 ) {
|
|
|
|
subs_len += l;
|
|
|
|
subs[ nsub - 1 ] =
|
|
|
|
calloc( sizeof( struct berval ), 1 );
|
|
|
|
if ( subs[ nsub - 1 ] == NULL ) {
|
|
|
|
/* cleanup */
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
subs[ nsub - 1 ]->bv_len = l;
|
|
|
|
subs[ nsub - 1 ]->bv_val = malloc( l + 1 );
|
|
|
|
if ( subs[ nsub - 1 ]->bv_val == NULL ) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2001-10-22 17:39:02 +08:00
|
|
|
AC_MEMCPY( subs[ nsub - 1 ]->bv_val, begin, l );
|
2001-05-12 08:51:28 +08:00
|
|
|
subs[ nsub - 1 ]->bv_val[ l ] = '\0';
|
|
|
|
} else {
|
|
|
|
subs[ nsub - 1 ] = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Substitution pattern
|
|
|
|
*/
|
2002-04-08 17:43:22 +08:00
|
|
|
if ( isdigit( (unsigned char) p[ 1 ] ) ) {
|
2001-05-12 08:51:28 +08:00
|
|
|
int d = p[ 1 ] - '0';
|
2001-10-22 18:24:32 +08:00
|
|
|
struct rewrite_submatch **tmpsm;
|
2001-05-12 08:51:28 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Add a new value substitution scheme
|
|
|
|
*/
|
2001-10-22 18:24:32 +08:00
|
|
|
tmpsm = realloc( submatch,
|
2001-05-12 08:51:28 +08:00
|
|
|
sizeof( struct rewrite_submatch * )*( nsub + 1 ) );
|
2001-10-22 18:24:32 +08:00
|
|
|
if ( tmpsm == NULL ) {
|
2001-05-12 08:51:28 +08:00
|
|
|
/* cleanup */
|
|
|
|
return NULL;
|
|
|
|
}
|
2001-10-22 18:24:32 +08:00
|
|
|
submatch = tmpsm;
|
2001-05-12 08:51:28 +08:00
|
|
|
submatch[ nsub ] = NULL;
|
2001-10-22 18:24:32 +08:00
|
|
|
|
2001-05-12 08:51:28 +08:00
|
|
|
submatch[ nsub - 1 ] =
|
|
|
|
calloc( sizeof( struct rewrite_submatch ), 1 );
|
|
|
|
if ( submatch[ nsub - 1 ] == NULL ) {
|
|
|
|
/* cleanup */
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
submatch[ nsub - 1 ]->ls_submatch = d;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If there is no argument, use default
|
|
|
|
* (substitute substring as is)
|
|
|
|
*/
|
|
|
|
if ( p[ 2 ] != '{' ) {
|
|
|
|
submatch[ nsub - 1 ]->ls_type =
|
|
|
|
REWRITE_SUBMATCH_ASIS;
|
|
|
|
begin = ++p + 1;
|
|
|
|
} else {
|
|
|
|
struct rewrite_map *map;
|
|
|
|
|
|
|
|
submatch[ nsub - 1 ]->ls_type =
|
|
|
|
REWRITE_SUBMATCH_XMAP;
|
|
|
|
|
|
|
|
map = rewrite_xmap_parse( info,
|
|
|
|
p + 3, &begin );
|
|
|
|
if ( map == NULL ) {
|
|
|
|
/* cleanup */
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
p = begin - 1;
|
|
|
|
|
|
|
|
submatch[ nsub - 1 ]->ls_map = map;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Map with args ...
|
|
|
|
*/
|
|
|
|
} else if ( p[ 1 ] == '{' ) {
|
|
|
|
struct rewrite_map *map;
|
2001-10-22 18:24:32 +08:00
|
|
|
struct rewrite_submatch **tmpsm;
|
2001-05-12 08:51:28 +08:00
|
|
|
|
|
|
|
map = rewrite_map_parse( info, p + 2, &begin );
|
|
|
|
if ( map == NULL ) {
|
|
|
|
/* cleanup */
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
p = begin - 1;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Add a new value substitution scheme
|
|
|
|
*/
|
2001-10-22 18:24:32 +08:00
|
|
|
tmpsm = realloc( submatch,
|
2001-05-12 08:51:28 +08:00
|
|
|
sizeof( struct rewrite_submatch * )*( nsub + 1 ) );
|
2001-10-22 18:24:32 +08:00
|
|
|
if ( tmpsm == NULL ) {
|
2001-05-12 08:51:28 +08:00
|
|
|
/* cleanup */
|
|
|
|
return NULL;
|
|
|
|
}
|
2001-10-22 18:24:32 +08:00
|
|
|
submatch = tmpsm;
|
2001-05-12 08:51:28 +08:00
|
|
|
submatch[ nsub ] = NULL;
|
|
|
|
submatch[ nsub - 1 ] =
|
|
|
|
calloc( sizeof( struct rewrite_submatch ), 1 );
|
|
|
|
if ( submatch[ nsub - 1 ] == NULL ) {
|
|
|
|
/* cleanup */
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
submatch[ nsub - 1 ]->ls_type =
|
|
|
|
REWRITE_SUBMATCH_MAP_W_ARG;
|
|
|
|
|
|
|
|
submatch[ nsub - 1 ]->ls_map = map;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Last part of string
|
|
|
|
*/
|
2001-10-22 18:24:32 +08:00
|
|
|
tmps = realloc( subs, sizeof( struct berval *)*( nsub + 2 ) );
|
|
|
|
if ( tmps == NULL ) {
|
2001-05-12 08:51:28 +08:00
|
|
|
/*
|
|
|
|
* XXX need to free the value subst stuff!
|
|
|
|
*/
|
|
|
|
free( submatch );
|
|
|
|
return NULL;
|
|
|
|
}
|
2001-10-22 18:24:32 +08:00
|
|
|
|
|
|
|
subs = tmps;
|
2001-05-12 08:51:28 +08:00
|
|
|
subs[ nsub + 1 ] = NULL;
|
|
|
|
l = p - begin;
|
|
|
|
if ( l > 0 ) {
|
|
|
|
subs[ nsub ] = calloc( sizeof( struct berval ), 1 );
|
|
|
|
subs_len += l;
|
|
|
|
subs[ nsub ]->bv_len = l;
|
|
|
|
subs[ nsub ]->bv_val = malloc( l + 1 );
|
2001-10-22 17:39:02 +08:00
|
|
|
AC_MEMCPY( subs[ nsub ]->bv_val, begin, l );
|
2001-05-12 08:51:28 +08:00
|
|
|
subs[ nsub ]->bv_val[ l ] = '\0';
|
|
|
|
} else {
|
|
|
|
subs[ nsub ] = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
s = calloc( sizeof( struct rewrite_subst ), 1 );
|
|
|
|
if ( s == NULL ) {
|
|
|
|
/* cleanup */
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
s->lt_subs_len = subs_len;
|
|
|
|
s->lt_subs = subs;
|
|
|
|
s->lt_num_submatch = nsub;
|
|
|
|
s->lt_submatch = submatch;
|
|
|
|
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copies the match referred to by submatch and fetched in string by match.
|
|
|
|
* Helper for rewrite_rule_apply.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
submatch_copy(
|
|
|
|
struct rewrite_submatch *submatch,
|
|
|
|
const char *string,
|
|
|
|
const regmatch_t *match,
|
|
|
|
struct berval *val
|
|
|
|
)
|
|
|
|
{
|
|
|
|
int c, l;
|
|
|
|
const char *s;
|
|
|
|
|
|
|
|
assert( submatch != NULL );
|
|
|
|
assert( submatch->ls_type == REWRITE_SUBMATCH_ASIS
|
|
|
|
|| submatch->ls_type == REWRITE_SUBMATCH_XMAP );
|
|
|
|
assert( string != NULL );
|
|
|
|
assert( match != NULL );
|
|
|
|
assert( val != NULL );
|
|
|
|
|
|
|
|
c = submatch->ls_submatch;
|
|
|
|
s = string + match[ c ].rm_so;
|
|
|
|
l = match[ c ].rm_eo - match[ c ].rm_so;
|
|
|
|
|
|
|
|
val->bv_val = NULL;
|
|
|
|
val->bv_len = l;
|
|
|
|
val->bv_val = calloc( sizeof( char ), l + 1 );
|
|
|
|
if ( val->bv_val == NULL ) {
|
|
|
|
return REWRITE_ERR;
|
|
|
|
}
|
|
|
|
|
2001-10-22 17:39:02 +08:00
|
|
|
AC_MEMCPY( val->bv_val, s, l );
|
2001-05-12 08:51:28 +08:00
|
|
|
val->bv_val[ l ] = '\0';
|
|
|
|
|
|
|
|
return REWRITE_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Substitutes a portion of rewritten string according to substitution
|
|
|
|
* pattern using submatches
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
rewrite_subst_apply(
|
|
|
|
struct rewrite_info *info,
|
|
|
|
struct rewrite_op *op,
|
|
|
|
struct rewrite_subst *subst,
|
|
|
|
const char *string,
|
|
|
|
const regmatch_t *match,
|
|
|
|
struct berval *val
|
|
|
|
)
|
|
|
|
{
|
|
|
|
struct berval *submatch = NULL;
|
|
|
|
char *res = NULL;
|
|
|
|
int n, l, cl;
|
|
|
|
int rc = REWRITE_REGEXEC_OK;
|
|
|
|
|
|
|
|
assert( info != NULL );
|
|
|
|
assert( op != NULL );
|
|
|
|
assert( subst != NULL );
|
|
|
|
assert( string != NULL );
|
|
|
|
assert( match != NULL );
|
|
|
|
assert( val != NULL );
|
|
|
|
|
|
|
|
val->bv_val = NULL;
|
|
|
|
val->bv_len = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Prepare room for submatch expansion
|
|
|
|
*/
|
2003-04-05 19:30:43 +08:00
|
|
|
if ( subst->lt_num_submatch > 0 ) {
|
|
|
|
submatch = calloc( sizeof( struct berval ),
|
|
|
|
subst->lt_num_submatch );
|
|
|
|
if ( submatch == NULL ) {
|
|
|
|
return REWRITE_REGEXEC_ERR;
|
|
|
|
}
|
2001-05-12 08:51:28 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Resolve submatches (simple subst, map expansion and so).
|
|
|
|
*/
|
|
|
|
for ( n = 0, l = 0; n < subst->lt_num_submatch; n++ ) {
|
|
|
|
struct berval key;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get key
|
|
|
|
*/
|
|
|
|
switch( subst->lt_submatch[ n ]->ls_type ) {
|
|
|
|
case REWRITE_SUBMATCH_ASIS:
|
|
|
|
case REWRITE_SUBMATCH_XMAP:
|
|
|
|
rc = submatch_copy( subst->lt_submatch[ n ],
|
|
|
|
string, match, &key );
|
|
|
|
if ( rc != REWRITE_SUCCESS ) {
|
|
|
|
free( submatch );
|
|
|
|
return REWRITE_REGEXEC_ERR;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case REWRITE_SUBMATCH_MAP_W_ARG:
|
|
|
|
switch ( subst->lt_submatch[ n ]->ls_map->lm_type ) {
|
|
|
|
case REWRITE_MAP_GET_OP_VAR:
|
|
|
|
case REWRITE_MAP_GET_SESN_VAR:
|
|
|
|
case REWRITE_MAP_GET_PARAM:
|
|
|
|
rc = REWRITE_SUCCESS;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
rc = rewrite_subst_apply( info, op,
|
|
|
|
subst->lt_submatch[ n ]->ls_map->lm_subst,
|
|
|
|
string, match, &key);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( rc != REWRITE_SUCCESS ) {
|
|
|
|
free( submatch );
|
|
|
|
return REWRITE_REGEXEC_ERR;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
Debug( LDAP_DEBUG_ANY, "Not Implemented\n%s%s%s",
|
|
|
|
"", "", "" );
|
|
|
|
rc = REWRITE_ERR;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( rc != REWRITE_SUCCESS ) {
|
|
|
|
free( submatch );
|
|
|
|
return REWRITE_REGEXEC_ERR;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Resolve key
|
|
|
|
*/
|
|
|
|
switch ( subst->lt_submatch[ n ]->ls_type ) {
|
|
|
|
case REWRITE_SUBMATCH_ASIS:
|
|
|
|
submatch[ n ] = key;
|
|
|
|
rc = REWRITE_SUCCESS;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case REWRITE_SUBMATCH_XMAP:
|
|
|
|
rc = rewrite_xmap_apply( info, op,
|
|
|
|
subst->lt_submatch[ n ]->ls_map,
|
|
|
|
&key, &submatch[ n ] );
|
|
|
|
break;
|
|
|
|
|
|
|
|
case REWRITE_SUBMATCH_MAP_W_ARG:
|
|
|
|
rc = rewrite_map_apply( info, op,
|
|
|
|
subst->lt_submatch[ n ]->ls_map,
|
|
|
|
&key, &submatch[ n ] );
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
/*
|
|
|
|
* When implemented, this might return the
|
|
|
|
* exit status of a rewrite context,
|
|
|
|
* which may include a stop, or an
|
|
|
|
* unwilling to perform
|
|
|
|
*/
|
|
|
|
rc = REWRITE_ERR;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( rc != REWRITE_SUCCESS ) {
|
|
|
|
free( submatch );
|
|
|
|
return REWRITE_REGEXEC_ERR;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Increment the length of the resulting string
|
|
|
|
*/
|
|
|
|
l += submatch[ n ].bv_len;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Alloc result buffer as big as the constant part
|
|
|
|
* of the subst pattern and initialize it
|
|
|
|
*/
|
|
|
|
l += subst->lt_subs_len;
|
|
|
|
res = calloc( sizeof( char ), l + 1 );
|
|
|
|
if ( res == NULL ) {
|
2003-04-05 19:30:43 +08:00
|
|
|
rc = REWRITE_REGEXEC_ERR;
|
|
|
|
goto cleanup;
|
2001-05-12 08:51:28 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Apply submatches (possibly resolved thru maps
|
|
|
|
*/
|
|
|
|
for ( n = 0, cl = 0; n < subst->lt_num_submatch; n++ ) {
|
|
|
|
if ( subst->lt_subs[ n ] != NULL ) {
|
2001-10-22 17:39:02 +08:00
|
|
|
AC_MEMCPY( res + cl, subst->lt_subs[ n ]->bv_val,
|
|
|
|
subst->lt_subs[ n ]->bv_len );
|
2001-05-12 08:51:28 +08:00
|
|
|
cl += subst->lt_subs[ n ]->bv_len;
|
|
|
|
}
|
2001-10-22 17:39:02 +08:00
|
|
|
AC_MEMCPY( res + cl, submatch[ n ].bv_val,
|
|
|
|
submatch[ n ].bv_len );
|
2001-05-12 08:51:28 +08:00
|
|
|
cl += submatch[ n ].bv_len;
|
|
|
|
free( submatch[ n ].bv_val );
|
|
|
|
}
|
|
|
|
if ( subst->lt_subs[ n ] != NULL ) {
|
2001-10-22 17:39:02 +08:00
|
|
|
AC_MEMCPY( res + cl, subst->lt_subs[ n ]->bv_val,
|
|
|
|
subst->lt_subs[ n ]->bv_len );
|
2001-05-12 08:51:28 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
val->bv_val = res;
|
|
|
|
val->bv_len = l;
|
2003-04-05 19:30:43 +08:00
|
|
|
|
|
|
|
cleanup:;
|
|
|
|
if ( submatch ) {
|
|
|
|
free( submatch );
|
|
|
|
}
|
|
|
|
|
2001-05-12 08:51:28 +08:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|