/*
elmo - ELectronic Mail Operator
Copyright (C) 2004 rzyjontko
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
----------------------------------------------------------------------
MODULE_DESCRIPTION
*/
/****************************************************************************
* IMPLEMENTATION HEADERS
****************************************************************************/
#include <sys/types.h>
#include <regex.h>
#include <string.h>
#include "property.h"
#include "str.h"
#include "rstring.h"
#include "hash.h"
#include "ask.h"
#include "xmalloc.h"
#include "error.h"
#include "misc.h"
#include "gettext.h"
#include "eprintf.h"
/****************************************************************************
* IMPLEMENTATION PRIVATE DEFINITIONS / ENUMERATIONS / SIMPLE TYPEDEFS
****************************************************************************/
#define MAX_CONDITIONS 10
/****************************************************************************
* IMPLEMENTATION PRIVATE CLASS PROTOTYPES / EXTERNAL CLASS REFERENCES
****************************************************************************/
/****************************************************************************
* IMPLEMENTATION PRIVATE STRUCTURES / UTILITY CLASSES
****************************************************************************/
struct condition {
struct condition *next;
int count;
regex_t conds[MAX_CONDITIONS];
char *value;
};
struct property {
char *name;
rstring_t *args;
struct condition *conditions;
char *(*fallback)(const char *);
};
/****************************************************************************
* IMPLEMENTATION REQUIRED EXTERNAL REFERENCES (AVOID)
****************************************************************************/
/****************************************************************************
* IMPLEMENTATION PRIVATE DATA
****************************************************************************/
static htable_t *properties = NULL;
static struct property *prop_new = NULL;
static struct condition *cond_new = NULL;
/****************************************************************************
* INTERFACE DATA
****************************************************************************/
/****************************************************************************
* IMPLEMENTATION PRIVATE FUNCTION PROTOTYPES
****************************************************************************/
/****************************************************************************
* IMPLEMENTATION PRIVATE FUNCTIONS
****************************************************************************/
static struct property *
lookup_property (const char *name)
{
str_t *str;
char *seek;
entry_t *entry = htable_lookup (properties, name);
if (entry != NULL)
return (struct property *) entry->content;
seek = strchr (name, '.');
if (seek == NULL)
return NULL;
str = str_create ();
str_put_string_len (str, name, seek - name);
entry = htable_lookup (properties, str->str);
str_destroy (str);
if (entry == NULL)
return NULL;
return (struct property *) entry->content;
}
static int
match_property (regex_t *re, const char *property)
{
int ret;
char *txt = property_get (property);
char *str;
if (txt == NULL)
str = "_";
else
str = txt;
ret = regexec (re, str, 0, NULL, 0);
if (ret && ret != REG_NOMATCH){
error_regex (ret, re, NULL);
}
if (txt)
xfree (txt);
return ! ret;
}
static char *
eval_condition (struct condition *cond, rstring_t *args)
{
int i;
char *result;
if (cond == NULL)
return NULL;
result = eval_condition (cond->next, args);
if (result)
return result;
for (i = 0; i < cond->count; i++){
if (! match_property (cond->conds + i, args->array[i]))
return NULL;
}
return eprintf_rstring (cond->value, args);
}
static char *
eval_property (struct property *prop, const char *name)
{
char *result = NULL;
if (prop->args)
result = eval_condition (prop->conditions, prop->args);
if (result)
return result;
if (prop->fallback)
return prop->fallback (name);
return NULL;
}
static void
destroy_condition (struct condition *cond)
{
int i;
if (cond == NULL)
return;
destroy_condition (cond->next);
for (i = 0; i < cond->count; i++)
regfree (cond->conds + i);
if (cond->value)
xfree (cond->value);
xfree (cond);
}
static void
destroy_property (void *data)
{
struct property *property = (struct property *) data;
if (property->name)
xfree (property->name);
if (property->args)
rstring_delete (property->args);
destroy_condition (property->conditions);
xfree (property);
}
/****************************************************************************
* INTERFACE FUNCTIONS
****************************************************************************/
void
property_init (void)
{
properties = htable_create (5);
}
void
property_free_resources (void)
{
htable_destroy (properties, destroy_property);
}
void
property_register (const char *name, char *(*fallback)(const char *))
{
struct property *prop = xmalloc (sizeof (struct property));
prop->name = xstrdup (name);
prop->args = NULL;
prop->conditions = NULL;
prop->fallback = fallback;
htable_insert (properties, prop->name, prop);
}
void
property_new (const char *name)
{
entry_t *entry;
entry = htable_insert (properties, name, NULL);
if (entry->content == NULL){
prop_new = xmalloc (sizeof (struct property));
prop_new->name = xstrdup (name);
prop_new->args = NULL;
prop_new->conditions = NULL;
prop_new->fallback = NULL;
entry->content = prop_new;
}
else {
prop_new = entry->content;
}
}
void
property_add_arg (const char *arg)
{
if (prop_new->args == NULL){
prop_new->args = rstring_create ();
prop_new->args->allocated_all = 1;
}
if (prop_new->args->count >= MAX_CONDITIONS){
error_ (0, _("too many conditions for property %s"),
prop_new->name);
return;
}
rstring_add (prop_new->args, xstrdup (arg));
}
void
property_add_cond_re (const char *cond)
{
int ret;
if (cond_new == NULL){
cond_new = xmalloc (sizeof (struct condition));
cond_new->next = prop_new->conditions;
cond_new->count = 0;
cond_new->value = NULL;
}
if (cond_new->count >= MAX_CONDITIONS){
error_ (0, _("too many conditions for property %s"),
prop_new->name);
return;
}
ret = regcomp (& cond_new->conds[cond_new->count], cond,
REG_NOSUB | REG_NEWLINE);
if (ret){
error_regex (ret, & cond_new->conds[cond_new->count], cond);
return;
}
cond_new->count++;
}
void
property_add_cond_str (const char *cond)
{
char *re = misc_re_from_str (cond);
property_add_cond_re (re);
xfree (re);
}
void
property_add_value (char *value)
{
cond_new->value = value;
prop_new->conditions = cond_new;
cond_new = NULL;
}
char *
property_get (const char *name)
{
struct property *property;
property = lookup_property (name);
if (property == NULL)
return NULL;
return eval_property (property, name);
}
/****************************************************************************
* INTERFACE CLASS BODIES
****************************************************************************/
/****************************************************************************
*
* END MODULE property.c
*
****************************************************************************/
syntax highlighted by Code2HTML, v. 0.9.1