1 /* $OpenLDAP: pkg/ldap/libraries/librewrite/rule.c,v 1.23.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.
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
;
128 int max_passes
= info
->li_max_passes_per_rule
;
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
);
142 * A null flagstring should be allowed
146 * Take care of substitution string
148 subst
= rewrite_subst_compile( info
, result
);
149 if ( subst
== NULL
) {
156 for ( p
= flagstring
; p
[ 0 ] != '\0'; p
++ ) {
162 case REWRITE_FLAG_HONORCASE
: /* 'C' */
164 * Honor case (default is case insensitive)
166 flags
&= ~REWRITE_REGEX_ICASE
;
169 case REWRITE_FLAG_BASICREGEX
: /* 'R' */
171 * Use POSIX Basic Regular Expression syntax
172 * instead of POSIX Extended Regular Expression
175 flags
&= ~REWRITE_REGEX_EXTENDED
;
179 * Execution mode flags
181 case REWRITE_FLAG_EXECONCE
: /* ':' */
183 * Apply rule once only
185 mode
&= ~REWRITE_RECURSE
;
186 mode
|= REWRITE_EXEC_ONCE
;
190 * Special action flags
192 case REWRITE_FLAG_STOP
: /* '@' */
194 * Bail out after applying rule
196 action
= calloc( sizeof( struct rewrite_action
), 1 );
197 if ( action
== NULL
) {
201 action
->la_type
= REWRITE_ACTION_STOP
;
204 case REWRITE_FLAG_UNWILLING
: /* '#' */
206 * Matching objs will be marked as gone!
208 action
= calloc( sizeof( struct rewrite_action
), 1 );
209 if ( action
== NULL
) {
213 mode
&= ~REWRITE_RECURSE
;
214 mode
|= REWRITE_EXEC_ONCE
;
215 action
->la_type
= REWRITE_ACTION_UNWILLING
;
218 case REWRITE_FLAG_GOTO
: /* 'G' */
220 * After applying rule, jump N rules
223 case REWRITE_FLAG_USER
: { /* 'U' */
225 * After applying rule, return user-defined
231 if ( p
[ 1 ] != '{' ) {
235 d
= malloc( sizeof( int ) );
240 d
[ 0 ] = strtol( &p
[ 2 ], &next
, 0 );
241 if ( next
== &p
[ 2 ] || next
[0] != '}' ) {
246 action
= calloc( sizeof( struct rewrite_action
), 1 );
247 if ( action
== NULL
) {
252 case REWRITE_FLAG_GOTO
:
253 action
->la_type
= REWRITE_ACTION_GOTO
;
256 case REWRITE_FLAG_USER
:
257 action
->la_type
= REWRITE_ACTION_USER
;
264 action
->la_args
= (void *)d
;
266 p
= next
; /* p is incremented by the for ... */
271 case REWRITE_FLAG_MAX_PASSES
: { /* 'U' */
273 * Set the number of max passes per rule
277 if ( p
[ 1 ] != '{' ) {
281 max_passes
= strtol( &p
[ 2 ], &next
, 0 );
282 if ( next
== &p
[ 2 ] || next
[0] != '}' ) {
286 if ( max_passes
< 1 ) {
287 /* FIXME: nonsense ... */
291 p
= next
; /* p is incremented by the for ... */
296 case REWRITE_FLAG_IGNORE_ERR
: /* 'I' */
300 action
= calloc( sizeof( struct rewrite_action
), 1 );
301 if ( action
== NULL
) {
305 action
->la_type
= REWRITE_ACTION_IGNORE_ERR
;
313 * Unimplemented feature (complain only)
319 * Stupid way to append to a list ...
321 if ( action
!= NULL
) {
322 append_action( &first_action
, action
);
328 * Finally, rule allocation
330 rule
= calloc( sizeof( struct rewrite_rule
), 1 );
331 if ( rule
== NULL
) {
336 * REGEX compilation (luckily I don't need to take care of this ...)
338 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
);
351 * Load compiled data into rule
353 rule
->lr_subst
= subst
;
356 * Set various parameters
358 rule
->lr_flags
= flags
; /* don't really need any longer ... */
359 rule
->lr_mode
= mode
;
360 rule
->lr_max_passes
= max_passes
;
361 rule
->lr_action
= first_action
;
364 * Append rule at the end of the rewrite context
366 append_rule( context
, rule
);
368 return REWRITE_SUCCESS
;
371 destroy_actions( first_action
);
377 * Rewrites string according to rule; may return:
378 * OK: fine; if *result != NULL rule matched and rewrite succeeded.
379 * STOP: fine, rule matched; stop processing following rules
380 * UNWILL: rule matched; force 'unwilling to perform'
384 struct rewrite_info
*info
,
385 struct rewrite_op
*op
,
386 struct rewrite_rule
*rule
,
391 size_t nmatch
= REWRITE_MAX_MATCH
;
392 regmatch_t match
[ REWRITE_MAX_MATCH
];
394 int rc
= REWRITE_SUCCESS
;
398 struct berval val
= { 0, NULL
};
400 assert( info
!= NULL
);
401 assert( op
!= NULL
);
402 assert( rule
!= NULL
);
403 assert( arg
!= NULL
);
404 assert( result
!= NULL
);
408 string
= (char *)arg
;
411 * In case recursive match is required (default)
415 Debug( LDAP_DEBUG_TRACE
, "==> rewrite_rule_apply"
416 " rule='%s' string='%s' [%d pass(es)]\n",
417 rule
->lr_pattern
, string
, strcnt
+ 1 );
421 rc
= regexec( &rule
->lr_regex
, string
, nmatch
, match
, 0 );
423 if ( *result
== NULL
&& string
!= arg
) {
428 * No match is OK; *result = NULL means no match
430 return REWRITE_REGEXEC_OK
;
433 rc
= rewrite_subst_apply( info
, op
, rule
->lr_subst
, string
,
436 *result
= val
.bv_val
;
438 if ( string
!= arg
) {
443 if ( rc
!= REWRITE_REGEXEC_OK
) {
447 if ( ( rule
->lr_mode
& REWRITE_RECURSE
) == REWRITE_RECURSE
448 && op
->lo_num_passes
< info
->li_max_passes
449 && ++strcnt
< rule
->lr_max_passes
) {
455 return REWRITE_REGEXEC_OK
;
459 rewrite_rule_destroy(
460 struct rewrite_rule
**prule
463 struct rewrite_rule
*rule
;
465 assert( prule
!= NULL
);
466 assert( *prule
!= NULL
);
470 if ( rule
->lr_pattern
) {
471 free( rule
->lr_pattern
);
472 rule
->lr_pattern
= NULL
;
475 if ( rule
->lr_subststring
) {
476 free( rule
->lr_subststring
);
477 rule
->lr_subststring
= NULL
;
480 if ( rule
->lr_flagstring
) {
481 free( rule
->lr_flagstring
);
482 rule
->lr_flagstring
= NULL
;
485 if ( rule
->lr_subst
) {
486 rewrite_subst_destroy( &rule
->lr_subst
);
489 regfree( &rule
->lr_regex
);
491 destroy_actions( rule
->lr_action
);