mirror of
https://github.com/nzp-team/fteqw.git
synced 2024-11-29 23:22:01 +00:00
8d09710ed1
added 'pkg' console command. will still need more tweaking. r_renderscale < 0 means nearest filtering (may need a vid_restart for that to take effect though). fteqccgui: added 'make installer' options. fteqcc: fix framemacro issue that was breaking due to invalid dupes in hipnotic's code cl_lerp_smooth: by default now enabled for singleplayer as well as just demos. this smooths out platforms etc. q2 demos: explicitly recognise .dm2 extension, to try to avoid issues. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5024 fc73d0e0-1445-4013-8a0c-d673dee63da5
376 lines
7.2 KiB
C
376 lines
7.2 KiB
C
#if _MSC_VER >= 1300
|
|
#ifndef _CRT_SECURE_NO_WARNINGS
|
|
#define _CRT_SECURE_NO_WARNINGS
|
|
#endif
|
|
#ifndef _CRT_NONSTDC_NO_WARNINGS
|
|
#define _CRT_NONSTDC_NO_WARNINGS
|
|
#endif
|
|
#endif
|
|
|
|
#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_KeyInsensitive(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_GetInsensitive(hashtable_t *table, const char *name)
|
|
{
|
|
unsigned int bucknum = Hash_KeyInsensitive(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_GetInsensitiveBucket(hashtable_t *table, const char *name)
|
|
{
|
|
unsigned int bucknum = Hash_KeyInsensitive(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_GetNextInsensitive(hashtable_t *table, const char *name, void *old)
|
|
{
|
|
unsigned int bucknum = Hash_KeyInsensitive(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_AddInsensitive(hashtable_t *table, const char *name, void *data, bucket_t *buck)
|
|
{
|
|
unsigned int bucknum = Hash_KeyInsensitive(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_RemoveDataInsensitive(hashtable_t *table, const char *name, void *data)
|
|
{
|
|
unsigned int bucknum = Hash_KeyInsensitive(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;
|
|
}
|
|
}
|
|
}
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
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;
|
|
}
|