e3aaff8e |
/* |
e1cbc270 |
* Copyright (C) 2013-2019 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
* Copyright (C) 2007-2013 Sourcefire, Inc. |
2023340a |
*
* Authors: Nigel Horne |
e3aaff8e |
*
* This program is free software; you can redistribute it and/or modify |
2023340a |
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. |
e3aaff8e |
*
* 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 |
48b7b4a7 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA. |
23a5e3b7 |
*
* TODO: Allow individual items to be updated or removed
*
* It is up to the caller to create a mutex for the table if needed |
e3aaff8e |
*/
|
7c5a7a47 |
#if HAVE_CONFIG_H
#include "clamav-config.h"
#endif
|
e3aaff8e |
#include <stdlib.h>
#include <string.h> |
288057e9 |
#ifdef HAVE_STRINGS_H |
e3aaff8e |
#include <strings.h> |
bc6bbeff |
#endif |
e3aaff8e |
#include <assert.h>
|
60d8d2c3 |
#include "clamav.h" |
e3aaff8e |
#include "table.h"
#include "others.h"
struct table *
tableCreate(void)
{ |
288057e9 |
return (struct table *)cli_calloc(1, sizeof(struct table)); |
e3aaff8e |
}
|
288057e9 |
void tableDestroy(table_t *table) |
e3aaff8e |
{ |
288057e9 |
tableEntry *tableItem; |
e3aaff8e |
|
288057e9 |
assert(table != NULL); |
e3aaff8e |
|
288057e9 |
tableItem = table->tableHead; |
e3aaff8e |
|
288057e9 |
while (tableItem) {
tableEntry *tableNext = tableItem->next; |
e3aaff8e |
|
288057e9 |
if (tableItem->key)
free(tableItem->key);
free(tableItem); |
e3aaff8e |
|
288057e9 |
tableItem = tableNext;
} |
e3aaff8e |
|
288057e9 |
free(table); |
e3aaff8e |
}
/*
* Returns the value, or -1 for failure
*/ |
288057e9 |
int tableInsert(table_t *table, const char *key, int value) |
e3aaff8e |
{ |
288057e9 |
const int v = tableFind(table, key); |
e3aaff8e |
|
288057e9 |
if (v > 0) /* duplicate key */
return (v == value) ? value : -1; /* allow real dups */ |
e3aaff8e |
|
288057e9 |
assert(value != -1); /* that would confuse us */ |
e3aaff8e |
|
288057e9 |
if (table->tableHead == NULL)
table->tableLast = table->tableHead = (tableEntry *)cli_malloc(sizeof(tableEntry));
else {
/* |
821dd71e |
* Re-use deleted items
*/ |
288057e9 |
if (table->flags & TABLE_HAS_DELETED_ENTRIES) {
tableEntry *tableItem; |
821dd71e |
|
288057e9 |
assert(table->tableHead != NULL); |
821dd71e |
|
288057e9 |
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;
} |
821dd71e |
|
288057e9 |
table->flags &= ~TABLE_HAS_DELETED_ENTRIES;
} |
821dd71e |
|
288057e9 |
table->tableLast = table->tableLast->next =
(tableEntry *)cli_malloc(sizeof(tableEntry));
} |
e3aaff8e |
|
288057e9 |
if (table->tableLast == NULL) { |
241e7eb1 |
cli_dbgmsg("tableInsert: Unable to allocate memory for table\n"); |
288057e9 |
return -1; |
241e7eb1 |
} |
767f16ab |
|
288057e9 |
table->tableLast->next = NULL;
table->tableLast->key = cli_strdup(key);
table->tableLast->value = value; |
e3aaff8e |
|
288057e9 |
return value; |
e3aaff8e |
}
/* |
23a5e3b7 |
* Returns the value - -1 for not found. This means the value of a valid key
* can't be -1 :-( |
9fe789f8 |
*
* Linear search. Since tables are rarely more than 3 or 4 in size, and never |
7cd9337a |
* reach double figures, there's no need for optimization |
e3aaff8e |
*/ |
288057e9 |
int tableFind(const table_t *table, const char *key) |
e3aaff8e |
{ |
288057e9 |
const tableEntry *tableItem;
#ifdef CL_DEBUG
int cost; |
7c5a7a47 |
#endif |
e3aaff8e |
|
288057e9 |
assert(table != NULL); |
e3aaff8e |
|
288057e9 |
if (key == NULL)
return -1; /* not treated as a fatal error */ |
e3aaff8e |
|
288057e9 |
#ifdef CL_DEBUG
cost = 0; |
27328356 |
#endif |
7c5a7a47 |
|
288057e9 |
for (tableItem = table->tableHead; tableItem; tableItem = tableItem->next) {
#ifdef CL_DEBUG
cost++; |
7c5a7a47 |
#endif |
288057e9 |
if (tableItem->key && (strcasecmp(tableItem->key, key) == 0)) {
#ifdef CL_DEBUG
cli_dbgmsg("tableFind: Cost of '%s' = %d\n", key, cost); |
7c5a7a47 |
#endif |
288057e9 |
return tableItem->value;
}
} |
e3aaff8e |
|
288057e9 |
return -1; /* not found */ |
e3aaff8e |
} |
23a5e3b7 |
/*
* Change a value in the table. If the key isn't in the table insert it
* Returns -1 for error, otherwise the new value
*/ |
288057e9 |
int tableUpdate(table_t *table, const char *key, int new_value) |
23a5e3b7 |
{ |
288057e9 |
tableEntry *tableItem; |
23a5e3b7 |
|
288057e9 |
assert(table != NULL); |
23a5e3b7 |
|
288057e9 |
if (key == NULL)
return -1; /* not treated as a fatal error */ |
23a5e3b7 |
|
288057e9 |
for (tableItem = table->tableHead; tableItem; tableItem = tableItem->next)
if (tableItem->key && (strcasecmp(tableItem->key, key) == 0)) {
tableItem->value = new_value;
return new_value;
} |
23a5e3b7 |
|
288057e9 |
/* not found */
return tableInsert(table, key, new_value); |
23a5e3b7 |
} |
b650cc71 |
/*
* Remove an item from the table
*/ |
288057e9 |
void tableRemove(table_t *table, const char *key) |
b650cc71 |
{ |
288057e9 |
tableEntry *tableItem; |
b650cc71 |
|
288057e9 |
assert(table != NULL); |
b650cc71 |
|
288057e9 |
if (key == NULL)
return; /* not treated as a fatal error */ |
b650cc71 |
|
288057e9 |
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 */
} |
b650cc71 |
}
|
288057e9 |
void tableIterate(table_t *table, void (*callback)(char *key, int value, void *arg), void *arg) |
b650cc71 |
{ |
288057e9 |
tableEntry *tableItem; |
b650cc71 |
|
288057e9 |
if (table == NULL)
return; |
b650cc71 |
|
288057e9 |
for (tableItem = table->tableHead; tableItem; tableItem = tableItem->next)
if (tableItem->key) /* check node has not been deleted */
(*callback)(tableItem->key, tableItem->value, arg); |
b650cc71 |
} |