Commit 800864a0 authored by Eric Pouech's avatar Eric Pouech Committed by Alexandre Julliard

First shot at implementing dbghelp.

parent 7e301d8a
......@@ -1510,6 +1510,7 @@ dlls/d3d8/Makefile
dlls/d3d9/Makefile
dlls/d3dim/Makefile
dlls/d3dx8/Makefile
dlls/dbghelp/Makefile
dlls/dciman32/Makefile
dlls/ddraw/Makefile
dlls/ddraw/tests/Makefile
......
......@@ -31,6 +31,7 @@ BASEDIRS = \
crypt32 \
ctl3d \
d3dim \
dbghelp \
dciman32 \
devenum \
dinput \
......@@ -243,6 +244,7 @@ SYMLINKS_SO = \
crypt32.dll.so \
ctl3d32.dll.so \
d3dim.dll.so \
dbghelp.dll.so \
dciman32.dll.so \
devenum.dll.so \
dinput.dll.so \
......@@ -443,6 +445,9 @@ d3dim.dll.so: d3dim/d3dim.dll.so
d3dx8.dll.so: d3dx8/d3dx8.dll.so
$(RM) $@ && $(LN_S) d3dx8/d3dx8.dll.so $@
dbghelp.dll.so: dbghelp/dbghelp.dll.so
$(RM) $@ && $(LN_S) dbghelp/dbghelp.dll.so $@
dciman32.dll.so: dciman32/dciman32.dll.so
$(RM) $@ && $(LN_S) dciman32/dciman32.dll.so $@
......@@ -926,6 +931,7 @@ IMPORT_LIBS = \
libd3d9 \
libd3dim \
libd3dx8 \
libdbghelp \
libdciman32 \
libddraw \
libdevenum \
......@@ -1123,6 +1129,11 @@ libd3dx8.def: d3dx8/d3dx8.spec.def
libd3dx8.a: d3dx8/d3dx8.spec.def
$(DLLTOOL) -k -l $@ -d d3dx8/d3dx8.spec.def
libdbghelp.def: dbghelp/dbghelp.spec.def
$(RM) $@ && $(LN_S) dbghelp/dbghelp.spec.def $@
libdbghelp.a: dbghelp/dbghelp.spec.def
$(DLLTOOL) -k -l $@ -d dbghelp/dbghelp.spec.def
libdciman32.def: dciman32/dciman32.spec.def
$(RM) $@ && $(LN_S) dciman32/dciman32.spec.def $@
libdciman32.a: dciman32/dciman32.spec.def
......@@ -1626,6 +1637,7 @@ d3d8/d3d8.spec.def: $(WINEBUILD)
d3d9/d3d9.spec.def: $(WINEBUILD)
d3dim/d3dim.spec.def: $(WINEBUILD)
d3dx8/d3dx8.spec.def: $(WINEBUILD)
dbghelp/dbghelp.spec.def: $(WINEBUILD)
dciman32/dciman32.spec.def: $(WINEBUILD)
ddraw/ddraw.spec.def: $(WINEBUILD)
devenum/devenum.spec.def: $(WINEBUILD)
......@@ -1747,6 +1759,7 @@ d3d8/d3d8.dll.so: d3d8
d3d9/d3d9.dll.so: d3d9
d3dim/d3dim.dll.so: d3dim
d3dx8/d3dx8.dll.so: d3dx8
dbghelp/dbghelp.dll.so: dbghelp
dciman32/dciman32.dll.so: dciman32
ddraw/ddraw.dll.so: ddraw
devenum/devenum.dll.so: devenum
......
Makefile
dbghelp.dll.dbg.c
dbghelp.spec.def
TOPSRCDIR = @top_srcdir@
TOPOBJDIR = ../..
SRCDIR = @srcdir@
VPATH = @srcdir@
MODULE = dbghelp.dll
IMPORTS = psapi kernel32 ntdll
C_SRCS = \
dbghelp.c \
elf_module.c \
image.c \
memory.c \
minidump.c \
module.c \
msc.c \
path.c \
pe_module.c \
source.c \
stabs.c \
stack.c \
storage.c \
symbol.c \
type.c
@MAKE_DLL_RULES@
### Dependencies:
@ stub DbgHelpCreateUserDump
@ stub DbgHelpCreateUserDumpW
@ stdcall EnumerateLoadedModules(long ptr ptr)
@ stub EnumerateLoadedModules64
@ stub ExtensionApiVersion
@ stdcall FindDebugInfoFile(str str ptr)
@ stdcall FindDebugInfoFileEx(str str ptr ptr ptr)
@ stdcall FindExecutableImage(str str str)
@ stub FindExecutableImageEx
@ stub FindFileInPath
@ stub FindFileInSearchPath
@ stdcall GetTimestampForLoadedLibrary(long)
@ stub ImageDirectoryEntryToData
@ stub ImageDirectoryEntryToDataEx
@ stdcall ImageNtHeader(ptr) ntdll.RtlImageNtHeader
@ stdcall ImageRvaToSection(ptr ptr long) ntdll.RtlImageRvaToSection
@ stdcall ImageRvaToVa(ptr ptr long ptr) ntdll.RtlImageRvaToVa
@ stdcall ImagehlpApiVersion()
@ stdcall ImagehlpApiVersionEx(ptr)
@ stdcall MakeSureDirectoryPathExists(str)
@ stdcall MapDebugInformation(long str str long)
@ stub MiniDumpReadDumpStream
@ stub MiniDumpWriteDump
@ stdcall SearchTreeForFile(str str str)
@ stdcall StackWalk(long long long ptr ptr ptr ptr ptr ptr)
@ stub StackWalk64
@ stdcall SymCleanup(long)
@ stdcall SymEnumSourceFiles(long long str ptr ptr)
@ stub SymEnumSym
@ stdcall SymEnumSymbols(long long str ptr ptr)
@ stdcall SymEnumTypes(long long ptr ptr)
@ stdcall SymEnumerateModules(long ptr ptr)
@ stub SymEnumerateModules64
@ stdcall SymEnumerateSymbols(long long ptr ptr)
@ stub SymEnumerateSymbols64
@ stub SymEnumerateSymbolsW
@ stub SymEnumerateSymbolsW64
@ stub SymFindFileInPath
@ stdcall SymFromAddr(long long ptr ptr)
@ stdcall SymFromName(long str ptr)
@ stdcall SymFunctionTableAccess(long long)
@ stub SymFunctionTableAccess64
@ stub SymGetFileLineOffsets64
@ stdcall SymGetLineFromAddr(long long ptr ptr)
@ stub SymGetLineFromAddr64
@ stub SymGetLineFromName
@ stub SymGetLineFromName64
@ stdcall SymGetLineNext(long ptr)
@ stub SymGetLineNext64
@ stdcall SymGetLinePrev(long ptr)
@ stub SymGetLinePrev64
@ stdcall SymGetModuleBase(long long)
@ stub SymGetModuleBase64
@ stdcall SymGetModuleInfo(long long ptr)
@ stub SymGetModuleInfo64
@ stub SymGetModuleInfoW
@ stub SymGetModuleInfoW64
@ stdcall SymGetOptions()
@ stdcall SymGetSearchPath(long str long)
@ stdcall SymGetSymFromAddr(long long ptr ptr)
@ stub SymGetSymFromAddr64
@ stdcall SymGetSymFromName(long str ptr)
@ stub SymGetSymFromName64
@ stdcall SymGetSymNext(long ptr)
@ stub SymGetSymNext64
@ stdcall SymGetSymPrev(long ptr)
@ stub SymGetSymPrev64
@ stdcall SymGetTypeFromName(long long str ptr)
@ stdcall SymGetTypeInfo(long long long long ptr)
@ stdcall SymInitialize(long str long)
@ stdcall SymLoadModule(long long str str long long)
@ stub SymLoadModule64
@ stub SymLoadModuleEx
@ stub SymMatchFileName
@ stub SymMatchString
@ stdcall SymRegisterCallback(long ptr ptr)
@ stub SymRegisterCallback64
@ stub SymRegisterFunctionEntryCallback
@ stub SymRegisterFunctionEntryCallback64
@ stdcall SymSetContext(long ptr ptr)
@ stdcall SymSetOptions(long)
@ stdcall SymSetSearchPath(long str)
@ stub SymSetSymWithAddr64
@ stdcall SymUnDName(ptr str long)
@ stub SymUnDName64
@ stdcall SymUnloadModule(long long)
@ stub SymUnloadModule64
@ stdcall UnDecorateSymbolName(str str long long)
@ stdcall UnmapDebugInformation(ptr)
@ stub WinDbgExtensionDllInit
#@ stub dbghelp
#@ stub dh
#@ stub lm
#@ stub lmi
#@ stub omap
#@ stub srcfiles
#@ stub sym
#@ stub vc7fpo
/*
* File image.c - managing images
*
* Copyright (C) 2004, Eric Pouech
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "dbghelp_private.h"
#include "winreg.h"
#include "winternl.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
/***********************************************************************
* GetTimestampForLoadedLibrary (DBGHELP.@)
*/
DWORD WINAPI GetTimestampForLoadedLibrary(HMODULE Module)
{
IMAGE_NT_HEADERS* nth = RtlImageNtHeader(Module);
return (nth) ? nth->FileHeader.TimeDateStamp : 0;
}
/***********************************************************************
* MapDebugInformation (DBGHELP.@)
*/
PIMAGE_DEBUG_INFORMATION WINAPI MapDebugInformation(HANDLE FileHandle, LPSTR FileName,
LPSTR SymbolPath, DWORD ImageBase)
{
FIXME("(%p, %s, %s, 0x%08lx): stub\n", FileHandle, FileName, SymbolPath, ImageBase);
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return NULL;
}
/***********************************************************************
* UnmapDebugInformation (DBGHELP.@)
*/
BOOL WINAPI UnmapDebugInformation(PIMAGE_DEBUG_INFORMATION DebugInfo)
{
FIXME("(%p): stub\n", DebugInfo);
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
/*
* File memory.c - managing memory
*
* Copyright (C) 2004, Eric Pouech
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include <assert.h>
#include "dbghelp_private.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
BOOL win32_read_mem(HANDLE hProcess, DWORD addr, void* buf, DWORD len)
{
return ReadProcessMemory(hProcess, (void*)addr, buf, len, NULL);
}
BOOL win32_write_mem(HANDLE hProcess, DWORD addr, void* buf, DWORD len)
{
return WriteProcessMemory(hProcess, (void*)addr, buf, len, NULL);
}
/* standard routines for reading / writing memory. Can be overriden for some
* minidump usage
*/
struct memory_access mem_access = {win32_read_mem, win32_write_mem};
/******************************************************************
* addr_to_linear
*
* converts an address into its linear value
*/
unsigned long WINAPI addr_to_linear(HANDLE hProcess, HANDLE hThread, ADDRESS* addr)
{
LDT_ENTRY le;
switch (addr->Mode)
{
case AddrMode1616:
if (GetThreadSelectorEntry(hThread, addr->Segment, &le))
return (le.HighWord.Bits.BaseHi << 24) +
(le.HighWord.Bits.BaseMid << 16) + le.BaseLow + LOWORD(addr->Offset);
break;
case AddrMode1632:
if (GetThreadSelectorEntry(hThread, addr->Segment, &le))
return (le.HighWord.Bits.BaseHi << 24) +
(le.HighWord.Bits.BaseMid << 16) + le.BaseLow + addr->Offset;
break;
case AddrModeReal:
return (DWORD)(LOWORD(addr->Segment) << 4) + addr->Offset;
case AddrModeFlat:
return addr->Offset;
default:
FIXME("Unsupported (yet) mode (%x)\n", addr->Mode);
return 0;
}
FIXME("Failed to linearize address %04x:%08lx (mode %x)\n",
addr->Segment, addr->Offset, addr->Mode);
return 0;
}
/*
* File path.c - managing path in debugging environments
*
* Copyright (C) 2004, Eric Pouech
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "dbghelp_private.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
/******************************************************************
* FindDebugInfoFile (DBGHELP.@)
*
*/
HANDLE WINAPI FindDebugInfoFile(PSTR FileName, PSTR SymbolPath, PSTR DebugFilePath)
{
HANDLE h;
h = CreateFileA(DebugFilePath, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (h == INVALID_HANDLE_VALUE)
{
const char* p = strrchr(FileName, '/');
if (!p) p = FileName;
if (!SearchPathA(SymbolPath, p, NULL, MAX_PATH, DebugFilePath, NULL))
return NULL;
h = CreateFileA(DebugFilePath, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
}
return (h == INVALID_HANDLE_VALUE) ? NULL : h;
}
/******************************************************************
* FindDebugInfoFileEx (DBGHELP.@)
*
*/
HANDLE WINAPI FindDebugInfoFileEx(PSTR FileName, PSTR SymbolPath,
PSTR DebugFilePath,
PFIND_DEBUG_FILE_CALLBACK Callback,
PVOID CallerData)
{
FIXME("(%s %s %p %p %p): stub\n",
FileName, SymbolPath, DebugFilePath, Callback, CallerData);
return NULL;
}
/******************************************************************
* FindExecutableImage (DBGHELP.@)
*
*/
HANDLE WINAPI FindExecutableImage(PSTR FileName, PSTR SymbolPath, PSTR ImageFilePath)
{
HANDLE h;
if (!SearchPathA(SymbolPath, FileName, NULL, MAX_PATH, ImageFilePath, NULL))
return NULL;
h = CreateFileA(ImageFilePath, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
return (h == INVALID_HANDLE_VALUE) ? NULL : h;
}
/***********************************************************************
* MakeSureDirectoryPathExists (DBGHELP.@)
*/
BOOL WINAPI MakeSureDirectoryPathExists(LPCSTR DirPath)
{
if (CreateDirectoryA(DirPath, NULL)) return TRUE;
if (GetLastError() == ERROR_ALREADY_EXISTS)
{
SetLastError(ERROR_SUCCESS);
return TRUE;
}
return FALSE;
}
/***********************************************************************
* SearchTreeForFile (DBGHELP.@)
*/
BOOL WINAPI SearchTreeForFile(LPSTR RootPath, LPSTR InputPathName,
LPSTR OutputPathBuffer)
{
FIXME("(%s, %s, %s): stub\n",
debugstr_a(RootPath), debugstr_a(InputPathName),
debugstr_a(OutputPathBuffer));
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
/*
* File source.c - source files management
*
* Copyright (C) 2004, Eric Pouech.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "dbghelp_private.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
/******************************************************************
* source_find
*
* check whether a source file has already been stored
*/
static unsigned source_find(const struct module* module, const char* name)
{
char* ptr = module->sources;
while (*ptr)
{
if (strcmp(ptr, name) == 0) return ptr - module->sources;
ptr += strlen(ptr) + 1;
}
return (unsigned)-1;
}
/******************************************************************
* source_new
*
* checks if source exists. if not, add it
*/
unsigned source_new(struct module* module, const char* name)
{
int len;
unsigned ret;
if (!name) return (unsigned)-1;
if (module->sources && (ret = source_find(module, name)) != (unsigned)-1)
return ret;
len = strlen(name) + 1;
if (module->sources_used + len + 1 > module->sources_alloc)
{
/* Alloc by block of 256 bytes */
module->sources_alloc = (module->sources_used + len + 1 + 255) & ~255;
if (!module->sources)
module->sources = HeapAlloc(GetProcessHeap(), 0, module->sources_alloc);
else
module->sources = HeapReAlloc(GetProcessHeap(), 0, module->sources,
module->sources_alloc);
}
ret = module->sources_used;
strcpy(module->sources + module->sources_used, name);
module->sources_used += len;
module->sources[module->sources_used] = '\0';
return ret;
}
/******************************************************************
* source_get
*
* returns a stored source file name
*/
const char* source_get(const struct module* module, unsigned idx)
{
if (idx == -1) return "";
assert(module->sources);
return module->sources + idx;
}
/******************************************************************
* SymEnumSourceFiles (DBGHELP.@)
*
*/
BOOL WINAPI SymEnumSourceFiles(HANDLE hProcess, ULONG ModBase, LPSTR Mask,
PSYM_ENUMSOURCFILES_CALLBACK cbSrcFiles,
void* UserContext)
{
struct process* pcs;
struct module* module;
SOURCEFILE sf;
char* ptr;
if (!cbSrcFiles) return FALSE;
pcs = process_find_by_handle(hProcess);
if (!pcs) return FALSE;
if (ModBase)
{
module = module_find_by_addr(pcs, ModBase, DMT_UNKNOWN);
if (!(module = module_get_debug(pcs, module))) return FALSE;
}
else
{
if (Mask[0] == '!')
{
module = module_find_by_name(pcs, Mask + 1, DMT_UNKNOWN);
if (!(module = module_get_debug(pcs, module))) return FALSE;
}
else
{
FIXME("Unsupported yet (should get info from current context)\n");
return FALSE;
}
}
if (!module->sources) return FALSE;
for (ptr = module->sources; *ptr; ptr += strlen(ptr) + 1)
{
/* FIXME: not using Mask */
sf.ModBase = ModBase;
sf.FileName = ptr;
if (!cbSrcFiles(&sf, UserContext)) break;
}
return TRUE;
}
/*
* Various storage structures (pool allocation, vector, hash table)
*
* Copyright (C) 1993, Eric Youngdale.
* 2004, Eric Pouech
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include <assert.h>
#include <stdlib.h>
#include "wine/debug.h"
#include "dbghelp_private.h"
#ifdef USE_STATS
#include <math.h>
#endif
WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
struct pool_arena
{
struct pool_arena* next;
char* current;
};
void pool_init(struct pool* a, unsigned arena_size)
{
a->arena_size = arena_size;
a->first = NULL;
}
void pool_destroy(struct pool* pool)
{
struct pool_arena* arena;
struct pool_arena* next;
#ifdef USE_STATS
unsigned alloc, used, num;
for (alloc = used = num = 0, arena = pool->first; arena; arena = arena->next)
{
alloc += pool->arena_size;
used += arena->current - (char*)arena;
num++;
}
FIXME("STATS: pool %p has allocated %u kbytes, used %u kbytes in %u arenas,\n"
"\t\t\t\tnon-allocation ratio: %.2f%%\n",
pool, alloc >> 10, used >> 10, num, 100.0 - (float)used / (float)alloc * 100.0);
#endif
for (arena = pool->first; arena; arena = next)
{
next = arena->next;
HeapFree(GetProcessHeap(), 0, arena);
}
pool_init(pool, 0);
}
void* pool_alloc(struct pool* pool, unsigned len)
{
struct pool_arena** parena;
struct pool_arena* arena;
void* ret;
len = (len + 3) & ~3; /* round up size on DWORD boundary */
assert(sizeof(struct pool_arena) + len <= pool->arena_size && len);
for (parena = &pool->first; *parena; parena = &(*parena)->next)
{
if ((char*)(*parena) + pool->arena_size - (*parena)->current >= len)
{
ret = (*parena)->current;
(*parena)->current += len;
return ret;
}
}
arena = HeapAlloc(GetProcessHeap(), 0, pool->arena_size);
if (!arena) {FIXME("OOM\n");return NULL;}
*parena = arena;
ret = (char*)arena + sizeof(*arena);
arena->next = NULL;
arena->current = (char*)ret + len;
return ret;
}
static struct pool_arena* pool_is_last(struct pool* pool, void* p, unsigned old_size)
{
struct pool_arena* arena;
for (arena = pool->first; arena; arena = arena->next)
{
if (arena->current == (char*)p + old_size) return arena;
}
return NULL;
}
void* pool_realloc(struct pool* pool, void* p, unsigned old_size, unsigned new_size)
{
struct pool_arena* arena;
void* new;
if ((arena = pool_is_last(pool, p, old_size)) &&
(char*)p + new_size <= (char*)arena + pool->arena_size)
{
arena->current = (char*)p + new_size;
return p;
}
if ((new = pool_alloc(pool, new_size)) && old_size)
memcpy(new, p, min(old_size, new_size));
return new;
}
char* pool_strdup(struct pool* pool, const char* str)
{
char* ret;
if ((ret = pool_alloc(pool, strlen(str) + 1))) strcpy(ret, str);
return ret;
}
void vector_init(struct vector* v, unsigned esz, unsigned bucket_sz)
{
v->buckets = NULL;
/* align size on DWORD boundaries */
v->elt_size = (esz + 3) & ~3;
switch (bucket_sz)
{
case 2: v->shift = 1; break;
case 4: v->shift = 2; break;
case 8: v->shift = 3; break;
case 16: v->shift = 4; break;
case 32: v->shift = 5; break;
case 64: v->shift = 6; break;
case 128: v->shift = 7; break;
case 256: v->shift = 8; break;
case 512: v->shift = 9; break;
case 1024: v->shift = 10; break;
default: assert(0);
}
v->num_buckets = 0;
v->num_elts = 0;
}
unsigned vector_length(const struct vector* v)
{
return v->num_elts;
}
void* vector_at(const struct vector* v, unsigned pos)
{
unsigned o;
if (pos >= v->num_elts) return NULL;
o = pos & ((1 << v->shift) - 1);
return (char*)v->buckets[pos >> v->shift] + o * v->elt_size;
}
void* vector_add(struct vector* v, struct pool* pool)
{
unsigned ncurr = v->num_elts++;
/* check that we don't wrap around */
assert(v->num_elts > ncurr);
if (ncurr == (v->num_buckets << v->shift))
{
v->buckets = pool_realloc(pool, v->buckets,
v->num_buckets * sizeof(void*),
(v->num_buckets + 1) * sizeof(void*));
v->buckets[v->num_buckets] = pool_alloc(pool, v->elt_size << v->shift);
return v->buckets[v->num_buckets++];
}
return vector_at(v, ncurr);
}
static unsigned vector_position(const struct vector* v, const void* elt)
{
int i;
for (i = 0; i < v->num_buckets; i++)
{
if (v->buckets[i] <= elt &&
(const char*)elt < (const char*)v->buckets[i] + (v->elt_size << v->shift))
{
return (i << v->shift) +
((const char*)elt - (const char*)v->buckets[i]) / v->elt_size;
}
}
assert(0);
}
void* vector_iter_up(const struct vector* v, void* elt)
{
unsigned pos;
if (!elt) return vector_at(v, 0);
pos = vector_position(v, elt) + 1;
if (pos >= vector_length(v)) return NULL;
return vector_at(v, pos);
}
void* vector_iter_down(const struct vector* v, void* elt)
{
unsigned pos;
if (!elt) return vector_at(v, vector_length(v) - 1);
pos = vector_position(v, elt);
if (pos == 0) return NULL;
return vector_at(v, pos - 1);
}
unsigned hash_table_hash(const char* name, unsigned num_buckets)
{
unsigned hash = 0;
while (*name)
{
hash += *name++;
hash += (hash << 10);
hash ^= (hash >> 6);
}
hash += (hash << 3);
hash ^= (hash >> 11);
hash += (hash << 15);
return hash % num_buckets;
}
void hash_table_init(struct pool* pool, struct hash_table* ht, unsigned num_buckets)
{
ht->buckets = pool_alloc(pool, num_buckets * sizeof(struct hash_table_elt*));
assert(ht->buckets);
ht->num_buckets = num_buckets;
memset(ht->buckets, 0, num_buckets * sizeof(struct hash_table_elt*));
}
void hash_table_destroy(struct hash_table* ht)
{
#if defined(USE_STATS)
int i;
unsigned len;
unsigned num = 0, min = 0xffffffff, max = 0, sq = 0;
struct hash_table_elt* elt;
double mean, variance;
for (i = 0; i < ht->num_buckets; i++)
{
for (len = 0, elt = ht->buckets[i]; elt; elt = elt->next) len++;
if (len < min) min = len;
if (len > max) max = len;
num += len;
sq += len * len;
}
mean = (double)num / ht->num_buckets;
variance = (double)sq / ht->num_buckets - mean * mean;
FIXME("STATS: elts[num:%-4u size:%u mean:%f] buckets[min:%-4u variance:%+f max:%-4u]\n",
num, ht->num_buckets, mean, min, variance, max);
#if 1
for (i = 0; i < ht->num_buckets; i++)
{
for (len = 0, elt = ht->buckets[i]; elt; elt = elt->next) len++;
if (len == max)
{
FIXME("Longuest bucket:\n");
for (elt = ht->buckets[i]; elt; elt = elt->next)
FIXME("\t%s\n", elt->name);
break;
}
}
#endif
#endif
}
void hash_table_add(struct hash_table* ht, struct hash_table_elt* elt)
{
unsigned hash = hash_table_hash(elt->name, ht->num_buckets);
elt->next = ht->buckets[hash];
ht->buckets[hash] = elt;
}
void* hash_table_find(const struct hash_table* ht, const char* name)
{
unsigned hash = hash_table_hash(name, ht->num_buckets);
struct hash_table_elt* elt;
for (elt = ht->buckets[hash]; elt; elt = elt->next)
if (!strcmp(name, elt->name)) return elt;
return NULL;
}
void hash_table_iter_init(const struct hash_table* ht,
struct hash_table_iter* hti, const char* name)
{
hti->ht = ht;
if (name)
{
hti->last = hash_table_hash(name, ht->num_buckets);
hti->index = hti->last - 1;
}
else
{
hti->last = ht->num_buckets - 1;
hti->index = -1;
}
hti->element = NULL;
}
void* hash_table_iter_up(struct hash_table_iter* hti)
{
if (hti->element) hti->element = hti->element->next;
while (!hti->element && hti->index < hti->last)
hti->element = hti->ht->buckets[++hti->index];
return hti->element;
}
......@@ -44,6 +44,7 @@ WINDOWS_INCLUDES = \
control.h \
cpl.h \
custcntl.h \
cvconst.h \
d3d.h \
d3d8.h \
d3d8caps.h \
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment