libclamav/table.c
b151ef55
 /*
  *  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
30738099
  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  *  MA 02110-1301, USA.
9cc71091
  *
  * TODO: Allow individual items to be updated or removed
  *
  * It is up to the caller to create a mutex for the table if needed
b151ef55
  */
 
5eeffbb9
 #if HAVE_CONFIG_H
 #include "clamav-config.h"
 #endif
 
 #ifndef	CL_DEBUG
 #define	NDEBUG	/* map CLAMAV debug onto standard */
 #endif
 
b151ef55
 #include <stdlib.h>
 #include <string.h>
40d54f7f
 #ifdef	HAVE_STRINGS_H
b151ef55
 #include <strings.h>
40d54f7f
 #endif
b151ef55
 #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;
 
41154db1
 		if(tableItem->key)
 			free(tableItem->key);
b151ef55
 		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)
aedb0336
 		table->tableLast = table->tableHead = (tableEntry *)cli_malloc(sizeof(tableEntry));
c9deecd1
 	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 = strdup(key);
 					tableItem->value = value;
 					return value;
 				}
 
 			table->flags &= ~TABLE_HAS_DELETED_ENTRIES;
 		}
 
7b8fb055
 		table->tableLast = table->tableLast->next =
aedb0336
 			(tableEntry *)cli_malloc(sizeof(tableEntry));
c9deecd1
 	}
b151ef55
 
4d9c0ca8
 	if(table->tableLast == NULL)
 		return -1;
 
b151ef55
 	table->tableLast->next = NULL;
 	table->tableLast->key = strdup(key);
 	table->tableLast->value = value;
 
 	return value;
 }
 
 /*
9cc71091
  * Returns the value - -1 for not found. This means the value of a valid key
  *	can't be -1 :-(
b151ef55
  */
 int
 tableFind(const table_t *table, const char *key)
 {
 	const tableEntry *tableItem;
5eeffbb9
 #ifdef	CL_DEBUG
 	int cost;
 #endif
b151ef55
 
 	assert(table != NULL);
 
 	if(key == NULL)
 		return -1;	/* not treated as a fatal error */
 
3810a396
 #ifdef	CL_DEBUG
5eeffbb9
 	cost = 0;
3810a396
 #endif
5eeffbb9
 
 	for(tableItem = table->tableHead; tableItem; tableItem = tableItem->next) {
 #ifdef	CL_DEBUG
 		cost++;
 #endif
87f2c204
 		if(tableItem->key && (strcasecmp(tableItem->key, key) == 0)) {
5eeffbb9
 #ifdef	CL_DEBUG
 			cli_dbgmsg("tableFind: Cost of '%s' = %d\n", key, cost);
 #endif
aedb0336
 			return tableItem->value;
5eeffbb9
 		}
 	}
b151ef55
 
 	return -1;	/* not found */
 }
9cc71091
 
 /*
  * 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)
87f2c204
 		if(tableItem->key && (strcasecmp(tableItem->key, key) == 0)) {
9cc71091
 			tableItem->value = new_value;
 			return new_value;
 		}
 
 	/* not found */
 	return tableInsert(table, key, new_value);
 }
41154db1
 
 /*
  * 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)
87f2c204
 		if(tableItem->key && (strcasecmp(tableItem->key, key) == 0)) {
41154db1
 			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))
 {
 	tableEntry *tableItem;
 
 	if(table == NULL)
 		return;
 
 	for(tableItem = table->tableHead; tableItem; tableItem = tableItem->next)
c9deecd1
 		if(tableItem->key)	/* check node has not been deleted */
41154db1
 			(*callback)(tableItem->key, tableItem->value);
 }