1 /******************************************************************************
3 * Copyright (C) 2000 Pierangelo Masarati, <ando@sys-net.it>
6 * Permission is granted to anyone to use this software for any purpose
7 * on any computer system, and to alter it and redistribute it, subject
8 * to the following restrictions:
10 * 1. The author is not responsible for the consequences of use of this
11 * software, no matter how awful, even if they arise from flaws in it.
13 * 2. The origin of this software must not be misrepresented, either by
14 * explicit claim or by omission. Since few users ever read sources,
15 * credits should appear in the documentation.
17 * 3. Altered versions must be plainly marked as such, and must not be
18 * misrepresented as being the original software. Since few users
19 * ever read sources, credits should appear in the documentation.
21 * 4. This notice may not be removed or altered.
23 ******************************************************************************/
27 #include "rewrite-int.h"
30 * Appends a rule to the double linked list of rules
31 * Helper for rewrite_rule_compile
35 struct rewrite_context *context,
36 struct rewrite_rule *rule
39 struct rewrite_rule *r;
41 assert( context != NULL );
42 assert( context->lc_rule != NULL );
43 assert( rule != NULL );
45 for ( r = context->lc_rule; r->lr_next != NULL; r = r->lr_next );
49 return REWRITE_SUCCESS;
53 * Appends an action to the linked list of actions
54 * Helper for rewrite_rule_compile
58 struct rewrite_action *base,
59 struct rewrite_action *action
62 struct rewrite_action *a;
64 assert( base != NULL );
65 assert( action != NULL );
67 for ( a = base; a->la_next != NULL; a = a->la_next );
70 return REWRITE_SUCCESS;
75 struct rewrite_action **paction
78 struct rewrite_action *action;
86 switch ( action->la_type ) {
87 case REWRITE_FLAG_GOTO: {
88 int *pi = (int *)action->la_args;
107 * In case of error it returns NULL and does not free all the memory
108 * it allocated; as this is a once only phase, and an error at this stage
109 * would require the server to stop, there is no need to be paranoid
110 * about memory allocation
113 rewrite_rule_compile(
114 struct rewrite_info *info,
115 struct rewrite_context *context,
118 const char *flagstring
121 int flags = REWRITE_REGEX_EXTENDED | REWRITE_REGEX_ICASE;
122 int mode = REWRITE_RECURSE;
124 struct rewrite_rule *rule = NULL;
125 struct rewrite_subst *subst = NULL;
126 struct rewrite_action *action = NULL, *first_action = NULL;
130 assert( info != NULL );
131 assert( context != NULL );
132 assert( pattern != NULL );
133 assert( result != NULL );
136 * A null flagstring should be allowed
140 * Take care of substitution string
142 subst = rewrite_subst_compile( info, result );
143 if ( subst == NULL ) {
150 for ( p = flagstring; p[ 0 ] != '\0'; p++ ) {
156 case REWRITE_FLAG_HONORCASE: /* 'C' */
158 * Honor case (default is case insensitive)
160 flags &= ~REWRITE_REGEX_ICASE;
163 case REWRITE_FLAG_BASICREGEX: /* 'R' */
165 * Use POSIX Basic Regular Expression syntax
166 * instead of POSIX Extended Regular Expression
169 flags &= ~REWRITE_REGEX_EXTENDED;
173 * Execution mode flags
175 case REWRITE_FLAG_EXECONCE: /* ':' */
177 * Apply rule once only
179 mode &= ~REWRITE_RECURSE;
180 mode |= REWRITE_EXEC_ONCE;
184 * Special action flags
186 case REWRITE_FLAG_STOP: /* '@' */
188 * Bail out after applying rule
190 action = calloc( sizeof( struct rewrite_action ), 1 );
191 if ( action == NULL ) {
196 mode &= ~REWRITE_RECURSE;
197 mode |= REWRITE_EXEC_ONCE;
198 action->la_type = REWRITE_ACTION_STOP;
201 case REWRITE_FLAG_UNWILLING: /* '#' */
203 * Matching objs will be marked as gone!
205 action = calloc( sizeof( struct rewrite_action ), 1 );
206 if ( action == NULL ) {
211 mode &= ~REWRITE_RECURSE;
212 mode |= REWRITE_EXEC_ONCE;
213 action->la_type = REWRITE_ACTION_UNWILLING;
216 case REWRITE_FLAG_GOTO: { /* 'G' */
218 * After applying rule, jump N rules
225 if ( p[ 1 ] != '{' ) {
226 /* XXX Need to free stuff */
230 q = strchr( p + 2, '}' );
232 /* XXX Need to free stuff */
237 if ( l >= sizeof( buf ) ) {
238 /* XXX Need to free stuff */
241 AC_MEMCPY( buf, p + 2, l );
244 d = malloc( sizeof( int ) );
246 /* XXX Need to free stuff */
249 d[ 0 ] = atoi( buf );
251 action = calloc( sizeof( struct rewrite_action ), 1 );
252 if ( action == NULL ) {
256 action->la_type = REWRITE_ACTION_GOTO;
257 action->la_args = (void *)d;
259 p = q; /* p is incremented by the for ... */
264 case REWRITE_FLAG_IGNORE_ERR: /* 'I' */
268 action = calloc( sizeof( struct rewrite_action ), 1 );
269 if ( action == NULL ) {
274 action->la_type = REWRITE_ACTION_IGNORE_ERR;
282 * Unimplemented feature (complain only)
288 * Stupid way to append to a list ...
290 if ( action != NULL ) {
291 if ( first_action == NULL ) {
292 first_action = action;
294 append_action( first_action, action );
301 * Finally, rule allocation
303 rule = calloc( sizeof( struct rewrite_rule ), 1 );
304 if ( rule == NULL ) {
305 /* charray_free( res ); */
307 * XXX need to free the value subst stuff!
313 * REGEX compilation (luckily I don't need to take care of this ...)
315 if ( regcomp( &rule->lr_regex, ( char * )pattern, flags ) != 0 ) {
316 /* charray_free( res ); */
318 *XXX need to free the value subst stuff!
325 * Just to remember them ...
327 rule->lr_pattern = strdup( pattern );
328 rule->lr_subststring = strdup( result );
329 rule->lr_flagstring = strdup( flagstring );
332 * Load compiled data into rule
334 rule->lr_subst = subst;
337 * Set various parameters
339 rule->lr_flags = flags; /* don't really need any longer ... */
340 rule->lr_mode = mode;
341 rule->lr_action = first_action;
344 * Append rule at the end of the rewrite context
346 append_rule( context, rule );
348 return REWRITE_SUCCESS;
352 * Rewrites string according to rule; may return:
353 * OK: fine; if *result != NULL rule matched and rewrite succeeded.
354 * STOP: fine, rule matched; stop processing following rules
355 * UNWILL: rule matched; force 'unwilling to perform'
359 struct rewrite_info *info,
360 struct rewrite_op *op,
361 struct rewrite_rule *rule,
366 size_t nmatch = REWRITE_MAX_MATCH;
367 regmatch_t match[ REWRITE_MAX_MATCH ];
369 int rc = REWRITE_SUCCESS;
373 struct berval val = { 0, NULL };
375 assert( info != NULL );
376 assert( op != NULL );
377 assert( rule != NULL );
378 assert( arg != NULL );
379 assert( result != NULL );
383 string = (char *)arg;
386 * In case recursive match is required (default)
390 Debug( LDAP_DEBUG_TRACE, "==> rewrite_rule_apply"
391 " rule='%s' string='%s'\n",
392 rule->lr_pattern, string, 0 );
395 if ( regexec( &rule->lr_regex, string, nmatch, match, 0 ) != 0 ) {
396 if ( *result == NULL && strcnt > 0 ) {
402 * No match is OK; *result = NULL means no match
404 return REWRITE_REGEXEC_OK;
407 rc = rewrite_subst_apply( info, op, rule->lr_subst, string,
410 *result = val.bv_val;
417 if ( rc != REWRITE_REGEXEC_OK ) {
421 if ( ( rule->lr_mode & REWRITE_RECURSE ) == REWRITE_RECURSE
422 && op->lo_num_passes <= info->li_max_passes ) {
429 return REWRITE_REGEXEC_OK;
433 rewrite_rule_destroy(
434 struct rewrite_rule **prule
437 struct rewrite_rule *rule;
438 struct rewrite_action *action;
445 if ( rule->lr_pattern ) {
446 free( rule->lr_pattern );
447 rule->lr_pattern = NULL;
450 if ( rule->lr_subststring ) {
451 free( rule->lr_subststring );
452 rule->lr_subststring = NULL;
455 if ( rule->lr_flagstring ) {
456 free( rule->lr_flagstring );
457 rule->lr_flagstring = NULL;
460 if ( rule->lr_subst ) {
461 rewrite_subst_destroy( &rule->lr_subst );
464 regfree( &rule->lr_regex );
466 for ( action = rule->lr_action; action; ) {
467 struct rewrite_action *curraction = action;
469 action = action->la_next;
470 destroy_action( &curraction );