#include <portable.h>
#include "rewrite-int.h"
static int
rewrite_context_cmp(
const void *c1,
const void *c2
)
{
const struct rewrite_context *lc1, *lc2;
lc1 = (const struct rewrite_context *)c1;
lc2 = (const struct rewrite_context *)c2;
assert( c1 != NULL );
assert( c2 != NULL );
assert( lc1->lc_name != NULL );
assert( lc2->lc_name != NULL );
return strcasecmp( lc1->lc_name, lc2->lc_name );
}
static int
rewrite_context_dup(
void *c1,
void *c2
)
{
struct rewrite_context *lc1, *lc2;
lc1 = (struct rewrite_context *)c1;
lc2 = (struct rewrite_context *)c2;
assert( c1 != NULL );
assert( c2 != NULL );
assert( lc1->lc_name != NULL );
assert( lc2->lc_name != NULL );
return( strcasecmp( lc1->lc_name, lc2->lc_name) == 0 ? -1 : 0 );
}
struct rewrite_context *
rewrite_context_find(
struct rewrite_info *info,
const char *rewriteContext
)
{
struct rewrite_context *context, c;
assert( info != NULL );
assert( rewriteContext != NULL );
c.lc_name = (char *)rewriteContext;
context = (struct rewrite_context *)avl_find( info->li_context,
(caddr_t)&c, rewrite_context_cmp );
if ( context == NULL ) {
return NULL;
}
if ( context->lc_alias ) {
return context->lc_alias;
}
return context;
}
struct rewrite_context *
rewrite_context_create(
struct rewrite_info *info,
const char *rewriteContext
)
{
struct rewrite_context *context;
int rc;
assert( info != NULL );
assert( rewriteContext != NULL );
context = calloc( sizeof( struct rewrite_context ), 1 );
if ( context == NULL ) {
return NULL;
}
context->lc_name = strdup( rewriteContext );
if ( context->lc_name == NULL ) {
free( context );
return NULL;
}
context->lc_rule = calloc( sizeof( struct rewrite_rule ), 1 );
if ( context->lc_rule == NULL ) {
free( context->lc_name );
free( context );
return NULL;
}
memset( context->lc_rule, 0, sizeof( struct rewrite_rule ) );
rc = avl_insert( &info->li_context, (caddr_t)context,
rewrite_context_cmp, rewrite_context_dup );
if ( rc == -1 ) {
free( context->lc_rule );
free( context->lc_name );
free( context );
return NULL;
}
return context;
}
static struct rewrite_rule *
rewrite_action_goto(
struct rewrite_action *action,
struct rewrite_rule *rule
)
{
int n;
assert( action != NULL );
assert( action->la_args != NULL );
assert( rule != NULL );
n = ((int *)action->la_args)[ 0 ];
if ( n > 0 ) {
for ( ; n > 1 && rule != NULL ; n-- ) {
rule = rule->lr_next;
}
} else if ( n <= 0 ) {
for ( ; n < 1 && rule != NULL ; n++ ) {
rule = rule->lr_prev;
}
}
return rule;
}
int
rewrite_context_apply(
struct rewrite_info *info,
struct rewrite_op *op,
struct rewrite_context *context,
const char *string,
char **result
)
{
struct rewrite_rule *rule;
char *s, *res = NULL;
int return_code = REWRITE_REGEXEC_OK;
assert( info != NULL );
assert( op != NULL );
assert( context != NULL );
assert( context->lc_rule != NULL );
assert( string != NULL );
assert( result != NULL );
op->lo_depth++;
assert( op->lo_depth > 0 );
Debug( LDAP_DEBUG_TRACE, "==> rewrite_context_apply"
" [depth=%d] string='%s'\n",
op->lo_depth, string, 0 );
s = (char *)string;
for ( rule = context->lc_rule->lr_next;
rule != NULL && op->lo_num_passes < info->li_max_passes;
rule = rule->lr_next, op->lo_num_passes++ ) {
int rc;
rc = rewrite_rule_apply( info, op, rule, s, &res );
switch ( rc ) {
case REWRITE_REGEXEC_ERR:
Debug( LDAP_DEBUG_ANY, "==> rewrite_context_apply"
" error ...\n", 0, 0, 0);
if ( rule->lr_action != NULL ) {
struct rewrite_action *action;
int do_continue = 0;
for ( action = rule->lr_action;
action != NULL;
action = action->la_next ) {
switch ( action->la_type ) {
case REWRITE_ACTION_IGNORE_ERR:
Debug( LDAP_DEBUG_ANY,
"==> rewrite_context_apply"
" ignoring error ...\n", 0, 0, 0 );
do_continue = 1;
break;
case REWRITE_ACTION_GOTO:
if ( do_continue ) {
rule = rewrite_action_goto( action, rule );
if ( rule == NULL ) {
return_code = REWRITE_REGEXEC_ERR;
goto rc_end_of_context;
}
}
break;
default:
break;
}
}
if ( do_continue ) {
if ( rule->lr_next == NULL ) {
res = s;
}
goto rc_continue;
}
}
return_code = REWRITE_REGEXEC_ERR;
goto rc_end_of_context;
case REWRITE_REGEXEC_OK:
if ( res != NULL ) {
struct rewrite_action *action;
if ( s != string && s != res ) {
free( s );
}
s = res;
for ( action = rule->lr_action;
action != NULL;
action = action->la_next ) {
switch ( action->la_type ) {
case REWRITE_ACTION_STOP:
goto rc_end_of_context;
case REWRITE_ACTION_UNWILLING:
return_code = REWRITE_REGEXEC_UNWILLING;
goto rc_end_of_context;
case REWRITE_ACTION_GOTO:
rule = rewrite_action_goto( action, rule );
if ( rule == NULL ) {
return_code = REWRITE_REGEXEC_ERR;
goto rc_end_of_context;
}
break;
case REWRITE_ACTION_USER:
return_code = ((int *)action->la_args)[ 0 ];
goto rc_end_of_context;
default:
break;
}
}
} else if ( rule->lr_next == NULL ) {
res = s;
}
break;
case REWRITE_REGEXEC_STOP:
goto rc_end_of_context;
case REWRITE_REGEXEC_UNWILLING:
return_code = REWRITE_REGEXEC_UNWILLING;
goto rc_end_of_context;
default:
assert( rc >= REWRITE_REGEXEC_USER );
goto rc_end_of_context;
}
rc_continue:;
}
rc_end_of_context:;
*result = res;
Debug( LDAP_DEBUG_TRACE, "==> rewrite_context_apply"
" [depth=%d] res={%d,'%s'}\n",
op->lo_depth, return_code, ( res ? res : "NULL" ) );
assert( op->lo_depth > 0 );
op->lo_depth--;
return return_code;
}
void
rewrite_context_free(
void *tmp
)
{
struct rewrite_context *context = (struct rewrite_context *)tmp;
assert( tmp != NULL );
rewrite_context_destroy( &context );
}
int
rewrite_context_destroy(
struct rewrite_context **pcontext
)
{
struct rewrite_context *context;
struct rewrite_rule *r;
assert( pcontext != NULL );
assert( *pcontext != NULL );
context = *pcontext;
assert( context->lc_rule != NULL );
for ( r = context->lc_rule->lr_next; r; ) {
struct rewrite_rule *cr = r;
r = r->lr_next;
rewrite_rule_destroy( &cr );
}
free( context->lc_rule );
context->lc_rule = NULL;
assert( context->lc_name != NULL );
free( context->lc_name );
context->lc_name = NULL;
free( context );
*pcontext = NULL;
return 0;
}