mirror of
https://github.com/nzp-team/fteqw.git
synced 2024-11-23 12:22:42 +00:00
ffc2a08589
Added version+time+date to segfault lots. try to use vbo+vao as needed. added a manifest file in order to disable uac emulation and its virtual store lies. particles now support a sort of namespace. eg: an effect called "cfg.effect" will load up the 'cfg' particle config and use its 'effect' effect (but not replace any explicit effects). You can still create particle effects called 'cfg.effect' with no issue. Added support for fsarchive plugins. Added a sys_register_file_associations command. .bsp not yet handled, but demo playback should work fine. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4324 fc73d0e0-1445-4013-8a0c-d673dee63da5
353 lines
6.7 KiB
C
353 lines
6.7 KiB
C
#include "hash.h"
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#ifndef _WIN32
|
|
#ifndef stricmp
|
|
#define stricmp strcasecmp
|
|
#endif
|
|
#endif
|
|
|
|
// hash init assumes we get clean memory
|
|
void Hash_InitTable(hashtable_t *table, unsigned int numbucks, void *mem)
|
|
{
|
|
table->numbuckets = numbucks;
|
|
table->bucket = (bucket_t **)mem;
|
|
}
|
|
|
|
void *Hash_Enumerate(hashtable_t *table, void (*callback) (void *ctx, void *data), void *ctx)
|
|
{
|
|
unsigned int bucknum;
|
|
bucket_t *buck;
|
|
void *data;
|
|
|
|
for (bucknum = 0; bucknum < table->numbuckets; bucknum++)
|
|
{
|
|
buck = table->bucket[bucknum];
|
|
|
|
while(buck)
|
|
{
|
|
data = buck->data;
|
|
buck = buck->next;
|
|
|
|
//now that we don't care about backlinks etc, we can call the callback and it can safely nuke it (Hash_RemoveData or even destroy the bucket if the hash table is going to die).
|
|
callback(ctx, data);
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
unsigned int Hash_Key(const char *name, unsigned int modulus)
|
|
{ //fixme: optimize.
|
|
unsigned int key;
|
|
for (key=0;*name; name++)
|
|
key += ((key<<3) + (key>>28) + *name);
|
|
|
|
return (key%modulus);
|
|
}
|
|
unsigned int Hash_KeyInsensative(const char *name, unsigned int modulus)
|
|
{ //fixme: optimize.
|
|
unsigned int key;
|
|
for (key=0;*name; name++)
|
|
{
|
|
if (*name >= 'A' && *name <= 'Z')
|
|
key += ((key<<3) + (key>>28) + (*name-'A'+'a'));
|
|
else
|
|
key += ((key<<3) + (key>>28) + *name);
|
|
}
|
|
|
|
return (key%modulus);
|
|
}
|
|
|
|
void *Hash_GetIdx(hashtable_t *table, unsigned int idx)
|
|
{
|
|
unsigned int bucknum;
|
|
bucket_t *buck;
|
|
|
|
for (bucknum = 0; bucknum < table->numbuckets; bucknum++)
|
|
{
|
|
buck = table->bucket[bucknum];
|
|
|
|
while(buck)
|
|
{
|
|
if (!idx--)
|
|
return buck->data;
|
|
|
|
buck = buck->next;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void *Hash_Get(hashtable_t *table, const char *name)
|
|
{
|
|
unsigned int bucknum = Hash_Key(name, table->numbuckets);
|
|
bucket_t *buck;
|
|
|
|
buck = table->bucket[bucknum];
|
|
|
|
while(buck)
|
|
{
|
|
if (!STRCMP(name, buck->key.string))
|
|
return buck->data;
|
|
|
|
buck = buck->next;
|
|
}
|
|
return NULL;
|
|
}
|
|
void *Hash_GetInsensative(hashtable_t *table, const char *name)
|
|
{
|
|
unsigned int bucknum = Hash_KeyInsensative(name, table->numbuckets);
|
|
bucket_t *buck;
|
|
|
|
buck = table->bucket[bucknum];
|
|
|
|
while(buck)
|
|
{
|
|
if (!stricmp(name, buck->key.string))
|
|
return buck->data;
|
|
|
|
buck = buck->next;
|
|
}
|
|
return NULL;
|
|
}
|
|
void *Hash_GetInsensativeBucket(hashtable_t *table, const char *name)
|
|
{
|
|
unsigned int bucknum = Hash_KeyInsensative(name, table->numbuckets);
|
|
bucket_t *buck;
|
|
|
|
buck = table->bucket[bucknum];
|
|
|
|
while(buck)
|
|
{
|
|
if (!stricmp(name, buck->key.string))
|
|
return buck;
|
|
|
|
buck = buck->next;
|
|
}
|
|
return NULL;
|
|
}
|
|
void *Hash_GetKey(hashtable_t *table, unsigned int key)
|
|
{
|
|
unsigned int bucknum = key%table->numbuckets;
|
|
bucket_t *buck;
|
|
|
|
buck = table->bucket[bucknum];
|
|
|
|
while(buck)
|
|
{
|
|
if (buck->key.value == key)
|
|
return buck->data;
|
|
|
|
buck = buck->next;
|
|
}
|
|
return NULL;
|
|
}
|
|
/*Does _NOT_ support items that are added with two names*/
|
|
void *Hash_GetNextKey(hashtable_t *table, unsigned int key, void *old)
|
|
{
|
|
unsigned int bucknum = key%table->numbuckets;
|
|
bucket_t *buck;
|
|
|
|
buck = table->bucket[bucknum];
|
|
|
|
while(buck)
|
|
{
|
|
if (buck->data == old) //found the old one
|
|
break;
|
|
buck = buck->next;
|
|
}
|
|
if (!buck)
|
|
return NULL;
|
|
|
|
buck = buck->next;//don't return old
|
|
while(buck)
|
|
{
|
|
if (buck->key.value == key)
|
|
return buck->data;
|
|
|
|
buck = buck->next;
|
|
}
|
|
return NULL;
|
|
}
|
|
/*Does _NOT_ support items that are added with two names*/
|
|
void *Hash_GetNext(hashtable_t *table, const char *name, void *old)
|
|
{
|
|
unsigned int bucknum = Hash_Key(name, table->numbuckets);
|
|
bucket_t *buck;
|
|
|
|
buck = table->bucket[bucknum];
|
|
|
|
while(buck)
|
|
{
|
|
if (buck->data == old) //found the old one
|
|
// if (!STRCMP(name, buck->key.string))
|
|
break;
|
|
buck = buck->next;
|
|
}
|
|
if (!buck)
|
|
return NULL;
|
|
|
|
buck = buck->next;//don't return old
|
|
while(buck)
|
|
{
|
|
if (!STRCMP(name, buck->key.string))
|
|
return buck->data;
|
|
|
|
buck = buck->next;
|
|
}
|
|
return NULL;
|
|
}
|
|
/*Does _NOT_ support items that are added with two names*/
|
|
void *Hash_GetNextInsensative(hashtable_t *table, const char *name, void *old)
|
|
{
|
|
unsigned int bucknum = Hash_KeyInsensative(name, table->numbuckets);
|
|
bucket_t *buck;
|
|
|
|
buck = table->bucket[bucknum];
|
|
|
|
while(buck)
|
|
{
|
|
if (buck->data == old) //found the old one
|
|
{
|
|
// if (!stricmp(name, buck->key.string))
|
|
break;
|
|
}
|
|
|
|
buck = buck->next;
|
|
}
|
|
if (!buck)
|
|
return NULL;
|
|
|
|
buck = buck->next;//don't return old
|
|
while(buck)
|
|
{
|
|
if (!stricmp(name, buck->key.string))
|
|
return buck->data;
|
|
|
|
buck = buck->next;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
void *Hash_Add(hashtable_t *table, const char *name, void *data, bucket_t *buck)
|
|
{
|
|
unsigned int bucknum = Hash_Key(name, table->numbuckets);
|
|
|
|
buck->data = data;
|
|
buck->key.string = name;
|
|
buck->next = table->bucket[bucknum];
|
|
table->bucket[bucknum] = buck;
|
|
|
|
return buck;
|
|
}
|
|
void *Hash_AddInsensative(hashtable_t *table, const char *name, void *data, bucket_t *buck)
|
|
{
|
|
unsigned int bucknum = Hash_KeyInsensative(name, table->numbuckets);
|
|
|
|
buck->data = data;
|
|
buck->key.string = name;
|
|
buck->next = table->bucket[bucknum];
|
|
table->bucket[bucknum] = buck;
|
|
|
|
return buck;
|
|
}
|
|
void *Hash_AddKey(hashtable_t *table, unsigned int key, void *data, bucket_t *buck)
|
|
{
|
|
unsigned int bucknum = key%table->numbuckets;
|
|
|
|
buck->data = data;
|
|
buck->key.value = key;
|
|
buck->next = table->bucket[bucknum];
|
|
table->bucket[bucknum] = buck;
|
|
|
|
return buck;
|
|
}
|
|
|
|
void Hash_Remove(hashtable_t *table, const char *name)
|
|
{
|
|
unsigned int bucknum = Hash_Key(name, table->numbuckets);
|
|
bucket_t *buck;
|
|
|
|
buck = table->bucket[bucknum];
|
|
|
|
if (!STRCMP(name, buck->key.string))
|
|
{
|
|
table->bucket[bucknum] = buck->next;
|
|
return;
|
|
}
|
|
|
|
|
|
while(buck->next)
|
|
{
|
|
if (!STRCMP(name, buck->next->key.string))
|
|
{
|
|
buck->next = buck->next->next;
|
|
return;
|
|
}
|
|
|
|
buck = buck->next;
|
|
}
|
|
return;
|
|
}
|
|
|
|
void Hash_RemoveData(hashtable_t *table, const char *name, void *data)
|
|
{
|
|
unsigned int bucknum = Hash_Key(name, table->numbuckets);
|
|
bucket_t **link, *buck;
|
|
|
|
for (link = &table->bucket[bucknum]; *link; link = &(*link)->next)
|
|
{
|
|
buck = *link;
|
|
if (buck->data == data && !stricmp(name, buck->key.string))
|
|
{
|
|
*link = buck->next;
|
|
return;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
void Hash_RemoveBucket(hashtable_t *table, const char *name, bucket_t *data)
|
|
{
|
|
unsigned int bucknum = Hash_Key(name, table->numbuckets);
|
|
bucket_t **link, *buck;
|
|
|
|
for (link = &table->bucket[bucknum]; *link; link = &(*link)->next)
|
|
{
|
|
buck = *link;
|
|
if (buck == data && !stricmp(name, buck->key.string))
|
|
{
|
|
*link = buck->next;
|
|
return;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
void Hash_RemoveKey(hashtable_t *table, unsigned int key)
|
|
{
|
|
unsigned int bucknum = key%table->numbuckets;
|
|
bucket_t *buck;
|
|
|
|
buck = table->bucket[bucknum];
|
|
|
|
if (buck->key.value == key)
|
|
{
|
|
table->bucket[bucknum] = buck->next;
|
|
return;
|
|
}
|
|
|
|
|
|
while(buck->next)
|
|
{
|
|
if (buck->next->key.value == key)
|
|
{
|
|
buck->next = buck->next->next;
|
|
return;
|
|
}
|
|
|
|
buck = buck->next;
|
|
}
|
|
return;
|
|
}
|