diff options
Diffstat (limited to 'libraries/librewrite/var.c')
-rw-r--r-- | libraries/librewrite/var.c | 273 |
1 files changed, 273 insertions, 0 deletions
diff --git a/libraries/librewrite/var.c b/libraries/librewrite/var.c new file mode 100644 index 0000000..61adc57 --- /dev/null +++ b/libraries/librewrite/var.c @@ -0,0 +1,273 @@ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 2000-2021 The OpenLDAP Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ +/* ACKNOWLEDGEMENT: + * This work was initially developed by Pierangelo Masarati for + * inclusion in OpenLDAP Software. + */ + +#include <portable.h> + +#include "rewrite-int.h" + +/* + * Compares two vars + */ +static int +rewrite_var_cmp( + const void *c1, + const void *c2 +) +{ + const struct rewrite_var *v1, *v2; + + v1 = ( const struct rewrite_var * )c1; + v2 = ( const struct rewrite_var * )c2; + + assert( v1 != NULL ); + assert( v2 != NULL ); + assert( v1->lv_name != NULL ); + assert( v2->lv_name != NULL ); + + return strcasecmp( v1->lv_name, v2->lv_name ); +} + +/* + * Duplicate var ? + */ +static int +rewrite_var_dup( + void *c1, + void *c2 +) +{ + struct rewrite_var *v1, *v2; + + v1 = ( struct rewrite_var * )c1; + v2 = ( struct rewrite_var * )c2; + + assert( v1 != NULL ); + assert( v2 != NULL ); + assert( v1->lv_name != NULL ); + assert( v2->lv_name != NULL ); + + return ( strcasecmp( v1->lv_name, v2->lv_name ) == 0 ? -1 : 0 ); +} + +/* + * Frees a var + */ +static void +rewrite_var_free( + void *v_var +) +{ + struct rewrite_var *var = v_var; + assert( var != NULL ); + + assert( var->lv_name != NULL ); + assert( var->lv_value.bv_val != NULL ); + + if ( var->lv_flags & REWRITE_VAR_COPY_NAME ) + free( var->lv_name ); + if ( var->lv_flags & REWRITE_VAR_COPY_VALUE ) + free( var->lv_value.bv_val ); + free( var ); +} + +/* + * Deletes a var tree + */ +int +rewrite_var_delete( + Avlnode *tree +) +{ + avl_free( tree, rewrite_var_free ); + return REWRITE_SUCCESS; +} + +/* + * Finds a var + */ +struct rewrite_var * +rewrite_var_find( + Avlnode *tree, + const char *name +) +{ + struct rewrite_var var; + + assert( name != NULL ); + + var.lv_name = ( char * )name; + return ( struct rewrite_var * )avl_find( tree, + ( caddr_t )&var, rewrite_var_cmp ); +} + +int +rewrite_var_replace( + struct rewrite_var *var, + const char *value, + int flags +) +{ + ber_len_t len; + + assert( value != NULL ); + + len = strlen( value ); + + if ( var->lv_flags & REWRITE_VAR_COPY_VALUE ) { + if ( flags & REWRITE_VAR_COPY_VALUE ) { + if ( len <= var->lv_value.bv_len ) { + AC_MEMCPY(var->lv_value.bv_val, value, len + 1); + + } else { + free( var->lv_value.bv_val ); + var->lv_value.bv_val = strdup( value ); + } + + } else { + free( var->lv_value.bv_val ); + var->lv_value.bv_val = (char *)value; + var->lv_flags &= ~REWRITE_VAR_COPY_VALUE; + } + + } else { + if ( flags & REWRITE_VAR_COPY_VALUE ) { + var->lv_value.bv_val = strdup( value ); + var->lv_flags |= REWRITE_VAR_COPY_VALUE; + + } else { + var->lv_value.bv_val = (char *)value; + } + } + + if ( var->lv_value.bv_val == NULL ) { + return -1; + } + + var->lv_value.bv_len = len; + + return 0; +} + +/* + * Inserts a newly created var + */ +struct rewrite_var * +rewrite_var_insert_f( + Avlnode **tree, + const char *name, + const char *value, + int flags +) +{ + struct rewrite_var *var; + int rc = 0; + + assert( tree != NULL ); + assert( name != NULL ); + assert( value != NULL ); + + var = rewrite_var_find( *tree, name ); + if ( var != NULL ) { + if ( flags & REWRITE_VAR_UPDATE ) { + (void)rewrite_var_replace( var, value, flags ); + goto cleanup; + } + rc = -1; + goto cleanup; + } + + var = calloc( sizeof( struct rewrite_var ), 1 ); + if ( var == NULL ) { + return NULL; + } + + memset( var, 0, sizeof( struct rewrite_var ) ); + + if ( flags & REWRITE_VAR_COPY_NAME ) { + var->lv_name = strdup( name ); + if ( var->lv_name == NULL ) { + rc = -1; + goto cleanup; + } + var->lv_flags |= REWRITE_VAR_COPY_NAME; + + } else { + var->lv_name = (char *)name; + } + + if ( flags & REWRITE_VAR_COPY_VALUE ) { + var->lv_value.bv_val = strdup( value ); + if ( var->lv_value.bv_val == NULL ) { + rc = -1; + goto cleanup; + } + var->lv_flags |= REWRITE_VAR_COPY_VALUE; + + } else { + var->lv_value.bv_val = (char *)value; + } + var->lv_value.bv_len = strlen( value ); + rc = avl_insert( tree, ( caddr_t )var, + rewrite_var_cmp, rewrite_var_dup ); + +cleanup:; + if ( rc != 0 && var ) { + avl_delete( tree, ( caddr_t )var, rewrite_var_cmp ); + rewrite_var_free( var ); + var = NULL; + } + + return var; +} + +/* + * Sets/inserts a var + */ +struct rewrite_var * +rewrite_var_set_f( + Avlnode **tree, + const char *name, + const char *value, + int flags +) +{ + struct rewrite_var *var; + + assert( tree != NULL ); + assert( name != NULL ); + assert( value != NULL ); + + var = rewrite_var_find( *tree, name ); + if ( var == NULL ) { + if ( flags & REWRITE_VAR_INSERT ) { + return rewrite_var_insert_f( tree, name, value, flags ); + + } else { + return NULL; + } + + } else { + assert( var->lv_value.bv_val != NULL ); + + (void)rewrite_var_replace( var, value, flags ); + } + + return var; +} + |