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;
74 * In case of error it returns NULL and does not free all the memory
75 * it allocated; as this is a once only phase, and an error at this stage
76 * would require the server to stop, there is no need to be paranoid
77 * about memory allocation
81 struct rewrite_info *info,
82 struct rewrite_context *context,
85 const char *flagstring
88 int flags = REWRITE_REGEX_EXTENDED | REWRITE_REGEX_ICASE;
89 int mode = REWRITE_RECURSE;
91 struct rewrite_rule *rule = NULL;
92 struct rewrite_subst *subst = NULL;
93 struct rewrite_action *action = NULL, *first_action = NULL;
97 assert( info != NULL );
98 assert( context != NULL );
99 assert( pattern != NULL );
100 assert( result != NULL );
103 * A null flagstring should be allowed
107 * Take care of substitution string
109 subst = rewrite_subst_compile( info, result );
110 if ( subst == NULL ) {
117 for ( p = flagstring; p[ 0 ] != '\0'; p++ ) {
123 case REWRITE_FLAG_HONORCASE: /* 'C' */
125 * Honor case (default is case insensitive)
127 flags &= ~REWRITE_REGEX_ICASE;
130 case REWRITE_FLAG_BASICREGEX: /* 'R' */
132 * Use POSIX Basic Regular Expression syntax
133 * instead of POSIX Extended Regular Expression
136 flags &= ~REWRITE_REGEX_EXTENDED;
140 * Execution mode flags
142 case REWRITE_FLAG_EXECONCE: /* ':' */
144 * Apply rule once only
146 mode &= ~REWRITE_RECURSE;
147 mode |= REWRITE_EXEC_ONCE;
151 * Special action flags
153 case REWRITE_FLAG_STOP: /* '@' */
155 * Bail out after applying rule
157 action = calloc( sizeof( struct rewrite_action ), 1 );
158 if ( action == NULL ) {
163 mode &= ~REWRITE_RECURSE;
164 mode |= REWRITE_EXEC_ONCE;
165 action->la_type = REWRITE_ACTION_STOP;
168 case REWRITE_FLAG_UNWILLING: /* '#' */
170 * Matching objs will be marked as gone!
172 action = calloc( sizeof( struct rewrite_action ), 1 );
173 if ( action == NULL ) {
178 mode &= ~REWRITE_RECURSE;
179 mode |= REWRITE_EXEC_ONCE;
180 action->la_type = REWRITE_ACTION_UNWILLING;
183 case REWRITE_FLAG_GOTO: { /* 'G' */
185 * After applying rule, jump N rules
192 if ( p[ 1 ] != '{' ) {
193 /* XXX Need to free stuff */
197 q = strchr( p + 2, '}' );
199 /* XXX Need to free stuff */
204 if ( l >= sizeof( buf ) ) {
205 /* XXX Need to free stuff */
208 strncpy( buf, p + 2, l );
211 d = malloc( sizeof( int ) );
213 /* XXX Need to free stuff */
216 d[ 0 ] = atoi( buf );
218 action = calloc( sizeof( struct rewrite_action ), 1 );
219 if ( action == NULL ) {
223 action->la_type = REWRITE_ACTION_GOTO;
224 action->la_args = (void *)d;
226 p = q; /* p is incremented by the for ... */
231 case REWRITE_FLAG_IGNORE_ERR: /* 'I' */
235 action = calloc( sizeof( struct rewrite_action ), 1 );
236 if ( action == NULL ) {
241 action->la_type = REWRITE_ACTION_IGNORE_ERR;
249 * Unimplemented feature (complain only)
255 * Stupid way to append to a list ...
257 if ( action != NULL ) {
258 if ( first_action == NULL ) {
259 first_action = action;
261 append_action( first_action, action );
268 * Finally, rule allocation
270 rule = calloc( sizeof( struct rewrite_rule ), 1 );
271 if ( rule == NULL ) {
272 /* charray_free( res ); */
274 * XXX need to free the value subst stuff!
280 * REGEX compilation (luckily I don't need to take care of this ...)
282 if ( regcomp( &rule->lr_regex, ( char * )pattern, flags ) != 0 ) {
283 /* charray_free( res ); */
285 *XXX need to free the value subst stuff!
292 * Just to remember them ...
294 rule->lr_pattern = strdup( pattern );
295 rule->lr_subststring = strdup( result );
296 rule->lr_flagstring = strdup( flagstring );
299 * Load compiled data into rule
301 rule->lr_subst = subst;
304 * Set various parameters
306 rule->lr_flags = flags; /* don't really need any longer ... */
307 rule->lr_mode = mode;
308 rule->lr_action = first_action;
311 * Append rule at the end of the rewrite context
313 append_rule( context, rule );
315 return REWRITE_SUCCESS;
319 * Rewrites string according to rule; may return:
320 * OK: fine; if *result != NULL rule matched and rewrite succeeded.
321 * STOP: fine, rule matched; stop processing following rules
322 * UNWILL: rule matched; force 'unwilling to perform'
326 struct rewrite_info *info,
327 struct rewrite_op *op,
328 struct rewrite_rule *rule,
333 size_t nmatch = REWRITE_MAX_MATCH;
334 regmatch_t match[ REWRITE_MAX_MATCH ];
336 int rc = REWRITE_SUCCESS;
341 assert( info != NULL );
342 assert( op != NULL );
343 assert( rule != NULL );
344 assert( arg != NULL );
345 assert( result != NULL );
349 string = strdup( arg );
350 if ( string == NULL ) {
351 return REWRITE_REGEXEC_ERR;
355 * In case recursive match is required (default)
359 Debug( LDAP_DEBUG_TRACE, "==> rewrite_rule_apply"
360 " rule='%s' string='%s'\n%s",
361 rule->lr_pattern, string, "" );
364 if ( regexec( &rule->lr_regex, string, nmatch, match, 0 ) != 0 ) {
365 if ( *result == NULL ) {
370 * No match is OK; *result = NULL means no match
372 return REWRITE_REGEXEC_OK;
375 rc = rewrite_subst_apply( info, op, rule->lr_subst, string,
378 *result = val.bv_val;
381 if ( rc != REWRITE_REGEXEC_OK ) {
385 if ( ( rule->lr_mode & REWRITE_RECURSE ) == REWRITE_RECURSE
386 && op->lo_num_passes <= info->li_max_passes ) {
391 return REWRITE_REGEXEC_OK;