/* 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 #include #include #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 * ****************************************************************************/