2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 2000-2011 The OpenLDAP Foundation.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted only as authorized by the OpenLDAP
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>.
16 * This work was initially developed by Pierangelo Masarati for
17 * inclusion in OpenLDAP Software.
22 #include "rewrite-int.h"
25 * Appends a rule to the double linked list of rules
26 * Helper for rewrite_rule_compile
30 struct rewrite_context *context,
31 struct rewrite_rule *rule
34 struct rewrite_rule *r;
36 assert( context != NULL );
37 assert( context->lc_rule != NULL );
38 assert( rule != NULL );
40 for ( r = context->lc_rule; r->lr_next != NULL; r = r->lr_next );
44 return REWRITE_SUCCESS;
48 * Appends an action to the linked list of actions
49 * Helper for rewrite_rule_compile
53 struct rewrite_action **pbase,
54 struct rewrite_action *action
57 struct rewrite_action **pa;
59 assert( pbase != NULL );
60 assert( action != NULL );
62 for ( pa = pbase; *pa != NULL; pa = &(*pa)->la_next );
65 return REWRITE_SUCCESS;
70 struct rewrite_action **paction
73 struct rewrite_action *action;
75 assert( paction != NULL );
76 assert( *paction != NULL );
81 switch ( action->la_type ) {
82 case REWRITE_FLAG_GOTO:
83 case REWRITE_FLAG_USER: {
84 int *pi = (int *)action->la_args;
104 struct rewrite_action *paction
107 struct rewrite_action *next;
109 for (; paction; paction = next) {
110 next = paction->la_next;
111 destroy_action( &paction );
118 rewrite_rule_compile(
119 struct rewrite_info *info,
120 struct rewrite_context *context,
123 const char *flagstring
126 int flags = REWRITE_REGEX_EXTENDED | REWRITE_REGEX_ICASE;
127 int mode = REWRITE_RECURSE;
130 struct rewrite_rule *rule = NULL;
131 struct rewrite_subst *subst = NULL;
132 struct rewrite_action *action = NULL, *first_action = NULL;
136 assert( info != NULL );
137 assert( context != NULL );
138 assert( pattern != NULL );
139 assert( result != NULL );
141 * A null flagstring should be allowed
144 max_passes = info->li_max_passes_per_rule;
147 * Take care of substitution string
149 subst = rewrite_subst_compile( info, result );
150 if ( subst == NULL ) {
157 for ( p = flagstring; p[ 0 ] != '\0'; p++ ) {
163 case REWRITE_FLAG_HONORCASE: /* 'C' */
165 * Honor case (default is case insensitive)
167 flags &= ~REWRITE_REGEX_ICASE;
170 case REWRITE_FLAG_BASICREGEX: /* 'R' */
172 * Use POSIX Basic Regular Expression syntax
173 * instead of POSIX Extended Regular Expression
176 flags &= ~REWRITE_REGEX_EXTENDED;
180 * Execution mode flags
182 case REWRITE_FLAG_EXECONCE: /* ':' */
184 * Apply rule once only
186 mode &= ~REWRITE_RECURSE;
187 mode |= REWRITE_EXEC_ONCE;
191 * Special action flags
193 case REWRITE_FLAG_STOP: /* '@' */
195 * Bail out after applying rule
197 action = calloc( sizeof( struct rewrite_action ), 1 );
198 if ( action == NULL ) {
202 action->la_type = REWRITE_ACTION_STOP;
205 case REWRITE_FLAG_UNWILLING: /* '#' */
207 * Matching objs will be marked as gone!
209 action = calloc( sizeof( struct rewrite_action ), 1 );
210 if ( action == NULL ) {
214 mode &= ~REWRITE_RECURSE;
215 mode |= REWRITE_EXEC_ONCE;
216 action->la_type = REWRITE_ACTION_UNWILLING;
219 case REWRITE_FLAG_GOTO: /* 'G' */
221 * After applying rule, jump N rules
224 case REWRITE_FLAG_USER: { /* 'U' */
226 * After applying rule, return user-defined
232 if ( p[ 1 ] != '{' ) {
236 d = malloc( sizeof( int ) );
241 d[ 0 ] = strtol( &p[ 2 ], &next, 0 );
242 if ( next == &p[ 2 ] || next[0] != '}' ) {
247 action = calloc( sizeof( struct rewrite_action ), 1 );
248 if ( action == NULL ) {
253 case REWRITE_FLAG_GOTO:
254 action->la_type = REWRITE_ACTION_GOTO;
257 case REWRITE_FLAG_USER:
258 action->la_type = REWRITE_ACTION_USER;
265 action->la_args = (void *)d;
267 p = next; /* p is incremented by the for ... */
272 case REWRITE_FLAG_MAX_PASSES: { /* 'U' */
274 * Set the number of max passes per rule
278 if ( p[ 1 ] != '{' ) {
282 max_passes = strtol( &p[ 2 ], &next, 0 );
283 if ( next == &p[ 2 ] || next[0] != '}' ) {
287 if ( max_passes < 1 ) {
288 /* FIXME: nonsense ... */
292 p = next; /* p is incremented by the for ... */
297 case REWRITE_FLAG_IGNORE_ERR: /* 'I' */
301 action = calloc( sizeof( struct rewrite_action ), 1 );
302 if ( action == NULL ) {
306 action->la_type = REWRITE_ACTION_IGNORE_ERR;
314 * Unimplemented feature (complain only)
320 * Stupid way to append to a list ...
322 if ( action != NULL ) {
323 append_action( &first_action, action );
329 * Finally, rule allocation
331 rule = calloc( sizeof( struct rewrite_rule ), 1 );
332 if ( rule == NULL ) {
337 * REGEX compilation (luckily I don't need to take care of this ...)
339 if ( regcomp( &rule->lr_regex, ( char * )pattern, flags ) != 0 ) {
344 * Just to remember them ...
346 rule->lr_pattern = strdup( pattern );
347 rule->lr_subststring = strdup( result );
348 rule->lr_flagstring = strdup( flagstring );
349 if ( rule->lr_pattern == NULL
350 || rule->lr_subststring == NULL
351 || rule->lr_flagstring == NULL )
357 * Load compiled data into rule
359 rule->lr_subst = subst;
362 * Set various parameters
364 rule->lr_flags = flags; /* don't really need any longer ... */
365 rule->lr_mode = mode;
366 rule->lr_max_passes = max_passes;
367 rule->lr_action = first_action;
370 * Append rule at the end of the rewrite context
372 append_rule( context, rule );
374 return REWRITE_SUCCESS;
378 if ( rule->lr_pattern ) free( rule->lr_pattern );
379 if ( rule->lr_subststring ) free( rule->lr_subststring );
380 if ( rule->lr_flagstring ) free( rule->lr_flagstring );
383 destroy_actions( first_action );
389 * Rewrites string according to rule; may return:
390 * OK: fine; if *result != NULL rule matched and rewrite succeeded.
391 * STOP: fine, rule matched; stop processing following rules
392 * UNWILL: rule matched; force 'unwilling to perform'
396 struct rewrite_info *info,
397 struct rewrite_op *op,
398 struct rewrite_rule *rule,
403 size_t nmatch = REWRITE_MAX_MATCH;
404 regmatch_t match[ REWRITE_MAX_MATCH ];
406 int rc = REWRITE_SUCCESS;
410 struct berval val = { 0, NULL };
412 assert( info != NULL );
413 assert( op != NULL );
414 assert( rule != NULL );
415 assert( arg != NULL );
416 assert( result != NULL );
420 string = (char *)arg;
423 * In case recursive match is required (default)
427 Debug( LDAP_DEBUG_TRACE, "==> rewrite_rule_apply"
428 " rule='%s' string='%s' [%d pass(es)]\n",
429 rule->lr_pattern, string, strcnt + 1 );
433 rc = regexec( &rule->lr_regex, string, nmatch, match, 0 );
435 if ( *result == NULL && string != arg ) {
440 * No match is OK; *result = NULL means no match
442 return REWRITE_REGEXEC_OK;
445 rc = rewrite_subst_apply( info, op, rule->lr_subst, string,
448 *result = val.bv_val;
450 if ( string != arg ) {
455 if ( rc != REWRITE_REGEXEC_OK ) {
459 if ( ( rule->lr_mode & REWRITE_RECURSE ) == REWRITE_RECURSE
460 && op->lo_num_passes < info->li_max_passes
461 && ++strcnt < rule->lr_max_passes ) {
467 return REWRITE_REGEXEC_OK;
471 rewrite_rule_destroy(
472 struct rewrite_rule **prule
475 struct rewrite_rule *rule;
477 assert( prule != NULL );
478 assert( *prule != NULL );
482 if ( rule->lr_pattern ) {
483 free( rule->lr_pattern );
484 rule->lr_pattern = NULL;
487 if ( rule->lr_subststring ) {
488 free( rule->lr_subststring );
489 rule->lr_subststring = NULL;
492 if ( rule->lr_flagstring ) {
493 free( rule->lr_flagstring );
494 rule->lr_flagstring = NULL;
497 if ( rule->lr_subst ) {
498 rewrite_subst_destroy( &rule->lr_subst );
501 regfree( &rule->lr_regex );
503 destroy_actions( rule->lr_action );