| /* |
| * Copyright (C) 2002 Nigel Horne <njh@bandsman.co.uk> |
| * |
| * 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; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * 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., 51 Franklin Street, Fifth Floor, Boston, |
| * MA 02110-1301, USA. |
| * |
| * TODO: Allow individual items to be updated or removed |
| * |
| * It is up to the caller to create a mutex for the table if needed |
| */ |
| |
| #if HAVE_CONFIG_H |
| #include "clamav-config.h" |
| #endif |
| |
| #ifndef CL_DEBUG |
| #define NDEBUG /* map CLAMAV debug onto standard */ |
| #endif |
| |
| #include <stdlib.h> |
| #include <string.h> |
| #ifdef HAVE_STRINGS_H |
| #include <strings.h> |
| #endif |
| #include <assert.h> |
| |
| #include "table.h" |
| #include "others.h" |
| |
| struct table * |
| tableCreate(void) |
| { |
| return (struct table *)cli_calloc(1, sizeof(struct table)); |
| } |
| |
| void |
| tableDestroy(table_t *table) |
| { |
| tableEntry *tableItem; |
| |
| assert(table != NULL); |
| |
| tableItem = table->tableHead; |
| |
| while(tableItem) { |
| tableEntry *tableNext = tableItem->next; |
| |
| if(tableItem->key) |
| free(tableItem->key); |
| free(tableItem); |
| |
| tableItem = tableNext; |
| } |
| |
| free(table); |
| } |
| |
| /* |
| * Returns the value, or -1 for failure |
| */ |
| int |
| tableInsert(table_t *table, const char *key, int value) |
| { |
| const int v = tableFind(table, key); |
| |
| if(v > 0) /* duplicate key */ |
| return (v == value) ? value : -1; /* allow real dups */ |
| |
| assert(value != -1); /* that would confuse us */ |
| |
| if(table->tableHead == NULL) |
| table->tableLast = table->tableHead = (tableEntry *)cli_malloc(sizeof(tableEntry)); |
| else { |
| /* |
| * Re-use deleted items |
| */ |
| if(table->flags&TABLE_HAS_DELETED_ENTRIES) { |
| tableEntry *tableItem; |
| |
| assert(table->tableHead != NULL); |
| |
| for(tableItem = table->tableHead; tableItem; tableItem = tableItem->next) |
| if(tableItem->key == NULL) { |
| /* This item has been deleted */ |
| tableItem->key = cli_strdup(key); |
| tableItem->value = value; |
| return value; |
| } |
| |
| table->flags &= ~TABLE_HAS_DELETED_ENTRIES; |
| } |
| |
| table->tableLast = table->tableLast->next = |
| (tableEntry *)cli_malloc(sizeof(tableEntry)); |
| } |
| |
| if(table->tableLast == NULL) |
| return -1; |
| |
| table->tableLast->next = NULL; |
| table->tableLast->key = cli_strdup(key); |
| table->tableLast->value = value; |
| |
| return value; |
| } |
| |
| /* |
| * Returns the value - -1 for not found. This means the value of a valid key |
| * can't be -1 :-( |
| */ |
| int |
| tableFind(const table_t *table, const char *key) |
| { |
| const tableEntry *tableItem; |
| #ifdef CL_DEBUG |
| int cost; |
| #endif |
| |
| assert(table != NULL); |
| |
| if(key == NULL) |
| return -1; /* not treated as a fatal error */ |
| |
| #ifdef CL_DEBUG |
| cost = 0; |
| #endif |
| |
| for(tableItem = table->tableHead; tableItem; tableItem = tableItem->next) { |
| #ifdef CL_DEBUG |
| cost++; |
| #endif |
| if(tableItem->key && (strcasecmp(tableItem->key, key) == 0)) { |
| #ifdef CL_DEBUG |
| cli_dbgmsg("tableFind: Cost of '%s' = %d\n", key, cost); |
| #endif |
| return tableItem->value; |
| } |
| } |
| |
| return -1; /* not found */ |
| } |
| |
| /* |
| * Change a value in the table. If the key isn't in the table insert it |
| * Returns -1 for error, otherwise the new value |
| */ |
| int |
| tableUpdate(table_t *table, const char *key, int new_value) |
| { |
| tableEntry *tableItem; |
| |
| assert(table != NULL); |
| |
| if(key == NULL) |
| return -1; /* not treated as a fatal error */ |
| |
| for(tableItem = table->tableHead; tableItem; tableItem = tableItem->next) |
| if(tableItem->key && (strcasecmp(tableItem->key, key) == 0)) { |
| tableItem->value = new_value; |
| return new_value; |
| } |
| |
| /* not found */ |
| return tableInsert(table, key, new_value); |
| } |
| |
| /* |
| * Remove an item from the table |
| */ |
| void |
| tableRemove(table_t *table, const char *key) |
| { |
| tableEntry *tableItem; |
| |
| assert(table != NULL); |
| |
| if(key == NULL) |
| return; /* not treated as a fatal error */ |
| |
| for(tableItem = table->tableHead; tableItem; tableItem = tableItem->next) |
| if(tableItem->key && (strcasecmp(tableItem->key, key) == 0)) { |
| free(tableItem->key); |
| tableItem->key = NULL; |
| table->flags |= TABLE_HAS_DELETED_ENTRIES; |
| /* don't break, duplicate keys are allowed */ |
| } |
| } |
| |
| void |
| tableIterate(table_t *table, void(*callback)(char *key, int value, void *arg), void *arg) |
| { |
| tableEntry *tableItem; |
| |
| if(table == NULL) |
| return; |
| |
| for(tableItem = table->tableHead; tableItem; tableItem = tableItem->next) |
| if(tableItem->key) /* check node has not been deleted */ |
| (*callback)(tableItem->key, tableItem->value, arg); |
| } |