Sync usage with man page.
[netbsd-mini2440.git] / external / bsd / openldap / dist / libraries / librewrite / context.c
blobb12bf26900bab0a1f1df8e7e817b060af65b3f41
1 /* $OpenLDAP: pkg/ldap/libraries/librewrite/context.c,v 1.15.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.
5 * All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted only as authorized by the OpenLDAP
9 * Public License.
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>.
15 /* ACKNOWLEDGEMENT:
16 * This work was initially developed by Pierangelo Masarati for
17 * inclusion in OpenLDAP Software.
20 #include <portable.h>
22 #include "rewrite-int.h"
25 * Compares two struct rewrite_context based on the name;
26 * used by avl stuff
28 static int
29 rewrite_context_cmp(
30 const void *c1,
31 const void *c2
34 const struct rewrite_context *lc1, *lc2;
36 lc1 = (const struct rewrite_context *)c1;
37 lc2 = (const struct rewrite_context *)c2;
39 assert( c1 != NULL );
40 assert( c2 != NULL );
41 assert( lc1->lc_name != NULL );
42 assert( lc2->lc_name != NULL );
44 return strcasecmp( lc1->lc_name, lc2->lc_name );
48 * Returns -1 in case a duplicate struct rewrite_context
49 * has been inserted; used by avl stuff
51 static int
52 rewrite_context_dup(
53 void *c1,
54 void *c2
57 struct rewrite_context *lc1, *lc2;
59 lc1 = (struct rewrite_context *)c1;
60 lc2 = (struct rewrite_context *)c2;
62 assert( c1 != NULL );
63 assert( c2 != NULL );
64 assert( lc1->lc_name != NULL );
65 assert( lc2->lc_name != NULL );
67 return( strcasecmp( lc1->lc_name, lc2->lc_name) == 0 ? -1 : 0 );
71 * Finds the context named rewriteContext in the context tree
73 struct rewrite_context *
74 rewrite_context_find(
75 struct rewrite_info *info,
76 const char *rewriteContext
79 struct rewrite_context *context, c;
81 assert( info != NULL );
82 assert( rewriteContext != NULL );
85 * Fetches the required rewrite context
87 c.lc_name = (char *)rewriteContext;
88 context = (struct rewrite_context *)avl_find( info->li_context,
89 (caddr_t)&c, rewrite_context_cmp );
90 if ( context == NULL ) {
91 return NULL;
95 * De-aliases the context if required
97 if ( context->lc_alias ) {
98 return context->lc_alias;
101 return context;
105 * Creates a new context called rewriteContext and stores in into the tree
107 struct rewrite_context *
108 rewrite_context_create(
109 struct rewrite_info *info,
110 const char *rewriteContext
113 struct rewrite_context *context;
114 int rc;
116 assert( info != NULL );
117 assert( rewriteContext != NULL );
119 context = calloc( sizeof( struct rewrite_context ), 1 );
120 if ( context == NULL ) {
121 return NULL;
125 * Context name
127 context->lc_name = strdup( rewriteContext );
128 if ( context->lc_name == NULL ) {
129 free( context );
130 return NULL;
134 * The first, empty rule
136 context->lc_rule = calloc( sizeof( struct rewrite_rule ), 1 );
137 if ( context->lc_rule == NULL ) {
138 free( context->lc_name );
139 free( context );
140 return NULL;
142 memset( context->lc_rule, 0, sizeof( struct rewrite_rule ) );
145 * Add context to tree
147 rc = avl_insert( &info->li_context, (caddr_t)context,
148 rewrite_context_cmp, rewrite_context_dup );
149 if ( rc == -1 ) {
150 free( context->lc_rule );
151 free( context->lc_name );
152 free( context );
153 return NULL;
156 return context;
160 * Finds the next rule according to a goto action statement,
161 * or null in case of error.
162 * Helper for rewrite_context_apply.
164 static struct rewrite_rule *
165 rewrite_action_goto(
166 struct rewrite_action *action,
167 struct rewrite_rule *rule
170 int n;
172 assert( action != NULL );
173 assert( action->la_args != NULL );
174 assert( rule != NULL );
176 n = ((int *)action->la_args)[ 0 ];
178 if ( n > 0 ) {
179 for ( ; n > 1 && rule != NULL ; n-- ) {
180 rule = rule->lr_next;
182 } else if ( n <= 0 ) {
183 for ( ; n < 1 && rule != NULL ; n++ ) {
184 rule = rule->lr_prev;
188 return rule;
192 * Rewrites string according to context; may return:
193 * OK: fine; if *result != NULL rule matched and rewrite succeeded.
194 * STOP: fine, rule matched; stop processing following rules
195 * UNWILL: rule matched; force 'unwilling to perform'
198 rewrite_context_apply(
199 struct rewrite_info *info,
200 struct rewrite_op *op,
201 struct rewrite_context *context,
202 const char *string,
203 char **result
206 struct rewrite_rule *rule;
207 char *s, *res = NULL;
208 int return_code = REWRITE_REGEXEC_OK;
210 assert( info != NULL );
211 assert( op != NULL );
212 assert( context != NULL );
213 assert( context->lc_rule != NULL );
214 assert( string != NULL );
215 assert( result != NULL );
217 op->lo_depth++;
218 assert( op->lo_depth > 0 );
220 Debug( LDAP_DEBUG_TRACE, "==> rewrite_context_apply"
221 " [depth=%d] string='%s'\n",
222 op->lo_depth, string, 0 );
224 s = (char *)string;
226 for ( rule = context->lc_rule->lr_next;
227 rule != NULL && op->lo_num_passes < info->li_max_passes;
228 rule = rule->lr_next, op->lo_num_passes++ ) {
229 int rc;
232 * Apply a single rule
234 rc = rewrite_rule_apply( info, op, rule, s, &res );
237 * A rule may return:
238 * OK with result != NULL if matched
239 * ERR if anything was wrong
240 * UNWILLING if the server should drop the request
241 * the latter case in honored immediately;
242 * the other two may require some special actions to take
243 * place.
245 switch ( rc ) {
247 case REWRITE_REGEXEC_ERR:
248 Debug( LDAP_DEBUG_ANY, "==> rewrite_context_apply"
249 " error ...\n", 0, 0, 0);
252 * Checks for special actions to be taken
253 * in case of error ...
255 if ( rule->lr_action != NULL ) {
256 struct rewrite_action *action;
257 int do_continue = 0;
259 for ( action = rule->lr_action;
260 action != NULL;
261 action = action->la_next ) {
262 switch ( action->la_type ) {
265 * This action takes precedence
266 * over the others in case of failure
268 case REWRITE_ACTION_IGNORE_ERR:
269 Debug( LDAP_DEBUG_ANY,
270 "==> rewrite_context_apply"
271 " ignoring error ...\n", 0, 0, 0 );
272 do_continue = 1;
273 break;
276 * Goto is honored only if it comes
277 * after ignore error
279 case REWRITE_ACTION_GOTO:
280 if ( do_continue ) {
281 rule = rewrite_action_goto( action, rule );
282 if ( rule == NULL ) {
283 return_code = REWRITE_REGEXEC_ERR;
284 goto rc_end_of_context;
287 break;
290 * Other actions are ignored
292 default:
293 break;
297 if ( do_continue ) {
298 if ( rule->lr_next == NULL ) {
299 res = s;
301 goto rc_continue;
306 * Default behavior is to bail out ...
308 return_code = REWRITE_REGEXEC_ERR;
309 goto rc_end_of_context;
312 * OK means there were no errors or special return codes;
313 * if res is defined, it means the rule matched and we
314 * got a sucessful rewriting
316 case REWRITE_REGEXEC_OK:
319 * It matched! Check for actions ...
321 if ( res != NULL ) {
322 struct rewrite_action *action;
324 if ( s != string && s != res ) {
325 free( s );
327 s = res;
329 for ( action = rule->lr_action;
330 action != NULL;
331 action = action->la_next ) {
333 switch ( action->la_type ) {
336 * This ends the rewrite context
337 * successfully
339 case REWRITE_ACTION_STOP:
340 goto rc_end_of_context;
343 * This instructs the server to return
344 * an `unwilling to perform' error
345 * message
347 case REWRITE_ACTION_UNWILLING:
348 return_code = REWRITE_REGEXEC_UNWILLING;
349 goto rc_end_of_context;
352 * This causes the processing to
353 * jump n rules back and forth
355 case REWRITE_ACTION_GOTO:
356 rule = rewrite_action_goto( action, rule );
357 if ( rule == NULL ) {
358 return_code = REWRITE_REGEXEC_ERR;
359 goto rc_end_of_context;
361 break;
364 * This ends the rewrite context
365 * and returns a user-defined
366 * error code
368 case REWRITE_ACTION_USER:
369 return_code = ((int *)action->la_args)[ 0 ];
370 goto rc_end_of_context;
372 default:
373 /* ... */
374 break;
379 * If result was OK and string didn't match,
380 * in case of last rule we need to set the
381 * result back to the string
383 } else if ( rule->lr_next == NULL ) {
384 res = s;
387 break;
390 * A STOP has propagated ...
392 case REWRITE_REGEXEC_STOP:
393 goto rc_end_of_context;
396 * This will instruct the server to return
397 * an `unwilling to perform' error message
399 case REWRITE_REGEXEC_UNWILLING:
400 return_code = REWRITE_REGEXEC_UNWILLING;
401 goto rc_end_of_context;
404 * A user-defined error code has propagated ...
406 default:
407 assert( rc >= REWRITE_REGEXEC_USER );
408 goto rc_end_of_context;
412 rc_continue:; /* sent here by actions that require to continue */
416 rc_end_of_context:;
417 *result = res;
419 Debug( LDAP_DEBUG_TRACE, "==> rewrite_context_apply"
420 " [depth=%d] res={%d,'%s'}\n",
421 op->lo_depth, return_code, ( res ? res : "NULL" ) );
423 assert( op->lo_depth > 0 );
424 op->lo_depth--;
426 return return_code;
429 void
430 rewrite_context_free(
431 void *tmp
434 struct rewrite_context *context = (struct rewrite_context *)tmp;
436 assert( tmp != NULL );
438 rewrite_context_destroy( &context );
442 rewrite_context_destroy(
443 struct rewrite_context **pcontext
446 struct rewrite_context *context;
447 struct rewrite_rule *r;
449 assert( pcontext != NULL );
450 assert( *pcontext != NULL );
452 context = *pcontext;
454 assert( context->lc_rule != NULL );
456 for ( r = context->lc_rule->lr_next; r; ) {
457 struct rewrite_rule *cr = r;
459 r = r->lr_next;
460 rewrite_rule_destroy( &cr );
463 free( context->lc_rule );
464 context->lc_rule = NULL;
466 assert( context->lc_name != NULL );
467 free( context->lc_name );
468 context->lc_name = NULL;
470 free( context );
471 *pcontext = NULL;
473 return 0;