#include <portable.h>
#include "rewrite-int.h"
static int
append_rule(
struct rewrite_context *context,
struct rewrite_rule *rule
)
{
struct rewrite_rule *r;
assert( context != NULL );
assert( context->lc_rule != NULL );
assert( rule != NULL );
for ( r = context->lc_rule; r->lr_next != NULL; r = r->lr_next );
r->lr_next = rule;
rule->lr_prev = r;
return REWRITE_SUCCESS;
}
static int
append_action(
struct rewrite_action **pbase,
struct rewrite_action *action
)
{
struct rewrite_action **pa;
assert( pbase != NULL );
assert( action != NULL );
for ( pa = pbase; *pa != NULL; pa = &(*pa)->la_next );
*pa = action;
return REWRITE_SUCCESS;
}
static int
destroy_action(
struct rewrite_action **paction
)
{
struct rewrite_action *action;
assert( paction != NULL );
assert( *paction != NULL );
action = *paction;
switch ( action->la_type ) {
case REWRITE_FLAG_GOTO:
case REWRITE_FLAG_USER: {
int *pi = (int *)action->la_args;
if ( pi ) {
free( pi );
}
break;
}
default:
break;
}
free( action );
*paction = NULL;
return 0;
}
static void
destroy_actions(
struct rewrite_action *paction
)
{
struct rewrite_action *next;
for (; paction; paction = next) {
next = paction->la_next;
destroy_action( &paction );
}
}
int
rewrite_rule_compile(
struct rewrite_info *info,
struct rewrite_context *context,
const char *pattern,
const char *result,
const char *flagstring
)
{
int flags = REWRITE_REGEX_EXTENDED | REWRITE_REGEX_ICASE;
int mode = REWRITE_RECURSE;
int max_passes;
struct rewrite_rule *rule = NULL;
struct rewrite_subst *subst = NULL;
struct rewrite_action *action = NULL, *first_action = NULL;
const char *p;
assert( info != NULL );
assert( context != NULL );
assert( pattern != NULL );
assert( result != NULL );
max_passes = info->li_max_passes_per_rule;
subst = rewrite_subst_compile( info, result );
if ( subst == NULL ) {
return REWRITE_ERR;
}
for ( p = flagstring; p[ 0 ] != '\0'; p++ ) {
switch( p[ 0 ] ) {
case REWRITE_FLAG_HONORCASE:
flags &= ~REWRITE_REGEX_ICASE;
break;
case REWRITE_FLAG_BASICREGEX:
flags &= ~REWRITE_REGEX_EXTENDED;
break;
case REWRITE_FLAG_EXECONCE:
mode &= ~REWRITE_RECURSE;
mode |= REWRITE_EXEC_ONCE;
break;
case REWRITE_FLAG_STOP:
action = calloc( sizeof( struct rewrite_action ), 1 );
if ( action == NULL ) {
goto fail;
}
action->la_type = REWRITE_ACTION_STOP;
break;
case REWRITE_FLAG_UNWILLING:
action = calloc( sizeof( struct rewrite_action ), 1 );
if ( action == NULL ) {
goto fail;
}
mode &= ~REWRITE_RECURSE;
mode |= REWRITE_EXEC_ONCE;
action->la_type = REWRITE_ACTION_UNWILLING;
break;
case REWRITE_FLAG_GOTO:
case REWRITE_FLAG_USER: {
char *next = NULL;
int *d;
if ( p[ 1 ] != '{' ) {
goto fail;
}
d = malloc( sizeof( int ) );
if ( d == NULL ) {
goto fail;
}
d[ 0 ] = strtol( &p[ 2 ], &next, 0 );
if ( next == &p[ 2 ] || next[0] != '}' ) {
free( d );
goto fail;
}
action = calloc( sizeof( struct rewrite_action ), 1 );
if ( action == NULL ) {
free( d );
goto fail;
}
switch ( p[ 0 ] ) {
case REWRITE_FLAG_GOTO:
action->la_type = REWRITE_ACTION_GOTO;
break;
case REWRITE_FLAG_USER:
action->la_type = REWRITE_ACTION_USER;
break;
default:
assert(0);
}
action->la_args = (void *)d;
p = next;
break;
}
case REWRITE_FLAG_MAX_PASSES: {
char *next = NULL;
if ( p[ 1 ] != '{' ) {
goto fail;
}
max_passes = strtol( &p[ 2 ], &next, 0 );
if ( next == &p[ 2 ] || next[0] != '}' ) {
goto fail;
}
if ( max_passes < 1 ) {
max_passes = 1;
}
p = next;
break;
}
case REWRITE_FLAG_IGNORE_ERR:
action = calloc( sizeof( struct rewrite_action ), 1 );
if ( action == NULL ) {
goto fail;
}
action->la_type = REWRITE_ACTION_IGNORE_ERR;
break;
default:
break;
}
if ( action != NULL ) {
append_action( &first_action, action );
action = NULL;
}
}
rule = calloc( sizeof( struct rewrite_rule ), 1 );
if ( rule == NULL ) {
goto fail;
}
if ( regcomp( &rule->lr_regex, ( char * )pattern, flags ) != 0 ) {
goto fail;
}
rule->lr_pattern = strdup( pattern );
rule->lr_subststring = strdup( result );
rule->lr_flagstring = strdup( flagstring );
if ( rule->lr_pattern == NULL
|| rule->lr_subststring == NULL
|| rule->lr_flagstring == NULL )
{
goto fail;
}
rule->lr_subst = subst;
rule->lr_flags = flags;
rule->lr_mode = mode;
rule->lr_max_passes = max_passes;
rule->lr_action = first_action;
append_rule( context, rule );
return REWRITE_SUCCESS;
fail:
if ( rule ) {
if ( rule->lr_pattern ) free( rule->lr_pattern );
if ( rule->lr_subststring ) free( rule->lr_subststring );
if ( rule->lr_flagstring ) free( rule->lr_flagstring );
free( rule );
}
destroy_actions( first_action );
free( subst );
return REWRITE_ERR;
}
int
rewrite_rule_apply(
struct rewrite_info *info,
struct rewrite_op *op,
struct rewrite_rule *rule,
const char *arg,
char **result
)
{
size_t nmatch = REWRITE_MAX_MATCH;
regmatch_t match[ REWRITE_MAX_MATCH ];
int rc = REWRITE_SUCCESS;
char *string;
int strcnt = 0;
struct berval val = { 0, NULL };
assert( info != NULL );
assert( op != NULL );
assert( rule != NULL );
assert( arg != NULL );
assert( result != NULL );
*result = NULL;
string = (char *)arg;
recurse:;
Debug( LDAP_DEBUG_TRACE, "==> rewrite_rule_apply"
" rule='%s' string='%s' [%d pass(es)]\n",
rule->lr_pattern, string, strcnt + 1 );
op->lo_num_passes++;
rc = regexec( &rule->lr_regex, string, nmatch, match, 0 );
if ( rc != 0 ) {
if ( *result == NULL && string != arg ) {
free( string );
}
return REWRITE_REGEXEC_OK;
}
rc = rewrite_subst_apply( info, op, rule->lr_subst, string,
match, &val );
*result = val.bv_val;
val.bv_val = NULL;
if ( string != arg ) {
free( string );
string = NULL;
}
if ( rc != REWRITE_REGEXEC_OK ) {
return rc;
}
if ( ( rule->lr_mode & REWRITE_RECURSE ) == REWRITE_RECURSE
&& op->lo_num_passes < info->li_max_passes
&& ++strcnt < rule->lr_max_passes ) {
string = *result;
goto recurse;
}
return REWRITE_REGEXEC_OK;
}
int
rewrite_rule_destroy(
struct rewrite_rule **prule
)
{
struct rewrite_rule *rule;
assert( prule != NULL );
assert( *prule != NULL );
rule = *prule;
if ( rule->lr_pattern ) {
free( rule->lr_pattern );
rule->lr_pattern = NULL;
}
if ( rule->lr_subststring ) {
free( rule->lr_subststring );
rule->lr_subststring = NULL;
}
if ( rule->lr_flagstring ) {
free( rule->lr_flagstring );
rule->lr_flagstring = NULL;
}
if ( rule->lr_subst ) {
rewrite_subst_destroy( &rule->lr_subst );
}
regfree( &rule->lr_regex );
destroy_actions( rule->lr_action );
free( rule );
*prule = NULL;
return 0;
}