- massive overhaul of lib error code returning. int -> LibError everywhere.

- add translators from errno and GetLastError to LibError
- clarified return values of callbacks (they must return
INFO_CB_CONTINUE to continue)
- this exposed a few bugs in error handling chains (returning incorrect
values); also reduced say-nothing instances of return -1.
- move CHECK_ERR etc. macros to lib_error

This was SVN commit r3229.
This commit is contained in:
janwas 2005-12-11 22:23:55 +00:00
parent 78cc73481c
commit 1c1200a049
80 changed files with 1714 additions and 1557 deletions

View File

@ -42,7 +42,7 @@ static size_t round_up_to_page(size_t size)
// stored in da->prot to reduce size; doesn't conflict with any PROT_* flags.
const int DA_NOT_OUR_MEM = 0x40000000;
static int validate_da(DynArray* da)
static LibError validate_da(DynArray* da)
{
if(!da)
return ERR_INVALID_PARAM;
@ -53,19 +53,19 @@ static int validate_da(DynArray* da)
const int prot = da->prot;
if(debug_is_pointer_bogus(base))
return -1;
return ERR_1;
if(!is_page_multiple((uintptr_t)base))
return -2;
return ERR_2;
if(!is_page_multiple(max_size_pa))
return -3;
return ERR_3;
if(cur_size > max_size_pa)
return -4;
return ERR_4;
if(pos > cur_size || pos > max_size_pa)
return -5;
return ERR_5;
if(prot & ~(PROT_READ|PROT_WRITE|PROT_EXEC|DA_NOT_OUR_MEM))
return -6;
return ERR_6;
return 0;
return ERR_OK;
}
#define CHECK_DA(da) CHECK_ERR(validate_da(da))
@ -75,42 +75,52 @@ static int validate_da(DynArray* da)
// very thin wrapper on top of sys/mman.h that makes the intent more obvious
// (its commit/decommit semantics are difficult to tell apart).
static inline LibError LibError_from_mmap(void* ret)
{
if(ret != MAP_FAILED)
return ERR_OK;
return LibError_from_errno();
}
static const int mmap_flags = MAP_PRIVATE|MAP_ANONYMOUS;
static int mem_reserve(size_t size, u8** pp)
static LibError mem_reserve(size_t size, u8** pp)
{
errno = 0;
void* ret = mmap(0, size, PROT_NONE, mmap_flags|MAP_NORESERVE, -1, 0);
if(ret == MAP_FAILED)
return ERR_NO_MEM;
*pp = (u8*)ret;
return 0;
return LibError_from_mmap(ret);
}
static int mem_release(u8* p, size_t size)
static LibError mem_release(u8* p, size_t size)
{
return munmap(p, size);
errno = 0;
return LibError_from_posix(munmap(p, size));
}
static int mem_commit(u8* p, size_t size, int prot)
static LibError mem_commit(u8* p, size_t size, int prot)
{
if(prot == PROT_NONE)
{
debug_warn("mem_commit: prot=PROT_NONE isn't allowed (misinterpreted by mmap)");
return ERR_INVALID_PARAM;
}
errno = 0;
void* ret = mmap(p, size, prot, mmap_flags|MAP_FIXED, -1, 0);
return (ret == MAP_FAILED)? -1 : 0;
return LibError_from_mmap(ret);
}
static int mem_decommit(u8* p, size_t size)
static LibError mem_decommit(u8* p, size_t size)
{
errno = 0;
void* ret = mmap(p, size, PROT_NONE, mmap_flags|MAP_NORESERVE|MAP_FIXED, -1, 0);
return (ret == MAP_FAILED)? -1 : 0;
return LibError_from_mmap(ret);
}
static int mem_protect(u8* p, size_t size, int prot)
static LibError mem_protect(u8* p, size_t size, int prot)
{
return mprotect(p, size, prot);
errno = 0;
return LibError_from_posix(mprotect(p, size, prot));
}
@ -121,7 +131,7 @@ static int mem_protect(u8* p, size_t size, int prot)
// (rounded up to the next page size multiple) of address space for the
// array; it can never grow beyond this.
// no virtual memory is actually committed until calls to da_set_size.
int da_alloc(DynArray* da, size_t max_size)
LibError da_alloc(DynArray* da, size_t max_size)
{
const size_t max_size_pa = round_up_to_page(max_size);
@ -134,7 +144,7 @@ int da_alloc(DynArray* da, size_t max_size)
da->prot = PROT_READ|PROT_WRITE;
da->pos = 0;
CHECK_DA(da);
return 0;
return ERR_OK;
}
@ -142,7 +152,7 @@ int da_alloc(DynArray* da, size_t max_size)
// DynArray object, preparing it for use with da_read or da_append.
// da_free should be called when the DynArray is no longer needed,
// even though it doesn't free this memory (but does zero the DynArray).
int da_wrap_fixed(DynArray* da, u8* p, size_t size)
LibError da_wrap_fixed(DynArray* da, u8* p, size_t size)
{
da->base = p;
da->max_size_pa = round_up_to_page(size);
@ -150,14 +160,14 @@ int da_wrap_fixed(DynArray* da, u8* p, size_t size)
da->prot = PROT_READ|PROT_WRITE|DA_NOT_OUR_MEM;
da->pos = 0;
CHECK_DA(da);
return 0;
return ERR_OK;
}
// free all memory (address space + physical) that constitutes the
// given array. use-after-free is impossible because the memory is
// marked not-present via MMU. also zeroes the contents of <da>.
int da_free(DynArray* da)
LibError da_free(DynArray* da)
{
CHECK_DA(da);
@ -174,21 +184,21 @@ int da_free(DynArray* da)
// da_free is supposed to be called even in the above case.
if(!was_wrapped)
CHECK_ERR(mem_release(p, size));
return 0;
return ERR_OK;
}
// expand or shrink the array: changes the amount of currently committed
// (i.e. usable) memory pages. pages are added/removed until
// new_size (rounded up to the next page size multiple) is met.
int da_set_size(DynArray* da, size_t new_size)
LibError da_set_size(DynArray* da, size_t new_size)
{
CHECK_DA(da);
if(da->prot & DA_NOT_OUR_MEM)
{
debug_warn("da is marked DA_NOT_OUR_MEM, must not be altered");
return -1;
return ERR_LOGIC;
}
// determine how much to add/remove
@ -210,7 +220,7 @@ int da_set_size(DynArray* da, size_t new_size)
da->cur_size = new_size;
CHECK_DA(da);
return 0;
return ERR_OK;
}
@ -218,7 +228,7 @@ int da_set_size(DynArray* da, size_t new_size)
// write-protection. affects the currently committed pages as well as
// all subsequently added pages.
// prot can be a combination of the PROT_* values used with mprotect.
int da_set_prot(DynArray* da, int prot)
LibError da_set_prot(DynArray* da, int prot)
{
CHECK_DA(da);
@ -227,39 +237,39 @@ int da_set_prot(DynArray* da, int prot)
if(da->prot & DA_NOT_OUR_MEM)
{
debug_warn("da is marked DA_NOT_OUR_MEM, must not be altered");
return -1;
return ERR_LOGIC;
}
da->prot = prot;
CHECK_ERR(mem_protect(da->base, da->cur_size, prot));
CHECK_DA(da);
return 0;
return ERR_OK;
}
// "read" from array, i.e. copy into the given buffer.
// starts at offset DynArray.pos and advances this.
int da_read(DynArray* da, void* data, size_t size)
LibError da_read(DynArray* da, void* data, size_t size)
{
// make sure we have enough data to read
if(da->pos+size > da->cur_size)
return -1;
return ERR_EOF;
memcpy2(data, da->base+da->pos, size);
da->pos += size;
return 0;
return ERR_OK;
}
// "write" to array, i.e. copy from the given buffer.
// starts at offset DynArray.pos and advances this.
int da_append(DynArray* da, const void* data, size_t size)
LibError da_append(DynArray* da, const void* data, size_t size)
{
RETURN_ERR(da_set_size(da, da->pos+size));
memcpy2(da->base+da->pos, data, size);
da->pos += size;
return 0;
return ERR_OK;
}
@ -304,7 +314,7 @@ static const size_t POOL_CHUNK = 4*KiB;
//
// note: el_size must at least be enough for a pointer (due to freelist
// implementation) but not exceed the expand-by amount.
int pool_create(Pool* p, size_t max_size, size_t el_size)
LibError pool_create(Pool* p, size_t max_size, size_t el_size)
{
if(el_size < sizeof(void*) || el_size > POOL_CHUNK)
CHECK_ERR(ERR_INVALID_PARAM);
@ -312,14 +322,14 @@ int pool_create(Pool* p, size_t max_size, size_t el_size)
RETURN_ERR(da_alloc(&p->da, max_size));
p->pos = 0;
p->el_size = el_size;
return 0;
return ERR_OK;
}
// free all memory that ensued from <p>. all elements are made unusable
// (it doesn't matter if they were "allocated" or in freelist or unused);
// future alloc and free calls on this pool will fail.
int pool_destroy(Pool* p)
LibError pool_destroy(Pool* p)
{
// don't be picky and complain if the freelist isn't empty;
// we don't care since it's all part of the da anyway.
@ -342,7 +352,8 @@ bool pool_contains(Pool* p, void* el)
}
// return an entry from the pool, or 0 if it cannot be expanded as necessary.
// return an entry from the pool, or 0 if it would have to be expanded and
// there isn't enough memory to do so.
// exhausts the freelist before returning new entries to improve locality.
void* pool_alloc(Pool* p)
{

View File

@ -45,37 +45,37 @@ struct DynArray
// (rounded up to the next page size multiple) of address space for the
// array; it can never grow beyond this.
// no virtual memory is actually committed until calls to da_set_size.
extern int da_alloc(DynArray* da, size_t max_size);
extern LibError da_alloc(DynArray* da, size_t max_size);
// free all memory (address space + physical) that constitutes the
// given array. use-after-free is impossible because the memory is
// marked not-present via MMU. also zeroes the contents of <da>.
extern int da_free(DynArray* da);
extern LibError da_free(DynArray* da);
// expand or shrink the array: changes the amount of currently committed
// (i.e. usable) memory pages. pages are added/removed until
// new_size (rounded up to the next page size multiple) is met.
extern int da_set_size(DynArray* da, size_t new_size);
extern LibError da_set_size(DynArray* da, size_t new_size);
// change access rights of the array memory; used to implement
// write-protection. affects the currently committed pages as well as
// all subsequently added pages.
// prot can be a combination of the PROT_* values used with mprotect.
extern int da_set_prot(DynArray* da, int prot);
extern LibError da_set_prot(DynArray* da, int prot);
// "wrap" (i.e. store information about) the given buffer in a
// DynArray object, preparing it for use with da_read or da_append.
// da_free should be called when the DynArray is no longer needed,
// even though it doesn't free this memory (but does zero the DynArray).
extern int da_wrap_fixed(DynArray* da, u8* p, size_t size);
extern LibError da_wrap_fixed(DynArray* da, u8* p, size_t size);
// "read" from array, i.e. copy into the given buffer.
// starts at offset DynArray.pos and advances this.
extern int da_read(DynArray* da, void* data_dst, size_t size);
extern LibError da_read(DynArray* da, void* data_dst, size_t size);
// "write" to array, i.e. copy from the given buffer.
// starts at offset DynArray.pos and advances this.
extern int da_append(DynArray* da, const void* data_src, size_t size);
extern LibError da_append(DynArray* da, const void* data_src, size_t size);
@ -108,18 +108,19 @@ struct Pool
//
// note: el_size must at least be enough for a pointer (due to freelist
// implementation) but not exceed the expand-by amount.
extern int pool_create(Pool* p, size_t max_size, size_t el_size);
extern LibError pool_create(Pool* p, size_t max_size, size_t el_size);
// free all memory that ensued from <p>. all elements are made unusable
// (it doesn't matter if they were "allocated" or in freelist or unused);
// future alloc and free calls on this pool will fail.
extern int pool_destroy(Pool* p);
extern LibError pool_destroy(Pool* p);
// indicate whether <el> was allocated from the given pool.
// this is useful for callers that use several types of allocators.
extern bool pool_contains(Pool* p, void* el);
// return an entry from the pool, or 0 if it cannot be expanded as necessary.
// return an entry from the pool, or 0 if it would have to be expanded and
// there isn't enough memory to do so.
// exhausts the freelist before returning new entries to improve locality.
extern void* pool_alloc(Pool* p);

View File

@ -105,7 +105,7 @@ FUNC(void, log, (const wchar_t* text), (text), (void))
// holds a function pointer for each hook. passed to set_app_hooks.
struct AppHooks
{
#define FUNC(ret, name, params, param_names, call_prefix) ret(*name) params;
#define FUNC(ret, name, params, param_names, call_prefix) ret (*name) params;
#include "app_hooks.h"
#undef FUNC

View File

@ -207,13 +207,13 @@ void debug_wprintf(const wchar_t* fmt, ...)
//-----------------------------------------------------------------------------
int debug_write_crashlog(const wchar_t* text)
LibError debug_write_crashlog(const wchar_t* text)
{
FILE* f = fopen("crashlog.txt", "w");
if(!f)
{
DISPLAY_ERROR(L"debug_write_crashlog: unable to open file");
return -1;
return ERR_FILE_ACCESS;
}
fputwc(0xfeff, f); // BOM
@ -226,7 +226,7 @@ int debug_write_crashlog(const wchar_t* text)
fwprintf(f, L"Last known activity:\n\n %ls\n", debug_log);
fclose(f);
return 0;
return ERR_OK;
}

View File

@ -232,7 +232,7 @@ extern void debug_filter_clear();
extern void debug_wprintf_mem(const wchar_t* fmt, ...);
// write all logs and <text> out to crashlog.txt (unicode format).
extern int debug_write_crashlog(const wchar_t* text);
extern LibError debug_write_crashlog(const wchar_t* text);
//-----------------------------------------------------------------------------
@ -270,11 +270,11 @@ enum DbgBreakType
// from addr's alignment, and is typically 1 machine word.
// breakpoints are a limited resource (4 on IA-32); if none are
// available, we return ERR_LIMIT.
extern int debug_set_break(void* addr, DbgBreakType type);
extern LibError debug_set_break(void* addr, DbgBreakType type);
// remove all breakpoints that were set by debug_set_break.
// important, since these are a limited resource.
extern int debug_remove_all_breaks();
extern LibError debug_remove_all_breaks();
//-----------------------------------------------------------------------------
@ -293,7 +293,7 @@ const size_t DBG_FILE_LEN = 100;
// sym_name and file must hold at least the number of chars above;
// file is the base name only, not path (see rationale in wdbg_sym).
// the PDB implementation is rather slow (~500us).
extern int debug_resolve_symbol(void* ptr_of_interest, char* sym_name, char* file, int* line);
extern LibError debug_resolve_symbol(void* ptr_of_interest, char* sym_name, char* file, int* line);
// write a complete stack trace (including values of local variables) into
// the specified buffer. if <context> is nonzero, it is assumed to be a

View File

@ -636,14 +636,14 @@ template<class T> bool get_container_info(T* t, size_t size, size_t el_size,
// return number of elements and an iterator (any data it needs is stored in
// it_mem, which must hold DEBUG_STL_MAX_ITERATOR_SIZE bytes).
// returns 0 on success or an StlContainerError.
int stl_get_container_info(const char* type_name, const u8* p, size_t size,
LibError stl_get_container_info(const char* type_name, const u8* p, size_t size,
size_t el_size, size_t* el_count, DebugIterator* el_iterator, void* it_mem)
{
// HACK: The debug_stl code breaks VS2005's STL badly, causing crashes in
// later pieces of code that try to manipulate the STL containers. Presumably
// it needs to be altered/rewritten to work happily with the new STL debug iterators.
#if MSC_VERSION >= 1400
return -1;
return ERR_FAIL;
#endif
bool handled = false, valid = false;
@ -690,10 +690,10 @@ int stl_get_container_info(const char* type_name, const u8* p, size_t size,
#endif
if(!handled)
return STL_CNT_UNKNOWN;
return ERR_STL_CNT_UNKNOWN;
if(!valid)
return STL_CNT_INVALID;
return 0;
return ERR_STL_CNT_INVALID;
return ERR_OK;
}
#endif

View File

@ -28,22 +28,12 @@ extern char* stl_simplify_name(char* name);
// no STL iterator is larger than this; see below.
const size_t DEBUG_STL_MAX_ITERATOR_SIZE = 64;
enum StlContainerError
{
// type_name is not that of a known STL container.
STL_CNT_UNKNOWN = -100,
// the container is of a known type but its contents are invalid.
// likely causes: not yet initialized or memory corruption.
STL_CNT_INVALID = -101
};
// if <wtype_name> indicates the object <p, size> to be an STL container,
// and given the size of its value_type (retrieved via debug information),
// return number of elements and an iterator (any data it needs is stored in
// it_mem, which must hold DEBUG_STL_MAX_ITERATOR_SIZE bytes).
// returns 0 on success or an StlContainerError.
extern int stl_get_container_info(const char* type_name, const u8* p, size_t size,
extern LibError stl_get_container_info(const char* type_name, const u8* p, size_t size,
size_t el_size, size_t* el_count, DebugIterator* el_iterator, void* it_mem);
#endif // #ifndef DEBUG_STL_H_INCLUDED

View File

@ -33,14 +33,14 @@
#endif
#if OS_WIN
extern int win_get_gfx_info();
extern int win_get_cpu_info();
extern int win_get_snd_info();
extern LibError win_get_gfx_info();
extern LibError win_get_cpu_info();
extern LibError win_get_snd_info();
#elif OS_UNIX
extern int unix_get_cpu_info();
extern LibError unix_get_cpu_info();
#endif
extern "C" int ogl_get_gfx_info();
extern "C" LibError ogl_get_gfx_info();
//

View File

@ -94,7 +94,7 @@ void in_stop()
}
int in_record(const char* fn)
LibError in_record(const char* fn)
{
if(state == INIT)
atexit(in_stop);
@ -103,17 +103,17 @@ int in_record(const char* fn)
f = fopen(fn, "wb");
if(!f)
return -1;
return ERR_FILE_ACCESS;
fwrite(&game_ticks, sizeof(u32), 1, f);
state = RECORD;
return 0;
return ERR_OK;
}
int in_playback(const char* fn)
LibError in_playback(const char* fn)
{
if(state == INIT)
atexit(in_stop);
@ -122,7 +122,7 @@ int in_playback(const char* fn)
f = fopen(fn, "rb");
if(!f)
return -1;
return ERR_FILE_NOT_FOUND;
u32 rec_start_time;
fread(&rec_start_time, sizeof(u32), 1, f);
@ -133,7 +133,7 @@ int in_playback(const char* fn)
state = PLAYBACK;
return 0;
return ERR_OK;
}

View File

@ -51,8 +51,8 @@ extern void in_dispatch_event(const SDL_Event* event);
extern void in_dispatch_recorded_events();
extern int in_record(const char* fn);
extern int in_playback(const char* fn);
extern LibError in_record(const char* fn);
extern LibError in_playback(const char* fn);
extern void in_stop(void);

View File

@ -59,8 +59,6 @@ scope
#include "config.h"
#include "lib/types.h"
#include "lib/lib_errors.h"
#include "sysdep/sysdep.h"
#include "sysdep/cpu.h" // CAS
@ -81,6 +79,9 @@ scope
// squelch the warning (unfortunately non-portable).
#define STMT(STMT_code__) do { STMT_code__; } while(false)
// must come after definition of STMT
#include "lib/lib_errors.h"
// execute the code passed as a parameter only the first time this is
// reached.
// may be called at any time (in particular before main), but is not
@ -109,110 +110,6 @@ STMT(\
)
// be careful here. the given expression (e.g. variable or
// function return value) may be a Handle (=i64), so it needs to be
// stored and compared as such. (very large but legitimate Handle values
// casted to int can end up negative)
// all functions using this return int (instead of i64) for efficiency and
// simplicity. if the input was negative, it is an error code and is
// therefore known to fit; we still mask with UINT_MAX to avoid
// VC cast-to-smaller-type warnings.
// if expression evaluates to a negative i64, warn user and return the number.
#if OS_WIN
#define CHECK_ERR(expression)\
STMT(\
i64 err__ = (i64)(expression);\
if(err__ < 0)\
{\
DEBUG_WARN_ERR(err__);\
return (int)(err__ & UINT_MAX);\
}\
)
#else
#define CHECK_ERR(expression)\
STMT(\
i64 err__ = (i64)(expression);\
if(err__ < 0)\
{\
DEBUG_WARN_ERR(err__);\
return (int)(err__ & UINT_MAX);\
}\
)
#endif
// just pass on errors without any kind of annoying warning
// (useful for functions that can legitimately fail, e.g. vfs_exists).
#define RETURN_ERR(expression)\
STMT(\
i64 err__ = (i64)(expression);\
if(err__ < 0)\
return (int)(err__ & UINT_MAX);\
)
// if expression evaluates to a negative i64, warn user and throw the number.
#define THROW_ERR(expression)\
STMT(\
i64 err__ = (i64)(expression);\
if(err__ < 0)\
{\
DEBUG_WARN_ERR(err__);\
throw (int)(err__ & UINT_MAX);\
}\
)
// if expression evaluates to a negative i64, warn user and just return
// (useful for void functions that must bail and complain)
#define WARN_ERR_RETURN(expression)\
STMT(\
i64 err__ = (i64)(expression);\
if(err__ < 0)\
{\
DEBUG_WARN_ERR(err__);\
return;\
}\
)
// if expression evaluates to a negative i64, warn user
// (this is similar to debug_assert but also works in release mode)
#define WARN_ERR(expression)\
STMT(\
i64 err__ = (i64)(expression);\
if(err__ < 0)\
DEBUG_WARN_ERR(err__);\
)
// if ok evaluates to false or FALSE, warn user and return -1.
#define WARN_RETURN_IF_FALSE(ok)\
STMT(\
if(!(ok))\
{\
debug_warn("FYI: WARN_RETURN_IF_FALSE reports that a function failed."\
"feel free to ignore or suppress this warning.");\
return -1;\
}\
)
// if ok evaluates to false or FALSE, return -1.
#define RETURN_IF_FALSE(ok)\
STMT(\
if(!(ok))\
return -1;\
)
// if ok evaluates to false or FALSE, warn user.
#define WARN_IF_FALSE(ok)\
STMT(\
if(!(ok))\
debug_warn("FYI: WARN_IF_FALSE reports that a function failed."\
"feel free to ignore or suppress this warning.");\
)
// useful because VC6 may return 0 on failure, instead of throwing.
// this wraps the exception handling, and creates a NULL pointer on failure.
#define SAFE_NEW(type, ptr)\

View File

@ -74,3 +74,45 @@ void error_description_r(int err, char* buf, size_t max_chars)
if(!have_output)
snprintf(buf, max_chars, "Unknown error (%d, 0x%X)", err, err);
}
// return the LibError equivalent of errno, or ERR_FAIL if
// there's no equal.
// only call after a POSIX function indicates failure.
LibError LibError_from_errno()
{
switch(errno)
{
case ENOMEM:
return ERR_NO_MEM;
case EINVAL:
return ERR_INVALID_PARAM;
case ENOSYS:
return ERR_NOT_IMPLEMENTED;
case ENOENT:
return ERR_PATH_NOT_FOUND;
case EACCES:
return ERR_FILE_ACCESS;
case EIO:
return ERR_IO;
case ENAMETOOLONG:
return ERR_PATH_LENGTH;
default:
return ERR_FAIL;
}
UNREACHABLE;
}
// translate the return value of any POSIX function into LibError.
// ret is typically to -1 to indicate error and 0 on success.
// you should set errno to 0 before calling the POSIX function to
// make sure we do not return any stale errors.
LibError LibError_from_posix(int ret)
{
debug_assert(ret == 0 || ret == -1);
return (ret == 0)? ERR_OK : LibError_from_errno();
}

View File

@ -32,6 +32,127 @@ enum LibError {
// "Unknown error (65536, 0x10000)".
extern void error_description_r(int err, char* buf, size_t max_chars);
// return the LibError equivalent of errno, or ERR_FAIL if there's no equal.
// only call after a POSIX function indicates failure.
extern LibError LibError_from_errno();
// translate the return value of any POSIX function into LibError.
// ret is typically to -1 to indicate error and 0 on success.
// you should set errno to 0 before calling the POSIX function to
// make sure we do not return any stale errors.
extern LibError LibError_from_posix(int ret);
// be careful here. the given expression (e.g. variable or
// function return value) may be a Handle (=i64), so it needs to be
// stored and compared as such. (very large but legitimate Handle values
// casted to int can end up negative)
// all functions using this return int (instead of i64) for efficiency and
// simplicity. if the input was negative, it is an error code and is
// therefore known to fit; we still mask with UINT_MAX to avoid
// VC cast-to-smaller-type warnings.
// if expression evaluates to a negative i64, warn user and return the number.
#if OS_WIN
#define CHECK_ERR(expression)\
STMT(\
i64 err__ = (i64)(expression);\
if(err__ < 0)\
{\
DEBUG_WARN_ERR(err__);\
return (LibError)(err__ & UINT_MAX);\
}\
)
#else
#define CHECK_ERR(expression)\
STMT(\
i64 err__ = (i64)(expression);\
if(err__ < 0)\
{\
DEBUG_WARN_ERR(err__);\
return (LibError)(err__ & UINT_MAX);\
}\
)
#endif
// just pass on errors without any kind of annoying warning
// (useful for functions that can legitimately fail, e.g. vfs_exists).
#define RETURN_ERR(expression)\
STMT(\
i64 err__ = (i64)(expression);\
if(err__ < 0)\
return (LibError)(err__ & UINT_MAX);\
)
// return an error and warn about it (replaces debug_warn+return)
#define WARN_RETURN(err)\
STMT(\
DEBUG_WARN_ERR(err);\
return err;\
)
// if expression evaluates to a negative i64, warn user and throw the number.
#define THROW_ERR(expression)\
STMT(\
i64 err__ = (i64)(expression);\
if(err__ < 0)\
{\
DEBUG_WARN_ERR(err__);\
throw (LibError)(err__ & UINT_MAX);\
}\
)
// if expression evaluates to a negative i64, warn user and just return
// (useful for void functions that must bail and complain)
#define WARN_ERR_RETURN(expression)\
STMT(\
i64 err__ = (i64)(expression);\
if(err__ < 0)\
{\
DEBUG_WARN_ERR(err__);\
return;\
}\
)
// if expression evaluates to a negative i64, warn user
// (this is similar to debug_assert but also works in release mode)
#define WARN_ERR(expression)\
STMT(\
i64 err__ = (i64)(expression);\
if(err__ < 0)\
DEBUG_WARN_ERR(err__);\
)
// if ok evaluates to false or FALSE, warn user and return -1.
#define WARN_RETURN_IF_FALSE(ok)\
STMT(\
if(!(ok))\
{\
debug_warn("FYI: WARN_RETURN_IF_FALSE reports that a function failed."\
"feel free to ignore or suppress this warning.");\
return -1;\
}\
)
// if ok evaluates to false or FALSE, return -1.
#define RETURN_IF_FALSE(ok)\
STMT(\
if(!(ok))\
return -1;\
)
// if ok evaluates to false or FALSE, warn user.
#define WARN_IF_FALSE(ok)\
STMT(\
if(!(ok))\
debug_warn("FYI: WARN_IF_FALSE reports that a function failed."\
"feel free to ignore or suppress this warning.");\
)
#endif // #ifndef ERRORS_H__
//-----------------------------------------------------------------------------
@ -42,31 +163,85 @@ extern void error_description_r(int err, char* buf, size_t max_chars);
// error code is usually negative; positive denotes warnings.
// its absolute value must be within [ERR_MIN, ERR_MAX).
// ERR_OK doesn't really need a string, but must be part of enum LibError
// due to compiler checks. (and calling error_description_r(0) should
// never happen, but we set the text accordingly..)
ERR(0, ERR_OK, "(but return value was 0 which indicates success)")
ERR(-1, ERR_FAIL, "Function failed (no details available)")
ERR(1, INFO_CB_CONTINUE , "1 (not an error)")
// these are all basically the same thing
ERR(2, INFO_CANNOT_HANDLE, "2 (not an error)")
ERR(3, INFO_NO_REPLACE , "3 (not an error)")
ERR(4, INFO_SKIPPED , "4 (not an error)")
ERR(-100000, ERR_LOGIC, "Logic error in code")
ERR(-100060, ERR_TIMED_OUT, "Timed out")
// these are for cases where we just want a distinct value to display and
// a symbolic name + string would be overkill (e.g. the various
// test cases in a validate() call). they are shared between multiple
// functions; when something fails, the stack trace will show in which
// one it was => these errors are unambiguous.
// there are 3 tiers - 1..9 are used in most functions, 11..19 are
// used in a function that calls another validator and 21..29 are
// for for functions that call 2 other validators (this avoids
// ambiguity as to which error actually happened where)
ERR(-100101, ERR_1, "Case 1")
ERR(-100102, ERR_2, "Case 2")
ERR(-100103, ERR_3, "Case 3")
ERR(-100104, ERR_4, "Case 4")
ERR(-100105, ERR_5, "Case 5")
ERR(-100106, ERR_6, "Case 6")
ERR(-100107, ERR_7, "Case 7")
ERR(-100108, ERR_8, "Case 8")
ERR(-100109, ERR_9, "Case 9")
ERR(-100111, ERR_11, "Case 11")
ERR(-100112, ERR_12, "Case 12")
ERR(-100113, ERR_13, "Case 13")
ERR(-100114, ERR_14, "Case 14")
ERR(-100115, ERR_15, "Case 15")
ERR(-100116, ERR_16, "Case 16")
ERR(-100117, ERR_17, "Case 17")
ERR(-100118, ERR_18, "Case 18")
ERR(-100119, ERR_19, "Case 19")
ERR(-100121, ERR_21, "Case 21")
ERR(-100122, ERR_22, "Case 22")
ERR(-100123, ERR_23, "Case 23")
ERR(-100124, ERR_24, "Case 24")
ERR(-100125, ERR_25, "Case 25")
ERR(-100126, ERR_26, "Case 26")
ERR(-100127, ERR_27, "Case 27")
ERR(-100128, ERR_28, "Case 28")
ERR(-100129, ERR_29, "Case 29")
// function arguments
ERR(-100000, ERR_INVALID_PARAM, "Invalid function argument")
ERR(-100001, ERR_INVALID_HANDLE, "Invalid Handle (argument)")
ERR(-100002, ERR_BUF_SIZE, "Buffer argument too small")
ERR(-100220, ERR_INVALID_PARAM, "Invalid function argument")
ERR(-100221, ERR_INVALID_HANDLE, "Invalid Handle (argument)")
ERR(-100222, ERR_BUF_SIZE, "Buffer argument too small")
// system limitations
ERR(-100020, ERR_NO_MEM, "Not enough memory")
ERR(-100021, ERR_AGAIN, "Try again later")
ERR(-100022, ERR_LIMIT, "Fixed limit exceeded")
ERR(-100023, ERR_NO_SYS, "OS doesn't provide a required API")
ERR(-100024, ERR_NOT_IMPLEMENTED, "Feature currently not implemented")
ERR(-100025, ERR_NOT_SUPPORTED, "Feature isn't and won't be supported")
ERR(-1060, ERR_TIMED_OUT, "Timed out")
ERR(-100240, ERR_NO_MEM, "Not enough memory")
ERR(-100241, ERR_AGAIN, "Try again later")
ERR(-100242, ERR_LIMIT, "Fixed limit exceeded")
ERR(-100243, ERR_NO_SYS, "OS doesn't provide a required API")
ERR(-100244, ERR_NOT_IMPLEMENTED, "Feature currently not implemented")
ERR(-100245, ERR_NOT_SUPPORTED, "Feature isn't and won't be supported")
// file + vfs
ERR(-100200, ERR_FILE_NOT_FOUND, "VFile not found")
ERR(-100201, ERR_PATH_NOT_FOUND, "VDir not found")
ERR(-100202, ERR_PATH_LENGTH, "Path exceeds VFS_MAX_PATH characters")
ERR(-100203, ERR_PATH_INVALID, "Path is invalid")
ERR(-100210, ERR_DIR_END, "End of directory reached (no more files)")
ERR(-100220, ERR_NOT_FILE, "Not a file")
ERR(-100230, ERR_FILE_ACCESS, "Insufficient access rights to open file")
ERR(-100231, ERR_IO, "Error during IO")
ERR(-100232, ERR_EOF, "Reading beyond end of file")
ERR(-100300, ERR_FILE_NOT_FOUND, "VFile not found")
ERR(-100301, ERR_PATH_NOT_FOUND, "VDir not found")
ERR(-100302, ERR_PATH_LENGTH, "Path exceeds VFS_MAX_PATH characters")
ERR(-100303, ERR_PATH_INVALID, "Path is invalid")
ERR(-100310, ERR_DIR_END, "End of directory reached (no more files)")
ERR(-100320, ERR_NOT_FILE, "Not a file")
ERR(-100321, ERR_NOT_DIR, "Not a directory")
ERR(-100330, ERR_FILE_ACCESS, "Insufficient access rights to open file")
ERR(-100331, ERR_IO, "Error during IO")
ERR(-100332, ERR_EOF, "Reading beyond end of file")
ERR(-100333, ERR_IS_COMPRESSED, "Invalid operation for a compressed file")
ERR(-100334, ERR_ALREADY_MOUNTED, "Directory (tree) already mounted")
ERR(-100335, ERR_INVALID_MOUNT_TYPE, "Invalid mount type (memory corruption?)")
// file format
ERR(-100400, ERR_UNKNOWN_FORMAT, "Unknown file format")
@ -81,7 +256,9 @@ ERR(-100503, ERR_TEX_INVALID_LAYOUT, "Unsupported texel layout, e.g. right-to-le
ERR(-100504, ERR_TEX_COMPRESSED, "Unsupported texture compression")
ERR(+100505, WARN_TEX_INVALID_DATA, "Warning: invalid texel data encountered")
ERR(-100506, ERR_TEX_INVALID_SIZE, "Texture size is incorrect")
ERR(-100507, ERR_TEX_CODEC_CANNOT_HANDLE, "Texture codec cannot handle the given format")
// CPU
ERR(-100600, ERR_CPU_FEATURE_MISSING, "This CPU doesn't support a required feature")
// shaders
@ -91,5 +268,28 @@ ERR(-100702, ERR_SHDR_NO_SHADER, "Invalid shader reference")
ERR(-100703, ERR_SHDR_LINK, "Shader linking failed")
ERR(-100704, ERR_SHDR_NO_PROGRAM, "Invalid shader program reference")
// debug symbol engine
ERR(-100800, ERR_SYM_NO_STACK_FRAMES_FOUND, "No stack frames found")
ERR(-100801, ERR_SYM_UNRETRIEVABLE_STATIC, "Value unretrievable (stored in external module)")
ERR(-100802, ERR_SYM_UNRETRIEVABLE_REG, "Value unretrievable (stored in register)")
ERR(-100803, ERR_SYM_TYPE_INFO_UNAVAILABLE, "Error getting type_info")
// .. this limit is to prevent infinite recursion.
ERR(-100804, ERR_SYM_NESTING_LIMIT, "Symbol nesting too deep or infinite recursion")
// .. this limit is to prevent large symbols (e.g. arrays or linked lists) from
// hogging all stack trace buffer space.
ERR(-100805, ERR_SYM_SINGLE_SYMBOL_LIMIT, "Symbol has produced too much output")
ERR(-100806, ERR_SYM_INTERNAL_ERROR, "Exception raised while processing a symbol")
ERR(-100807, ERR_SYM_UNSUPPORTED, "Symbol type not (fully) supported")
// .. one of the dump_sym* functions decided not to output anything at
// all (e.g. for member functions in UDTs - we don't want those).
// therefore, skip any post-symbol formatting (e.g. ",") as well.
ERR(-100808, ERR_SYM_SUPPRESS_OUTPUT, "Symbol was suppressed")
ERR(-100809, ERR_SYM_CHILD_NOT_FOUND, "Symbol does not have the given child")
// STL debug
ERR(-100900, ERR_STL_CNT_UNKNOWN, "Unknown STL container type_name")
// .. likely causes: not yet initialized or memory corruption.
ERR(-100901, ERR_STL_CNT_INVALID, "Container type is known but contents are invalid")
#undef ERR
#endif // #ifdef ERR

View File

@ -430,7 +430,7 @@ static inline Node* without_mark(Node* p)
// make ready a previously unused(!) list object. if a negative error
// code (currently only ERR_NO_MEM) is returned, the list can't be used.
int lfl_init(LFList* list)
LibError lfl_init(LFList* list)
{
// make sure a TLS slot has been allocated for this thread.
// if not (out of memory), the list object must not be used -
@ -447,7 +447,7 @@ int lfl_init(LFList* list)
list->head = 0;
atomic_add(&active_data_structures, 1);
return 0;
return ERR_OK;
}
@ -611,7 +611,7 @@ have_node:
// remove from list; return -1 if not found, or 0 on success.
int lfl_erase(LFList* list, uintptr_t key)
LibError lfl_erase(LFList* list, uintptr_t key)
{
TLS* tls = tls_get();
debug_assert(tls != (void*)-1);
@ -623,7 +623,7 @@ int lfl_erase(LFList* list, uintptr_t key)
retry:
// not found in list - abort.
if(!list_lookup(list, key, pos))
return -1;
return ERR_FAIL;
// mark as removed (avoids subsequent linking to it). failure implies
// at least of the following happened after list_lookup; we try again.
// - next was removed
@ -639,7 +639,7 @@ retry:
// call list_lookup to ensure # non-released nodes < # threads.
else
list_lookup(list, key, pos);
return 0;
return ERR_OK;
}
@ -669,7 +669,7 @@ static LFList* chain(LFHash* hash, uintptr_t key)
// make ready a previously unused(!) hash object. table size will be
// <num_entries>; this cannot currently be expanded. if a negative error
// code (currently only ERR_NO_MEM) is returned, the hash can't be used.
int lfh_init(LFHash* hash, size_t num_entries)
LibError lfh_init(LFHash* hash, size_t num_entries)
{
hash->tbl = 0;
hash->mask = ~0u;
@ -697,7 +697,7 @@ int lfh_init(LFHash* hash, size_t num_entries)
}
}
return 0;
return ERR_OK;
}
@ -734,7 +734,7 @@ void* lfh_insert(LFHash* hash, uintptr_t key, size_t additional_bytes, int* was_
// remove from hash; return -1 if not found, or 0 on success.
int lfh_erase(LFHash* hash, uintptr_t key)
LibError lfh_erase(LFHash* hash, uintptr_t key)
{
return lfl_erase(chain(hash,key), key);
}
@ -893,10 +893,10 @@ static void* thread_func(void* arg)
int err;
err = lfl_erase(&list, key);
TEST(was_in_set == (err == 0));
TEST(was_in_set == (err == ERR_OK));
err = lfh_erase(&hash, key);
TEST(was_in_set == (err == 0));
TEST(was_in_set == (err == ERR_OK));
}
break;

View File

@ -109,7 +109,7 @@ struct LFList
// make ready a previously unused(!) list object. if a negative error
// code (currently only ERR_NO_MEM) is returned, the list can't be used.
extern int lfl_init(LFList* list);
extern LibError lfl_init(LFList* list);
// call when list is no longer needed; should no longer hold any references.
extern void lfl_free(LFList* list);
@ -125,7 +125,7 @@ extern void* lfl_find(LFList* list, void* key);
extern void* lfl_insert(LFList* list, void* key, size_t additional_bytes, int* was_inserted);
// remove from list; return -1 if not found, or 0 on success.
extern int lfl_erase(LFList* list, void* key);
extern LibError lfl_erase(LFList* list, void* key);
//
@ -141,7 +141,7 @@ struct LFHash
// make ready a previously unused(!) hash object. table size will be
// <num_entries>; this cannot currently be expanded. if a negative error
// code (currently only ERR_NO_MEM) is returned, the hash can't be used.
extern int lfh_init(LFHash* hash, size_t num_entries);
extern LibError lfh_init(LFHash* hash, size_t num_entries);
// call when hash is no longer needed; should no longer hold any references.
extern void lfh_free(LFHash* hash);
@ -156,7 +156,7 @@ extern void* lfh_find(LFHash* hash, uintptr_t key);
extern void* lfh_insert(LFHash* hash, uintptr_t key, size_t additional_bytes, int* was_inserted);
// remove from hash; return -1 if not found, or 0 on success.
extern int lfh_erase(LFHash* hash, uintptr_t key);
extern LibError lfh_erase(LFHash* hash, uintptr_t key);
#endif // #ifndef LOCKFREE_H__

View File

@ -350,7 +350,7 @@ static Alloc* allocs_find(const void* user_p)
return a;
}
static void allocs_foreach(void(*cb)(const Alloc*, void*), void* arg)
static void allocs_foreach(void (*cb)(const Alloc*, void*), void* arg)
{
for(uint i = 0; i < hash_entries; i++)
{

View File

@ -332,7 +332,7 @@ int ogl_max_tex_units = -1; // limit on GL_TEXTUREn
// gfx_card and gfx_drv_ver are unchanged on failure.
int ogl_get_gfx_info()
LibError ogl_get_gfx_info()
{
const char* vendor = (const char*)glGetString(GL_VENDOR);
const char* renderer = (const char*)glGetString(GL_RENDERER);
@ -340,14 +340,14 @@ int ogl_get_gfx_info()
// can fail if OpenGL not yet initialized,
// or if called between glBegin and glEnd.
if(!vendor || !renderer || !version)
return -1;
return ERR_AGAIN;
snprintf(gfx_card, ARRAY_SIZE(gfx_card), "%s %s", vendor, renderer);
// add "OpenGL" to differentiate this from the real driver version
// (returned by platform-specific detect routines).
snprintf(gfx_drv_ver, ARRAY_SIZE(gfx_drv_ver), "OpenGL %s", version);
return 0;
return ERR_OK;
}

View File

@ -102,7 +102,7 @@ extern int ogl_max_tex_units; // limit on GL_TEXTUREn
//
// fails if OpenGL not ready for use.
// gfx_card and gfx_drv_ver are unchanged on failure.
extern int ogl_get_gfx_info(void);
extern LibError ogl_get_gfx_info(void);
//

View File

@ -70,7 +70,7 @@ const size_t SECTOR_SIZE = 4096;
// write the given directory path into our buffer and set end/chars_left
// accordingly. <dir> need and should not end with a directory separator.
int pp_set_dir(PathPackage* pp, const char* dir)
LibError pp_set_dir(PathPackage* pp, const char* dir)
{
// note: use / instead of DIR_SEP because pp->path is portable.
const int len = snprintf(pp->path, ARRAY_SIZE(pp->path), "%s/", dir);
@ -84,16 +84,16 @@ int pp_set_dir(PathPackage* pp, const char* dir)
// when attempting to vfs_open the file).
if(len >= 2) // protect against underrun
debug_assert(pp->end[-2] != '/' && pp->end[-2] != DIR_SEP);
return 0;
return ERR_OK;
}
// append the given filename to the directory established by the last
// pp_set_dir on this package. the whole path is accessible at pp->path.
int pp_append_file(PathPackage* pp, const char* fn)
LibError pp_append_file(PathPackage* pp, const char* fn)
{
CHECK_ERR(strcpy_s(pp->end, pp->chars_left, fn));
return 0;
return ERR_OK;
}
//-----------------------------------------------------------------------------
@ -138,7 +138,7 @@ enum Conversion
TO_PORTABLE
};
static int convert_path(char* dst, const char* src, Conversion conv = TO_NATIVE)
static LibError convert_path(char* dst, const char* src, Conversion conv = TO_NATIVE)
{
// DIR_SEP is assumed to be a single character!
@ -166,7 +166,7 @@ static int convert_path(char* dst, const char* src, Conversion conv = TO_NATIVE)
// end of string - done
if(c == '\0')
return 0;
return ERR_OK;
}
}
@ -179,7 +179,7 @@ static size_t n_root_dir_len;
// return the native equivalent of the given relative portable path
// (i.e. convert all '/' to the platform's directory separator)
// makes sure length < PATH_MAX.
int file_make_native_path(const char* path, char* n_path)
LibError file_make_native_path(const char* path, char* n_path)
{
return convert_path(n_path, path, TO_NATIVE);
}
@ -187,7 +187,7 @@ int file_make_native_path(const char* path, char* n_path)
// return the portable equivalent of the given relative native path
// (i.e. convert the platform's directory separators to '/')
// makes sure length < PATH_MAX.
int file_make_portable_path(const char* n_path, char* path)
LibError file_make_portable_path(const char* n_path, char* path)
{
return convert_path(path, n_path, TO_PORTABLE);
}
@ -197,7 +197,7 @@ int file_make_portable_path(const char* n_path, char* path)
// (i.e. convert all '/' to the platform's directory separator).
// also prepends current directory => n_full_path is absolute.
// makes sure length < PATH_MAX.
int file_make_full_native_path(const char* path, char* n_full_path)
LibError file_make_full_native_path(const char* path, char* n_full_path)
{
debug_assert(path != n_full_path); // doesn't work in-place
@ -210,12 +210,12 @@ int file_make_full_native_path(const char* path, char* n_full_path)
// n_full_path is absolute; if it doesn't match the current dir, fail.
// (note: portable paths are always relative to the file root dir).
// makes sure length < PATH_MAX.
int file_make_full_portable_path(const char* n_full_path, char* path)
LibError file_make_full_portable_path(const char* n_full_path, char* path)
{
debug_assert(path != n_full_path); // doesn't work in-place
if(strncmp(n_full_path, n_root_dir, n_root_dir_len) != 0)
return -1;
return ERR_PATH_NOT_FOUND;
return convert_path(path, n_full_path+n_root_dir_len, TO_PORTABLE);
}
@ -233,7 +233,7 @@ int file_make_full_portable_path(const char* n_full_path, char* path)
// easiest portable way to find our install directory.
//
// can only be called once, by design (see below). rel_path is trusted.
int file_set_root_dir(const char* argv0, const char* rel_path)
LibError file_set_root_dir(const char* argv0, const char* rel_path)
{
const char* msg = 0;
@ -259,12 +259,18 @@ int file_set_root_dir(const char* argv0, const char* rel_path)
{
// .. failed; use argv[0]
if(!realpath(argv0, n_path))
{
msg = "realpath(argv[0]) failed";
goto fail;
}
}
// make sure it's valid
if(access(n_path, X_OK) < 0)
{
msg = "ERR_FILE_ACCESS";
goto fail;
}
// strip executable name, append rel_path, convert to native
char* fn = strrchr(n_path, DIR_SEP);
@ -283,7 +289,7 @@ int file_set_root_dir(const char* argv0, const char* rel_path)
// (note: already 0-terminated, since it's static)
n_root_dir_len = strlen(n_root_dir)+1; // +1 for trailing DIR_SEP
n_root_dir[n_root_dir_len-1] = DIR_SEP;
return 0;
return ERR_OK;
}
@ -292,10 +298,10 @@ fail:
if(msg)
{
debug_printf("%s: %s\n", __func__, msg);
return -1;
return ERR_FAIL;
}
return -errno;
return LibError_from_errno();
}
@ -304,8 +310,6 @@ fail:
// layer on top of POSIX opendir/readdir/closedir that handles
// portable -> native path conversion, ignores non-file/directory entries,
// and additionally returns the file status (size and mtime).
//
// all functions return an int error code to allow CHECK_ERR.
// rationale: see DirIterator definition in header.
struct DirIterator_
@ -326,7 +330,7 @@ cassert(sizeof(DirIterator_) <= sizeof(DirIterator));
// prepare to iterate (once) over entries in the given directory.
// returns a negative error code or 0 on success, in which case <d> is
// ready for subsequent dir_next_ent calls and must be freed via dir_close.
int dir_open(const char* P_path, DirIterator* d_)
LibError dir_open(const char* P_path, DirIterator* d_)
{
DirIterator_* d = (DirIterator_*)d_;
@ -346,32 +350,17 @@ int dir_open(const char* P_path, DirIterator* d_)
d->os_dir = opendir(n_path);
if(!d->os_dir)
{
int err;
switch(errno)
{
case ENOMEM:
err = ERR_NO_MEM;
break;
case ENOENT:
err = ERR_PATH_NOT_FOUND;
break;
default:
err = -1;
break;
}
CHECK_ERR(err);
}
CHECK_ERR(LibError_from_errno());
RETURN_ERR(pp_set_dir(&d->pp, n_path));
return 0;
return ERR_OK;
}
// return ERR_DIR_END if all entries have already been returned once,
// another negative error code, or 0 on success, in which case <ent>
// describes the next (order is unspecified) directory entry.
int dir_next_ent(DirIterator* d_, DirEnt* ent)
LibError dir_next_ent(DirIterator* d_, DirEnt* ent)
{
DirIterator_* d = (DirIterator_*)d_;
@ -420,17 +409,17 @@ get_another_entry:
ent->size = s.st_size;
ent->mtime = s.st_mtime;
ent->name = name;
return 0;
return ERR_OK;
}
// indicate the directory iterator is no longer needed; all resources it
// held are freed.
int dir_close(DirIterator* d_)
LibError dir_close(DirIterator* d_)
{
DirIterator_* d = (DirIterator_*)d_;
WARN_ERR(closedir(d->os_dir));
return 0;
return ERR_OK;
}
@ -456,7 +445,7 @@ static bool dirent_less(const DirEnt* d1, const DirEnt* d2)
// special-case Zip files anyway.
// the advantage here is simplicity, and sparing callbacks the trouble
// of converting from/to native path (we just give 'em the dirent name).
int file_enum(const char* P_path, const FileCB cb, const uintptr_t user)
LibError file_enum(const char* P_path, const FileCB cb, const uintptr_t user)
{
// pointer to DirEnt: faster sorting, but more allocs.
typedef std::vector<const DirEnt*> DirEnts;
@ -467,8 +456,8 @@ int file_enum(const char* P_path, const FileCB cb, const uintptr_t user)
DirEnts dirents;
dirents.reserve(125); // preallocate for efficiency
int stat_err = 0; // first error encountered by stat()
int cb_err = 0; // first error returned by cb
LibError stat_err = ERR_OK; // first error encountered by stat()
LibError cb_err = ERR_OK; // first error returned by cb
DirIterator d;
CHECK_ERR(dir_open(P_path, &d));
@ -476,7 +465,7 @@ int file_enum(const char* P_path, const FileCB cb, const uintptr_t user)
DirEnt ent;
for(;;) // instead of while() to avoid warnings
{
int ret = dir_next_ent(&d, &ent);
LibError ret = dir_next_ent(&d, &ent);
if(ret == ERR_DIR_END)
break;
if(!stat_err)
@ -508,8 +497,8 @@ int file_enum(const char* P_path, const FileCB cb, const uintptr_t user)
s.st_mode = (ent->size == -1)? S_IFDIR : S_IFREG;
s.st_size = ent->size;
s.st_mtime = ent->mtime;
int ret = cb(ent->name, &s, user);
if(ret != 0)
LibError ret = cb(ent->name, &s, user);
if(ret != INFO_CB_CONTINUE)
{
cb_err = ret; // first error (since we now abort)
break;
@ -524,21 +513,22 @@ fail:
for(DirEntRIt rit = dirents.rbegin(); rit != dirents.rend(); ++rit)
free((void*)(*rit));
if(cb_err != 0)
if(cb_err != ERR_OK)
return cb_err;
return stat_err;
}
// get file information. output param is zeroed on error.
int file_stat(const char* path, struct stat* s)
LibError file_stat(const char* path, struct stat* s)
{
memset(s, 0, sizeof(struct stat));
char n_path[PATH_MAX+1];
CHECK_ERR(file_make_full_native_path(path, n_path));
return stat(n_path, s);
errno = 0;
return LibError_from_posix(stat(n_path, s));
}
@ -572,28 +562,28 @@ int file_stat(const char* path, struct stat* s)
// close(our_fd_value) directly, either.
int file_validate(const File* f)
LibError file_validate(const File* f)
{
if(!f)
return ERR_INVALID_PARAM;
else if(f->fd < 0)
return -2;
return ERR_1;
// mapped but refcount is invalid
else if((f->mapping != 0) ^ (f->map_refs != 0))
return -3;
return ERR_2;
// fn_hash not set
#ifndef NDEBUG
else if(!f->fn_hash)
return -4;
return ERR_3;
#endif
return 0;
return ERR_OK;
}
#define CHECK_FILE(f) CHECK_ERR(file_validate(f))
int file_open(const char* p_fn, const uint flags, File* f)
LibError file_open(const char* p_fn, const uint flags, File* f)
{
// zero output param in case we fail below.
memset(f, 0, sizeof(*f));
@ -656,11 +646,11 @@ int file_open(const char* p_fn, const uint flags, File* f)
f->map_refs = 0;
f->fd = fd;
CHECK_FILE(f);
return 0;
return ERR_OK;
}
int file_close(File* f)
LibError file_close(File* f)
{
CHECK_FILE(f);
@ -683,7 +673,7 @@ int file_close(File* f)
f->fd = -1;
}
return 0;
return ERR_OK;
}
@ -743,7 +733,7 @@ static inline void aiocb_pool_free(void* cb)
// starts transferring to/from the given buffer.
// no attempt is made at aligning or padding the transfer.
int file_io_issue(File* f, off_t ofs, size_t size, void* p, FileIo* io)
LibError file_io_issue(File* f, off_t ofs, size_t size, void* p, FileIo* io)
{
// zero output param in case we fail below.
memset(io, 0, sizeof(FileIo));
@ -798,10 +788,10 @@ debug_printf("FILE| issue2 io=%p nbytes=%d\n", io, cb->aio_nbytes);
{
debug_printf("lio_listio: %d, %d[%s]\n", err, errno, strerror(errno));
file_io_discard(io);
return err;
return LibError_from_errno();
}
return 0;
return ERR_OK;
}
@ -821,7 +811,7 @@ int file_io_has_completed(FileIo* io)
}
int file_io_wait(FileIo* io, void*& p, size_t& size)
LibError file_io_wait(FileIo* io, void*& p, size_t& size)
{
debug_printf("FILE| wait io=%p\n", io);
@ -845,33 +835,33 @@ int file_io_wait(FileIo* io, void*& p, size_t& size)
p = (void*)cb->aio_buf; // cast from volatile void*
size = bytes_transferred;
return 0;
return ERR_OK;
}
int file_io_discard(FileIo* io)
LibError file_io_discard(FileIo* io)
{
memset(io->cb, 0, sizeof(aiocb));
// discourage further use.
aiocb_pool_free(io->cb);
io->cb = 0;
return 0;
return ERR_OK;
}
int file_io_validate(const FileIo* io)
LibError file_io_validate(const FileIo* io)
{
const aiocb* cb = (const aiocb*)io->cb;
// >= 0x100 is not necessarily bogus, but suspicious.
// this also catches negative values.
if((uint)cb->aio_fildes >= 0x100)
return -2;
return ERR_1;
if(debug_is_pointer_bogus((void*)cb->aio_buf))
return -3;
return ERR_2;
if(cb->aio_lio_opcode != LIO_WRITE && cb->aio_lio_opcode != LIO_READ && cb->aio_lio_opcode != LIO_NOP)
return -4;
return ERR_3;
// all other aiocb fields have no invariants we could check.
return 0;
return ERR_OK;
}
@ -1026,7 +1016,7 @@ static void block_shutdown()
// remove all blocks loaded from the file <fn>. used when reloading the file.
int file_invalidate_cache(const char* fn)
LibError file_invalidate_cache(const char* fn)
{
// convert to native path to match fn_hash set by file_open
char n_fn[PATH_MAX];
@ -1041,7 +1031,7 @@ int file_invalidate_cache(const char* fn)
if((it->first >> 32) == fn_hash)
block_cache.erase(it);
return 0;
return ERR_OK;
}
@ -1300,7 +1290,7 @@ static const uint MAX_MAP_REFS = 255;
// rationale: reference counting is required for zip_map: several
// Zip "mappings" each reference one ZArchive's actual file mapping.
// implement it here so that we also get refcounting for normal files.
int file_map(File* f, void*& p, size_t& size)
LibError file_map(File* f, void*& p, size_t& size)
{
p = 0;
size = 0;
@ -1314,10 +1304,7 @@ int file_map(File* f, void*& p, size_t& size)
{
// prevent overflow; if we have this many refs, should find out why.
if(f->map_refs >= MAX_MAP_REFS)
{
debug_warn("too many references to mapping");
return -1;
}
CHECK_ERR(ERR_LIMIT);
f->map_refs++;
goto have_mapping;
}
@ -1327,18 +1314,19 @@ int file_map(File* f, void*& p, size_t& size)
// then again, don't complain, because this might happen when mounting
// a dir containing empty files; each is opened as a Zip file.
if(f->size == 0)
return -1;
return ERR_FAIL;
errno = 0;
f->mapping = mmap((void*)0, f->size, prot, MAP_PRIVATE, f->fd, (off_t)0);
if(!f->mapping)
return ERR_NO_MEM;
if(f->mapping == MAP_FAILED)
return LibError_from_errno();
f->map_refs = 1;
have_mapping:
p = f->mapping;
size = f->size;
return 0;
return ERR_OK;
}
@ -1348,7 +1336,7 @@ have_mapping:
// the mapping will be removed (if still open) when its file is closed.
// however, map/unmap calls should still be paired so that the mapping
// may be removed when no longer needed.
int file_unmap(File* f)
LibError file_unmap(File* f)
{
CHECK_FILE(f);
@ -1356,25 +1344,26 @@ int file_unmap(File* f)
if(f->map_refs == 0)
{
debug_warn("not currently mapped");
return -1;
return ERR_FAIL;
}
// still more than one reference remaining - done.
if(--f->map_refs > 0)
return 0;
return ERR_OK;
// no more references: remove the mapping
void* p = f->mapping;
f->mapping = 0;
// don't clear f->size - the file is still open.
return munmap(p, f->size);
errno = 0;
return LibError_from_posix(munmap(p, f->size));
}
int file_shutdown()
LibError file_shutdown()
{
aiocb_pool_shutdown();
block_shutdown();
return 0;
return ERR_OK;
}

View File

@ -36,11 +36,11 @@ struct PathPackage
// write the given directory path into our buffer and set end/chars_left
// accordingly. <dir> need and should not end with a directory separator.
extern int pp_set_dir(PathPackage* pp, const char* dir);
extern LibError pp_set_dir(PathPackage* pp, const char* dir);
// append the given filename to the directory established by the last
// pp_set_dir on this package. the whole path is accessible at pp->path.
extern int pp_append_file(PathPackage* pp, const char* file);
extern LibError pp_append_file(PathPackage* pp, const char* file);
// is s2 a subpath of s1, or vice versa? used by VFS and wdir_watch.
@ -57,13 +57,13 @@ extern bool file_is_subpath(const char* s1, const char* s2);
//
// relative paths (relative to root dir)
extern int file_make_native_path(const char* path, char* n_path);
extern int file_make_portable_path(const char* n_path, char* path);
extern LibError file_make_native_path(const char* path, char* n_path);
extern LibError file_make_portable_path(const char* n_path, char* path);
// as above, but with full native paths (portable paths are always relative).
// prepends current directory, resp. makes sure it matches the given path.
extern int file_make_full_native_path(const char* path, char* n_full_path);
extern int file_make_full_portable_path(const char* n_full_path, char* path);
extern LibError file_make_full_native_path(const char* path, char* n_full_path);
extern LibError file_make_full_portable_path(const char* n_full_path, char* path);
// establish the root directory from <rel_path>, which is treated as
@ -79,7 +79,7 @@ extern int file_make_full_portable_path(const char* n_full_path, char* path);
// easiest portable way to find our install directory.
//
// can only be called once, by design (see below). rel_path is trusted.
extern int file_set_root_dir(const char* argv0, const char* rel_path);
extern LibError file_set_root_dir(const char* argv0, const char* rel_path);
//
@ -89,8 +89,6 @@ extern int file_set_root_dir(const char* argv0, const char* rel_path);
// layer on top of POSIX opendir/readdir/closedir that handles
// portable -> native path conversion, ignores non-file/directory entries,
// and additionally returns the file status (size and mtime).
//
// all functions return an int error code to allow CHECK_ERR.
// directory state initialized by dir_open.
// rationale: some private storage apart from opendir's DIR* is required
@ -132,22 +130,23 @@ struct DirEnt
// prepare to iterate (once) over entries in the given directory.
// returns a negative error code or 0 on success, in which case <d> is
// ready for subsequent dir_next_ent calls and must be freed via dir_close.
extern int dir_open(const char* P_path, DirIterator* d);
extern LibError dir_open(const char* P_path, DirIterator* d);
// return ERR_DIR_END if all entries have already been returned once,
// another negative error code, or 0 on success, in which case <ent>
// describes the next (order is unspecified) directory entry.
extern int dir_next_ent(DirIterator* d, DirEnt* ent);
extern LibError dir_next_ent(DirIterator* d, DirEnt* ent);
// indicate the directory iterator is no longer needed; all resources it
// held are freed.
extern int dir_close(DirIterator* d);
extern LibError dir_close(DirIterator* d);
// called by file_enum for each entry in the directory.
// name doesn't include path!
// return non-zero to immediately abort; file_enum will return that value.
typedef int(*FileCB)(const char* name, const struct stat* s, const uintptr_t user);
// return INFO_CB_CONTINUE to continue calling; anything else will cause
// file_enum to abort and immediately return that value.
typedef LibError (*FileCB)(const char* name, const struct stat* s, const uintptr_t user);
// call <cb> for each file and subdirectory in <dir> (alphabetical order),
// passing the entry name (not full path!), stat info, and <user>.
@ -155,7 +154,7 @@ typedef int(*FileCB)(const char* name, const struct stat* s, const uintptr_t use
// first builds a list of entries (sorted) and remembers if an error occurred.
// if <cb> returns non-zero, abort immediately and return that; otherwise,
// return first error encountered while listing files, or 0 on success.
extern int file_enum(const char* dir, FileCB cb, uintptr_t user);
extern LibError file_enum(const char* dir, FileCB cb, uintptr_t user);
@ -211,19 +210,19 @@ enum
// get file information. output param is zeroed on error.
extern int file_stat(const char* path, struct stat*);
extern LibError file_stat(const char* path, struct stat*);
extern int file_open(const char* fn, uint flags, File* f);
extern LibError file_open(const char* fn, uint flags, File* f);
// note: final file size is calculated and returned in f->size.
// see implementation for rationale.
extern int file_close(File* f);
extern LibError file_close(File* f);
extern int file_validate(const File* f);
extern LibError file_validate(const File* f);
// remove all blocks loaded from the file <fn>. used when reloading the file.
extern int file_invalidate_cache(const char* fn);
extern LibError file_invalidate_cache(const char* fn);
//
@ -237,17 +236,17 @@ struct FileIo
// rationale: this interface is more convenient than implicitly advancing a
// file pointer because zip.cpp often accesses random offsets.
extern int file_io_issue(File* f, off_t ofs, size_t size, void* buf, FileIo* io);
extern LibError file_io_issue(File* f, off_t ofs, size_t size, void* buf, FileIo* io);
// indicates if the given IO has completed.
// return value: 0 if pending, 1 if complete, < 0 on error.
extern int file_io_has_completed(FileIo* io);
extern int file_io_wait(FileIo* io, void*& p, size_t& size);
extern LibError file_io_wait(FileIo* io, void*& p, size_t& size);
extern int file_io_discard(FileIo* io);
extern LibError file_io_discard(FileIo* io);
extern int file_io_validate(const FileIo* io);
extern LibError file_io_validate(const FileIo* io);
//
@ -261,7 +260,7 @@ const size_t FILE_BLOCK_SIZE = 64*KiB;
// return value:
// < 0: failed; abort transfer.
// >= 0: bytes output; continue.
typedef ssize_t(*FileIOCB)(uintptr_t ctx, void* p, size_t size);
typedef ssize_t (*FileIOCB)(uintptr_t ctx, void* p, size_t size);
// transfer <size> bytes, starting at <ofs>, to/from the given file.
// (read or write access was chosen at file-open time).
@ -296,7 +295,7 @@ extern ssize_t file_io(File* f, off_t ofs, size_t size, void* buf, FileIOCB cb =
// rationale: reference counting is required for zip_map: several
// Zip "mappings" each reference one ZArchive's actual file mapping.
// implement it here so that we also get refcounting for normal files.
extern int file_map(File* f, void*& p, size_t& size);
extern LibError file_map(File* f, void*& p, size_t& size);
// decrement the reference count for the mapping belonging to file <f>.
// fail if there are no references; remove the mapping if the count reaches 0.
@ -304,9 +303,9 @@ extern int file_map(File* f, void*& p, size_t& size);
// the mapping will be removed (if still open) when its file is closed.
// however, map/unmap calls should still be paired so that the mapping
// may be removed when no longer needed.
extern int file_unmap(File* f);
extern LibError file_unmap(File* f);
extern int file_shutdown();
extern LibError file_shutdown();
#endif // #ifndef FILE_H

View File

@ -122,7 +122,7 @@ static void VDir_dtor(VDir* vd)
}
}
static int VDir_reload(VDir* vd, const char* path, Handle UNUSED(hvd))
static LibError VDir_reload(VDir* vd, const char* path, Handle UNUSED(hvd))
{
// add required trailing slash if not already present to make
// caller's life easier.
@ -131,18 +131,18 @@ static int VDir_reload(VDir* vd, const char* path, Handle UNUSED(hvd))
RETURN_ERR(tree_dir_open(V_path_slash, &vd->it));
vd->it_valid = 1;
return 0;
return ERR_OK;
}
static int VDir_validate(const VDir* vd)
static LibError VDir_validate(const VDir* vd)
{
// note: <it> is opaque and cannot be validated.
if(vd->filter && !isprint(vd->filter[0]))
return -2;
return 0;
return ERR_1;
return ERR_OK;
}
static int VDir_to_string(const VDir* d, char* buf)
static LibError VDir_to_string(const VDir* d, char* buf)
{
const char* filter = d->filter;
if(!d->filter_latched)
@ -150,7 +150,7 @@ static int VDir_to_string(const VDir* d, char* buf)
if(!filter)
filter = "*";
snprintf(buf, H_STRING_LEN, "(\"%s\")", filter);
return 0;
return ERR_OK;
}
@ -165,7 +165,7 @@ Handle vfs_dir_open(const char* v_dir)
// close the handle to a directory.
int vfs_dir_close(Handle& hd)
LibError vfs_dir_close(Handle& hd)
{
return h_free(hd, H_VDir);
}
@ -188,7 +188,7 @@ int vfs_dir_close(Handle& hd)
// most callers don't need it and the overhead is considerable
// (we'd have to store all entries in a vector). it is left up to
// higher-level code such as VfsUtil.
int vfs_dir_next_ent(const Handle hd, DirEnt* ent, const char* filter)
LibError vfs_dir_next_ent(const Handle hd, DirEnt* ent, const char* filter)
{
H_DEREF(hd, VDir, vd);
@ -238,7 +238,7 @@ int vfs_dir_next_ent(const Handle hd, DirEnt* ent, const char* filter)
}
}
return 0; // success
return ERR_OK;
}
@ -317,7 +317,7 @@ void vfs_enable_file_listing(bool want_enabled)
// return actual path to the specified file:
// "<real_directory>/fn" or "<archive_name>/fn".
int vfs_realpath(const char* v_path, char* realpath)
LibError vfs_realpath(const char* v_path, char* realpath)
{
TFile* tf;
char V_exact_path[VFS_MAX_PATH];
@ -339,7 +339,7 @@ bool vfs_exists(const char* v_fn)
// get file status (mode, size, mtime). output param is zeroed on error.
int vfs_stat(const char* v_path, struct stat* s)
LibError vfs_stat(const char* v_path, struct stat* s)
{
memset(s, 0, sizeof(*s));
@ -388,21 +388,21 @@ static void VFile_dtor(VFile* vf)
(void)mem_free_h(vf->hm);
}
static int VFile_reload(VFile* vf, const char* V_path, Handle)
static LibError VFile_reload(VFile* vf, const char* V_path, Handle)
{
const uint flags = x_flags(&vf->xf);
// we're done if file is already open. need to check this because
// reload order (e.g. if resource opens a file) is unspecified.
if(x_is_open(&vf->xf))
return 0;
return ERR_OK;
file_listing_add(V_path);
TFile* tf;
char V_exact_path[VFS_MAX_PATH];
uint lf = (flags & FILE_WRITE)? LF_CREATE_MISSING : 0;
int err = tree_lookup(V_path, &tf, lf, V_exact_path);
LibError err = tree_lookup(V_path, &tf, lf, V_exact_path);
if(err < 0)
{
// don't CHECK_ERR - this happens often and the dialog is annoying
@ -414,17 +414,17 @@ static int VFile_reload(VFile* vf, const char* V_path, Handle)
return x_open(m, V_exact_path, flags, tf, &vf->xf);
}
static int VFile_validate(const VFile* vf)
static LibError VFile_validate(const VFile* vf)
{
// <ofs> doesn't have any invariant we can check.
RETURN_ERR(x_validate(&vf->xf));
return 0;
return ERR_OK;
}
static int VFile_to_string(const VFile* UNUSED(vf), char* buf)
static LibError VFile_to_string(const VFile* UNUSED(vf), char* buf)
{
strcpy(buf, ""); // safe
return 0;
return ERR_OK;
}
@ -456,7 +456,7 @@ Handle vfs_open(const char* v_fn, uint file_flags)
// close the handle to a file.
int vfs_close(Handle& hf)
LibError vfs_close(Handle& hf)
{
// h_free already complains on error.
return h_free(hf, H_VFile);
@ -681,7 +681,7 @@ static void VIo_dtor(VIo* vio)
// doesn't look possible without controlling the AIO implementation:
// when we cancel, we can't prevent the app from calling
// aio_result, which would terminate the read.
static int VIo_reload(VIo* vio, const char* UNUSED(fn), Handle UNUSED(h))
static LibError VIo_reload(VIo* vio, const char* UNUSED(fn), Handle UNUSED(h))
{
size_t size = vio->size;
void* buf = vio->buf;
@ -693,20 +693,20 @@ static int VIo_reload(VIo* vio, const char* UNUSED(fn), Handle UNUSED(h))
return x_io_issue(&vf->xf, ofs, size, buf, &vio->xio);
}
static int VIo_validate(const VIo* vio)
static LibError VIo_validate(const VIo* vio)
{
if(vio->hf < 0)
return -200;
return ERR_21;
// <size> doesn't have any invariant we can check.
if(debug_is_pointer_bogus(vio->buf))
return -201;
return ERR_22;
return x_io_validate(&vio->xio);
}
static int VIo_to_string(const VIo* vio, char* buf)
static LibError VIo_to_string(const VIo* vio, char* buf)
{
snprintf(buf, H_STRING_LEN, "buf=%p size=%d", vio->buf, vio->size);
return 0;
return ERR_OK;
}
@ -722,7 +722,7 @@ Handle vfs_io_issue(Handle hf, size_t size, void* buf)
// finished with transfer <hio> - free its buffer (returned by vfs_io_wait)
int vfs_io_discard(Handle& hio)
LibError vfs_io_discard(Handle& hio)
{
return h_free(hio, H_VIo);
}
@ -739,7 +739,7 @@ int vfs_io_has_completed(Handle hio)
// wait until the transfer <hio> completes, and return its buffer.
// output parameters are zeroed on error.
int vfs_io_wait(Handle hio, void*& p, size_t& size)
LibError vfs_io_wait(Handle hio, void*& p, size_t& size)
{
H_DEREF(hio, VIo, vio);
return x_io_wait(&vio->xio, p, size);
@ -760,7 +760,7 @@ int vfs_io_wait(Handle hio, void*& p, size_t& size)
// the mapping will be removed (if still open) when its file is closed.
// however, map/unmap calls should still be paired so that the mapping
// may be removed when no longer needed.
int vfs_map(const Handle hf, const uint UNUSED(flags), void*& p, size_t& size)
LibError vfs_map(const Handle hf, const uint UNUSED(flags), void*& p, size_t& size)
{
p = 0;
size = 0;
@ -777,7 +777,7 @@ int vfs_map(const Handle hf, const uint UNUSED(flags), void*& p, size_t& size)
// the mapping will be removed (if still open) when its file is closed.
// however, map/unmap calls should still be paired so that the mapping
// may be removed when no longer needed.
int vfs_unmap(const Handle hf)
LibError vfs_unmap(const Handle hf)
{
H_DEREF(hf, VFile, vf);
return x_unmap(&vf->xf);
@ -790,7 +790,7 @@ int vfs_unmap(const Handle hf)
// called by vfs_reload and vfs_reload_changed_files (which will already
// have rebuilt the VFS - doing so more than once a frame is unnecessary).
static int reload_without_rebuild(const char* fn)
static LibError reload_without_rebuild(const char* fn)
{
// invalidate this file's cached blocks to make sure its contents are
// loaded anew.
@ -798,12 +798,12 @@ static int reload_without_rebuild(const char* fn)
RETURN_ERR(h_reload(fn));
return 0;
return ERR_OK;
}
// called via console command.
int vfs_reload(const char* fn)
LibError vfs_reload(const char* fn)
{
// if <fn> currently maps to an archive, the VFS must switch
// over to using the loose file (that was presumably changed).
@ -816,7 +816,7 @@ int vfs_reload(const char* fn)
// get directory change notifications, and reload all affected files.
// must be called regularly (e.g. once a frame). this is much simpler
// than asynchronous notifications: everything would need to be thread-safe.
int vfs_reload_changed_files()
LibError vfs_reload_changed_files()
{
// array of reloads requested this frame (see 'do we really need to
// reload' below). go through gyrations to avoid heap allocs.
@ -832,10 +832,10 @@ int vfs_reload_changed_files()
{
// get next notification
char N_path[PATH_MAX];
int ret = dir_get_changed_file(N_path);
CHECK_ERR(ret); // error? (doesn't cover 'none available')
if(ret != 0) // none available; done.
LibError ret = dir_get_changed_file(N_path);
if(ret == ERR_AGAIN) // none available; done.
break;
CHECK_ERR(ret);
// convert to VFS path
char P_path[PATH_MAX];
@ -893,7 +893,7 @@ int vfs_reload_changed_files()
for(uint i = 0; i < num_pending; i++)
CHECK_ERR(reload_without_rebuild(pending_reloads[i]));
return 0;
return ERR_OK;
}

View File

@ -227,7 +227,7 @@ extern void vfs_path_copy(char* dst, const char* src);
// if necessary, a directory separator is added between the paths.
// each may be empty, filenames, or full paths.
// total path length (including '\0') must not exceed VFS_MAX_PATH.
extern int vfs_path_append(char* dst, const char* path1, const char* path2);
extern LibError vfs_path_append(char* dst, const char* path1, const char* path2);
// VFS paths are of the form: "(dir/)*file?"
// in English: '/' as path separator; trailing '/' required for dir names;
@ -265,10 +265,10 @@ enum VfsMountFlags
// flags determines extra actions to perform; see VfsMountFlags.
//
// P_real_dir = "." or "./" isn't allowed - see implementation for rationale.
extern int vfs_mount(const char* V_mount_point, const char* P_real_dir, int flags = 0, uint pri = 0);
extern LibError vfs_mount(const char* V_mount_point, const char* P_real_dir, int flags = 0, uint pri = 0);
// unmount a previously mounted item, and rebuild the VFS afterwards.
extern int vfs_unmount(const char* name);
extern LibError vfs_unmount(const char* name);
//
@ -281,7 +281,7 @@ extern Handle vfs_dir_open(const char* dir);
// close the handle to a directory.
// all DirEnt.name strings are now invalid.
extern int vfs_dir_close(Handle& hd);
extern LibError vfs_dir_close(Handle& hd);
// retrieve the next (order is unspecified) dir entry matching <filter>.
// return 0 on success, ERR_DIR_END if no matching entry was found,
@ -302,7 +302,7 @@ extern int vfs_dir_close(Handle& hd);
// most callers don't need it and the overhead is considerable
// (we'd have to store all entries in a vector). it is left up to
// higher-level code such as VfsUtil.
extern int vfs_dir_next_ent(Handle hd, DirEnt* ent, const char* filter = 0);
extern LibError vfs_dir_next_ent(Handle hd, DirEnt* ent, const char* filter = 0);
//
@ -311,14 +311,14 @@ extern int vfs_dir_next_ent(Handle hd, DirEnt* ent, const char* filter = 0);
// return actual path to the specified file:
// "<real_directory>/fn" or "<archive_name>/fn".
extern int vfs_realpath(const char* fn, char* realpath);
extern LibError vfs_realpath(const char* fn, char* realpath);
// does the specified file exist? return false on error.
// useful because a "file not found" warning is not raised, unlike vfs_stat.
extern bool vfs_exists(const char* fn);
// get file status (size, mtime). output param is zeroed on error.
extern int vfs_stat(const char* fn, struct stat*);
extern LibError vfs_stat(const char* fn, struct stat*);
// return the size of an already opened file, or a negative error code.
extern ssize_t vfs_size(Handle hf);
@ -329,7 +329,7 @@ extern ssize_t vfs_size(Handle hf);
extern Handle vfs_open(const char* fn, uint flags = 0);
// close the handle to a file.
extern int vfs_close(Handle& h);
extern LibError vfs_close(Handle& h);
//
@ -348,10 +348,10 @@ extern int vfs_io_has_completed(Handle hio);
// wait until the transfer <hio> completes, and return its buffer.
// output parameters are zeroed on error.
extern int vfs_io_wait(Handle hio, void*& p, size_t& size);
extern LibError vfs_io_wait(Handle hio, void*& p, size_t& size);
// finished with transfer <hio> - free its buffer (returned by vfs_wait_read).
extern int vfs_io_discard(Handle& hio);
extern LibError vfs_io_discard(Handle& hio);
//
@ -414,7 +414,7 @@ extern ssize_t vfs_store(const char* fn, void* p, size_t size, uint flags = 0);
// the mapping will be removed (if still open) when its file is closed.
// however, map/unmap calls should still be paired so that the mapping
// may be removed when no longer needed.
extern int vfs_map(Handle hf, uint flags, void*& p, size_t& size);
extern LibError vfs_map(Handle hf, uint flags, void*& p, size_t& size);
// decrement the reference count for the mapping belonging to file <f>.
// fail if there are no references; remove the mapping if the count reaches 0.
@ -422,16 +422,16 @@ extern int vfs_map(Handle hf, uint flags, void*& p, size_t& size);
// the mapping will be removed (if still open) when its file is closed.
// however, map/unmap calls should still be paired so that the mapping
// may be removed when no longer needed.
extern int vfs_unmap(Handle hf);
extern LibError vfs_unmap(Handle hf);
//
// hotloading
//
extern int vfs_reload(const char* fn);
extern LibError vfs_reload(const char* fn);
// this must be called from the main thread? (wdir_watch problem)
extern int vfs_reload_changed_files(void);
extern LibError vfs_reload_changed_files(void);
#endif // #ifndef __VFS_H__

View File

@ -184,7 +184,7 @@ private:
// we get the full path, since that's what is stored in Zip archives.
//
// [total time 21ms, with ~2000 file's (includes add_file cost)]
static int zip_cb(const char* path, const struct stat* s, uintptr_t user)
static LibError zip_cb(const char* path, const struct stat* s, uintptr_t user)
{
CHECK_PATH(path);
@ -228,7 +228,8 @@ static int zip_cb(const char* path, const struct stat* s, uintptr_t user)
last_td = td;
}
return tree_add_file(td, fn, m, s->st_size, s->st_mtime);
WARN_ERR(tree_add_file(td, fn, m, s->st_size, s->st_mtime));
return INFO_CB_CONTINUE;
}
@ -242,48 +243,46 @@ static bool archive_less(Handle hza1, Handle hza2)
typedef std::vector<Handle> Archives;
typedef Archives::const_iterator ArchiveCIt;
static int enqueue_archive(const char* name, const char* P_archive_dir, Archives* archives)
// return value is ERR_OK iff archives != 0 and name is a valid archive that
// was successfully added to the list. see comments below.
static LibError enqueue_archive(const char* name, const char* P_archive_dir, Archives* archives)
{
// caller wants us to check if this is a Zip file and if so, append it to
// a list. this is only done in the mounted directory itself, not its
// subdirectories! see mount_dir_tree.
// the archives will be mounted after regular directory mounts are done.
if(archives)
{
// get complete path for zip_archive_open.
// this doesn't (need to) work for subdirectories of the mounted td!
// we can't use mount_get_path because we don't have the VFS path.
char P_path[PATH_MAX];
vfs_path_append(P_path, P_archive_dir, name);
// caller doesn't want us to check if this is a Zip file. this is the
// case in all subdirectories of the mount point, since checking for all
// mounted files would be slow. see mount_dir_tree.
if(!archives)
return INFO_SKIPPED;
// just open the Zip file and see if it's valid. we don't bother
// checking the extension because archives won't necessarily be
// called .zip (e.g. Quake III .pk3).
Handle archive = zip_archive_open(P_path);
if(archive > 0)
{
archives->push_back(archive);
// get complete path for zip_archive_open.
// this doesn't (need to) work for subdirectories of the mounted td!
// we can't use mount_get_path because we don't have the VFS path.
char P_path[PATH_MAX];
RETURN_ERR(vfs_path_append(P_path, P_archive_dir, name));
// avoid also adding the Zip file itself to <td>.
return 0;
}
}
// just open the Zip file and see if it's valid. we don't bother
// checking the extension because archives won't necessarily be
// called .zip (e.g. Quake III .pk3).
Handle archive = zip_archive_open(P_path);
RETURN_ERR(archive);
archives->push_back(archive);
return 1;
// avoid also adding the Zip file itself to <td>.
// (when caller sees ERR_OK, they skip the file)
return ERR_OK;
}
static int mount_archive(TDir* td, const Mount& m)
static LibError mount_archive(TDir* td, const Mount& m)
{
ZipCBParams params(td, &m);
zip_enum(m.archive, zip_cb, (uintptr_t)&params);
return 0;
return ERR_OK;
}
static int mount_archives(TDir* td, Archives* archives, const Mount* mount)
static LibError mount_archives(TDir* td, Archives* archives, const Mount* mount)
{
// VFS_MOUNT_ARCHIVES flag wasn't set, or no archives present
if(archives->empty())
return 0;
return ERR_OK;
std::sort(archives->begin(), archives->end(), archive_less);
@ -298,7 +297,7 @@ static int mount_archives(TDir* td, Archives* archives, const Mount* mount)
mount_archive(td, m);
}
return 0;
return ERR_OK;
}
@ -323,12 +322,12 @@ typedef std::deque<TDirAndPath> DirQueue;
static int enqueue_dir(TDir* parent_td, const char* name,
static LibError enqueue_dir(TDir* parent_td, const char* name,
const char* P_parent_path, DirQueue* dir_queue)
{
// caller doesn't want us to enqueue subdirectories; bail.
if(!dir_queue)
return 0;
return ERR_OK;
// skip versioning system directories - this avoids cluttering the
// VFS with hundreds of irrelevant files.
@ -336,7 +335,7 @@ static int enqueue_dir(TDir* parent_td, const char* name,
// strstr the entire path) and it is assumed the Zip file builder
// will take care of it.
if(!strcmp(name, "CVS") || !strcmp(name, ".svn"))
return 0;
return ERR_OK;
// prepend parent path to get complete pathname.
char P_path[PATH_MAX];
@ -347,7 +346,7 @@ static int enqueue_dir(TDir* parent_td, const char* name,
CHECK_ERR(tree_add_dir(parent_td, name, &td));
// .. and add it to the list of directories to visit.
dir_queue->push_back(TDirAndPath(td, const_cast<const char*>(P_path)));
return 0;
return ERR_OK;
}
@ -370,7 +369,7 @@ static int enqueue_dir(TDir* parent_td, const char* name,
// m - real td's location; assigned to all files added from this mounting
// archives - if the dirent is an archive, its Mount is added here.
static int add_ent(TDir* td, DirEnt* ent, const char* P_parent_path, const Mount* m,
static LibError add_ent(TDir* td, DirEnt* ent, const char* P_parent_path, const Mount* m,
DirQueue* dir_queue, Archives* archives)
{
const char* name = ent->name;
@ -381,8 +380,8 @@ static int add_ent(TDir* td, DirEnt* ent, const char* P_parent_path, const Mount
// else: it's a file (dir_next_ent discards everything except for
// file and subdirectory entries).
if(enqueue_archive(name, m->P_name.c_str(), archives) == 0)
return 0;
if(enqueue_archive(name, m->P_name.c_str(), archives) == ERR_OK)
return ERR_OK;
// it's a regular data file; add it to the directory.
return tree_add_file(td, name, m, ent->size, ent->mtime);
@ -390,10 +389,10 @@ static int add_ent(TDir* td, DirEnt* ent, const char* P_parent_path, const Mount
// note: full path is needed for the dir watch.
static int populate_dir(TDir* td, const char* P_path, const Mount* m,
static LibError populate_dir(TDir* td, const char* P_path, const Mount* m,
DirQueue* dir_queue, Archives* archives, int flags)
{
int err;
LibError err;
RealDir* rd = tree_get_real_dir(td);
WARN_ERR(mount_attach_real_dir(rd, P_path, m, flags));
@ -406,7 +405,7 @@ static int populate_dir(TDir* td, const char* P_path, const Mount* m,
{
// don't RETURN_ERR since we need to close d.
err = dir_next_ent(&d, &ent);
if(err != 0)
if(err != ERR_OK)
break;
err = add_ent(td, &ent, P_path, m, dir_queue, archives);
@ -414,7 +413,7 @@ static int populate_dir(TDir* td, const char* P_path, const Mount* m,
}
WARN_ERR(dir_close(&d));
return 0;
return ERR_OK;
}
@ -430,9 +429,9 @@ static int populate_dir(TDir* td, const char* P_path, const Mount* m,
// note: we are only able to add archives found in the root directory,
// due to dirent_cb implementation. that's ok - we don't want to check
// every single file to see if it's an archive (slow!).
static int mount_dir_tree(TDir* td, const Mount& m)
static LibError mount_dir_tree(TDir* td, const Mount& m)
{
int err = 0;
LibError err = ERR_OK;
// add_ent fills these queues with dirs/archives if the corresponding
// flags are set.
@ -454,8 +453,8 @@ static int mount_dir_tree(TDir* td, const Mount& m)
TDir* const td = dir_queue.front().td;
const char* P_path = dir_queue.front().path.c_str();
int ret = populate_dir(td, P_path, &m, pdir_queue, parchives, m.flags);
if(!err)
LibError ret = populate_dir(td, P_path, &m, pdir_queue, parchives, m.flags);
if(err == ERR_OK)
err = ret;
// prevent searching for archives in subdirectories (slow!). this
@ -470,7 +469,7 @@ static int mount_dir_tree(TDir* td, const Mount& m)
// do not pass parchives because that has been set to 0!
mount_archives(td, &archives, &m);
return 0;
return ERR_OK;
}
@ -531,7 +530,7 @@ static const Mount& add_mount(const char* V_mount_point, const char* P_real_path
// note: this is not a member function of Mount to avoid having to
// forward-declare mount_archive, mount_dir_tree.
static int remount(const Mount& m)
static LibError remount(const Mount& m)
{
TDir* td;
CHECK_ERR(tree_lookup_dir(m.V_mount_point.c_str(), &td, LF_CREATE_MISSING));
@ -571,7 +570,7 @@ static inline void remount_all()
// flags determines extra actions to perform; see VfsMountFlags.
//
// P_real_path = "." or "./" isn't allowed - see implementation for rationale.
int vfs_mount(const char* V_mount_point, const char* P_real_path, int flags, uint pri)
LibError vfs_mount(const char* V_mount_point, const char* P_real_path, int flags, uint pri)
{
// callers have a tendency to forget required trailing '/';
// complain if it's not there, unless path = "" (root td).
@ -590,20 +589,14 @@ int vfs_mount(const char* V_mount_point, const char* P_real_path, int flags, uin
for(MountIt it = mounts.begin(); it != mounts.end(); ++it)
{
if(file_is_subpath(P_real_path, it->P_name.c_str()))
{
debug_warn("already mounted");
return -1;
}
CHECK_ERR(ERR_ALREADY_MOUNTED);
}
// disallow "." because "./" isn't supported on Windows.
// it would also create a loophole for the parent td check above.
// "./" and "/." are caught by CHECK_PATH.
if(!strcmp(P_real_path, "."))
{
debug_warn("mounting . not allowed");
return -1;
}
CHECK_ERR(ERR_PATH_INVALID);
const Mount& m = add_mount(V_mount_point, P_real_path, 0, flags, pri);
return remount(m);
@ -616,17 +609,17 @@ int vfs_mount(const char* V_mount_point, const char* P_real_path, int flags, uin
// dir_watch reports changes; can also be called from the console after a
// rebuild command. there is no provision for updating single VFS dirs -
// it's not worth the trouble.
int mount_rebuild()
LibError mount_rebuild()
{
tree_clear();
tree_init();
remount_all();
return 0;
return ERR_OK;
}
// unmount a previously mounted item, and rebuild the VFS afterwards.
int vfs_unmount(const char* P_name)
LibError vfs_unmount(const char* P_name)
{
// this removes all Mounts ensuing from the given mounting. their dtors
// free all resources and there's no need to remove the files from
@ -652,7 +645,7 @@ int vfs_unmount(const char* P_name)
// if <path> or its ancestors are mounted,
// return a VFS path that accesses it.
// used when receiving paths from external code.
int mount_make_vfs_path(const char* P_path, char* V_path)
LibError mount_make_vfs_path(const char* P_path, char* V_path)
{
for(MountIt it = mounts.begin(); it != mounts.end(); ++it)
{
@ -664,10 +657,10 @@ int mount_make_vfs_path(const char* P_path, char* V_path)
const char* replace = m.V_mount_point.c_str();
if(path_replace(V_path, P_path, remove, replace) == 0)
return 0;
return ERR_OK;
}
return -1;
return ERR_PATH_NOT_FOUND;
}
@ -688,7 +681,7 @@ void mount_shutdown()
int mount_attach_real_dir(RealDir* rd, const char* P_path, const Mount* m, int flags)
LibError mount_attach_real_dir(RealDir* rd, const char* P_path, const Mount* m, int flags)
{
// more than one real dir mounted into VFS dir
// (=> can't create files for writing here)
@ -706,7 +699,7 @@ int mount_attach_real_dir(RealDir* rd, const char* P_path, const Mount* m, int f
}
#endif
return 0;
return ERR_OK;
}
@ -722,11 +715,11 @@ void mount_detach_real_dir(RealDir* rd)
}
int mount_populate(TDir* td, RealDir* rd)
LibError mount_populate(TDir* td, RealDir* rd)
{
UNUSED2(td);
UNUSED2(rd);
return 0;
return ERR_OK;
}
@ -745,7 +738,7 @@ int mount_populate(TDir* td, RealDir* rd)
// given a Mount, return the actual location (portable path) of
// <V_path>. used by vfs_realpath and VFile_reopen.
int x_realpath(const Mount* m, const char* V_exact_path, char* P_real_path)
LibError x_realpath(const Mount* m, const char* V_exact_path, char* P_real_path)
{
const char* P_parent_path = 0;
@ -758,8 +751,7 @@ int x_realpath(const Mount* m, const char* V_exact_path, char* P_real_path)
P_parent_path = m->P_name.c_str();
break;
default:
debug_warn("invalid type");
return -1;
WARN_RETURN(ERR_INVALID_MOUNT_TYPE);
}
const char* remove = m->V_mount_point.c_str();
@ -769,7 +761,7 @@ int x_realpath(const Mount* m, const char* V_exact_path, char* P_real_path)
int x_open(const Mount* m, const char* V_exact_path, int flags, TFile* tf, XFile* xf)
LibError x_open(const Mount* m, const char* V_exact_path, int flags, TFile* tf, XFile* xf)
{
// declare variables used in the switch below to avoid needing {}.
char P_path[PATH_MAX];
@ -780,7 +772,7 @@ int x_open(const Mount* m, const char* V_exact_path, int flags, TFile* tf, XFile
if(flags & FILE_WRITE)
{
debug_warn("requesting write access to file in archive");
return -1;
return ERR_NOT_IMPLEMENTED;
}
RETURN_ERR(zip_open(m->archive, V_exact_path, flags, &xf->u.zf));
break;
@ -789,8 +781,7 @@ int x_open(const Mount* m, const char* V_exact_path, int flags, TFile* tf, XFile
RETURN_ERR(file_open(P_path, flags, &xf->u.f));
break;
default:
debug_warn("invalid type");
return ERR_CORRUPTED;
WARN_RETURN(ERR_INVALID_MOUNT_TYPE);
}
// success
@ -798,17 +789,17 @@ int x_open(const Mount* m, const char* V_exact_path, int flags, TFile* tf, XFile
// false impression that all is well.
xf->type = m->type;
xf->tf = tf;
return 0;
return ERR_OK;
}
int x_close(XFile* xf)
LibError x_close(XFile* xf)
{
switch(xf->type)
{
// no file open (e.g. because x_open failed) -> nothing to do.
case MT_NONE:
return 0;
return ERR_OK;
case MT_ARCHIVE:
(void)zip_close(&xf->u.zf);
@ -817,8 +808,7 @@ int x_close(XFile* xf)
(void)file_close(&xf->u.f);
break;
default:
debug_warn("invalid type");
break;
WARN_RETURN(ERR_INVALID_MOUNT_TYPE);
}
// update file state in VFS tree
@ -827,22 +817,22 @@ int x_close(XFile* xf)
tree_update_file(xf->tf, xf->u.f.size, time(0)); // can't fail
xf->type = MT_NONE;
return 0;
return ERR_OK;
}
int x_validate(const XFile* xf)
LibError x_validate(const XFile* xf)
{
switch(xf->type)
{
case MT_NONE:
if(xf->tf != 0)
return -100;
return 0; // ok, nothing else to check
return ERR_11;
return ERR_OK; // ok, nothing else to check
case MT_FILE:
if(xf->tf == 0)
return -101;
return ERR_12;
return file_validate(&xf->u.f);
case MT_ARCHIVE:
@ -850,11 +840,11 @@ int x_validate(const XFile* xf)
// VFS after newly written files are closed, but archive files
// cannot be modified), but it's not ATM.
if(xf->tf == 0)
return -102;
return ERR_13;
return zip_validate(&xf->u.zf);
default:
return -103; // invalid type
return ERR_INVALID_MOUNT_TYPE;
}
UNREACHABLE;
}
@ -891,7 +881,7 @@ uint x_flags(const XFile* xf)
int x_io(XFile* xf, off_t ofs, size_t size, void* buf, FileIOCB cb, uintptr_t ctx)
ssize_t x_io(XFile* xf, off_t ofs, size_t size, void* buf, FileIOCB cb, uintptr_t ctx)
{
switch(xf->type)
{
@ -906,13 +896,12 @@ int x_io(XFile* xf, off_t ofs, size_t size, void* buf, FileIOCB cb, uintptr_t ct
return file_io(&xf->u.f, ofs, size, buf, cb, ctx);
default:
debug_warn("invalid file type");
return ERR_CORRUPTED;
WARN_RETURN(ERR_INVALID_MOUNT_TYPE);
}
}
int x_map(XFile* xf, void*& p, size_t& size)
LibError x_map(XFile* xf, void*& p, size_t& size)
{
switch(xf->type)
{
@ -921,13 +910,12 @@ int x_map(XFile* xf, void*& p, size_t& size)
case MT_FILE:
return file_map(&xf->u.f, p, size);
default:
debug_warn("invalid file type");
return ERR_CORRUPTED;
WARN_RETURN(ERR_INVALID_MOUNT_TYPE);
}
}
int x_unmap(XFile* xf)
LibError x_unmap(XFile* xf)
{
switch(xf->type)
{
@ -936,13 +924,12 @@ int x_unmap(XFile* xf)
case MT_FILE:
return file_unmap(&xf->u.f);
default:
debug_warn("invalid file type");
return ERR_CORRUPTED;
WARN_RETURN(ERR_INVALID_MOUNT_TYPE);
}
}
int x_io_issue(XFile* xf, off_t ofs, size_t size, void* buf, XIo* xio)
LibError x_io_issue(XFile* xf, off_t ofs, size_t size, void* buf, XIo* xio)
{
xio->type = xf->type;
switch(xio->type)
@ -952,8 +939,7 @@ int x_io_issue(XFile* xf, off_t ofs, size_t size, void* buf, XIo* xio)
case MT_FILE:
return file_io_issue(&xf->u.f, ofs, size, buf, &xio->u.fio);
default:
debug_warn("invalid file type");
return ERR_CORRUPTED;
WARN_RETURN(ERR_INVALID_MOUNT_TYPE);
}
}
@ -967,13 +953,12 @@ int x_io_has_completed(XIo* xio)
case MT_FILE:
return file_io_has_completed(&xio->u.fio);
default:
debug_warn("invalid file type");
return ERR_CORRUPTED;
WARN_RETURN(ERR_INVALID_MOUNT_TYPE);
}
}
int x_io_wait(XIo* xio, void*& p, size_t& size)
LibError x_io_wait(XIo* xio, void*& p, size_t& size)
{
switch(xio->type)
{
@ -982,13 +967,12 @@ int x_io_wait(XIo* xio, void*& p, size_t& size)
case MT_FILE:
return file_io_wait(&xio->u.fio, p, size);
default:
debug_warn("invalid file type");
return ERR_CORRUPTED;
WARN_RETURN(ERR_INVALID_MOUNT_TYPE);
}
}
int x_io_discard(XIo* xio)
LibError x_io_discard(XIo* xio)
{
switch(xio->type)
{
@ -997,13 +981,12 @@ int x_io_discard(XIo* xio)
case MT_FILE:
return file_io_discard(&xio->u.fio);
default:
debug_warn("invalid file type");
return ERR_CORRUPTED;
WARN_RETURN(ERR_INVALID_MOUNT_TYPE);
}
}
int x_io_validate(const XIo* xio)
LibError x_io_validate(const XIo* xio)
{
switch(xio->type)
{
@ -1012,7 +995,7 @@ int x_io_validate(const XIo* xio)
case MT_FILE:
return file_io_validate(&xio->u.fio);
default:
return -100; // invalid type
return ERR_INVALID_MOUNT_TYPE;
}
UNREACHABLE;
}

View File

@ -57,28 +57,28 @@ struct XFile
// given a Mount, return the actual location (portable path) of
// <V_path>. used by vfs_realpath and VFile_reopen.
extern int x_realpath(const Mount* m, const char* V_exact_path, char* P_real_path);
extern LibError x_realpath(const Mount* m, const char* V_exact_path, char* P_real_path);
extern int x_open(const Mount* m, const char* V_exact_path, int flags, TFile* tf, XFile* xf);
extern int x_close(XFile* xf);
extern LibError x_open(const Mount* m, const char* V_exact_path, int flags, TFile* tf, XFile* xf);
extern LibError x_close(XFile* xf);
extern int x_validate(const XFile* xf);
extern LibError x_validate(const XFile* xf);
extern bool x_is_open(const XFile* xf);
extern off_t x_size(const XFile* xf);
extern uint x_flags(const XFile* xf);
extern void x_set_flags(XFile* xf, uint flags);
extern int x_io(XFile* xf, off_t ofs, size_t size, void* buf, FileIOCB cb, uintptr_t ctx);;
extern ssize_t x_io(XFile* xf, off_t ofs, size_t size, void* buf, FileIOCB cb, uintptr_t ctx);;
extern int x_map(XFile* xf, void*& p, size_t& size);
extern int x_unmap(XFile* xf);
extern LibError x_map(XFile* xf, void*& p, size_t& size);
extern LibError x_unmap(XFile* xf);
extern int x_io_issue(XFile* xf, off_t ofs, size_t size, void* buf, XIo* xio);
extern LibError x_io_issue(XFile* xf, off_t ofs, size_t size, void* buf, XIo* xio);
extern int x_io_has_completed(XIo* xio);
extern int x_io_wait(XIo* xio, void*& p, size_t& size);
extern int x_io_discard(XIo* xio);
extern int x_io_validate(const XIo* xio);
extern LibError x_io_wait(XIo* xio, void*& p, size_t& size);
extern LibError x_io_discard(XIo* xio);
extern LibError x_io_validate(const XIo* xio);
@ -119,11 +119,11 @@ struct RealDir
#endif
};
extern int mount_attach_real_dir(RealDir* rd, const char* P_path, const Mount* m, int flags);
extern LibError mount_attach_real_dir(RealDir* rd, const char* P_path, const Mount* m, int flags);
extern void mount_detach_real_dir(RealDir* rd);
struct TDir;
extern int mount_populate(TDir* td, RealDir* rd);
extern LibError mount_populate(TDir* td, RealDir* rd);
// rebuild the VFS, i.e. re-mount everything. open files are not affected.
@ -132,11 +132,11 @@ extern int mount_populate(TDir* td, RealDir* rd);
// dir_watch reports changes; can also be called from the console after a
// rebuild command. there is no provision for updating single VFS dirs -
// it's not worth the trouble.
extern int mount_rebuild();
extern LibError mount_rebuild();
// if <path> or its ancestors are mounted,
// return a VFS path that accesses it.
// used when receiving paths from external code.
extern int mount_make_vfs_path(const char* P_path, char* V_path);
extern LibError mount_make_vfs_path(const char* P_path, char* V_path);
#endif // #ifndef VFS_MOUNT_H__

View File

@ -26,7 +26,7 @@
// if path is invalid (see source for criteria), print a diagnostic message
// (indicating line number of the call that failed) and
// return a negative error code. used by CHECK_PATH.
int path_validate(const uint line, const char* path)
LibError path_validate(const uint line, const char* path)
{
size_t path_len = 0; // counted as we go; checked against max.
@ -80,10 +80,10 @@ int path_validate(const uint line, const char* path)
fail:
debug_printf("%s called from line %d failed: %s\n", __func__, line, msg);
debug_warn("failed");
return -1;
return ERR_FAIL;
ok:
return 0;
return ERR_OK;
}
@ -124,7 +124,7 @@ void vfs_path_copy(char* dst, const char* src)
// if necessary, a directory separator is added between the paths.
// each may be empty, filenames, or full paths.
// total path length (including '\0') must not exceed VFS_MAX_PATH.
int vfs_path_append(char* dst, const char* path1, const char* path2)
LibError vfs_path_append(char* dst, const char* path1, const char* path2)
{
const size_t len1 = strlen(path1);
const size_t len2 = strlen(path2);
@ -147,19 +147,19 @@ int vfs_path_append(char* dst, const char* path1, const char* path2)
if(need_separator)
*dst++ = '/';
strcpy(dst, path2); // safe
return 0;
return ERR_OK;
}
// strip <remove> from the start of <src>, prepend <replace>,
// and write to <dst>.
// used when converting VFS <--> real paths.
int path_replace(char* dst, const char* src, const char* remove, const char* replace)
LibError path_replace(char* dst, const char* src, const char* remove, const char* replace)
{
// remove doesn't match start of <src>
const size_t remove_len = strlen(remove);
if(strncmp(src, remove, remove_len) != 0)
return -1;
return ERR_FAIL;
// get rid of trailing / in src (must not be included in remove)
const char* start = src+remove_len;
@ -168,5 +168,5 @@ int path_replace(char* dst, const char* src, const char* remove, const char* rep
// prepend replace.
CHECK_ERR(vfs_path_append(dst, replace, start));
return 0;
return ERR_OK;
}

View File

@ -8,7 +8,7 @@
// if path is invalid (see source for criteria), print a diagnostic message
// (indicating line number of the call that failed) and
// return a negative error code. used by CHECK_PATH.
extern int path_validate(const uint line, const char* path);
extern LibError path_validate(const uint line, const char* path);
#define CHECK_PATH(path) CHECK_ERR(path_validate(__LINE__, path))
extern bool path_component_valid(const char* name);
@ -16,6 +16,6 @@ extern bool path_component_valid(const char* name);
// strip <remove> from the start of <src>, prepend <replace>,
// and write to <dst>.
// used when converting VFS <--> real paths.
extern int path_replace(char* dst, const char* src, const char* remove, const char* replace);
extern LibError path_replace(char* dst, const char* src, const char* remove, const char* replace);
#endif // #ifndef VFS_PATH_H__

View File

@ -306,9 +306,9 @@ struct TDir
void init();
TNode* find(const char* name, TNodeType desired_type);
int add(const char* name, TNodeType new_type, TNode** pnode);
int attach_real_dir(const char* path, int flags, const Mount* new_m);
int lookup(const char* path, uint flags, TNode** pnode, char* exact_path);
LibError add(const char* name, TNodeType new_type, TNode** pnode);
LibError attach_real_dir(const char* path, int flags, const Mount* new_m);
LibError lookup(const char* path, uint flags, TNode** pnode, char* exact_path);
void clearR();
void displayR(int indent_level);
};
@ -381,7 +381,7 @@ TNode* TDir::find(const char* name, TNodeType desired_type)
return node;
}
int TDir::add(const char* name, TNodeType new_type, TNode** pnode)
LibError TDir::add(const char* name, TNodeType new_type, TNode** pnode)
{
if(!path_component_valid(name))
return ERR_PATH_INVALID;
@ -396,7 +396,7 @@ int TDir::add(const char* name, TNodeType new_type, TNode** pnode)
const size_t size = sizeof(TNode)+strnlen(name, VFS_MAX_PATH)+1;
node = (TNode*)bucket_alloc(&node_buckets, size);
if(!node)
return 0;
return ERR_OK;
strcpy(node->exact_name, name); // safe
node->type = new_type;
@ -404,7 +404,7 @@ int TDir::add(const char* name, TNodeType new_type, TNode** pnode)
{
debug_warn("failed to expand table");
// node will be freed by node_free_all
return 0;
return ERR_OK;
}
// note: this is called from lookup, which needs to create nodes.
@ -417,10 +417,10 @@ int TDir::add(const char* name, TNodeType new_type, TNode** pnode)
done:
*pnode = node;
return 0;
return ERR_OK;
}
int TDir::lookup(const char* path, uint flags, TNode** pnode, char* exact_path)
LibError TDir::lookup(const char* path, uint flags, TNode** pnode, char* exact_path)
{
// cleared on failure / if returning root dir node (= "")
if(exact_path)
@ -430,7 +430,7 @@ int TDir::lookup(const char* path, uint flags, TNode** pnode, char* exact_path)
if(path[0] == '\0')
{
*pnode = (TNode*)this; // HACK: TDir is at start of TNode
return 0;
return ERR_OK;
}
CHECK_PATH(path);
@ -522,7 +522,7 @@ int TDir::lookup(const char* path, uint flags, TNode** pnode, char* exact_path)
// success.
*pnode = node;
return 0;
return ERR_OK;
}
// empty this directory and all subdirectories; used when rebuilding VFS.
@ -638,7 +638,7 @@ void tree_display()
int tree_add_file(TDir* td, const char* name, const Mount* m,
LibError tree_add_file(TDir* td, const char* name, const Mount* m,
off_t size, time_t mtime)
{
TNode* node;
@ -650,53 +650,53 @@ int tree_add_file(TDir* td, const char* name, const Mount* m,
const bool is_same = (tf->size == size) &&
fabs(difftime(tf->mtime, mtime)) <= 2.0;
if(!mount_should_replace(tf->m, m, is_same))
return 1;
return INFO_NO_REPLACE;
tf->m = m;
tf->mtime = mtime;
tf->size = size;
return 0;
return ERR_OK;
}
int tree_add_dir(TDir* td, const char* name, TDir** ptd)
LibError tree_add_dir(TDir* td, const char* name, TDir** ptd)
{
TNode* node;
RETURN_ERR(td->add(name, N_DIR, &node));
*ptd = &node->u.dir;
return 0;
return ERR_OK;
}
int tree_lookup_dir(const char* path, TDir** ptd, uint flags, char* exact_path)
LibError tree_lookup_dir(const char* path, TDir** ptd, uint flags, char* exact_path)
{
// TDir::lookup would return a file node
// path is not a directory; TDir::lookup might return a file node
if(path[0] != '\0' && path[strlen(path)-1] != '/')
return -1;
return ERR_NOT_DIR;
TDir* td = (flags & LF_START_DIR)? *ptd : tree_root_dir;
TNode* node;
CHECK_ERR(td->lookup(path, flags, &node, exact_path));
// directories should exist, so warn if this fails
*ptd = &node->u.dir;
return 0;
return ERR_OK;
}
int tree_lookup(const char* path, TFile** pfile, uint flags, char* exact_path)
LibError tree_lookup(const char* path, TFile** pfile, uint flags, char* exact_path)
{
// TDir::lookup would return a directory node
// path is not a file; TDir::lookup might return a directory node
if(path[0] == '\0' || path[strlen(path)-1] == '/')
return -1;
return ERR_NOT_FILE;
TNode* node;
int ret = tree_root_dir->lookup(path, flags, &node, exact_path);
LibError ret = tree_root_dir->lookup(path, flags, &node, exact_path);
RETURN_ERR(ret);
*pfile = &node->u.file;
return 0;
return ERR_OK;
}
@ -721,7 +721,7 @@ struct TreeDirIterator_
cassert(sizeof(TreeDirIterator_) <= sizeof(TreeDirIterator));
int tree_dir_open(const char* path_slash, TreeDirIterator* d_)
LibError tree_dir_open(const char* path_slash, TreeDirIterator* d_)
{
TreeDirIterator_* d = (TreeDirIterator_*)d_;
@ -740,11 +740,11 @@ int tree_dir_open(const char* path_slash, TreeDirIterator* d_)
d->it = td->children.begin();
d->end = td->children.end();
d->td = td;
return 0;
return ERR_OK;
}
int tree_dir_next_ent(TreeDirIterator* d_, DirEnt* ent)
LibError tree_dir_next_ent(TreeDirIterator* d_, DirEnt* ent)
{
TreeDirIterator_* d = (TreeDirIterator_*)d_;
@ -769,17 +769,17 @@ int tree_dir_next_ent(TreeDirIterator* d_, DirEnt* ent)
debug_warn("invalid TNode type");
}
return 0; // success
return ERR_OK;
}
int tree_dir_close(TreeDirIterator* UNUSED(d))
LibError tree_dir_close(TreeDirIterator* UNUSED(d))
{
tree_unlock();
// no further cleanup needed. we could zero out d but that might
// hide bugs; the iterator is safe (will not go beyond end) anyway.
return 0;
return ERR_OK;
}
@ -800,7 +800,7 @@ void tree_update_file(TFile* tf, off_t size, time_t mtime)
// get file status (mode, size, mtime). output param is undefined on error.
int tree_stat(const TFile* tf, struct stat* s)
LibError tree_stat(const TFile* tf, struct stat* s)
{
// all stat members currently supported are stored in TFile, so we
// can return them directly without having to call file|zip_stat.
@ -808,7 +808,7 @@ int tree_stat(const TFile* tf, struct stat* s)
s->st_size = tf->size;
s->st_mtime = tf->mtime;
return 0;
return ERR_OK;
}

View File

@ -41,10 +41,10 @@ extern void tree_clear();
//
// note: if "priority" is the same, replace!
// this makes sure mods/patches etc. actually replace files.
extern int tree_add_file(TDir* td, const char* fn, const Mount* m,
extern LibError tree_add_file(TDir* td, const char* fn, const Mount* m,
off_t size, time_t mtime);
extern int tree_add_dir(TDir* dir, const char* name, TDir** ptd);
extern LibError tree_add_dir(TDir* dir, const char* name, TDir** ptd);
enum TreeLookupFlags
{
@ -63,7 +63,7 @@ enum TreeLookupFlags
//
// return 0 on success, or a negative error code
// (in which case output params are undefined).
extern int tree_lookup(const char* path, TFile** ptf, uint flags = 0, char* exact_path = 0);
extern LibError tree_lookup(const char* path, TFile** ptf, uint flags = 0, char* exact_path = 0);
// starting at VFS root, traverse <path> and pass back information
// for its last directory component.
@ -81,7 +81,7 @@ extern int tree_lookup(const char* path, TFile** ptf, uint flags = 0, char* exac
//
// return 0 on success, or a negative error code
// (in which case output params are undefined).
extern int tree_lookup_dir(const char* path, TDir** ptd, uint flags = 0, char* exact_path = 0);
extern LibError tree_lookup_dir(const char* path, TDir** ptd, uint flags = 0, char* exact_path = 0);
// documentation and rationale: see file.h's dir_next_ent interface
@ -90,17 +90,17 @@ struct TreeDirIterator
char opaque[32];
};
extern int tree_dir_open(const char* path_slash, TreeDirIterator* d);
extern int tree_dir_next_ent(TreeDirIterator* d, DirEnt* ent);
extern int tree_dir_close(TreeDirIterator* d);
extern LibError tree_dir_open(const char* path_slash, TreeDirIterator* d);
extern LibError tree_dir_next_ent(TreeDirIterator* d, DirEnt* ent);
extern LibError tree_dir_close(TreeDirIterator* d);
// given a file that is stored on disk and its VFS path,
// return its OS path (for use with file.cpp).
// used by vfs_realpath and VFile_reopen.
extern int tree_realpath(TFile* tf, const char* V_path, char* P_real_path);
extern LibError tree_realpath(TFile* tf, const char* V_path, char* P_real_path);
extern int tree_stat(const TFile* tf, struct stat* s);
extern LibError tree_stat(const TFile* tf, struct stat* s);
extern const Mount* tree_get_mount(const TFile* tf);

View File

@ -158,7 +158,7 @@ static const u8* z_find_id(const u8* file, size_t size, const u8* start, const c
// find "End of Central Dir Record" in file.
// z_is_header has made sure size >= ECDR_SIZE.
// return -1 on failure (output param invalid), otherwise 0.
static int z_find_ecdr(const u8* file, size_t size, const u8*& ecdr_)
static LibError z_find_ecdr(const u8* file, size_t size, const u8*& ecdr_)
{
// early out: check expected case (ECDR at EOF; no file comment)
const u8* ecdr = file + size - ECDR_SIZE;
@ -178,7 +178,7 @@ static int z_find_ecdr(const u8* file, size_t size, const u8*& ecdr_)
found_ecdr:
ecdr_ = ecdr;
return 0;
return ERR_OK;
}
@ -211,6 +211,24 @@ static time_t convert_dos_date(u16 fatdate, u16 fattime)
///////////////////////////////////////////////////////////////////////////////
static bool z_cdfh_is_valid_file(u16 method, size_t csize, size_t ucsize,
const u8* lfh)
{
// compression method is unknown (neither deflated nor stored)
if(method & ~8)
return false;
// it's a directory entry (we only want files).
if(!csize && !ucsize)
return false;
// LFH signature not found
if(!lfh)
return false;
return true;
}
enum z_extract_cdfh_ret
{
Z_CDFH_ABORT = -1, // next CDFH not found; abort.
@ -224,8 +242,8 @@ enum z_extract_cdfh_ret
// called by z_enum_files, which passes the output to lookup.
//
// [30ms]
static int z_extract_cdfh(const u8* file, size_t size, // in
const u8*& cdfh, const char*& fn, size_t& fn_len, ZLoc* loc) // out
static z_extract_cdfh_ret z_extract_cdfh(const u8* file, size_t size, // in
const u8*& cdfh, const char*& fn, size_t& fn_len, ZLoc* loc) // out
{
// scan for next CDFH (at or beyond current cdfh position)
cdfh = z_find_id(file, size, cdfh, cdfh_id, CDFH_SIZE);
@ -255,15 +273,7 @@ static int z_extract_cdfh(const u8* file, size_t size, // in
// but will still scan ahead for its id on next call.
cdfh += CDFH_SIZE + fn_len_ + e_len + c_len;
// is this entry not a valid file?
if(
// compression method is unknown (neither deflated nor stored)
(method & ~8) ||
// it's a directory entry (we only want files).
(!csize && !ucsize) ||
// LFH signature not found
(!lfh)
)
if(!z_cdfh_is_valid_file(method, csize, ucsize, lfh))
return Z_CDFH_SKIPPED;
// get actual file ofs (see above)
@ -285,9 +295,10 @@ static int z_extract_cdfh(const u8* file, size_t size, // in
}
// successively call <cb> for each valid file in the archive,
// successively called for each valid file in the archive,
// passing the complete path and <user>.
// if it returns a nonzero value, abort and return that, otherwise 0.
// return INFO_CB_CONTINUE to continue calling; anything else will cause
// the caller to abort and immediately return that value.
//
// HACK: call back with negative index the first time; its abs. value is
// the number of entries in the archive. lookup needs to know this so it can
@ -295,13 +306,13 @@ static int z_extract_cdfh(const u8* file, size_t size, // in
// z_enum_files would require passing around a ZipInfo struct, or searching
// for the ECDR twice - both ways aren't nice. nor is expanding on demand -
// we try to minimize allocations (faster, less fragmentation).
//
// fn (filename) is not necessarily 0-terminated!
// loc is only valid during the callback! must be copied or saved.
typedef int(*CDFH_CB)(uintptr_t user, i32 idx, const char* fn, size_t fn_len, const ZLoc* loc);
typedef LibError (*CDFH_CB)(uintptr_t user, i32 idx, const char* fn, size_t fn_len, const ZLoc* loc);
static int z_enum_files(const u8* file, const size_t size, const CDFH_CB cb, const uintptr_t user)
static LibError z_enum_files(const u8* file, const size_t size, const CDFH_CB cb, const uintptr_t user)
{
// find "End of Central Directory Record"
const u8* ecdr;
@ -314,8 +325,9 @@ static int z_enum_files(const u8* file, const size_t size, const CDFH_CB cb, con
const i32 num_entries = read_le16(ecdr+10);
// .. callback expects -num_entries < 0.
// if it's 0, the callback would treat it as an index => crash.
// ERR_FAIL means we'll no longer be called.
if(!num_entries)
return -1;
return ERR_FAIL;
CHECK_ERR(cb(user, -num_entries, 0, 0, 0));
// iterate through CDFH
@ -332,22 +344,24 @@ static int z_enum_files(const u8* file, const size_t size, const CDFH_CB cb, con
size_t fn_len;
ZLoc loc;
int ret = z_extract_cdfh(file, size, cdfh, fn, fn_len, &loc);
z_extract_cdfh_ret ret = z_extract_cdfh(file, size, cdfh, fn, fn_len, &loc);
// valid file
if(ret == Z_CDFH_FILE_OK)
{
cb(user, idx, fn, fn_len, &loc);
LibError cb_ret = cb(user, idx, fn, fn_len, &loc);
if(cb_ret != INFO_CB_CONTINUE)
return cb_ret;
idx++; // see rationale above
}
// next CDFH not found (Zip archive corrupted)
else if(ret == Z_CDFH_ABORT)
return -1;
return ERR_CORRUPTED;
// skipping this CDFH (e.g. if directory)
else
;
}
return 0;
return ERR_OK;
}
@ -422,7 +436,7 @@ struct LookupInfo
// - loc is only valid during the callback! must be copied or saved.
//
// [40ms]
static int lookup_add_file_cb(uintptr_t user, i32 idx,
static LibError lookup_add_file_cb(uintptr_t user, i32 idx,
const char* fn, size_t fn_len, const ZLoc* loc)
{
LookupInfo* li = (LookupInfo*)user;
@ -446,7 +460,7 @@ static int lookup_add_file_cb(uintptr_t user, i32 idx,
// will count below, since some entries aren't files.
li->ents = (ZEnt*)p;
li->fn_hashes = (FnHash*)((char*)p + ents_size);
return 0;
return INFO_CB_CONTINUE;
}
// adding a regular file.
@ -470,15 +484,15 @@ static int lookup_add_file_cb(uintptr_t user, i32 idx,
li->fn_hashes[idx] = fn_hash;
(*li->idx)[fn_hash] = idx;
return 0;
return INFO_CB_CONTINUE;
}
// initialize lookup data structure for the given Zip archive:
// adds all files to the index.
static int lookup_init(LookupInfo* li, const u8* file, const size_t size)
static LibError lookup_init(LookupInfo* li, const u8* file, const size_t size)
{
int err;
LibError err;
// check if it's even a Zip file.
// the VFS blindly opens files when mounting; it needs to open
@ -497,21 +511,21 @@ static int lookup_init(LookupInfo* li, const u8* file, const size_t size)
return err;
}
return 0;
return ERR_OK;
}
static int lookup_validate(const LookupInfo* li)
static LibError lookup_validate(const LookupInfo* li)
{
if(debug_is_pointer_bogus(li->ents) || debug_is_pointer_bogus(li->fn_hashes))
return -2;
return ERR_1;
if(li->num_files > li->num_entries || li->next_file > li->num_entries)
return -3;
return ERR_2;
if(li->num_entries < 0 || li->num_files < 0 || li->next_file < 0)
return -4;
return ERR_3;
if(debug_is_pointer_bogus(li->idx))
return -5;
return 0;
return ERR_4;
return ERR_OK;
}
@ -536,7 +550,7 @@ static void lookup_free(LookupInfo* li)
// look up ZLoc, given filename (untrusted!).
static int lookup_get_file_info(LookupInfo* li, const char* fn, ZLoc* loc)
static LibError lookup_get_file_info(LookupInfo* li, const char* fn, ZLoc* loc)
{
const FnHash fn_hash = fnv_lc_hash(fn);
@ -565,14 +579,14 @@ have_idx:
li->next_file = i+1;
*loc = li->ents[i].loc;
return 0;
return ERR_OK;
}
// successively call <cb> for each valid file in the index,
// passing the complete path and <user>.
// if it returns a nonzero value, abort and return that, otherwise 0.
static int lookup_enum_files(LookupInfo* li, FileCB cb, uintptr_t user)
static LibError lookup_enum_files(LookupInfo* li, FileCB cb, uintptr_t user)
{
struct stat s;
memset(&s, 0, sizeof(s));
@ -584,12 +598,12 @@ static int lookup_enum_files(LookupInfo* li, FileCB cb, uintptr_t user)
s.st_size = (off_t)ent->loc.ucsize;
s.st_mtime = ent->loc.mtime;
int ret = cb(ent->fn, &s, user);
if(ret != 0)
LibError ret = cb(ent->fn, &s, user);
if(ret != INFO_CB_CONTINUE)
return ret;
}
return 0;
return ERR_OK;
}
@ -646,7 +660,7 @@ static void ZArchive_dtor(ZArchive* za)
}
}
static int ZArchive_reload(ZArchive* za, const char* fn, Handle)
static LibError ZArchive_reload(ZArchive* za, const char* fn, Handle)
{
// (note: don't warn on failure - this happens when
// vfs_mount blindly zip_archive_opens a dir)
@ -665,20 +679,20 @@ static int ZArchive_reload(ZArchive* za, const char* fn, Handle)
(void)file_unmap(&za->f);
za->is_mapped = 0;
return 0;
return ERR_OK;
}
static int ZArchive_validate(const ZArchive* za)
static LibError ZArchive_validate(const ZArchive* za)
{
RETURN_ERR(file_validate(&za->f));
RETURN_ERR(lookup_validate(&za->li));
return 0;
return ERR_OK;
}
static int ZArchive_to_string(const ZArchive* za, char* buf)
static LibError ZArchive_to_string(const ZArchive* za, char* buf)
{
snprintf(buf, H_STRING_LEN, "(%d files)", lookup_get_num_files(&za->li));
return 0;
return ERR_OK;
}
@ -693,7 +707,7 @@ TIMER("zip_archive_open");
// close the archive <ha> and set ha to 0
int zip_archive_close(Handle& ha)
LibError zip_archive_close(Handle& ha)
{
return h_free(ha, H_ZArchive);
}
@ -702,7 +716,7 @@ int zip_archive_close(Handle& ha)
// successively call <cb> for each valid file in the archive <ha>,
// passing the complete path and <user>.
// if it returns a nonzero value, abort and return that, otherwise 0.
int zip_enum(const Handle ha, const FileCB cb, const uintptr_t user)
LibError zip_enum(const Handle ha, const FileCB cb, const uintptr_t user)
{
H_DEREF(ha, ZArchive, za);
@ -717,6 +731,27 @@ int zip_enum(const Handle ha, const FileCB cb, const uintptr_t user)
//
///////////////////////////////////////////////////////////////////////////////
static LibError LibError_from_zlib(int err)
{
switch(err)
{
case Z_OK:
return ERR_OK;
case Z_STREAM_END:
return ERR_EOF;
case Z_MEM_ERROR:
return ERR_NO_MEM;
case Z_DATA_ERROR:
return ERR_CORRUPTED;
case Z_STREAM_ERROR:
return ERR_INVALID_PARAM;
default:
return ERR_FAIL;
}
UNREACHABLE;
}
// must be dynamically allocated - need one for every open ZFile,
// and z_stream is large.
struct InfCtx
@ -767,7 +802,7 @@ static void free_in_buf(InfCtx* ctx)
// subsequent calls to inf_inflate will unzip into <out>.
int inf_set_dest(uintptr_t _ctx, void* out, size_t out_size)
LibError inf_set_dest(uintptr_t _ctx, void* out, size_t out_size)
{
#ifdef NO_ZLIB
return -1;
@ -778,11 +813,11 @@ int inf_set_dest(uintptr_t _ctx, void* out, size_t out_size)
if(zs->next_out || zs->avail_out)
{
debug_warn("ctx already in use!");
return -1;
return ERR_FAIL;
}
zs->next_out = (Byte*)out;
zs->avail_out = (uInt)out_size;
return 0;
return ERR_OK;
#endif
}
@ -815,12 +850,20 @@ ssize_t inf_inflate(uintptr_t _ctx, void* in, size_t in_size, bool free_in_buf =
ctx->in_buf = in;
}
int err = 0;
LibError err = ERR_OK;
if(ctx->compressed)
{
TIMER_ACCRUE(tc_zip_inflate);
err = inflate(zs, Z_SYNC_FLUSH);
int ret = inflate(zs, Z_SYNC_FLUSH);
err = LibError_from_zlib(ret);
// sanity check: if ZLib reports end of stream, all input data
// must have been consumed.
if(err == ERR_EOF)
{
debug_assert(zs->avail_in == 0);
err = ERR_OK;
}
}
else
{
@ -856,7 +899,7 @@ ssize_t inf_inflate(uintptr_t _ctx, void* in, size_t in_size, bool free_in_buf =
// free the given context.
int inf_free_ctx(uintptr_t _ctx)
LibError inf_free_ctx(uintptr_t _ctx)
{
#ifdef NO_ZLIB
return -1;
@ -871,7 +914,7 @@ int inf_free_ctx(uintptr_t _ctx)
inflateEnd(zs);
free(ctx);
return 0;
return ERR_OK;
#endif
}
@ -896,7 +939,7 @@ static inline bool zfile_compressed(ZFile* zf)
// get file status (size, mtime). output param is zeroed on error.
int zip_stat(Handle ha, const char* fn, struct stat* s)
LibError zip_stat(Handle ha, const char* fn, struct stat* s)
{
// zero output param in case we fail below.
memset(s, 0, sizeof(struct stat));
@ -909,24 +952,24 @@ int zip_stat(Handle ha, const char* fn, struct stat* s)
s->st_size = loc.ucsize;
s->st_mtime = loc.mtime;
return 0;
return ERR_OK;
}
int zip_validate(const ZFile* zf)
LibError zip_validate(const ZFile* zf)
{
if(!zf)
return ERR_INVALID_PARAM;
// note: don't check zf->ha - it may be freed at shutdown before
// its files. TODO: revisit once dependency support is added.
if(!zf->ucsize)
return -2;
return ERR_1;
else if(!zf->inf_ctx)
return -3;
return ERR_2;
return 0;
return ERR_OK;
}
#define CHECK_ZFILE(zf) CHECK_ERR(zip_validate(zf))
@ -934,7 +977,7 @@ int zip_validate(const ZFile* zf)
// open file, and fill *zf with information about it.
// return < 0 on error (output param zeroed).
int zip_open(const Handle ha, const char* fn, int flags, ZFile* zf)
LibError zip_open(const Handle ha, const char* fn, int flags, ZFile* zf)
{
// zero output param in case we fail below.
memset(zf, 0, sizeof(ZFile));
@ -956,12 +999,12 @@ int zip_open(const Handle ha, const char* fn, int flags, ZFile* zf)
zf->inf_ctx = inf_init_ctx(zfile_compressed(zf));
zf->is_mapped = 0;
CHECK_ZFILE(zf);
return 0;
return ERR_OK;
}
// close file.
int zip_close(ZFile* zf)
LibError zip_close(ZFile* zf)
{
CHECK_ZFILE(zf);
// other ZFile fields don't need to be freed/cleared
@ -989,7 +1032,7 @@ static const size_t CHUNK_SIZE = 16*KiB;
// begin transferring <size> bytes, starting at <ofs>. get result
// with zip_io_wait; when no longer needed, free via zip_io_discard.
int zip_io_issue(ZFile* zf, off_t user_ofs, size_t max_output_size, void* user_buf, ZipIo* io)
LibError zip_io_issue(ZFile* zf, off_t user_ofs, size_t max_output_size, void* user_buf, ZipIo* io)
{
// not needed, since ZFile tells us the last read offset in the file.
UNUSED2(user_ofs);
@ -1023,7 +1066,7 @@ int zip_io_issue(ZFile* zf, off_t user_ofs, size_t max_output_size, void* user_b
{
io->already_inflated = true;
io->max_output_size = bytes_inflated;
return 0;
return ERR_OK;
}
// read up to next chunk (so that the next read is aligned -
@ -1043,7 +1086,7 @@ int zip_io_issue(ZFile* zf, off_t user_ofs, size_t max_output_size, void* user_b
CHECK_ERR(file_io_issue(&za->f, ofs, size, buf, &io->io));
return 0;
return ERR_OK;
}
@ -1059,12 +1102,12 @@ int zip_io_has_completed(ZipIo* io)
// wait until the transfer <io> completes, and return its buffer.
// output parameters are zeroed on error.
int zip_io_wait(ZipIo* io, void*& buf, size_t& size)
LibError zip_io_wait(ZipIo* io, void*& buf, size_t& size)
{
buf = io->user_buf;
size = io->max_output_size;
if(io->already_inflated)
return 0;
return ERR_OK;
void* raw_buf;
size_t raw_size;
@ -1085,28 +1128,28 @@ int zip_io_wait(ZipIo* io, void*& buf, size_t& size)
size = raw_size;
}
return 0;
return ERR_OK;
}
// finished with transfer <io> - free its buffer (returned by zip_io_wait)
int zip_io_discard(ZipIo* io)
LibError zip_io_discard(ZipIo* io)
{
if(io->already_inflated)
return 0;
return ERR_OK;
return file_io_discard(&io->io);
}
int zip_io_validate(const ZipIo* io)
LibError zip_io_validate(const ZipIo* io)
{
if(debug_is_pointer_bogus(io->user_buf))
return -2;
return ERR_1;
if(*(u8*)&io->already_inflated > 1)
return -3;
return ERR_2;
// <inf_ctx> and <max_output_size> have no invariants we could check.
RETURN_ERR(file_io_validate(&io->io));
return 0;
return ERR_OK;
}
@ -1229,7 +1272,7 @@ ssize_t zip_read(ZFile* zf, off_t ofs, size_t size, void* p, FileIOCB cb, uintpt
// the mapping will be removed (if still open) when its file is closed.
// however, map/unmap calls should still be paired so that the mapping
// may be removed when no longer needed.
int zip_map(ZFile* zf, void*& p, size_t& size)
LibError zip_map(ZFile* zf, void*& p, size_t& size)
{
p = 0;
size = 0;
@ -1239,10 +1282,7 @@ int zip_map(ZFile* zf, void*& p, size_t& size)
// mapping compressed files doesn't make sense because the
// compression algorithm is unspecified - disallow it.
if(zfile_compressed(zf))
{
debug_warn("file is compressed");
return -1;
}
CHECK_ERR(ERR_IS_COMPRESSED);
// note: we mapped the archive in zip_archive_open, but unmapped it
// in the meantime to save memory in case it wasn't going to be mapped.
@ -1256,7 +1296,7 @@ int zip_map(ZFile* zf, void*& p, size_t& size)
size = zf->ucsize;
zf->is_mapped = 1;
return 0;
return ERR_OK;
}
@ -1265,14 +1305,14 @@ int zip_map(ZFile* zf, void*& p, size_t& size)
// the mapping will be removed (if still open) when its archive is closed.
// however, map/unmap calls should be paired so that the archive mapping
// may be removed when no longer needed.
int zip_unmap(ZFile* zf)
LibError zip_unmap(ZFile* zf)
{
CHECK_ZFILE(zf);
// make sure archive mapping refcount remains balanced:
// don't allow multiple|"false" unmaps.
if(!zf->is_mapped)
return -1;
return ERR_FAIL;
zf->is_mapped = 0;
H_DEREF(zf->ha, ZArchive, za);

View File

@ -35,12 +35,12 @@
extern Handle zip_archive_open(const char* fn);
// close the archive <ha> and set ha to 0
extern int zip_archive_close(Handle& ha);
extern LibError zip_archive_close(Handle& ha);
// successively call <cb> for each valid file in the archive <ha>,
// passing the complete path and <user>.
// if it returns a nonzero value, abort and return that, otherwise 0.
extern int zip_enum(const Handle ha, const FileCB cb, const uintptr_t user);
extern LibError zip_enum(const Handle ha, const FileCB cb, const uintptr_t user);
//
@ -69,16 +69,16 @@ struct ZFile
};
// get file status (size, mtime). output param is zeroed on error.
extern int zip_stat(Handle ha, const char* fn, struct stat* s);
extern LibError zip_stat(Handle ha, const char* fn, struct stat* s);
// open file, and fill *zf with information about it.
// return < 0 on error (output param zeroed).
extern int zip_open(Handle ha, const char* fn, int flags, ZFile* zf);
extern LibError zip_open(Handle ha, const char* fn, int flags, ZFile* zf);
// close file.
extern int zip_close(ZFile* zf);
extern LibError zip_close(ZFile* zf);
extern int zip_validate(const ZFile* zf);
extern LibError zip_validate(const ZFile* zf);
//
@ -99,7 +99,7 @@ struct ZipIo
// begin transferring <size> bytes, starting at <ofs>. get result
// with zip_io_wait; when no longer needed, free via zip_io_discard.
extern int zip_io_issue(ZFile* zf, off_t ofs, size_t size, void* buf, ZipIo* io);
extern LibError zip_io_issue(ZFile* zf, off_t ofs, size_t size, void* buf, ZipIo* io);
// indicates if the IO referenced by <io> has completed.
// return value: 0 if pending, 1 if complete, < 0 on error.
@ -107,12 +107,12 @@ extern int zip_io_has_completed(ZipIo* io);
// wait until the transfer <io> completes, and return its buffer.
// output parameters are zeroed on error.
extern int zip_io_wait(ZipIo* io, void*& p, size_t& size);
extern LibError zip_io_wait(ZipIo* io, void*& p, size_t& size);
// finished with transfer <io> - free its buffer (returned by zip_io_wait)
extern int zip_io_discard(ZipIo* io);
extern LibError zip_io_discard(ZipIo* io);
extern int zip_io_validate(const ZipIo* io);
extern LibError zip_io_validate(const ZipIo* io);
//
@ -152,14 +152,14 @@ extern ssize_t zip_read(ZFile* zf, off_t ofs, size_t size, void* buf, FileIOCB c
// the mapping will be removed (if still open) when its archive is closed.
// however, map/unmap calls should still be paired so that the archive mapping
// may be removed when no longer needed.
extern int zip_map(ZFile* zf, void*& p, size_t& size);
extern LibError zip_map(ZFile* zf, void*& p, size_t& size);
// remove the mapping of file <zf>; fail if not mapped.
//
// the mapping will be removed (if still open) when its archive is closed.
// however, map/unmap calls should be paired so that the archive mapping
// may be removed when no longer needed.
extern int zip_unmap(ZFile* zf);
extern LibError zip_unmap(ZFile* zf);
#endif // #ifndef ZIP_H__

View File

@ -64,7 +64,7 @@ class GLCursor
uint hotspotx, hotspoty;
public:
int create(const char* filename, uint hotspotx_, uint hotspoty_)
LibError create(const char* filename, uint hotspotx_, uint hotspoty_)
{
ht = ogl_tex_load(filename);
RETURN_ERR(ht);
@ -75,7 +75,7 @@ public:
(void)ogl_tex_set_filter(ht, GL_NEAREST);
(void)ogl_tex_upload(ht);
return 0;
return ERR_OK;
}
void destroy()
@ -109,10 +109,10 @@ public:
{
const uint A = 128; // no cursor is expected to get this big
if(w > A || h > A || hotspotx > A || hotspoty > A)
return -2;
return ERR_1;
if(ht < 0)
return -3;
return 0;
return ERR_2;
return ERR_OK;
}
};
@ -141,7 +141,7 @@ static void Cursor_dtor(Cursor* c)
c->gl_cursor.destroy();
}
static int Cursor_reload(Cursor* c, const char* name, Handle)
static LibError Cursor_reload(Cursor* c, const char* name, Handle)
{
char filename[VFS_MAX_PATH];
@ -166,24 +166,24 @@ static int Cursor_reload(Cursor* c, const char* name, Handle)
if(!c->sys_cursor)
RETURN_ERR(c->gl_cursor.create(filename, hotspotx, hotspoty));
return 0;
return ERR_OK;
}
static int Cursor_validate(const Cursor* c)
static LibError Cursor_validate(const Cursor* c)
{
// note: system cursors have no state to speak of, so we don't need to
// validate them.
if(!c->sys_cursor)
RETURN_ERR(c->gl_cursor.validate());
return 0;
return ERR_OK;
}
static int Cursor_to_string(const Cursor* c, char* buf)
static LibError Cursor_to_string(const Cursor* c, char* buf)
{
const char* type = c->sys_cursor? "sys" : "gl";
snprintf(buf, H_STRING_LEN, "(%s)", type);
return 0;
return ERR_OK;
}
@ -198,7 +198,7 @@ static Handle cursor_load(const char* name)
return h_alloc(H_Cursor, name, 0);
}
static int cursor_free(Handle& h)
static LibError cursor_free(Handle& h)
{
return h_free(h, H_Cursor);
}
@ -208,13 +208,13 @@ static int cursor_free(Handle& h)
// (origin is top-left to match the windowing system).
// uses a hardware mouse cursor where available, otherwise a
// portable OpenGL implementation.
int cursor_draw(const char* name, int x, int y)
LibError cursor_draw(const char* name, int x, int y)
{
// Use 'null' to disable the cursor
if(!name)
{
WARN_ERR(sys_cursor_set(0));
return 0;
return ERR_OK;
}
Handle hc = cursor_load(name);
@ -227,5 +227,5 @@ int cursor_draw(const char* name, int x, int y)
c->gl_cursor.draw(x, y);
(void)cursor_free(hc);
return 0;
return ERR_OK;
}

View File

@ -5,7 +5,7 @@
// (origin is top-left to match the windowing system).
// uses a hardware mouse cursor where available, otherwise a
// portable OpenGL implementation.
extern int cursor_draw(const char* name, int x, int y);
extern LibError cursor_draw(const char* name, int x, int y);
// internal use only:
extern int g_yres;

View File

@ -72,12 +72,12 @@ static void Ogl_Shader_init(Ogl_Shader* shdr, va_list args)
// have absolutely no effect on a program object that contains these shaders
// when the program object is already linked.
// So, how can we inform the "parent object" (i.e. the program object) of our change?
static int Ogl_Shader_reload(Ogl_Shader* shdr, const char* filename, Handle UNUSED(h))
static LibError Ogl_Shader_reload(Ogl_Shader* shdr, const char* filename, Handle UNUSED(h))
{
int err = -666;
LibError err = ERR_FAIL;
if (shdr->id)
return 0;
return ERR_OK;
void* file;
size_t file_size;
@ -140,7 +140,7 @@ static int Ogl_Shader_reload(Ogl_Shader* shdr, const char* filename, Handle UNUS
}
mem_free_h(hm);
return 0;
return ERR_OK;
fail_shadercreated:
pglDeleteObjectARB(shdr->id);
@ -162,16 +162,16 @@ static void Ogl_Shader_dtor(Ogl_Shader* shdr)
}
}
static int Ogl_Shader_validate(const Ogl_Shader* UNUSED(shdr))
static LibError Ogl_Shader_validate(const Ogl_Shader* UNUSED(shdr))
{
// TODO
return 0;
return ERR_OK;
}
static int Ogl_Shader_to_string(const Ogl_Shader* UNUSED(shdr), char* buf)
static LibError Ogl_Shader_to_string(const Ogl_Shader* UNUSED(shdr), char* buf)
{
snprintf(buf, H_STRING_LEN, "");
return 0;
return ERR_OK;
}
@ -195,7 +195,7 @@ void ogl_shader_free(Handle& h)
}
// Attach a shader to the given OpenGL program.
int ogl_shader_attach(GLhandleARB program, Handle& h)
LibError ogl_shader_attach(GLhandleARB program, Handle& h)
{
H_DEREF(h, Ogl_Shader, shdr);
@ -204,7 +204,7 @@ int ogl_shader_attach(GLhandleARB program, Handle& h)
pglAttachObjectARB(program, shdr->id);
return 0;
return ERR_OK;
}
@ -230,7 +230,7 @@ static void Ogl_Program_init(Ogl_Program* UNUSED(p), va_list UNUSED(args))
// Load the shader associated with one Shader element,
// and attach it to our program object.
static int do_load_shader(
static LibError do_load_shader(
Ogl_Program* p, const char* filename, Handle UNUSED(h),
const CXeromyces& XeroFile, const XMBElement& Shader)
{
@ -275,15 +275,15 @@ static int do_load_shader(
// TODO: How will this work with automatic reload?
ogl_shader_free(hshader);
return 0;
return ERR_OK;
}
// Reload the program object from the source file.
static int Ogl_Program_reload(Ogl_Program* p, const char* filename, Handle h)
static LibError Ogl_Program_reload(Ogl_Program* p, const char* filename, Handle h)
{
if (p->id)
return 0;
return ERR_OK;
oglCheck();
@ -338,9 +338,7 @@ static int Ogl_Program_reload(Ogl_Program* p, const char* filename, Handle h)
return ERR_CORRUPTED;
}
int ret = do_load_shader(p, filename, h, XeroFile, Shader);
if (ret < 0)
return ret;
RETURN_ERR(do_load_shader(p, filename, h, XeroFile, Shader));
}
}
else
@ -371,7 +369,7 @@ static int Ogl_Program_reload(Ogl_Program* p, const char* filename, Handle h)
return ERR_SHDR_LINK;
}
return 0;
return ERR_OK;
}
@ -385,16 +383,16 @@ static void Ogl_Program_dtor(Ogl_Program* p)
}
}
static int Ogl_Program_validate(const Ogl_Program* UNUSED(p))
static LibError Ogl_Program_validate(const Ogl_Program* UNUSED(p))
{
// TODO
return 0;
return ERR_OK;
}
static int Ogl_Program_to_string(const Ogl_Program* UNUSED(p), char* buf)
static LibError Ogl_Program_to_string(const Ogl_Program* UNUSED(p), char* buf)
{
snprintf(buf, H_STRING_LEN, "");
return 0;
return ERR_OK;
}
@ -417,12 +415,12 @@ void ogl_program_free(Handle& h)
// Activate the program (glUseProgramObjectARB).
// h may be 0, in which case program objects are disabled.
int ogl_program_use(Handle h)
LibError ogl_program_use(Handle h)
{
if (!h)
{
pglUseProgramObjectARB(0);
return 0;
return ERR_OK;
}
Ogl_Program* p = H_USER_DATA(h, Ogl_Program);
@ -434,7 +432,7 @@ int ogl_program_use(Handle h)
}
pglUseProgramObjectARB(p->id);
return 0;
return ERR_OK;
}

View File

@ -26,7 +26,7 @@ void ogl_shader_free(Handle& h);
// Attach a shader to the given OpenGL program.
// Returns 0 on success and a negative error code otherwise.
int ogl_shader_attach(GLhandleARB program, Handle& h);
LibError ogl_shader_attach(GLhandleARB program, Handle& h);
/*
@ -42,7 +42,7 @@ void ogl_program_free(Handle& h);
// Activate the program (glUseProgramObjectARB).
// h may be 0, in which case program objects are disabled.
int ogl_program_use(Handle h);
LibError ogl_program_use(Handle h);
// Query uniform information
GLint ogl_program_get_uniform_location(Handle h, const char* name);

View File

@ -404,11 +404,11 @@ static void OglTex_dtor(OglTex* ot)
ot->flags &= ~OT_IS_UPLOADED;
}
static int OglTex_reload(OglTex* ot, const char* fn, Handle h)
static LibError OglTex_reload(OglTex* ot, const char* fn, Handle h)
{
// we're reusing a freed but still in-memory OglTex object
if(ot->flags & OT_IS_UPLOADED)
return 0;
return ERR_OK;
// if we don't already have the texture in memory (*), load from file.
// * this happens if the texture is "wrapped".
@ -423,10 +423,10 @@ static int OglTex_reload(OglTex* ot, const char* fn, Handle h)
if(ot->flags & OT_NEED_AUTO_UPLOAD)
(void)ogl_tex_upload(h);
return 0;
return ERR_OK;
}
static int OglTex_validate(const OglTex* ot)
static LibError OglTex_validate(const OglTex* ot)
{
RETURN_ERR(tex_validate(&ot->t));
@ -437,41 +437,41 @@ static int OglTex_validate(const OglTex* ot)
GLsizei h = (GLsizei)ot->t.h;
// .. == 0; texture file probably not loaded successfully.
if(w == 0 || h == 0)
return -100;
return ERR_11;
// .. greater than max supported tex dimension.
// no-op if oglInit not yet called
if(w > (GLsizei)ogl_max_tex_size || h > (GLsizei)ogl_max_tex_size)
return -101;
return ERR_12;
// .. not power-of-2.
// note: we can't work around this because both NV_texture_rectangle
// and subtexture require work for the client (changing tex coords).
// TODO: ARB_texture_non_power_of_two
if(!is_pow2(w) || !is_pow2(h))
return -102;
return ERR_13;
// texture state
if(!filter_valid(ot->state.filter))
return -103;
return ERR_14;
if(!wrap_valid(ot->state.wrap))
return -104;
return ERR_15;
// misc
if(!q_flags_valid(ot->q_flags))
return -105;
return ERR_16;
if(ot->tmu >= 128) // unexpected that there will ever be this many
return -106;
return ERR_17;
if(ot->flags > OT_ALL_FLAGS)
return -107;
return ERR_18;
// .. note: don't check ot->fmt and ot->int_fmt - they aren't set
// until during ogl_tex_upload.
return 0;
return ERR_OK;
}
static int OglTex_to_string(const OglTex* ot, char* buf)
static LibError OglTex_to_string(const OglTex* ot, char* buf)
{
snprintf(buf, H_STRING_LEN, "id=%d", ot->id);
return 0;
return ERR_OK;
}
@ -520,7 +520,7 @@ Handle ogl_tex_wrap(Tex* t, const char* fn, uint flags)
// free all resources associated with the texture and make further
// use of it impossible. (subject to refcount)
int ogl_tex_free(Handle& ht)
LibError ogl_tex_free(Handle& ht)
{
return h_free(ht, H_OglTex);
}
@ -572,7 +572,7 @@ static void warn_if_uploaded(Handle ht, const OglTex* ot)
// must be called before uploading (raises a warning if called afterwards).
// filter is as defined by OpenGL; it is applied for both minification and
// magnification (for rationale and details, see OglTexState)
int ogl_tex_set_filter(Handle ht, GLint filter)
LibError ogl_tex_set_filter(Handle ht, GLint filter)
{
H_DEREF(ht, OglTex, ot);
@ -584,7 +584,7 @@ int ogl_tex_set_filter(Handle ht, GLint filter)
warn_if_uploaded(ht, ot);
ot->state.filter = filter;
}
return 0;
return ERR_OK;
}
@ -592,7 +592,7 @@ int ogl_tex_set_filter(Handle ht, GLint filter)
// must be called before uploading (raises a warning if called afterwards).
// wrap is as defined by OpenGL and applies to both S and T coordinates
// (rationale: see OglTexState).
int ogl_tex_set_wrap(Handle ht, GLint wrap)
LibError ogl_tex_set_wrap(Handle ht, GLint wrap)
{
H_DEREF(ht, OglTex, ot);
@ -604,7 +604,7 @@ int ogl_tex_set_wrap(Handle ht, GLint wrap)
warn_if_uploaded(ht, ot);
ot->state.wrap = wrap;
}
return 0;
return ERR_OK;
}
@ -676,7 +676,7 @@ static void detect_gl_upload_caps()
// whether mipmaps are needed and the quality settings).
// returns 0 to indicate success; otherwise, caller must disable
// mipmapping by switching filter to e.g. GL_LINEAR.
static int get_mipmaps(Tex* t, GLint filter, uint q_flags, int* plevels_to_skip)
static LibError get_mipmaps(Tex* t, GLint filter, uint q_flags, int* plevels_to_skip)
{
// decisions:
// .. does filter call for uploading mipmaps?
@ -689,7 +689,7 @@ static int get_mipmaps(Tex* t, GLint filter, uint q_flags, int* plevels_to_skip)
*plevels_to_skip = TEX_BASE_LEVEL_ONLY;
if(!need_mipmaps)
return 0;
return ERR_OK;
// image already contains pregenerated mipmaps; we need do nothing.
// this is the nicest case, because they are fastest to load
@ -712,7 +712,7 @@ static int get_mipmaps(Tex* t, GLint filter, uint q_flags, int* plevels_to_skip)
// all<->all transforms aren't implemented, it'd have to decompress
// from S3TC first), and DDS images ought to include mipmaps!
else if(is_s3tc)
return -1;
return ERR_FAIL;
// image is uncompressed and we're on an old OpenGL implementation;
// we will generate mipmaps in software.
else
@ -734,7 +734,7 @@ static int get_mipmaps(Tex* t, GLint filter, uint q_flags, int* plevels_to_skip)
*plevels_to_skip = log2(reduce);
}
return 0;
return ERR_OK;
}
@ -790,7 +790,7 @@ static void upload_impl(Tex* t, GLenum fmt, GLint int_fmt, int levels_to_skip)
// side effects:
// - enables texturing on TMU 0 and binds the texture to it;
// - frees the texel data! see ogl_tex_get_data.
int ogl_tex_upload(const Handle ht, GLenum fmt_ovr, uint q_flags_ovr, GLint int_fmt_ovr)
LibError ogl_tex_upload(const Handle ht, GLenum fmt_ovr, uint q_flags_ovr, GLint int_fmt_ovr)
{
ONCE(detect_gl_upload_caps());
@ -805,7 +805,7 @@ int ogl_tex_upload(const Handle ht, GLenum fmt_ovr, uint q_flags_ovr, GLint int_
// upload already happened; no work to do.
// (this also happens if a cached texture is "loaded")
if(ot->flags & OT_IS_UPLOADED)
return 0;
return ERR_OK;
debug_assert(ot->flags & OT_TEX_VALID);
@ -850,7 +850,7 @@ int ogl_tex_upload(const Handle ht, GLenum fmt_ovr, uint q_flags_ovr, GLint int_
ot->flags &= ~OT_TEX_VALID;
}
return 0;
return ERR_OK;
}
@ -860,7 +860,7 @@ int ogl_tex_upload(const Handle ht, GLenum fmt_ovr, uint q_flags_ovr, GLint int_
// retrieve texture dimensions and bits per pixel.
// all params are optional and filled if non-NULL.
int ogl_tex_get_size(Handle ht, uint* w, uint* h, uint* bpp)
LibError ogl_tex_get_size(Handle ht, uint* w, uint* h, uint* bpp)
{
H_DEREF(ht, OglTex, ot);
@ -870,14 +870,14 @@ int ogl_tex_get_size(Handle ht, uint* w, uint* h, uint* bpp)
*h = ot->t.h;
if(bpp)
*bpp = ot->t.bpp;
return 0;
return ERR_OK;
}
// retrieve Tex.flags and the corresponding OpenGL format.
// the latter is determined during ogl_tex_upload and is 0 before that.
// all params are optional and filled if non-NULL.
int ogl_tex_get_format(Handle ht, uint* flags, GLenum* fmt)
LibError ogl_tex_get_format(Handle ht, uint* flags, GLenum* fmt)
{
H_DEREF(ht, OglTex, ot);
@ -889,7 +889,7 @@ int ogl_tex_get_format(Handle ht, uint* flags, GLenum* fmt)
debug_warn("hasn't been defined yet!");
*fmt = ot->fmt;
}
return 0;
return ERR_OK;
}
@ -900,12 +900,12 @@ int ogl_tex_get_format(Handle ht, uint* flags, GLenum* fmt)
// the function doesn't fail (negative return value) by design.
// if you still need to get at the data, add a reference before
// uploading it or read directly from OpenGL (discouraged).
int ogl_tex_get_data(Handle ht, void** p)
LibError ogl_tex_get_data(Handle ht, void** p)
{
H_DEREF(ht, OglTex, ot);
*p = tex_get_data(&ot->t);
return 0;
return ERR_OK;
}
@ -924,7 +924,7 @@ int ogl_tex_get_data(Handle ht, void** p)
// - assumes multitexturing is available.
// - not necessary before calling ogl_tex_upload!
// - on error, the unit's texture state is unchanged; see implementation.
int ogl_tex_bind(Handle ht, uint unit)
LibError ogl_tex_bind(Handle ht, uint unit)
{
// note: there are many call sites of glActiveTextureARB, so caching
// those and ignoring redundant sets isn't feasible.
@ -934,7 +934,7 @@ int ogl_tex_bind(Handle ht, uint unit)
if(ht == 0)
{
glDisable(GL_TEXTURE_2D);
return 0;
return ERR_OK;
}
// if this fails, the texture unit's state remains unchanged.
@ -950,25 +950,25 @@ int ogl_tex_bind(Handle ht, uint unit)
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, ot->id);
return 0;
return ERR_OK;
}
// apply the specified transforms (as in tex_transform) to the image.
// must be called before uploading (raises a warning if called afterwards).
int ogl_tex_transform(Handle ht, uint transforms)
LibError ogl_tex_transform(Handle ht, uint transforms)
{
H_DEREF(ht, OglTex, ot);
int ret = tex_transform(&ot->t, transforms);
LibError ret = tex_transform(&ot->t, transforms);
return ret;
}
// change the pixel format to that specified by <new_flags>.
// (note: this is equivalent to ogl_tex_transform(ht, ht_flags^new_flags).
int ogl_tex_transform_to(Handle ht, uint new_flags)
LibError ogl_tex_transform_to(Handle ht, uint new_flags)
{
H_DEREF(ht, OglTex, ot);
int ret = tex_transform_to(&ot->t, new_flags);
LibError ret = tex_transform_to(&ot->t, new_flags);
return ret;
}

View File

@ -214,7 +214,7 @@ extern Handle ogl_tex_wrap(Tex* t, const char* fn = 0, uint flags = 0);
// free all resources associated with the texture and make further
// use of it impossible. (subject to refcount)
extern int ogl_tex_free(Handle& ht);
extern LibError ogl_tex_free(Handle& ht);
//
@ -228,13 +228,13 @@ extern int ogl_tex_free(Handle& ht);
// must be called before uploading (raises a warning if called afterwards).
// filter is as defined by OpenGL; it is applied for both minification and
// magnification (for rationale and details, see OglTexState)
extern int ogl_tex_set_filter(Handle ht, GLint filter);
extern LibError ogl_tex_set_filter(Handle ht, GLint filter);
// override default wrap mode (GL_REPEAT) for this texture.
// must be called before uploading (raises a warning if called afterwards).
// wrap is as defined by OpenGL and applies to both S and T coordinates
// (rationale: see OglTexState).
extern int ogl_tex_set_wrap(Handle ht, GLint wrap);
extern LibError ogl_tex_set_wrap(Handle ht, GLint wrap);
//
@ -266,7 +266,7 @@ extern void ogl_tex_override(OglTexOverrides what, OglTexAllow allow);
// side effects:
// - enables texturing on TMU 0 and binds the texture to it;
// - frees the texel data! see ogl_tex_get_data.
extern int ogl_tex_upload(const Handle ht, GLenum fmt_ovr = 0, uint q_flags_ovr = 0, GLint int_fmt_ovr = 0);
extern LibError ogl_tex_upload(const Handle ht, GLenum fmt_ovr = 0, uint q_flags_ovr = 0, GLint int_fmt_ovr = 0);
//
@ -275,12 +275,12 @@ extern int ogl_tex_upload(const Handle ht, GLenum fmt_ovr = 0, uint q_flags_ovr
// retrieve texture dimensions and bits per pixel.
// all params are optional and filled if non-NULL.
extern int ogl_tex_get_size(Handle ht, uint* w, uint* h, uint* bpp);
extern LibError ogl_tex_get_size(Handle ht, uint* w, uint* h, uint* bpp);
// retrieve Tex.flags and the corresponding OpenGL format.
// the latter is determined during ogl_tex_upload and is 0 before that.
// all params are optional and filled if non-NULL.
extern int ogl_tex_get_format(Handle ht, uint* flags, GLenum* fmt);
extern LibError ogl_tex_get_format(Handle ht, uint* flags, GLenum* fmt);
// retrieve pointer to texel data.
//
@ -289,7 +289,7 @@ extern int ogl_tex_get_format(Handle ht, uint* flags, GLenum* fmt);
// the function doesn't fail (negative return value) by design.
// if you still need to get at the data, add a reference before
// uploading it or read directly from OpenGL (discouraged).
extern int ogl_tex_get_data(Handle ht, void** p);
extern LibError ogl_tex_get_data(Handle ht, void** p);
//
@ -307,14 +307,14 @@ extern int ogl_tex_get_data(Handle ht, void** p);
// - assumes multitexturing is available.
// - not necessary before calling ogl_tex_upload!
// - on error, the unit's texture state is unchanged; see implementation.
extern int ogl_tex_bind(Handle ht, uint unit = 0);
extern LibError ogl_tex_bind(Handle ht, uint unit = 0);
// apply the specified transforms (as in tex_transform) to the image.
// must be called before uploading (raises a warning if called afterwards).
extern int ogl_tex_transform(Handle ht, uint flags);
extern LibError ogl_tex_transform(Handle ht, uint flags);
// change the pixel format to that specified by <new_flags>.
// (note: this is equivalent to ogl_tex_transform(ht, ht_flags^new_flags).
extern int ogl_tex_transform_to(Handle ht, uint new_flags);
extern LibError ogl_tex_transform_to(Handle ht, uint new_flags);
#endif // #ifndef OGL_TEX_H__

View File

@ -31,7 +31,7 @@
// be careful not to use other tex_* APIs here because they call us.
int tex_validate(const Tex* t)
LibError tex_validate(const Tex* t)
{
// pixel data
size_t tex_file_size;
@ -44,25 +44,25 @@ int tex_validate(const Tex* t)
// possible causes: texture file header is invalid,
// or file wasn't loaded completely.
if(tex_file_size < t->ofs + t->w*t->h*t->bpp/8)
return -2;
return ERR_1;
}
// bits per pixel
// (we don't bother checking all values; a sanity check is enough)
if(t->bpp % 4 || t->bpp > 32)
return -3;
return ERR_2;
// flags
// .. DXT value
const uint dxt = t->flags & TEX_DXT;
if(dxt != 0 && dxt != 1 && dxt != DXT1A && dxt != 3 && dxt != 5)
return -4;
return ERR_3;
// .. orientation
const uint orientation = t->flags & TEX_ORIENTATION;
if(orientation == (TEX_BOTTOM_UP|TEX_TOP_DOWN))
return -5;
return ERR_4;
return 0;
return ERR_OK;
}
#define CHECK_TEX(t) CHECK_ERR(tex_validate(t))
@ -74,7 +74,7 @@ int tex_validate(const Tex* t)
// tex_codec_plain_transform.
// return 0 if ok, otherwise negative error code (but doesn't warn;
// caller is responsible for using CHECK_ERR et al.)
int tex_validate_plain_format(uint bpp, uint flags)
LibError tex_validate_plain_format(uint bpp, uint flags)
{
const bool alpha = (flags & TEX_ALPHA ) != 0;
const bool grey = (flags & TEX_GREY ) != 0;
@ -88,14 +88,14 @@ int tex_validate_plain_format(uint bpp, uint flags)
if(grey)
{
if(bpp == 8 && !alpha)
return 0;
return ERR_OK;
return ERR_TEX_FMT_INVALID;
}
if(bpp == 24 && !alpha)
return 0;
return ERR_OK;
if(bpp == 32 && alpha)
return 0;
return ERR_OK;
return ERR_TEX_FMT_INVALID;
}
@ -181,7 +181,7 @@ TIMER_ADD_CLIENT(tc_plain_transform);
// but is much easier to maintain than providing all<->all conversion paths.
//
// somewhat optimized (loops are hoisted, cache associativity accounted for)
static int plain_transform(Tex* t, uint transforms)
static LibError plain_transform(Tex* t, uint transforms)
{
TIMER_ACCRUE(tc_plain_transform);
@ -197,13 +197,13 @@ TIMER_ACCRUE(tc_plain_transform);
// sanity checks (not errors, we just can't handle these cases)
// .. unknown transform
if(transforms & ~(TEX_BGR|TEX_ORIENTATION|TEX_MIPMAPS))
return TEX_CODEC_CANNOT_HANDLE;
return ERR_TEX_CODEC_CANNOT_HANDLE;
// .. data is not in "plain" format
if(tex_validate_plain_format(bpp, flags) != 0)
return TEX_CODEC_CANNOT_HANDLE;
return ERR_TEX_CODEC_CANNOT_HANDLE;
// .. nothing to do
if(!transforms)
return 0;
return ERR_OK;
// setup row source/destination pointers (simplifies outer loop)
u8* dst = data;
@ -295,7 +295,7 @@ TIMER_ACCRUE(tc_plain_transform);
}
CHECK_TEX(t);
return 0;
return ERR_OK;
}
@ -407,7 +407,7 @@ void tex_util_foreach_mipmap(uint w, uint h, uint bpp, const u8* restrict data,
//-----------------------------------------------------------------------------
// split out of tex_load to ease resource cleanup
static int tex_load_impl(void* file_, size_t file_size, Tex* t)
static LibError tex_load_impl(void* file_, size_t file_size, Tex* t)
{
u8* file = (u8*)file_;
const TexCodecVTbl* c;
@ -438,20 +438,20 @@ static int tex_load_impl(void* file_, size_t file_size, Tex* t)
flip_to_global_orientation(t);
return 0;
return ERR_OK;
}
// load the specified image from file into the given Tex object.
// currently supports BMP, TGA, JPG, JP2, PNG, DDS.
int tex_load(const char* fn, Tex* t)
LibError tex_load(const char* fn, Tex* t)
{
// load file
void* file; size_t file_size;
Handle hm = vfs_load(fn, file, file_size);
RETURN_ERR(hm); // (need handle below; can't test return value directly)
t->hm = hm;
int ret = tex_load_impl(file, file_size, t);
LibError ret = tex_load_impl(file, file_size, t);
if(ret < 0)
{
(void)tex_free(t);
@ -463,7 +463,7 @@ int tex_load(const char* fn, Tex* t)
// wasn't compressed) or was replaced by a new buffer for the image data.
CHECK_TEX(t);
return 0;
return ERR_OK;
}
@ -480,7 +480,7 @@ int tex_load(const char* fn, Tex* t)
//
// we need only add bookkeeping information and "wrap" it in
// our Tex struct, hence the name.
int tex_wrap(uint w, uint h, uint bpp, uint flags, void* img, Tex* t)
LibError tex_wrap(uint w, uint h, uint bpp, uint flags, void* img, Tex* t)
{
t->w = w;
t->h = h;
@ -500,18 +500,18 @@ int tex_wrap(uint w, uint h, uint bpp, uint flags, void* img, Tex* t)
t->ofs = (u8*)img - (u8*)reported_ptr;
CHECK_TEX(t);
return 0;
return ERR_OK;
}
// free all resources associated with the image and make further
// use of it impossible.
int tex_free(Tex* t)
LibError tex_free(Tex* t)
{
// do not validate <t> - this is called from tex_load if loading
// failed, so not all fields may be valid.
int ret = mem_free_h(t->hm);
LibError ret = mem_free_h(t->hm);
// do not zero out the fields! that could lead to trouble since
// ogl_tex_upload followed by ogl_tex_free is legit, but would
@ -526,7 +526,7 @@ TIMER_ADD_CLIENT(tc_transform);
// change <t>'s pixel format by flipping the state of all TEX_* flags
// that are set in transforms.
int tex_transform(Tex* t, uint transforms)
LibError tex_transform(Tex* t, uint transforms)
{
TIMER_ACCRUE(tc_transform);
CHECK_TEX(t);
@ -538,22 +538,22 @@ TIMER_ACCRUE(tc_transform);
remaining_transforms = target_flags ^ t->flags;
// we're finished (all required transforms have been done)
if(remaining_transforms == 0)
return 0;
return ERR_OK;
int ret = tex_codec_transform(t, remaining_transforms);
LibError ret = tex_codec_transform(t, remaining_transforms);
if(ret != 0)
break;
}
// last chance
CHECK_ERR(plain_transform(t, remaining_transforms));
return 0;
return ERR_OK;
}
// change <t>'s pixel format to the new format specified by <new_flags>.
// (note: this is equivalent to tex_transform(t, t->flags^new_flags).
int tex_transform_to(Tex* t, uint new_flags)
LibError tex_transform_to(Tex* t, uint new_flags)
{
// tex_transform takes care of validating <t>
const uint transforms = t->flags ^ new_flags;
@ -621,7 +621,7 @@ size_t tex_hdr_size(const char* fn)
// write the specified texture to disk.
// note: <t> cannot be made const because the image may have to be
// transformed to write it out in the format determined by <fn>'s extension.
int tex_write(Tex* t, const char* fn)
LibError tex_write(Tex* t, const char* fn)
{
CHECK_TEX(t);
CHECK_ERR(tex_validate_plain_format(t->bpp, t->flags));
@ -639,7 +639,7 @@ int tex_write(Tex* t, const char* fn)
CHECK_ERR(tex_codec_for_filename(fn, &c));
// encode into <da>
int err;
LibError err;
size_t rounded_size;
ssize_t bytes_written;
err = c->encode(t, &da);

View File

@ -185,7 +185,7 @@ extern void tex_set_global_orientation(int orientation);
// load the specified image from file into the given Tex object.
// currently supports BMP, TGA, JPG, JP2, PNG, DDS.
extern int tex_load(const char* fn, Tex* t);
extern LibError tex_load(const char* fn, Tex* t);
// store the given image data into a Tex object; this will be as if
// it had been loaded via tex_load.
@ -200,11 +200,11 @@ extern int tex_load(const char* fn, Tex* t);
//
// we need only add bookkeeping information and "wrap" it in
// our Tex struct, hence the name.
extern int tex_wrap(uint w, uint h, uint bpp, uint flags, void* img, Tex* t);
extern LibError tex_wrap(uint w, uint h, uint bpp, uint flags, void* img, Tex* t);
// free all resources associated with the image and make further
// use of it impossible.
extern int tex_free(Tex* t);
extern LibError tex_free(Tex* t);
//
@ -213,11 +213,11 @@ extern int tex_free(Tex* t);
// change <t>'s pixel format by flipping the state of all TEX_* flags
// that are set in transforms.
extern int tex_transform(Tex* t, uint transforms);
extern LibError tex_transform(Tex* t, uint transforms);
// change <t>'s pixel format to the new format specified by <new_flags>.
// (note: this is equivalent to tex_transform(t, t->flags^new_flags).
extern int tex_transform_to(Tex* t, uint new_flags);
extern LibError tex_transform_to(Tex* t, uint new_flags);
//
@ -255,11 +255,11 @@ extern size_t tex_hdr_size(const char* fn);
// write the specified texture to disk.
// note: <t> cannot be made const because the image may have to be
// transformed to write it out in the format determined by <fn>'s extension.
extern int tex_write(Tex* t, const char* fn);
extern LibError tex_write(Tex* t, const char* fn);
// internal use only:
extern int tex_validate(const Tex* t);
extern LibError tex_validate(const Tex* t);
// check if the given texture format is acceptable: 8bpp grey,
// 24bpp color or 32bpp color+alpha (BGR / upside down are permitted).
@ -267,7 +267,7 @@ extern int tex_validate(const Tex* t);
// tex_codec_plain_transform.
// return 0 if ok, otherwise negative error code (but doesn't warn;
// caller is responsible for using CHECK_ERR et al.)
extern int tex_validate_plain_format(uint bpp, uint flags);
extern LibError tex_validate_plain_format(uint bpp, uint flags);
// indicate if the orientation specified by <src_flags> matches
@ -276,7 +276,7 @@ extern int tex_validate_plain_format(uint bpp, uint flags);
// have to mask off TEX_ORIENTATION)
extern bool tex_orientations_match(uint src_flags, uint dst_orientation);
typedef void(*MipmapCB)(uint level, uint level_w, uint level_h,
typedef void (*MipmapCB)(uint level, uint level_w, uint level_h,
const u8* level_data, size_t level_data_size, void* ctx);
// special value for levels_to_skip: the callback will only be called

View File

@ -34,9 +34,9 @@ struct BmpHeader
#define BI_RGB 0 // biCompression
static int bmp_transform(Tex* UNUSED(t), uint UNUSED(transforms))
static LibError bmp_transform(Tex* UNUSED(t), uint UNUSED(transforms))
{
return TEX_CODEC_CANNOT_HANDLE;
return ERR_TEX_CODEC_CANNOT_HANDLE;
}
@ -69,7 +69,7 @@ static size_t bmp_hdr_size(const u8* file)
// requirements: uncompressed, direct colour, bottom up
static int bmp_decode(DynArray* restrict da, Tex* restrict t)
static LibError bmp_decode(DynArray* restrict da, Tex* restrict t)
{
u8* file = da->base;
@ -96,11 +96,11 @@ static int bmp_decode(DynArray* restrict da, Tex* restrict t)
t->h = h;
t->bpp = bpp;
t->flags = flags;
return 0;
return ERR_OK;
}
static int bmp_encode(Tex* restrict t, DynArray* restrict da)
static LibError bmp_encode(Tex* restrict t, DynArray* restrict da)
{
const size_t hdr_size = sizeof(BmpHeader); // needed for BITMAPFILEHEADER
const size_t img_size = tex_img_size(t);

View File

@ -12,6 +12,8 @@ static const TexCodecVTbl* codecs;
// TEX_CODEC_REGISTER in each codec file. note that call order and therefore
// order in the list is undefined, but since each codec only steps up if it
// can handle the given format, this is not a problem.
//
// returns int to alloc calling from a macro at file scope.
int tex_codec_register(TexCodecVTbl* c)
{
debug_assert(c);
@ -25,7 +27,7 @@ int tex_codec_register(TexCodecVTbl* c)
// find codec that recognizes the desired output file extension
int tex_codec_for_filename(const char* fn, const TexCodecVTbl** c)
LibError tex_codec_for_filename(const char* fn, const TexCodecVTbl** c)
{
const char* ext = strrchr(fn, '.');
if(!ext)
@ -36,7 +38,7 @@ int tex_codec_for_filename(const char* fn, const TexCodecVTbl** c)
{
// we found it
if((*c)->is_ext(ext))
return 0;
return ERR_OK;
}
return ERR_UNKNOWN_FORMAT;
@ -44,7 +46,7 @@ int tex_codec_for_filename(const char* fn, const TexCodecVTbl** c)
// find codec that recognizes the header's magic field
int tex_codec_for_header(const u8* file, size_t file_size, const TexCodecVTbl** c)
LibError tex_codec_for_header(const u8* file, size_t file_size, const TexCodecVTbl** c)
{
// we guarantee at least 4 bytes for is_hdr to look at
if(file_size < 4)
@ -54,26 +56,26 @@ int tex_codec_for_header(const u8* file, size_t file_size, const TexCodecVTbl**
{
// we found it
if((*c)->is_hdr(file))
return 0;
return ERR_OK;
}
return ERR_UNKNOWN_FORMAT;
}
int tex_codec_transform(Tex* t, uint transforms)
LibError tex_codec_transform(Tex* t, uint transforms)
{
int ret = TEX_CODEC_CANNOT_HANDLE;
LibError ret = ERR_TEX_CODEC_CANNOT_HANDLE;
// find codec that understands the data, and transform
for(const TexCodecVTbl* c = codecs; c; c = c->next)
{
int err = c->transform(t, transforms);
LibError err = c->transform(t, transforms);
// success
if(err == 0)
return 0;
if(err == ERR_OK)
return ERR_OK;
// something went wrong
else if(err != TEX_CODEC_CANNOT_HANDLE)
else if(err != ERR_TEX_CODEC_CANNOT_HANDLE)
{
ret = err;
debug_warn("codec indicates error");
@ -97,7 +99,7 @@ int tex_codec_transform(Tex* t, uint transforms)
//
// note: we don't allocate the data param ourselves because this function is
// needed for encoding, too (where data is already present).
int tex_codec_alloc_rows(const u8* data, size_t h, size_t pitch,
LibError tex_codec_alloc_rows(const u8* data, size_t h, size_t pitch,
uint src_flags, uint dst_orientation, RowArray& rows)
{
const bool flip = !tex_orientations_match(src_flags, dst_orientation);
@ -118,16 +120,16 @@ int tex_codec_alloc_rows(const u8* data, size_t h, size_t pitch,
}
debug_assert(pos == end);
return 0;
return ERR_OK;
}
int tex_codec_write(Tex* t, uint transforms, const void* hdr, size_t hdr_size, DynArray* da)
LibError tex_codec_write(Tex* t, uint transforms, const void* hdr, size_t hdr_size, DynArray* da)
{
RETURN_ERR(tex_transform(t, transforms));
void* img_data = tex_get_data(t); const size_t img_size = tex_img_size(t);
RETURN_ERR(da_append(da, hdr, hdr_size));
RETURN_ERR(da_append(da, img_data, img_size));
return 0;
return ERR_OK;
}

View File

@ -15,7 +15,7 @@ struct TexCodecVTbl
// size is guaranteed to be >= 4.
// (usually enough to compare the header's "magic" field;
// anyway, no legitimate file will be smaller)
int (*decode)(DynArray* restrict da, Tex* restrict t);
LibError (*decode)(DynArray* restrict da, Tex* restrict t);
// rationale: some codecs cannot calculate the output size beforehand
// (e.g. PNG output via libpng); we therefore require each one to
@ -23,9 +23,9 @@ struct TexCodecVTbl
//
// note: <t> cannot be made const because encoding may require a
// tex_transform.
int (*encode)(Tex* restrict t, DynArray* restrict da);
LibError (*encode)(Tex* restrict t, DynArray* restrict da);
int (*transform)(Tex* t, uint transforms);
LibError (*transform)(Tex* t, uint transforms);
// only guaranteed 4 bytes!
bool (*is_hdr)(const u8* file);
@ -49,24 +49,22 @@ struct TexCodecVTbl
static int dummy = tex_codec_register(&vtbl);
// the given texture cannot be handled by this codec; pass the buck on to the next one
const int TEX_CODEC_CANNOT_HANDLE = 1;
// add this vtbl to the codec list. called at NLSO init time by the
// TEX_CODEC_REGISTER in each codec file. note that call order and therefore
// order in the list is undefined, but since each codec only steps up if it
// can handle the given format, this is not a problem.
//
// returns int to alloc calling from a macro at file scope.
extern int tex_codec_register(TexCodecVTbl* c);
// find codec that recognizes the desired output file extension
extern int tex_codec_for_filename(const char* fn, const TexCodecVTbl** c);
extern LibError tex_codec_for_filename(const char* fn, const TexCodecVTbl** c);
// find codec that recognizes the header's magic field
extern int tex_codec_for_header(const u8* file, size_t file_size, const TexCodecVTbl** c);
extern LibError tex_codec_for_header(const u8* file, size_t file_size, const TexCodecVTbl** c);
extern int tex_codec_transform(Tex* t, uint transforms);
extern LibError tex_codec_transform(Tex* t, uint transforms);
// allocate an array of row pointers that point into the given texture data.
@ -80,9 +78,9 @@ extern int tex_codec_transform(Tex* t, uint transforms);
// needed for encoding, too (where data is already present).
typedef const u8* RowPtr;
typedef RowPtr* RowArray;
extern int tex_codec_alloc_rows(const u8* data, size_t h, size_t pitch,
extern LibError tex_codec_alloc_rows(const u8* data, size_t h, size_t pitch,
uint src_flags, uint dst_orientation, RowArray& rows);
extern int tex_codec_write(Tex* t, uint transforms, const void* hdr, size_t hdr_size, DynArray* da);
extern LibError tex_codec_write(Tex* t, uint transforms, const void* hdr, size_t hdr_size, DynArray* da);
#endif // #ifndef TEX_CODEC_H__

View File

@ -253,7 +253,7 @@ static void s3tc_decompress_level(uint UNUSED(level), uint level_w, uint level_h
// decompress the given image (which is known to be stored as DXTn)
// effectively in-place. updates Tex fields.
static int s3tc_decompress(Tex* t)
static LibError s3tc_decompress(Tex* t)
{
// alloc new image memory
// notes:
@ -279,7 +279,7 @@ static int s3tc_decompress(Tex* t)
t->ofs = 0;
t->bpp = out_bpp;
t->flags &= ~TEX_DXT;
return 0;
return ERR_OK;
}
@ -388,7 +388,7 @@ static bool is_valid_dxt(uint dxt)
// pf points to the DDS file's header; all fields must be endian-converted
// before use.
// output parameters invalid on failure.
static int decode_pf(const DDPIXELFORMAT* pf, uint* bpp_, uint* flags_)
static LibError decode_pf(const DDPIXELFORMAT* pf, uint* bpp_, uint* flags_)
{
uint bpp = 0;
uint flags = 0;
@ -449,7 +449,7 @@ static int decode_pf(const DDPIXELFORMAT* pf, uint* bpp_, uint* flags_)
*bpp_ = bpp;
*flags_ = flags;
return 0;
return ERR_OK;
}
@ -457,7 +457,7 @@ static int decode_pf(const DDPIXELFORMAT* pf, uint* bpp_, uint* flags_)
// sd points to the DDS file's header; all fields must be endian-converted
// before use.
// output parameters invalid on failure.
static int decode_sd(const DDSURFACEDESC2* sd, uint* w_, uint* h_,
static LibError decode_sd(const DDSURFACEDESC2* sd, uint* w_, uint* h_,
uint* bpp_, uint* flags_)
{
// check header size
@ -537,7 +537,7 @@ static int decode_sd(const DDSURFACEDESC2* sd, uint* w_, uint* h_,
*h_ = h;
*bpp_ = bpp;
*flags_ = flags;
return 0;
return ERR_OK;
}
@ -561,7 +561,7 @@ static size_t dds_hdr_size(const u8* UNUSED(file))
}
static int dds_decode(DynArray* restrict da, Tex* restrict t)
static LibError dds_decode(DynArray* restrict da, Tex* restrict t)
{
u8* file = da->base;
const DDSURFACEDESC2* sd = (const DDSURFACEDESC2*)(file+4);
@ -575,19 +575,19 @@ static int dds_decode(DynArray* restrict da, Tex* restrict t)
t->h = h;
t->bpp = bpp;
t->flags = flags;
return 0;
return ERR_OK;
}
static int dds_encode(Tex* restrict UNUSED(t), DynArray* restrict UNUSED(da))
static LibError dds_encode(Tex* restrict UNUSED(t), DynArray* restrict UNUSED(da))
{
// note: do not return ERR_NOT_IMPLEMENTED et al. because that would
// break tex_write (which assumes either this, 0 or errors are returned).
return TEX_CODEC_CANNOT_HANDLE;
return ERR_TEX_CODEC_CANNOT_HANDLE;
}
static int dds_transform(Tex* t, uint transforms)
static LibError dds_transform(Tex* t, uint transforms)
{
uint dxt = t->flags & TEX_DXT;
debug_assert(is_valid_dxt(dxt));
@ -597,13 +597,13 @@ static int dds_transform(Tex* t, uint transforms)
if(dxt && transform_dxt)
{
RETURN_ERR(s3tc_decompress(t));
return 0;
return ERR_OK;
}
// both are DXT (unsupported; there are no flags we can change while
// compressed) or requesting compression (not implemented) or
// both not DXT (nothing we can do) - bail.
else
return TEX_CODEC_CANNOT_HANDLE;
return ERR_TEX_CODEC_CANNOT_HANDLE;
}

View File

@ -398,9 +398,9 @@ JpgErrorMgr::JpgErrorMgr(j_common_ptr cinfo)
//-----------------------------------------------------------------------------
static int jpg_transform(Tex* UNUSED(t), uint UNUSED(transforms))
static LibError jpg_transform(Tex* UNUSED(t), uint UNUSED(transforms))
{
return TEX_CODEC_CANNOT_HANDLE;
return ERR_TEX_CODEC_CANNOT_HANDLE;
}
@ -415,7 +415,7 @@ static int jpg_transform(Tex* UNUSED(t), uint UNUSED(transforms))
// due to less copying.
static int jpg_decode_impl(DynArray* da,
static LibError jpg_decode_impl(DynArray* da,
jpeg_decompress_struct* cinfo,
Handle& img_hm, RowArray& rows, Tex* t)
{
@ -477,7 +477,7 @@ static int jpg_decode_impl(DynArray* da,
// mem data source.
(void)jpeg_finish_decompress(cinfo);
int ret = 0;
LibError ret = ERR_OK;
if(cinfo->err->num_warnings != 0)
ret = WARN_TEX_INVALID_DATA;
@ -495,7 +495,7 @@ static int jpg_decode_impl(DynArray* da,
}
static int jpg_encode_impl(Tex* t,
static LibError jpg_encode_impl(Tex* t,
jpeg_compress_struct* cinfo,
RowArray& rows, DynArray* da)
{
@ -538,7 +538,7 @@ static int jpg_encode_impl(Tex* t,
jpeg_finish_compress(cinfo);
int ret = 0;
LibError ret = ERR_OK;
if(cinfo->err->num_warnings != 0)
ret = WARN_TEX_INVALID_DATA;
@ -567,9 +567,9 @@ static size_t jpg_hdr_size(const u8* UNUSED(file))
}
static int jpg_decode(DynArray* restrict da, Tex* restrict t)
static LibError jpg_decode(DynArray* restrict da, Tex* restrict t)
{
int err;
LibError err;
// freed when ret is reached:
// .. contains the JPEG decompression parameters and pointers to
@ -584,7 +584,7 @@ static int jpg_decode(DynArray* restrict da, Tex* restrict t)
JpgErrorMgr jerr((j_common_ptr)&cinfo);
if(setjmp(jerr.call_site))
{
err = -1;
err = ERR_FAIL;
goto fail;
}
@ -606,9 +606,9 @@ fail:
// limitation: palette images aren't supported
static int jpg_encode(Tex* restrict t, DynArray* restrict da)
static LibError jpg_encode(Tex* restrict t, DynArray* restrict da)
{
int err;
LibError err;
// freed when ret is reached:
// .. contains the JPEG compression parameters and pointers to
@ -620,7 +620,7 @@ static int jpg_encode(Tex* restrict t, DynArray* restrict da)
JpgErrorMgr jerr((j_common_ptr)&cinfo);
if(setjmp(jerr.call_site))
{
err = -1;
err = ERR_FAIL;
goto fail;
}

View File

@ -64,9 +64,9 @@ static void io_flush(png_structp UNUSED(png_ptr))
//-----------------------------------------------------------------------------
static int png_transform(Tex* UNUSED(t), uint UNUSED(transforms))
static LibError png_transform(Tex* UNUSED(t), uint UNUSED(transforms))
{
return TEX_CODEC_CANNOT_HANDLE;
return ERR_TEX_CODEC_CANNOT_HANDLE;
}
@ -75,7 +75,7 @@ static int png_transform(Tex* UNUSED(t), uint UNUSED(transforms))
// split out of png_decode to simplify resource cleanup and avoid
// "dtor / setjmp interaction" warning.
static int png_decode_impl(DynArray* da,
static LibError png_decode_impl(DynArray* da,
png_structp png_ptr, png_infop info_ptr,
Handle& img_hm, RowArray& rows, Tex* t)
{
@ -124,13 +124,13 @@ static int png_decode_impl(DynArray* da,
t->bpp = bpp;
t->flags = flags;
return 0;
return ERR_OK;
}
// split out of png_encode to simplify resource cleanup and avoid
// "dtor / setjmp interaction" warning.
static int png_encode_impl(Tex* t,
static LibError png_encode_impl(Tex* t,
png_structp png_ptr, png_infop info_ptr,
RowArray& rows, DynArray* da)
{
@ -167,7 +167,7 @@ static int png_encode_impl(Tex* t,
png_set_rows(png_ptr, info_ptr, (png_bytepp)rows);
png_write_png(png_ptr, info_ptr, png_transforms, 0);
return 0;
return ERR_OK;
}
@ -195,11 +195,11 @@ static size_t png_hdr_size(const u8* UNUSED(file))
TIMER_ADD_CLIENT(tc_png_decode);
// limitation: palette images aren't supported
static int png_decode(DynArray* restrict da, Tex* restrict t)
static LibError png_decode(DynArray* restrict da, Tex* restrict t)
{
TIMER_ACCRUE(tc_png_decode);
int err = -1;
LibError err = ERR_FAIL;
// freed when ret is reached:
png_structp png_ptr = 0;
png_infop info_ptr = 0;
@ -238,9 +238,9 @@ ret:
// limitation: palette images aren't supported
static int png_encode(Tex* restrict t, DynArray* restrict da)
static LibError png_encode(Tex* restrict t, DynArray* restrict da)
{
int err = -1;
LibError err = ERR_FAIL;
// freed when ret is reached:
png_structp png_ptr = 0;
png_infop info_ptr = 0;

View File

@ -41,9 +41,9 @@ TgaHeader;
#pragma pack(pop)
static int tga_transform(Tex* UNUSED(t), uint UNUSED(transforms))
static LibError tga_transform(Tex* UNUSED(t), uint UNUSED(transforms))
{
return TEX_CODEC_CANNOT_HANDLE;
return ERR_TEX_CODEC_CANNOT_HANDLE;
}
@ -86,7 +86,7 @@ static size_t tga_hdr_size(const u8* file)
// requirements: uncompressed, direct colour, bottom up
static int tga_decode(DynArray* restrict da, Tex* restrict t)
static LibError tga_decode(DynArray* restrict da, Tex* restrict t)
{
u8* file = da->base;
@ -116,11 +116,11 @@ static int tga_decode(DynArray* restrict da, Tex* restrict t)
t->h = h;
t->bpp = bpp;
t->flags = flags;
return 0;
return ERR_OK;
}
static int tga_encode(Tex* restrict t, DynArray* restrict da)
static LibError tga_encode(Tex* restrict t, DynArray* restrict da)
{
u8 img_desc = 0;
if(t->flags & TEX_TOP_DOWN)

View File

@ -59,11 +59,11 @@ static void UniFont_dtor(UniFont* f)
SAFE_DELETE(f->glyphs_size);
}
static int UniFont_reload(UniFont* f, const char* fn, Handle UNUSED(h))
static LibError UniFont_reload(UniFont* f, const char* fn, Handle UNUSED(h))
{
// already loaded
if(f->ht > 0)
return 0;
return ERR_OK;
f->glyphs_id = new glyphmap_id;
f->glyphs_size = new glyphmap_size;
@ -107,7 +107,7 @@ static int UniFont_reload(UniFont* f, const char* fn, Handle UNUSED(h))
if (f->ListBase == 0) // My Voodoo2 drivers didn't support display lists (although I'd be surprised if they got this far)
{
debug_warn("Display list creation failed");
return -1;
return ERR_FAIL;
}
for (int i = 0; i < NumGlyphs; ++i)
@ -162,7 +162,7 @@ static int UniFont_reload(UniFont* f, const char* fn, Handle UNUSED(h))
// but we want ALPHA. there is no way of knowing what format
// 8bpp textures are in - we could adopt a naming convention and
// add some TEX_ flags, but that's overkill.
int err = ogl_tex_upload(ht, GL_ALPHA);
LibError err = ogl_tex_upload(ht, GL_ALPHA);
if(err < 0)
{
(void)ogl_tex_free(ht);
@ -170,44 +170,44 @@ static int UniFont_reload(UniFont* f, const char* fn, Handle UNUSED(h))
}
f->ht = ht;
return 0;
return ERR_OK;
}
static int UniFont_validate(const UniFont* f)
static LibError UniFont_validate(const UniFont* f)
{
if(f->ht < 0)
return -2;
return ERR_1;
if(debug_is_pointer_bogus(f->glyphs_id) || debug_is_pointer_bogus(f->glyphs_size))
return -3;
return ERR_2;
// <LineSpacing> and <Height> are read directly from font file.
// negative values don't make sense, but that's all we can check.
if(f->LineSpacing < 0 || f->Height < 0)
return -4;
return ERR_3;
if(f->ListBase == 0 || f->ListBase > 1000000) // suspicious
return -5;
return 0;
return ERR_4;
return ERR_OK;
}
static int UniFont_to_string(const UniFont* UNUSED(f), char* buf)
static LibError UniFont_to_string(const UniFont* UNUSED(f), char* buf)
{
snprintf(buf, H_STRING_LEN, "");
return 0;
return ERR_OK;
}
Handle unifont_load(const char* fn, int scope)
Handle unifont_load(const char* fn, int flags)
{
return h_alloc(H_UniFont, fn, scope);
return h_alloc(H_UniFont, fn, flags);
}
int unifont_unload(Handle& h)
LibError unifont_unload(Handle& h)
{
return h_free(h, H_UniFont);
}
int unifont_bind(const Handle h)
LibError unifont_bind(const Handle h)
{
H_DEREF(h, UniFont, f);
@ -215,7 +215,7 @@ int unifont_bind(const Handle h)
glListBase(f->ListBase);
BoundGlyphs = f->glyphs_id;
return 0;
return ERR_OK;
}
@ -233,7 +233,7 @@ int unifont_height(const Handle h)
}
int unifont_character_width(const Handle h, const wchar_t& c)
int unifont_character_width(const Handle h, wchar_t c)
{
H_DEREF(h, UniFont, f);
glyphmap_size::iterator it = f->glyphs_size->find(c);
@ -296,7 +296,7 @@ void glwprintf(const wchar_t* fmt, ...)
}
int unifont_stringsize(const Handle h, const wchar_t* text, int& width, int& height)
LibError unifont_stringsize(const Handle h, const wchar_t* text, int& width, int& height)
{
H_DEREF(h, UniFont, f);
@ -315,11 +315,11 @@ int unifont_stringsize(const Handle h, const wchar_t* text, int& width, int& hei
if (it == f->glyphs_size->end()) // Missing the missing glyph symbol - give up
{
debug_warn("Missing the missing glyph in a unifont!\n");
return 0;
return ERR_OK;
}
width += it->second; // Add the character's advance distance
}
return 0;
return ERR_OK;
}

View File

@ -9,14 +9,14 @@
// Load and return a handle to the font defined
// in fn+".fnt" with texture fn+".tga"
extern Handle unifont_load(const char* fn, int scope = 0);
extern Handle unifont_load(const char* fn, int flags = 0);
// Release a handle to a previously loaded font
extern int unifont_unload(Handle& h);
extern LibError unifont_unload(Handle& h);
// Use the font referenced by h for all subsequent glwprintf() calls.
// Must be called before any glwprintf().
extern int unifont_bind(Handle h);
extern LibError unifont_bind(Handle h);
// Output text at current OpenGL modelview pos.
extern void glvwprintf(const wchar_t* fmt, va_list args);
@ -37,13 +37,13 @@ extern void glwprintf(const wchar_t* fmt, ...);
// Intended for the GUI (hence Unicode). 'height' is roughly the height of
// a capital letter, for use when aligning text in an aesthetically pleasing way.
int unifont_stringsize(const Handle h, const wchar_t* text, int& width, int& height);
LibError unifont_stringsize(const Handle h, const wchar_t* text, int& width, int& height);
// Get only the height
int unifont_height(const Handle h);
// Get only the width of one character
int unifont_character_width(const Handle h, const wchar_t& c);
int unifont_character_width(const Handle h, wchar_t c);
// Return spacing in pixels from one line of text to the next
int unifont_linespacing(const Handle h);

View File

@ -260,7 +260,7 @@ static HDATA* h_data_tag_type(const Handle h, const H_Type type)
// idx and hd are undefined if we fail.
// called by h_alloc only.
static int alloc_idx(i32& idx, HDATA*& hd)
static LibError alloc_idx(i32& idx, HDATA*& hd)
{
// we already know the first free entry
if(first_free != -1)
@ -311,15 +311,15 @@ have_idx:;
if(idx > last_in_use)
last_in_use = idx;
return 0;
return ERR_OK;
}
static int free_idx(i32 idx)
static LibError free_idx(i32 idx)
{
if(first_free == -1 || idx < first_free)
first_free = idx;
return 0;
return ERR_OK;
}
@ -488,8 +488,8 @@ static void warn_if_invalid(HDATA* hd)
// the others have no invariants we could check.
// have the resource validate its user_data
int err = vtbl->validate(hd->user);
debug_assert(err == 0);
LibError err = vtbl->validate(hd->user);
debug_assert(err == ERR_OK);
// make sure empty space in control block isn't touched
// .. but only if we're not storing a filename there
@ -507,31 +507,25 @@ static void warn_if_invalid(HDATA* hd)
}
static int type_validate(H_Type type)
static LibError type_validate(H_Type type)
{
int err = ERR_INVALID_PARAM;
if(!type)
{
debug_warn("type is 0");
goto fail;
return ERR_INVALID_PARAM;
}
if(type->user_size > HDATA_USER_SIZE)
{
debug_warn("type's user data is too large for HDATA");
goto fail;
return ERR_LIMIT;
}
if(type->name == 0)
{
debug_warn("type's name field is 0");
goto fail;
return ERR_INVALID_PARAM;
}
// success
err = 0;
fail:
return err;
return ERR_OK;
}
@ -583,9 +577,9 @@ static Handle reuse_existing_handle(uintptr_t key, H_Type type, uint flags)
}
static int call_init_and_reload(Handle h, H_Type type, HDATA* hd, const char* fn, va_list* init_args)
static LibError call_init_and_reload(Handle h, H_Type type, HDATA* hd, const char* fn, va_list* init_args)
{
int err = 0;
LibError err = ERR_OK;
H_VTbl* vtbl = type; // exact same thing but for clarity
// init
@ -599,7 +593,7 @@ static int call_init_and_reload(Handle h, H_Type type, HDATA* hd, const char* fn
try
{
err = vtbl->reload(hd->user, fn, h);
if(err == 0)
if(err == ERR_OK)
warn_if_invalid(hd);
}
catch(std::bad_alloc)
@ -642,7 +636,7 @@ static Handle alloc_new_handle(H_Type type, const char* fn, uintptr_t key,
if(key && !hd->unique)
key_add(key, h);
int err = call_init_and_reload(h, type, hd, fn, init_args);
LibError err = call_init_and_reload(h, type, hd, fn, init_args);
if(err < 0)
goto fail;
@ -703,7 +697,7 @@ Handle h_alloc(H_Type type, const char* fn, uint flags, ...)
//-----------------------------------------------------------------------------
// currently cannot fail.
static int h_free_idx(i32 idx, HDATA* hd)
static LibError h_free_idx(i32 idx, HDATA* hd)
{
// debug_printf("free %s %s\n", type->name, hd->fn);
@ -713,7 +707,7 @@ static int h_free_idx(i32 idx, HDATA* hd)
// still references open or caching requests it stays - do not release.
if(hd->refs > 0 || hd->keep_open)
return 0;
return ERR_OK;
// actually release the resource (call dtor, free control block).
@ -751,11 +745,11 @@ static int h_free_idx(i32 idx, HDATA* hd)
free_idx(idx);
return 0;
return ERR_OK;
}
int h_free(Handle& h, H_Type type)
LibError h_free(Handle& h, H_Type type)
{
i32 idx = h_idx(h);
HDATA* hd = h_data_tag_type(h, type);
@ -770,7 +764,7 @@ int h_free(Handle& h, H_Type type)
// 0-initialized or an error code; don't complain because this
// happens often and is harmless.
if(h_copy <= 0)
return 0;
return ERR_OK;
// this was a valid handle but was probably freed in the meantime.
// complain because this probably indicates a bug somewhere.
CHECK_ERR(ERR_INVALID_HANDLE);
@ -816,7 +810,7 @@ const char* h_filename(const Handle h)
// TODO: what if iterating through all handles is too slow?
int h_reload(const char* fn)
LibError h_reload(const char* fn)
{
if(!fn)
{
@ -840,7 +834,7 @@ int h_reload(const char* fn)
hd->type->dtor(hd->user);
}
int ret = 0;
LibError ret = ERR_OK;
// now reload all affected handles
for(i32 i = 0; i <= last_in_use; i++)
@ -851,7 +845,7 @@ int h_reload(const char* fn)
Handle h = handle(i, hd->tag);
int err = hd->type->reload(hd->user, hd->fn, h);
LibError err = hd->type->reload(hd->user, hd->fn, h);
// don't stop if an error is encountered - try to reload them all.
if(err < 0)
{
@ -880,7 +874,7 @@ Handle h_find(H_Type type, uintptr_t key)
// to later close the object.
// this is used when reinitializing the sound engine -
// at that point, all (cached) OpenAL resources must be freed.
int h_force_free(Handle h, H_Type type)
LibError h_force_free(Handle h, H_Type type)
{
// require valid index; ignore tag; type checked below.
HDATA* hd = h_data_no_tag(h);

View File

@ -125,7 +125,7 @@ reload:
does all initialization of the resource that requires its source file.
called after init; also after dtor every time the file is reloaded.
static int Type_reload(Res1* r, const char* filename, Handle);
static LibError Type_reload(Res1* r, const char* filename, Handle);
{
// already loaded; done
if(r->data)
@ -180,16 +180,16 @@ or "compact/free extraneous resources" may be added.
validate:
makes sure the resource control block is in a valid state. returns 0 if
all is well, or a distinct negative value (error code, if appropriate).
all is well, or a negative error code.
called automatically when the Handle is dereferenced or freed.
static int Type_validate(const Res1* r);
static LibError Type_validate(const Res1* r);
{
const int permissible_flags = 0x01;
if(debug_is_pointer_bogus(r->data))
return -2;
return ERR_1;
if(r->flags & ~permissible_flags)
return -3;
return ERR_2;
return 0;
}
@ -201,7 +201,7 @@ Handle res1_load(const char* filename, int my_flags)
return h_alloc(H_Res1, filename, 0, my_flags);
}
int res1_free(Handle& h)
LibError res1_free(Handle& h)
{
// control block is automatically zeroed after this.
return h_free(h, H_Res1);
@ -308,11 +308,11 @@ but- has to handle variable params, a bit ugly
// dependencies.
struct H_VTbl
{
void(*init)(void* user, va_list);
int(*reload)(void* user, const char* fn, Handle);
void(*dtor)(void* user);
int(*validate)(const void* user);
int(*to_string)(const void* user, char* buf);
void (*init)(void* user, va_list);
LibError (*reload)(void* user, const char* fn, Handle);
void (*dtor)(void* user);
LibError (*validate)(const void* user);
LibError (*to_string)(const void* user, char* buf);
size_t user_size;
const char* name;
};
@ -322,17 +322,17 @@ typedef H_VTbl* H_Type;
#define H_TYPE_DEFINE(type)\
/* forward decls */\
static void type##_init(type*, va_list);\
static int type##_reload(type*, const char*, Handle);\
static LibError type##_reload(type*, const char*, Handle);\
static void type##_dtor(type*);\
static int type##_validate(const type*);\
static int type##_to_string(const type*, char* buf);\
static LibError type##_validate(const type*);\
static LibError type##_to_string(const type*, char* buf);\
static H_VTbl V_##type =\
{\
(void(*)(void*, va_list))type##_init,\
(int(*)(void*, const char*, Handle))type##_reload,\
(void(*)(void*))type##_dtor,\
(int(*)(const void*))type##_validate,\
(int(*)(const void*, char*))type##_to_string,\
(void (*)(void*, va_list))type##_init,\
(LibError (*)(void*, const char*, Handle))type##_reload,\
(void (*)(void*))type##_dtor,\
(LibError (*)(const void*))type##_validate,\
(LibError (*)(const void*, char*))type##_to_string,\
sizeof(type), /* control block size */\
#type /* name */\
};\
@ -410,7 +410,7 @@ const size_t H_STRING_LEN = 256;
// dtor is associated with type and called when the object is freed.
// handle data is initialized to 0; optionally, a pointer to it is returned.
extern Handle h_alloc(H_Type type, const char* fn, uint flags = 0, ...);
extern int h_free(Handle& h, H_Type type);
extern LibError h_free(Handle& h, H_Type type);
// find and return a handle by key (typically filename hash)
@ -428,7 +428,7 @@ extern void* h_user_data(Handle h, H_Type type);
extern const char* h_filename(Handle h);
extern int h_reload(const char* fn);
extern LibError h_reload(const char* fn);
// force the resource to be freed immediately, even if cached.
// tag is not checked - this allows the first Handle returned
@ -436,7 +436,7 @@ extern int h_reload(const char* fn);
// to later close the object.
// this is used when reinitializing the sound engine -
// at that point, all (cached) OpenAL resources must be freed.
extern int h_force_free(Handle h, H_Type type);
extern LibError h_force_free(Handle h, H_Type type);
// increment Handle <h>'s reference count.
// only meant to be used for objects that free a Handle in their dtor,

View File

@ -158,26 +158,26 @@ static void Mem_dtor(Mem* m)
// can't alloc here, because h_alloc needs the key when called
// (key == pointer we allocate)
static int Mem_reload(Mem* m, const char* UNUSED(fn), Handle hm)
static LibError Mem_reload(Mem* m, const char* UNUSED(fn), Handle hm)
{
set_alloc(m->raw_p, hm);
return 0;
return ERR_OK;
}
static int Mem_validate(const Mem* m)
static LibError Mem_validate(const Mem* m)
{
if(debug_is_pointer_bogus(m->p))
return -2;
return ERR_1;
if(!m->size)
return -3;
return ERR_2;
if(m->raw_p && m->raw_p > m->p)
return -4;
return ERR_3;
if(m->raw_size && m->raw_size < m->size)
return -5;
return 0;
return ERR_4;
return ERR_OK;
}
static int Mem_to_string(const Mem* m, char* buf)
static LibError Mem_to_string(const Mem* m, char* buf)
{
char owner_sym[DBG_SYMBOL_LEN];
if(debug_resolve_symbol(m->owner, owner_sym, 0, 0) < 0)
@ -189,7 +189,7 @@ static int Mem_to_string(const Mem* m, char* buf)
}
snprintf(buf, H_STRING_LEN, "p=%p size=%d owner=%s", m->p, m->size, owner_sym);
return 0;
return ERR_OK;
}
@ -222,17 +222,17 @@ static void* heap_alloc(size_t raw_size, uintptr_t& ctx)
//////////////////////////////////////////////////////////////////////////////
int mem_free_h(Handle& hm)
LibError mem_free_h(Handle& hm)
{
SCOPED_LOCK;
return h_free(hm, H_Mem);
}
int mem_free_p(void*& p)
LibError mem_free_p(void*& p)
{
if(!p)
return 0;
return ERR_OK;
Handle hm;
{
@ -244,7 +244,7 @@ int mem_free_p(void*& p)
if(hm <= 0)
{
debug_warn("mem_free_p: not found in map");
return -1;
return ERR_FAIL;
}
return mem_free_h(hm);
}
@ -284,7 +284,7 @@ Handle mem_wrap(void* p, size_t size, uint flags, void* raw_p, size_t raw_size,
/*
int mem_assign_user(Handle hm, void* user_p, size_t user_size)
LibError mem_assign_user(Handle hm, void* user_p, size_t user_size)
{
H_DEREF(hm, Mem, m);
@ -295,12 +295,12 @@ int mem_assign_user(Handle hm, void* user_p, size_t user_size)
if(user_p < m->raw_p || user_end > raw_end)
{
debug_warn("mem_assign_user: user buffer not contained in real buffer");
return -EINVAL;
return -1;
}
m->p = user_p;
m->size = user_size;
return 0;
return ERR_OK;
}
*/
@ -392,7 +392,7 @@ void* mem_get_ptr(Handle hm, size_t* user_size /* = 0 */)
}
int mem_get(Handle hm, u8** pp, size_t* psize)
LibError mem_get(Handle hm, u8** pp, size_t* psize)
{
SCOPED_LOCK;
@ -402,7 +402,7 @@ int mem_get(Handle hm, u8** pp, size_t* psize)
if(psize)
*psize = m->size;
// leave hm locked
return 0;
return ERR_OK;
}

View File

@ -8,7 +8,7 @@
extern "C" {
#endif
typedef void(*MEM_DTOR)(void* p, size_t size, uintptr_t ctx);
typedef void (*MEM_DTOR)(void* p, size_t size, uintptr_t ctx);
// mem_alloc flags
enum
@ -21,14 +21,14 @@ enum
extern void* mem_alloc(size_t size, size_t align = 1, uint flags = 0, Handle* ph = 0);
#define mem_free(p) mem_free_p((void*&)p)
extern int mem_free_p(void*& p);
extern LibError mem_free_p(void*& p);
extern int mem_free_h(Handle& hm);
extern LibError mem_free_h(Handle& hm);
// returns 0 if the handle is invalid
extern void* mem_get_ptr(Handle h, size_t* size = 0);
extern int mem_get(Handle hm, u8** pp, size_t* psize);
extern LibError mem_get(Handle hm, u8** pp, size_t* psize);
extern Handle mem_wrap(void* p, size_t size, uint flags, void* raw_p, size_t raw_size, MEM_DTOR dtor, uintptr_t ctx, void* owner);

View File

@ -91,14 +91,14 @@ static bool al_initialized = false;
// used by snd_dev_set to reset OpenAL after device has been changed.
static int al_reinit();
static LibError al_reinit();
// used by VSrc_reload to init on demand.
static int snd_init();
static LibError snd_init();
// used by al_shutdown to free all VSrc and SndData objects, respectively,
// so that they release their OpenAL sources and buffers.
static int list_free_all();
static LibError list_free_all();
static void hsd_list_free_all();
@ -146,14 +146,14 @@ static const char* alc_dev_name = 0;
// so preferably call this routine before sounds are loaded.
//
// return 0 on success, or the status returned by OpenAL re-init.
int snd_dev_set(const char* alc_new_dev_name)
LibError snd_dev_set(const char* alc_new_dev_name)
{
// requesting a specific device
if(alc_new_dev_name)
{
// already using that device - done. (don't re-init)
if(alc_dev_name && !strcmp(alc_dev_name, alc_new_dev_name))
return 0;
return ERR_OK;
// store name (need to copy it, since alc_init is called later,
// and it must then still be valid)
@ -166,7 +166,7 @@ int snd_dev_set(const char* alc_new_dev_name)
{
// already using default device - done. (don't re-init)
if(alc_dev_name == 0)
return 0;
return ERR_OK;
alc_dev_name = 0;
}
@ -193,9 +193,9 @@ static void alc_shutdown()
}
static int alc_init()
static LibError alc_init()
{
int ret = 0;
LibError ret = ERR_OK;
// HACK: OpenAL loads and unloads these DLLs several times on Windows.
// we hold a reference to prevent the actual unload,
@ -242,7 +242,7 @@ static int alc_init()
if(err != ALC_NO_ERROR || !alc_dev || !alc_ctx)
{
debug_printf("alc_init failed. alc_dev=%p alc_ctx=%p alc_dev_name=%s err=%d\n", alc_dev, alc_ctx, alc_dev_name, err);
ret = -1;
ret = ERR_FAIL;
}
// release DLL references, so BoundsChecker doesn't complain at exit.
@ -287,7 +287,7 @@ static void al_listener_latch()
// set amplitude modifier, which is effectively applied to all sounds.
// must be non-negative; 1 -> unattenuated, 0.5 -> -6 dB, 0 -> silence.
int snd_set_master_gain(float gain)
LibError snd_set_master_gain(float gain)
{
if(gain < 0)
{
@ -301,7 +301,7 @@ int snd_set_master_gain(float gain)
// position will get sent too.
// this isn't called often, so we don't care.
return 0;
return ERR_OK;
}
@ -459,7 +459,7 @@ static void al_src_free(ALuint al_src)
// to reduce mixing cost on low-end systems.
// return 0 on success, or 1 if limit was ignored
// (e.g. if higher than an implementation-defined limit anyway).
int snd_set_max_voices(uint limit)
LibError snd_set_max_voices(uint limit)
{
// valid if cap is legit (less than what we allocated in al_src_init),
// or if al_src_init hasn't been called yet. note: we accept anything
@ -467,13 +467,15 @@ int snd_set_max_voices(uint limit)
if(!al_src_allocated || limit < al_src_allocated)
{
al_src_cap = limit;
return 0;
return ERR_OK;
}
// user is requesting a cap higher than what we actually allocated.
// that's fine (not an error), but we won't set the cap, since it
// determines how many sources may be returned.
// there's no return value to indicate this because the cap is
// precisely that - an upper limit only, we don't care if it can't be met.
else
return 1;
return ERR_OK;
}
@ -486,11 +488,11 @@ int snd_set_max_voices(uint limit)
///////////////////////////////////////////////////////////////////////////////
// called from each snd_open; no harm if called more than once.
static int al_init()
static LibError al_init()
{
// only take action on first call, OR when re-initializing.
if(al_initialized)
return 0;
return ERR_OK;
CHECK_ERR(alc_init());
@ -500,7 +502,7 @@ static int al_init()
al_src_init();
al_listener_latch();
return 0;
return ERR_OK;
}
@ -532,12 +534,12 @@ static void al_shutdown()
// called from snd_dev_set (no other settings require re-init ATM).
static int al_reinit()
static LibError al_reinit()
{
// not yet initialized. settings have been saved, and will be
// applied by the component init routines called from al_init.
if(!al_initialized)
return 0;
return ERR_OK;
// re-init (stops all currently playing sounds)
al_shutdown();
@ -563,13 +565,13 @@ static const char* devs;
// message should be presented to the user, and snd_dev_set need not be
// called; OpenAL will use its default device.
// may be called each time the device list is needed.
int snd_dev_prepare_enum()
LibError snd_dev_prepare_enum()
{
if(alcIsExtensionPresent(0, (ALubyte*)"ALC_ENUMERATION_EXT") != AL_TRUE)
return ERR_NO_SYS;
devs = (const char*)alcGetString(0, ALC_DEVICE_SPECIFIER);
return 0;
return ERR_OK;
}
@ -694,10 +696,10 @@ struct Stream
};
// called from SndData_reload and snd_data_buf_get.
static int stream_issue(Stream* s)
static LibError stream_issue(Stream* s)
{
if(s->active_ios >= MAX_IOS)
return 0;
return ERR_OK;
void* buf = io_buf_alloc();
if(!buf)
@ -706,14 +708,14 @@ static int stream_issue(Stream* s)
Handle h = vfs_io_issue(s->hf, STREAM_BUF_SIZE, buf);
CHECK_ERR(h);
s->ios[s->active_ios++] = h;
return 0;
return ERR_OK;
}
// if the first pending IO hasn't completed, return ERR_AGAIN;
// otherwise, return a negative error code or 0 on success,
// if the pending IO's buffer is returned.
static int stream_buf_get(Stream* s, void*& data, size_t& size)
static LibError stream_buf_get(Stream* s, void*& data, size_t& size)
{
if(s->active_ios == 0)
return ERR_EOF;
@ -721,17 +723,17 @@ static int stream_buf_get(Stream* s, void*& data, size_t& size)
// has it finished? if not, bail.
int is_complete = vfs_io_has_completed(hio);
CHECK_ERR(is_complete);
RETURN_ERR(is_complete);
if(is_complete == 0)
return ERR_AGAIN;
// get its buffer.
CHECK_ERR(vfs_io_wait(hio, data, size));
RETURN_ERR(vfs_io_wait(hio, data, size));
// no delay, since vfs_io_has_completed == 1
s->last_buf = data;
// (next stream_buf_discard will free this buffer)
return 0;
return ERR_OK;
}
@ -739,11 +741,11 @@ static int stream_buf_get(Stream* s, void*& data, size_t& size)
// and remove its IO slot from our queue.
// must be called exactly once after every successful stream_buf_get;
// call before calling any other stream_* functions!
static int stream_buf_discard(Stream* s)
static LibError stream_buf_discard(Stream* s)
{
Handle hio = s->ios[0];
int ret = vfs_io_discard(hio);
LibError ret = vfs_io_discard(hio);
// we implement the required 'circular queue' as a stack;
// have to shift all items after this one down.
@ -762,13 +764,13 @@ static uint active_streams;
// open a stream and begin reading from disk.
static int stream_open(Stream* s, const char* fn)
static LibError stream_open(Stream* s, const char* fn)
{
if(active_streams >= MAX_STREAMS)
{
debug_warn("MAX_STREAMS exceeded - why?");
return -1;
// fail, because we wouldn't have enough IO buffers for all
// bail because we wouldn't have enough IO buffers for all
return ERR_LIMIT;
}
active_streams++;
@ -778,16 +780,16 @@ static int stream_open(Stream* s, const char* fn)
for(int i = 0; i < MAX_IOS; i++)
CHECK_ERR(stream_issue(s));
return 0;
return ERR_OK;
}
// close a stream, which may currently be active.
// returns the first error that occurred while waiting for IOs / closing file.
static int stream_close(Stream* s)
static LibError stream_close(Stream* s)
{
int ret = 0;
int err;
LibError ret = ERR_OK;
LibError err;
// for each pending IO:
for(uint i = 0; i < s->active_ios; i++)
@ -816,12 +818,12 @@ static int stream_close(Stream* s)
}
static int stream_validate(const Stream* s)
static LibError stream_validate(const Stream* s)
{
if(s->active_ios > MAX_IOS)
return -2;
return ERR_1;
// <last_buf> has no invariant we could check.
return 0;
return ERR_OK;
}
@ -894,7 +896,7 @@ if(sd->o) ogg_release(sd->o);
static void hsd_list_add(Handle hsd);
static int SndData_reload(SndData* sd, const char* fn, Handle hsd)
static LibError SndData_reload(SndData* sd, const char* fn, Handle hsd)
{
hsd_list_add(hsd);
@ -942,11 +944,11 @@ static int SndData_reload(SndData* sd, const char* fn, Handle hsd)
// refuse to stream anything that cannot be passed directly to OpenAL -
// we'd have to extract the audio data ourselves (not worth it).
if(file_type != FT_OGG)
return -1;
return ERR_NOT_SUPPORTED;
RETURN_ERR(stream_open(&sd->s, fn));
sd->is_valid = 1;
return 0;
return ERR_OK;
}
// else: clip
@ -998,29 +1000,29 @@ else
(void)mem_free(file);
return 0;
return ERR_OK;
}
static int SndData_validate(const SndData* sd)
static LibError SndData_validate(const SndData* sd)
{
if(sd->al_fmt == 0)
return -100;
return ERR_11;
if((uint)sd->al_freq > 100000) // suspicious
return -101;
return ERR_12;
if(sd->al_buf == 0)
return -102;
return ERR_13;
if(sd->is_stream)
RETURN_ERR(stream_validate(&sd->s));
return 0;
return ERR_OK;
}
static int SndData_to_string(const SndData* sd, char* buf)
static LibError SndData_to_string(const SndData* sd, char* buf)
{
const char* type = sd->is_stream? "stream" : "clip";
snprintf(buf, H_STRING_LEN, "%s; al_buf=%d", type, sd->al_buf);
return 0;
return ERR_OK;
}
@ -1037,7 +1039,7 @@ static Handle snd_data_load(const char* fn, bool is_stream)
// close the sound file data <hsd> and set hsd to 0.
static int snd_data_free(Handle& hsd)
static LibError snd_data_free(Handle& hsd)
{
return h_free(hsd, H_SndData);
}
@ -1097,26 +1099,16 @@ static void hsd_list_free_all()
///////////////////////////////////////////////////////////////////////////////
// (need to convert ERR_EOF and ERR_AGAIN to legitimate return values -
// for the caller, those aren't errors.)
enum BufRet
// returns:
// ERR_OK = buffer has been returned; more are expected to be available.
// ERR_EOF = buffer has been returned but is the last one
// (end of file reached)
// ERR_AGAIN = no buffer returned yet; still streaming in ATM.
// call back later.
// or negative error code.
static LibError snd_data_buf_get(Handle hsd, ALuint& al_buf)
{
// buffer has been returned; barring errors, more will be available.
BUF_OK = 0,
// this was the last buffer we will return (end of file reached).
BUF_EOF = 1,
// no buffer returned - still streaming in ATM. call again later.
BUF_AGAIN = 2,
// anything else: negative error code
};
static int snd_data_buf_get(Handle hsd, ALuint& al_buf)
{
int err = 0;
LibError err = ERR_OK;
// in case H_DEREF fails
al_buf = 0;
@ -1127,7 +1119,7 @@ static int snd_data_buf_get(Handle hsd, ALuint& al_buf)
if(!sd->is_stream)
{
al_buf = sd->al_buf;
return BUF_EOF;
return ERR_EOF;
}
// stream:
@ -1137,7 +1129,7 @@ static int snd_data_buf_get(Handle hsd, ALuint& al_buf)
size_t size;
err = stream_buf_get(&sd->s, data, size);
if(err == ERR_AGAIN)
return BUF_AGAIN;
return ERR_AGAIN;
CHECK_ERR(err);
// .. yes: pass to OpenAL and discard IO buffer.
@ -1148,26 +1140,26 @@ static int snd_data_buf_get(Handle hsd, ALuint& al_buf)
// if EOF reached, indicate al_buf is the last that will be returned.
err = stream_issue(&sd->s);
if(err == ERR_EOF)
return BUF_EOF;
return ERR_EOF;
CHECK_ERR(err);
// al_buf valid and next IO issued successfully.
return BUF_OK;
return ERR_OK;
}
static int snd_data_buf_free(Handle hsd, ALuint al_buf)
static LibError snd_data_buf_free(Handle hsd, ALuint al_buf)
{
H_DEREF(hsd, SndData, sd);
// clip: no-op (caller will later release hsd reference;
// when hsd actually unloads, sd->al_buf will be freed).
if(!sd->is_stream)
return 0;
return ERR_OK;
// stream: we had allocated an additional buffer, so free it now.
al_buf_free(al_buf);
return 0;
return ERR_OK;
}
@ -1232,7 +1224,7 @@ static void VSrc_init(VSrc* vs, va_list args)
}
static void list_remove(VSrc* vs);
static int vsrc_reclaim(VSrc* vs);
static LibError vsrc_reclaim(VSrc* vs);
static void VSrc_dtor(VSrc* vs)
{
@ -1248,11 +1240,11 @@ static void VSrc_dtor(VSrc* vs)
(void)snd_data_free(vs->hsd);
}
static int VSrc_reload(VSrc* vs, const char* fn, Handle hvs)
static LibError VSrc_reload(VSrc* vs, const char* fn, Handle hvs)
{
// cannot wait till play(), need to init here:
// must load OpenAL so that snd_data_load can check for OGG extension.
int err = snd_init();
LibError err = snd_init();
// .. don't complain if sound is disabled; fail silently.
if(err == ERR_AGAIN)
return err;
@ -1303,29 +1295,29 @@ static int VSrc_reload(VSrc* vs, const char* fn, Handle hvs)
vs->hsd = snd_data_load(snd_fn, is_stream);
RETURN_ERR(vs->hsd);
return 0;
return ERR_OK;
}
static int VSrc_validate(const VSrc* vs)
static LibError VSrc_validate(const VSrc* vs)
{
// al_src can legitimately be 0 (if vs is low-pri)
if(vs->flags & ~VS_ALL_FLAGS)
return -2;
return ERR_1;
// no limitations on <pos>
if(!(0.0f <= vs->gain && vs->gain <= 1.0f))
return -3;
return ERR_2;
if(!(0.0f < vs->pitch && vs->pitch <= 1.0f))
return -4;
return ERR_3;
if(*(u8*)&vs->loop > 1 || *(u8*)&vs->relative > 1)
return -5;
return ERR_4;
// <static_pri> and <cur_pri> have no invariant we could check.
return 0;
return ERR_OK;
}
static int VSrc_to_string(const VSrc* vs, char* buf)
static LibError VSrc_to_string(const VSrc* vs, char* buf)
{
snprintf(buf, H_STRING_LEN, "al_src = %d", vs->al_src);
return 0;
return ERR_OK;
}
@ -1355,7 +1347,7 @@ Handle snd_open(const char* snd_fn, bool is_stream)
// close the sound <hvs> and set hvs to 0. if it was playing,
// it will be stopped. sounds are closed automatically when done
// playing; this is provided for completeness only.
int snd_free(Handle& hvs)
LibError snd_free(Handle& hvs)
{
return h_free(hvs, H_VSrc);
}
@ -1386,7 +1378,7 @@ static void list_add(VSrc* vs)
// skip past <skip> entries; if end_idx != 0, stop before that entry.
static void list_foreach(void(*cb)(VSrc*), uint skip = 0, uint end_idx = 0)
static void list_foreach(void (*cb)(VSrc*), uint skip = 0, uint end_idx = 0)
{
It begin = vsrcs.begin() + skip;
It end = vsrcs.end();
@ -1453,10 +1445,10 @@ static void free_vs(VSrc* vs)
snd_free(vs->hvs);
}
static int list_free_all()
static LibError list_free_all()
{
list_foreach(free_vs);
return 0;
return ERR_OK;
}
@ -1497,10 +1489,10 @@ static int vsrc_deque_finished_bufs(VSrc* vs)
}
static int vsrc_update(VSrc* vs)
static LibError vsrc_update(VSrc* vs)
{
if(!vs->al_src)
return 0;
return ERR_OK;
int num_queued;
alGetSourcei(vs->al_src, AL_BUFFERS_QUEUED, &num_queued);
@ -1514,7 +1506,7 @@ static int vsrc_update(VSrc* vs)
if(num_queued == 0)
{
snd_free(vs->hvs);
return 0;
return ERR_OK;
}
}
// can still read from SndData
@ -1532,35 +1524,37 @@ static int vsrc_update(VSrc* vs)
{
ALuint al_buf;
ret = snd_data_buf_get(vs->hsd, al_buf);
CHECK_ERR(ret);
// these 2 are legit (see above); otherwise, bail.
if(ret != ERR_AGAIN && ret != ERR_EOF)
CHECK_ERR(ret);
alSourceQueueBuffers(vs->al_src, 1, &al_buf);
al_check("vsrc_update alSourceQueueBuffers");
}
while(to_fill-- && ret == BUF_OK);
while(to_fill-- && ret == ERR_OK);
// SndData has reported that no further buffers are available.
if(ret == BUF_EOF)
if(ret == ERR_EOF)
vs->flags |= VS_EOF;
}
return 0;
return ERR_OK;
}
// attempt to (re)start playing. fails if a source cannot be allocated
// (see below). called by snd_play and voice management.
static int vsrc_grant(VSrc* vs)
static LibError vsrc_grant(VSrc* vs)
{
// already playing - bail
if(vs->al_src)
return 0;
return ERR_OK;
// try to alloc source. if none are available, bail -
// we get called in that hope that one is available by snd_play.
vs->al_src = al_src_alloc();
if(!vs->al_src)
return -1;
return ERR_FAIL;
// OpenAL docs don't specify default values, so initialize everything
// ourselves to be sure. note: alSourcefv param is not const.
@ -1579,18 +1573,18 @@ static int vsrc_grant(VSrc* vs)
alSourcePlay(vs->al_src);
al_check("vsrc_grant alSourcePlay");
return 0;
return ERR_OK;
}
// stop playback, and reclaim the OpenAL source.
// called when closing the VSrc, or when voice management decides
// this VSrc must yield to others of higher priority.
static int vsrc_reclaim(VSrc* vs)
static LibError vsrc_reclaim(VSrc* vs)
{
// don't own a source - bail.
if(!vs->al_src)
return -1;
return ERR_FAIL;
alSourceStop(vs->al_src);
al_check("src_stop");
@ -1600,7 +1594,7 @@ static int vsrc_reclaim(VSrc* vs)
vsrc_deque_finished_bufs(vs);
al_src_free(vs->al_src);
return 0;
return ERR_OK;
}
@ -1613,7 +1607,7 @@ static int vsrc_reclaim(VSrc* vs)
// priority (min 0 .. max 1, default 0) indicates which sounds are
// considered more important; this is attenuated by distance to the
// listener (see snd_update).
int snd_play(Handle hs, float static_pri)
LibError snd_play(Handle hs, float static_pri)
{
H_DEREF(hs, VSrc, vs);
@ -1628,7 +1622,7 @@ int snd_play(Handle hs, float static_pri)
// either we get a source and playing begins immediately,
// or it'll be taken care of on next update.
vsrc_grant(vs);
return 0;
return ERR_OK;
}
@ -1637,7 +1631,7 @@ int snd_play(Handle hs, float static_pri)
// listener; otherwise, it is the position in world coordinates.
// may be called at any time; fails with invalid handle return if
// the sound has already been closed (e.g. it never played).
int snd_set_pos(Handle hvs, float x, float y, float z, bool relative)
LibError snd_set_pos(Handle hvs, float x, float y, float z, bool relative)
{
H_DEREF(hvs, VSrc, vs);
@ -1645,7 +1639,7 @@ int snd_set_pos(Handle hvs, float x, float y, float z, bool relative)
vs->relative = relative;
vsrc_latch(vs);
return 0;
return ERR_OK;
}
@ -1653,17 +1647,17 @@ int snd_set_pos(Handle hvs, float x, float y, float z, bool relative)
// must be non-negative; 1 -> unattenuated, 0.5 -> -6 dB, 0 -> silence.
// may be called at any time; fails with invalid handle return if
// the sound has already been closed (e.g. it never played).
int snd_set_gain(Handle hvs, float gain)
LibError snd_set_gain(Handle hvs, float gain)
{
H_DEREF(hvs, VSrc, vs);
if(!(0.0f <= gain && gain <= 1.0f))
return -1;
return ERR_INVALID_PARAM;
vs->gain = gain;
vsrc_latch(vs);
return 0;
return ERR_OK;
}
@ -1672,17 +1666,17 @@ int snd_set_gain(Handle hvs, float gain)
// -12 semitones (one octave). zero is invalid.
// may be called at any time; fails with invalid handle return if
// the sound has already been closed (e.g. it never played).
int snd_set_pitch(Handle hvs, float pitch)
LibError snd_set_pitch(Handle hvs, float pitch)
{
H_DEREF(hvs, VSrc, vs);
if(!(0.0f < pitch && pitch <= 1.0f))
return -1;
return ERR_INVALID_PARAM;
vs->pitch = pitch;
vsrc_latch(vs);
return 0;
return ERR_OK;
}
@ -1696,14 +1690,14 @@ int snd_set_pitch(Handle hvs, float pitch)
// a hardware voice at the moment play was requested.
// - once looping is again disabled and the sound has reached its end,
// the sound instance is freed automatically (as if never looped).
int snd_set_loop(Handle hvs, bool loop)
LibError snd_set_loop(Handle hvs, bool loop)
{
H_DEREF(hvs, VSrc, vs);
vs->loop = loop;
vsrc_latch(vs);
return 0;
return ERR_OK;
}
@ -1760,7 +1754,7 @@ static void grant(VSrc* vs)
// no-op if OpenAL not yet initialized.
static int vm_update()
static LibError vm_update()
{
list_prune_removed();
@ -1778,9 +1772,9 @@ static int vm_update()
list_foreach(grant, 0, first_unimportant);
// add / remove buffers for each source.
list_foreach((void(*)(VSrc*))vsrc_update);
list_foreach((void (*)(VSrc*))vsrc_update);
return 0;
return ERR_OK;
}
@ -1792,7 +1786,7 @@ static int vm_update()
// additionally, if any parameter is non-NULL, we set the listener
// position, look direction, and up vector (in world coordinates).
// (allow any and all of them to be 0 in case world isn't initialized yet).
int snd_update(const float* pos, const float* dir, const float* up)
LibError snd_update(const float* pos, const float* dir, const float* up)
{
// there's no sense in updating anything if we weren't initialized
// yet (most notably, if sound is disabled). we check for this to
@ -1800,14 +1794,14 @@ int snd_update(const float* pos, const float* dir, const float* up)
// this fails, so report success here (everything will work once
// sound is re-enabled).
if(!al_initialized)
return 0;
return ERR_OK;
if(pos || dir || up)
al_listener_set_pos(pos, dir, up);
vm_update();
return 0;
return ERR_OK;
}
@ -1817,7 +1811,7 @@ static bool snd_disabled = false;
// extra layer on top of al_init that allows 'disabling' sound.
// called from each snd_open. returns ERR_AGAIN if sound disabled,
// otherwise the status returned by al_init.
static inline int snd_init()
static inline LibError snd_init()
{
// (note: each VSrc_reload and therefore snd_open will fail)
if(snd_disabled)
@ -1838,7 +1832,7 @@ static inline int snd_init()
//
// can later be called to reactivate sound; all settings ever changed
// will be applied and subsequent sound load / play requests will work.
int snd_disable(bool disabled)
LibError snd_disable(bool disabled)
{
snd_disabled = disabled;
@ -1846,7 +1840,7 @@ int snd_disable(bool disabled)
{
if(al_initialized)
debug_warn("already initialized => disable is pointless");
return 0;
return ERR_OK;
}
else
return snd_init();

View File

@ -92,7 +92,7 @@ terminology
// message should be presented to the user, and snd_dev_set need not be
// called; OpenAL will use its default device.
// may be called each time the device list is needed.
extern int snd_dev_prepare_enum();
extern LibError snd_dev_prepare_enum();
// return the next device name, or 0 if all have been returned.
// do not call unless snd_dev_prepare_enum succeeded!
@ -120,17 +120,17 @@ extern const char* snd_dev_next();
// so preferably call this routine before sounds are loaded.
//
// return 0 on success, or the status returned by OpenAL re-init.
extern int snd_dev_set(const char* alc_new_dev_name);
extern LibError snd_dev_set(const char* alc_new_dev_name);
// set maximum number of voices to play simultaneously,
// to reduce mixing cost on low-end systems.
// return 0 on success, or 1 if limit was ignored
// (e.g. if higher than an implementation-defined limit anyway).
extern int snd_set_max_voices(uint cap);
extern LibError snd_set_max_voices(uint cap);
// set amplitude modifier, which is effectively applied to all sounds.
// must be non-negative; 1 -> unattenuated, 0.5 -> -6 dB, 0 -> silence.
extern int snd_set_master_gain(float gain);
extern LibError snd_set_master_gain(float gain);
//
@ -153,7 +153,7 @@ extern Handle snd_open(const char* snd_fn, bool stream = false);
// close the sound <hs> and set hs to 0. if it was playing,
// it will be stopped. sounds are closed automatically when done
// playing; this is provided for completeness only.
extern int snd_free(Handle& hs);
extern LibError snd_free(Handle& hs);
// request the sound <hs> be played. once done playing, the sound is
// automatically closed (allows fire-and-forget play code).
@ -162,27 +162,27 @@ extern int snd_free(Handle& hs);
// priority (min 0 .. max 1, default 0) indicates which sounds are
// considered more important; this is attenuated by distance to the
// listener (see snd_update).
extern int snd_play(Handle hs, float priority = 0.0f);
extern LibError snd_play(Handle hs, float priority = 0.0f);
// change 3d position of the sound source.
// if relative (default false), (x,y,z) is treated as relative to the
// listener; otherwise, it is the position in world coordinates.
// may be called at any time; fails with invalid handle return if
// the sound has already been closed (e.g. it never played).
extern int snd_set_pos(Handle hs, float x, float y, float z, bool relative = false);
extern LibError snd_set_pos(Handle hs, float x, float y, float z, bool relative = false);
// change gain (amplitude modifier) of the sound source.
// must be non-negative; 1 -> unattenuated, 0.5 -> -6 dB, 0 -> silence.
// may be called at any time; fails with invalid handle return if
// the sound has already been closed (e.g. it never played).
extern int snd_set_gain(Handle hs, float gain);
extern LibError snd_set_gain(Handle hs, float gain);
// change pitch shift of the sound source.
// 1.0 means no change; each reduction by 50% equals a pitch shift of
// -12 semitones (one octave). zero is invalid.
// may be called at any time; fails with invalid handle return if
// the sound has already been closed (e.g. it never played).
extern int snd_set_pitch(Handle hs, float pitch);
extern LibError snd_set_pitch(Handle hs, float pitch);
// enable/disable looping on the sound source.
// used to implement variable-length sounds (e.g. while building).
@ -194,7 +194,7 @@ extern int snd_set_pitch(Handle hs, float pitch);
// a hardware voice at the moment play was requested.
// - once looping is again disabled and the sound has reached its end,
// the sound instance is freed automatically (as if never looped).
extern int snd_set_loop(Handle hs, bool loop);
extern LibError snd_set_loop(Handle hs, bool loop);
//
@ -212,13 +212,13 @@ extern int snd_set_loop(Handle hs, bool loop);
//
// can later be called to reactivate sound; all settings ever changed
// will be applied and subsequent sound load / play requests will work.
extern int snd_disable(bool disabled);
extern LibError snd_disable(bool disabled);
// perform housekeeping (e.g. streaming); call once a frame.
//
// additionally, if any parameter is non-NULL, we set the listener
// position, look direction, and up vector (in world coordinates).
extern int snd_update(const float* pos, const float* dir, const float* up);
extern LibError snd_update(const float* pos, const float* dir, const float* up);
// free all resources and shut down the sound system.
// call before h_mgr_shutdown.

View File

@ -27,7 +27,7 @@ bool self_test_active = false;
// trampoline that sets self_test_active and returns a dummy value;
// used by SELF_TEST_RUN.
int self_test_run(void(*func)())
int self_test_run(void (*func)())
{
self_test_active = true;
func();

View File

@ -1,8 +1,8 @@
// path: portable and relative, must add current directory and convert to native
// better to use a cached string from rel_chdir - secure
extern int dir_add_watch(const char* path, intptr_t* watch);
extern LibError dir_add_watch(const char* path, intptr_t* watch);
extern int dir_cancel_watch(intptr_t watch);
extern LibError dir_cancel_watch(intptr_t watch);
extern int dir_get_changed_file(char* fn);
extern LibError dir_get_changed_file(char* fn);

View File

@ -7,11 +7,11 @@ extern "C" {
// useful for choosing a video mode.
// if we fail, outputs are unchanged (assumed initialized to defaults)
extern int get_cur_vmode(int* xres, int* yres, int* bpp, int* freq);
extern LibError get_cur_vmode(int* xres, int* yres, int* bpp, int* freq);
// useful for determining aspect ratio.
// if we fail, outputs are unchanged (assumed initialized to defaults)
extern int get_monitor_size(int& width_mm, int& height_mm);
extern LibError get_monitor_size(int& width_mm, int& height_mm);
const size_t GFX_CARD_LEN = 128;

View File

@ -587,8 +587,14 @@ void ia32_get_cpu_info()
//-----------------------------------------------------------------------------
int ia32_get_call_target(void* ret_addr, void** target)
// checks if there is an IA-32 CALL instruction right before ret_addr.
// returns ERR_OK if so and ERR_FAIL if not.
// also attempts to determine the call target. if that is possible
// (directly addressed relative or indirect jumps), it is stored in
// target, which is otherwise 0.
//
// this is useful for walking the stack manually.
LibError ia32_get_call_target(void* ret_addr, void** target)
{
*target = 0;
@ -603,13 +609,13 @@ int ia32_get_call_target(void* ret_addr, void** target)
if(len >= 5 && c[-5] == 0xE8)
{
*target = (u8*)ret_addr + *(i32*)(c-4);
return 0;
return ERR_OK;
}
// CALL r/m32 (FF /2)
// .. CALL [r32 + r32*s] => FF 14 SIB
if(len >= 3 && c[-3] == 0xFF && c[-2] == 0x14)
return 1;
return ERR_OK;
// .. CALL [disp32] => FF 15 disp32
if(len >= 6 && c[6] == 0xFF && c[-5] == 0x15)
{
@ -617,29 +623,29 @@ int ia32_get_call_target(void* ret_addr, void** target)
if(!debug_is_pointer_bogus(addr_of_target))
{
*target = *(void**)addr_of_target;
return 0;
return ERR_OK;
}
}
// .. CALL [r32] => FF 00-3F(!14/15)
if(len >= 2 && c[-2] == 0xFF && c[-1] < 0x40 && c[-1] != 0x14 && c[-1] != 0x15)
return 1;
return ERR_OK;
// .. CALL [r32 + r32*s + disp8] => FF 54 SIB disp8
if(len >= 4 && c[-4] == 0xFF && c[-3] == 0x54)
return 1;
return ERR_OK;
// .. CALL [r32 + disp8] => FF 50-57(!54) disp8
if(len >= 3 && c[-3] == 0xFF && (c[-2] & 0xF8) == 0x50 && c[-2] != 0x54)
return 1;
return ERR_OK;
// .. CALL [r32 + r32*s + disp32] => FF 94 SIB disp32
if(len >= 7 && c[-7] == 0xFF && c[-6] == 0x94)
return 1;
return ERR_OK;
// .. CALL [r32 + disp32] => FF 90-97(!94) disp32
if(len >= 6 && c[-6] == 0xFF && (c[-5] & 0xF8) == 0x90 && c[-5] != 0x94)
return 1;
return ERR_OK;
// .. CALL r32 => FF D0-D7
if(len >= 2 && c[-2] == 0xFF && (c[-1] & 0xF8) == 0xD0)
return 1;
return ERR_OK;
return -3;
return ERR_FAIL;
}
@ -686,10 +692,10 @@ namespace test {
TEST(i32_from_double(1.01) == 1);
TEST(i32_from_double(5.6) == 5);
TEST(i64_from_double(0.99999) == 0i64);
TEST(i64_from_double(1.0) == 1i64);
TEST(i64_from_double(1.01) == 1i64);
TEST(i64_from_double(5.6) == 5i64);
TEST(i64_from_double(0.99999) == 0ll);
TEST(i64_from_double(1.0) == 1ll);
TEST(i64_from_double(1.01) == 1ll);
TEST(i64_from_double(5.6) == 5ll);
}
static void self_test()

View File

@ -117,7 +117,14 @@ extern void ia32_get_current_context(void* pcontext);
extern void ia32_asm_init();
extern int ia32_get_call_target(void* ret_addr, void** target);
// checks if there is an IA-32 CALL instruction right before ret_addr.
// returns ERR_OK if so and ERR_FAIL if not.
// also attempts to determine the call target. if that is possible
// (directly addressed relative or indirect jumps), it is stored in
// target, which is otherwise 0.
//
// this is useful for walking the stack manually.
extern LibError ia32_get_call_target(void* ret_addr, void** target);
// order in which registers are stored in regs array
// (do not change! brand string relies on this ordering)

View File

@ -171,7 +171,7 @@ extern ErrorReaction sys_display_error(const wchar_t* text, int flags);
//
// "copy" text into the clipboard. replaces previous contents.
extern int sys_clipboard_set(const wchar_t* text);
extern LibError sys_clipboard_set(const wchar_t* text);
// allow "pasting" from clipboard. returns the current contents if they
// can be represented as text, otherwise 0.
@ -181,7 +181,7 @@ extern wchar_t* sys_clipboard_get(void);
// frees memory used by <copy>, which must have been returned by
// sys_clipboard_get. see note above.
extern int sys_clipboard_free(wchar_t* copy);
extern LibError sys_clipboard_free(wchar_t* copy);
//
@ -200,16 +200,16 @@ extern int sys_clipboard_free(wchar_t* copy);
// return: negative error code, or 0 on success. cursor is filled with
// a pointer and undefined on failure. it must be sys_cursor_free-ed
// when no longer needed.
extern int sys_cursor_create(uint w, uint h, void* bgra_img,
extern LibError sys_cursor_create(uint w, uint h, void* bgra_img,
uint hx, uint hy, void** cursor);
// replaces the current system cursor with the one indicated. need only be
// called once per cursor; pass 0 to restore the default.
extern int sys_cursor_set(void* cursor);
extern LibError sys_cursor_set(void* cursor);
// destroys the indicated cursor and frees its resources. if it is
// currently the system cursor, the default cursor is restored first.
extern int sys_cursor_free(void* cursor);
extern LibError sys_cursor_free(void* cursor);
//
@ -219,7 +219,7 @@ extern int sys_cursor_free(void* cursor);
// OS-specific backend for error_description_r.
// NB: it is expected to be rare that OS return/error codes are actually
// seen by user code, but we still translate them for completeness.
extern int sys_error_description_r(int err, char* buf, size_t max_chars);
extern LibError sys_error_description_r(int err, char* buf, size_t max_chars);
// determine filename of the module to whom the given address belongs.
// useful for handling exceptions in other modules.
@ -231,13 +231,13 @@ wchar_t* sys_get_module_filename(void* addr, wchar_t* path);
// store full path to the current executable.
// returns 0 or a negative error code.
// useful for determining installation directory, e.g. for VFS.
extern int sys_get_executable_name(char* n_path, size_t buf_size);
extern LibError sys_get_executable_name(char* n_path, size_t buf_size);
// have the user specify a directory via OS dialog.
// stores its full path in the given buffer, which must hold at least
// PATH_MAX chars.
// returns 0 on success or a negative error code.
extern int sys_pick_directory(char* n_path, size_t buf_size);
extern LibError sys_pick_directory(char* n_path, size_t buf_size);
// execute the specified function once on each CPU.
// this includes logical HT units and proceeds serially (function
@ -247,7 +247,7 @@ extern int sys_pick_directory(char* n_path, size_t buf_size);
// return 0 on success or a negative error code on failure
// (e.g. if OS is preventing us from running on some CPUs).
// called from ia32.cpp get_cpu_count
extern int sys_on_each_cpu(void(*cb)());
extern LibError sys_on_each_cpu(void (*cb)());
// drop-in replacement for libc memcpy(). only requires CPU support for

View File

@ -138,7 +138,7 @@ static HANDLE aio_h_get(const int fd)
// associate h (an async-capable file handle) with fd;
// returned by subsequent aio_h_get(fd) calls.
// setting h = INVALID_HANDLE_VALUE removes the association.
static int aio_h_set(const int fd, const HANDLE h)
static LibError aio_h_set(const int fd, const HANDLE h)
{
lock();
@ -177,12 +177,12 @@ static int aio_h_set(const int fd, const HANDLE h)
aio_hs[fd] = h;
unlock();
return 0;
return ERR_OK;
fail:
unlock();
debug_warn("failed");
return -1;
return ERR_FAIL;
}
@ -353,11 +353,11 @@ static Req* req_alloc(aiocb* cb)
}
static int req_free(Req* r)
static LibError req_free(Req* r)
{
debug_assert(r->cb != 0 && "req_free: not currently in use");
r->cb = 0;
return 0;
return ERR_OK;
}
@ -707,7 +707,7 @@ int aio_fsync(int, struct aiocb*)
//////////////////////////////////////////////////////////////////////////////
static int waio_init()
static LibError waio_init()
{
req_init();
@ -747,13 +747,13 @@ static int waio_init()
SetErrorMode(old_err_mode);
debug_assert(is_pow2((long)sector_size));
return 0;
return ERR_OK;
}
static int waio_shutdown()
static LibError waio_shutdown()
{
req_cleanup();
aio_h_cleanup();
return 0;
return ERR_OK;
}

View File

@ -44,7 +44,7 @@ struct sigevent
int sigev_notify; // notification mode
int sigev_signo; // signal number
union sigval sigev_value; // signal value
void(*sigev_notify_function)(union sigval);
void (*sigev_notify_function)(union sigval);
};

View File

@ -92,7 +92,7 @@ static void check_speedstep()
}
int win_get_cpu_info()
LibError win_get_cpu_info()
{
// get number of CPUs (can't fail)
SYSTEM_INFO si;
@ -114,7 +114,7 @@ int win_get_cpu_info()
check_speedstep();
return 0;
return ERR_OK;
}
@ -251,7 +251,7 @@ static void* prof_thread_func(void* UNUSED(data))
// call from thread that is to be profiled
int prof_start()
LibError prof_start()
{
// we need a real HANDLE to the target thread for use with
// Suspend|ResumeThread and GetThreadContext.
@ -262,20 +262,20 @@ int prof_start()
if(hThread == INVALID_HANDLE_VALUE)
{
debug_warn("OpenThread failed");
return -1;
return ERR_FAIL;
}
prof_target_thread = hThread;
sem_init(&exit_flag, 0, 0);
pthread_create(&thread, 0, prof_thread_func, 0);
return 0;
return ERR_OK;
}
int prof_shutdown()
LibError prof_shutdown()
{
CloseHandle(prof_target_thread);
return 0;
WARN_IF_FALSE(CloseHandle(prof_target_thread));
return ERR_OK;
}

View File

@ -159,7 +159,7 @@ void debug_heap_enable(DebugHeapChecks what)
// to avoid deadlock, be VERY CAREFUL to avoid anything that may block,
// including locks taken by the OS (e.g. malloc, GetProcAddress).
typedef int(*WhileSuspendedFunc)(HANDLE hThread, void* user_arg);
typedef LibError (*WhileSuspendedFunc)(HANDLE hThread, void* user_arg);
struct WhileSuspendedParam
{
@ -173,10 +173,9 @@ static void* while_suspended_thread_func(void* user_arg)
{
debug_set_thread_name("suspender");
DWORD err;
WhileSuspendedParam* param = (WhileSuspendedParam*)user_arg;
err = SuspendThread(param->hThread);
DWORD err = SuspendThread(param->hThread);
// abort, since GetThreadContext only works if the target is suspended.
if(err == (DWORD)-1)
{
@ -186,16 +185,15 @@ static void* while_suspended_thread_func(void* user_arg)
// target is now guaranteed to be suspended,
// since the Windows counter never goes negative.
int ret = param->func(param->hThread, param->user_arg);
LibError ret = param->func(param->hThread, param->user_arg);
err = ResumeThread(param->hThread);
debug_assert(err != 0);
WARN_IF_FALSE(ResumeThread(param->hThread));
return (void*)(intptr_t)ret;
}
static int call_while_suspended(WhileSuspendedFunc func, void* user_arg)
static LibError call_while_suspended(WhileSuspendedFunc func, void* user_arg)
{
int err;
@ -208,7 +206,7 @@ static int call_while_suspended(WhileSuspendedFunc func, void* user_arg)
if(hThread == INVALID_HANDLE_VALUE)
{
debug_warn("OpenThread failed");
return -1;
return ERR_FAIL;
}
WhileSuspendedParam param = { hThread, func, user_arg };
@ -220,7 +218,7 @@ static int call_while_suspended(WhileSuspendedFunc func, void* user_arg)
err = pthread_join(thread, &ret);
debug_assert(err == 0 && ret == 0);
return (int)(intptr_t)ret;
return (LibError)(intptr_t)ret;
}
@ -260,17 +258,17 @@ static const uint MAX_BREAKPOINTS = 4;
// remove all breakpoints enabled by debug_set_break from <context>.
// called while target is suspended.
static int brk_disable_all_in_ctx(BreakInfo* UNUSED(bi), CONTEXT* context)
static LibError brk_disable_all_in_ctx(BreakInfo* UNUSED(bi), CONTEXT* context)
{
context->Dr7 &= ~brk_all_local_enables;
return 0;
return ERR_OK;
}
// find a free register, set type according to <bi> and
// mark it as enabled in <context>.
// called while target is suspended.
static int brk_enable_in_ctx(BreakInfo* bi, CONTEXT* context)
static LibError brk_enable_in_ctx(BreakInfo* bi, CONTEXT* context)
{
uint reg; // index (0..3) of first free reg
uint LE; // local enable bit for <reg>
@ -340,15 +338,15 @@ have_reg:
context->Dr7 |= LE;
brk_all_local_enables |= LE;
return 0;
return ERR_OK;
}
// carry out the request stored in the BreakInfo* parameter.
// called while target is suspended.
static int brk_do_request(HANDLE hThread, void* arg)
static LibError brk_do_request(HANDLE hThread, void* arg)
{
int ret;
LibError ret;
BreakInfo* bi = (BreakInfo*)arg;
CONTEXT context;
@ -374,9 +372,9 @@ static int brk_do_request(HANDLE hThread, void* arg)
goto fail;
}
return 0;
return ret;
fail:
return -1;
return ERR_FAIL;
}
@ -386,13 +384,13 @@ fail:
// derived from addr's alignment, and is typically 1 machine word.
// breakpoints are a limited resource (4 on IA-32); abort and
// return ERR_LIMIT if none are available.
int debug_set_break(void* p, DbgBreakType type)
LibError debug_set_break(void* p, DbgBreakType type)
{
lock();
brk_info.addr = (uintptr_t)p;
brk_info.type = type;
int ret = call_while_suspended(brk_do_request, &brk_info);
LibError ret = call_while_suspended(brk_do_request, &brk_info);
unlock();
return ret;
@ -401,12 +399,12 @@ int debug_set_break(void* p, DbgBreakType type)
// remove all breakpoints that were set by debug_set_break.
// important, since these are a limited resource.
int debug_remove_all_breaks()
LibError debug_remove_all_breaks()
{
lock();
brk_info.want_all_disabled = true;
int ret = call_while_suspended(brk_do_request, &brk_info);
LibError ret = call_while_suspended(brk_do_request, &brk_info);
brk_info.want_all_disabled = false;
unlock();
@ -734,7 +732,7 @@ static LONG WINAPI vectored_exception_handler(EXCEPTION_POINTERS* ep)
}
static int wdbg_init(void)
static LibError wdbg_init(void)
{
// see decl
main_thread_id = GetCurrentThreadId();
@ -753,7 +751,7 @@ static int wdbg_init(void)
pAddVectoredExceptionHandler(TRUE, vectored_exception_handler);
#endif
return 0;
return ERR_OK;
}

File diff suppressed because it is too large Load Diff

View File

@ -71,7 +71,7 @@
// EnumDisplayDevices is not available on Win95 or NT.
// try to import it manually here; return -1 if not available.
static BOOL (WINAPI *pEnumDisplayDevicesA)(LPCSTR, DWORD, LPDISPLAY_DEVICEA, DWORD);
static int import_EnumDisplayDevices()
static LibError import_EnumDisplayDevices()
{
if(!pEnumDisplayDevicesA)
{
@ -86,13 +86,13 @@ static int import_EnumDisplayDevices()
// so this resource leak is unavoidable.
}
return pEnumDisplayDevicesA? 0 : -1;
return pEnumDisplayDevicesA? ERR_OK : ERR_FAIL;
}
// useful for choosing a video mode.
// if we fail, outputs are unchanged (assumed initialized to defaults)
int get_cur_vmode(int* xres, int* yres, int* bpp, int* freq)
LibError get_cur_vmode(int* xres, int* yres, int* bpp, int* freq)
{
// don't use EnumDisplaySettingsW - BoundsChecker reports it causes
// a memory overrun (even if called as the very first thing, before
@ -104,7 +104,7 @@ int get_cur_vmode(int* xres, int* yres, int* bpp, int* freq)
// dm.dmDriverExtra already set to 0 by memset
if(!EnumDisplaySettingsA(0, ENUM_CURRENT_SETTINGS, &dm))
return -1;
return ERR_FAIL;
if(dm.dmFields & (DWORD)DM_PELSWIDTH && xres)
*xres = (int)dm.dmPelsWidth;
@ -115,20 +115,20 @@ int get_cur_vmode(int* xres, int* yres, int* bpp, int* freq)
if(dm.dmFields & (DWORD)DM_DISPLAYFREQUENCY && freq)
*freq = (int)dm.dmDisplayFrequency;
return 0;
return ERR_OK;
}
// useful for determining aspect ratio.
// if we fail, outputs are unchanged (assumed initialized to defaults)
int get_monitor_size(int& width_mm, int& height_mm)
LibError get_monitor_size(int& width_mm, int& height_mm)
{
// (DC for the primary monitor's entire screen)
HDC dc = GetDC(0);
width_mm = GetDeviceCaps(dc, HORZSIZE);
height_mm = GetDeviceCaps(dc, VERTSIZE);
ReleaseDC(0, dc);
return 0;
return ERR_OK;
}
@ -136,7 +136,7 @@ int get_monitor_size(int& width_mm, int& height_mm)
// support routines for getting DLL version
//----------------------------------------------------------------------------
static int get_ver(const char* module_path, char* out_ver, size_t out_ver_len)
static LibError get_ver(const char* module_path, char* out_ver, size_t out_ver_len)
{
WIN_SAVE_LAST_ERROR; // GetFileVersion*, Ver*
@ -144,12 +144,12 @@ static int get_ver(const char* module_path, char* out_ver, size_t out_ver_len)
DWORD unused;
const DWORD ver_size = GetFileVersionInfoSize(module_path, &unused);
if(!ver_size)
return -1;
return ERR_FAIL;
void* buf = malloc(ver_size);
if(!buf)
return ERR_NO_MEM;
int ret = -1; // single point of exit (for free())
LibError ret = ERR_FAIL; // single point of exit (for free())
if(GetFileVersionInfo(module_path, 0, ver_size, buf))
{
@ -165,7 +165,7 @@ static int get_ver(const char* module_path, char* out_ver, size_t out_ver_len)
if(VerQueryValue(buf, subblock, (void**)&in_ver, &in_ver_len))
{
strcpy_s(out_ver, out_ver_len, in_ver);
ret = 0; // success
ret = ERR_OK;
}
}
}
@ -198,13 +198,13 @@ static void dll_list_init(char* buf, size_t chars)
// name should preferably be the complete path to DLL, to make sure
// we don't inadvertently load another one on the library search path.
// we add the .dll extension if necessary.
static int dll_list_add(const char* name)
static LibError dll_list_add(const char* name)
{
// make sure we're allowed to be called.
if(!dll_list_pos)
{
debug_warn("called before dll_list_init or after failure");
return -1;
return ERR_FAIL;
}
// some driver names are stored in the registry without .dll extension.
@ -241,7 +241,7 @@ static int dll_list_add(const char* name)
if(len > 0)
{
dll_list_pos += len;
return 0;
return ERR_OK;
}
// didn't fit; complain
@ -259,7 +259,7 @@ static int dll_list_add(const char* name)
//////////////////////////////////////////////////////////////////////////////
static int win_get_gfx_card()
static LibError win_get_gfx_card()
{
// make sure EnumDisplayDevices is available (as pEnumDisplayDevicesA)
if(import_EnumDisplayDevices() >= 0)
@ -282,20 +282,21 @@ static int win_get_gfx_card()
if(dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
{
strcpy_s(gfx_card, ARRAY_SIZE(gfx_card), (const char*)dd.DeviceString);
return 0;
return ERR_OK;
}
}
}
return -1;
return ERR_FAIL;
}
// note: this implementation doesn't require OpenGL to be initialized.
static int win_get_gfx_drv_ver()
static LibError win_get_gfx_drv_ver()
{
// don't overwrite existing information
if(gfx_drv_ver[0] != '\0')
return -1;
return ERR_FAIL;
// rationale:
// - we could easily determine the 2d driver via EnumDisplaySettings,
@ -314,7 +315,7 @@ static int win_get_gfx_drv_ver()
// gfx_card which one is correct; we thus avoid driver-specific
// name checks and reporting incorrectly.
int ret = -1; // single point of exit (for RegCloseKey)
LibError ret = ERR_FAIL; // single point of exit (for RegCloseKey)
DWORD i;
char drv_name[MAX_PATH+1];
@ -323,7 +324,7 @@ static int win_get_gfx_drv_ver()
HKEY hkOglDrivers;
const char* key = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\OpenGLDrivers";
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, key, 0, KEY_READ, &hkOglDrivers) != 0)
return -1;
return ERR_FAIL;
// for each subkey (i.e. set of installed OpenGL drivers):
for(i = 0; ; i++)
@ -367,15 +368,15 @@ static int win_get_gfx_drv_ver()
}
int win_get_gfx_info()
LibError win_get_gfx_info()
{
int err1 = win_get_gfx_card();
int err2 = win_get_gfx_drv_ver();
LibError err1 = win_get_gfx_card();
LibError err2 = win_get_gfx_drv_ver();
// don't exit before trying both
CHECK_ERR(err1);
CHECK_ERR(err2);
return 0;
return ERR_OK;
}
@ -399,25 +400,25 @@ typedef std::set<std::string> StringSet;
// note: we need the full DLL path for dll_list_add but DirEnt only gives us
// the name. for efficiency, we append this in a PathPackage allocated by
// add_oal_dlls_in_dir.
static int add_if_oal_dll(const DirEnt* ent, PathPackage* pp, StringSet* dlls)
static LibError add_if_oal_dll(const DirEnt* ent, PathPackage* pp, StringSet* dlls)
{
const char* fn = ent->name;
// skip non-files.
if(!DIRENT_IS_DIR(ent))
return 0;
return ERR_OK;
// skip if not an OpenAL DLL.
const size_t len = strlen(fn);
const bool oal = len >= 7 && !stricmp(fn+len-7, "oal.dll");
const bool openal = strstr(fn, "OpenAL") != 0;
if(!oal && !openal)
return 0;
return ERR_OK;
// skip if already in StringSet (i.e. has already been dll_list_add-ed)
std::pair<StringSet::iterator, bool> ret = dlls->insert(fn);
if(!ret.second) // insert failed - element already there
return 0;
return ERR_OK;
RETURN_ERR(pp_append_file(pp, fn));
return dll_list_add(pp->path);
@ -430,7 +431,7 @@ static int add_if_oal_dll(const DirEnt* ent, PathPackage* pp, StringSet* dlls)
// same name in the system directory.
//
// <dir>: no trailing.
static int add_oal_dlls_in_dir(const char* dir, StringSet* dlls)
static LibError add_oal_dlls_in_dir(const char* dir, StringSet* dlls)
{
PathPackage pp;
RETURN_ERR(pp_set_dir(&pp, dir));
@ -441,14 +442,14 @@ static int add_oal_dlls_in_dir(const char* dir, StringSet* dlls)
DirEnt ent;
for(;;) // instead of while to avoid warning
{
int err = dir_next_ent(&d, &ent);
if(err != 0)
LibError err = dir_next_ent(&d, &ent);
if(err != ERR_OK)
break;
(void)add_if_oal_dll(&ent, &pp, dlls);
}
(void)dir_close(&d);
return 0;
return ERR_OK;
}
@ -476,7 +477,7 @@ static BOOL CALLBACK ds_enum(void* UNUSED(guid), const char* description,
}
int win_get_snd_info()
LibError win_get_snd_info()
{
// get sound card name and DS driver path.
if(DirectSoundEnumerateA((LPDSENUMCALLBACKA)ds_enum, (void*)0) != DS_OK)
@ -488,7 +489,7 @@ int win_get_snd_info()
{
strcpy_s(snd_card, SND_CARD_LEN, "(none)");
strcpy_s(snd_drv_ver, SND_DRV_VER_LEN, "(none)");
return 0;
return ERR_OK;
}
// find all DLLs related to OpenAL, retrieve their versions,
@ -498,5 +499,5 @@ int win_get_snd_info()
StringSet dlls; // ensures uniqueness
(void)add_oal_dlls_in_dir(win_exe_dir, &dlls);
(void)add_oal_dlls_in_dir(win_sys_dir, &dlls);
return 0;
return ERR_OK;
}

View File

@ -153,7 +153,7 @@ static Events pending_events;
// but that's more complicated, and this way is cleaner anyway.
static int wdir_watch_shutdown()
static LibError wdir_watch_shutdown()
{
CloseHandle(hIOCP);
hIOCP = INVALID_HANDLE_VALUE;
@ -163,12 +163,12 @@ static int wdir_watch_shutdown()
delete it->second;
watches.clear();
return 0;
return ERR_OK;
}
// HACK - see call site
static int get_packet();
static void get_packet();
static Watch* find_watch(intptr_t reqnum)
@ -178,9 +178,9 @@ static Watch* find_watch(intptr_t reqnum)
// path: portable and relative, must add current directory and convert to native
// better to use a cached string from rel_chdir - secure
int dir_add_watch(const char* dir, intptr_t* _reqnum)
LibError dir_add_watch(const char* dir, intptr_t* _reqnum)
{
int err = -1;
LibError err = ERR_FAIL;
WIN_SAVE_LAST_ERROR; // Create*
intptr_t reqnum;
@ -237,10 +237,10 @@ int dir_add_watch(const char* dir, intptr_t* _reqnum)
}
// allocate watch, add to list, associate with reqnum
// note: can't use SAFE_NEW due to ctor params.
try
{
Watch* w = new Watch(reqnum, dir_s, hDir);
debug_assert(w != 0); // happened once; heap corruption?
// add trailing \ if not already there
if(dir_s[dir_s.length()-1] != '\\')
@ -263,7 +263,7 @@ int dir_add_watch(const char* dir, intptr_t* _reqnum)
}
done:
err = 0;
err = ERR_OK;
*_reqnum = reqnum;
fail:
@ -272,7 +272,7 @@ fail:
}
int dir_cancel_watch(const intptr_t reqnum)
LibError dir_cancel_watch(const intptr_t reqnum)
{
if(reqnum <= 0)
return ERR_INVALID_PARAM;
@ -281,28 +281,28 @@ int dir_cancel_watch(const intptr_t reqnum)
if(!w)
{
debug_warn("watches[reqnum] invalid");
return -1;
return ERR_FAIL;
}
// we're freeing a reference - done.
debug_assert(w->refs >= 1);
if(--w->refs != 0)
return 0;
return ERR_OK;
// contrary to dox, the RDC IOs do not issue a completion notification.
// no packet was received on the IOCP while or after cancelling in a test.
//
// if cancel somehow fails though, no matter - the Watch is freed, and
// its reqnum isn't reused; if we receive a packet, it's ignored.
BOOL ret = CancelIo(w->hDir);
BOOL ok = CancelIo(w->hDir);
delete w;
watches[reqnum] = 0;
return ret? 0 : -1;
return LibError_from_win32(ok);
}
static int extract_events(Watch* w)
static void extract_events(Watch* w)
{
debug_assert(w);
@ -330,13 +330,12 @@ static int extract_events(Watch* w)
break;
pos += ofs;
}
return 0;
}
// if a packet is pending, extract its events and re-issue its watch.
static int get_packet()
// if a packet is pending, extract its events, post them in the queue and
// re-issue its watch.
static void get_packet()
{
// poll for change notifications from all pending watches
DWORD bytes_transferred;
@ -345,13 +344,13 @@ static int get_packet()
OVERLAPPED* povl;
BOOL got_packet = GetQueuedCompletionStatus(hIOCP, &bytes_transferred, &key, &povl, 0);
if(!got_packet) // no new packet - done
return 1;
return;
const intptr_t reqnum = (intptr_t)key;
Watch* const w = find_watch(reqnum);
// watch was subsequently removed - ignore the error.
if(!w)
return 1;
return;
// this is an actual packet, not just a kickoff for issuing the watch.
// extract the events and push them onto AppState's queue.
@ -367,29 +366,27 @@ static int get_packet()
memset(&w->ovl, 0, sizeof(w->ovl));
BOOL watch_subtree = TRUE;
// much faster than watching every dir separately. see dir_add_watch.
BOOL ret = ReadDirectoryChangesW(w->hDir, w->change_buf, buf_size, watch_subtree, filter, &w->dummy_nbytes, &w->ovl, 0);
if(!ret)
debug_warn("ReadDirectoryChangesW failed");
return 0;
BOOL ok = ReadDirectoryChangesW(w->hDir, w->change_buf, buf_size, watch_subtree, filter, &w->dummy_nbytes, &w->ovl, 0);
WARN_IF_FALSE(ok);
}
// if a file change notification is pending, store its filename in <fn> and
// return 0; otherwise, return 1 ('none currently pending') or an error code.
// return ERR_OK; otherwise, return ERR_AGAIN ('none currently pending') or
// a negative error code.
// <fn> must hold at least PATH_MAX chars.
int dir_get_changed_file(char* fn)
LibError dir_get_changed_file(char* fn)
{
// queue one or more events, or return 1 if none pending.
CHECK_ERR(get_packet());
// may or may not queue event(s).
get_packet();
// nothing to return; call again later.
if(pending_events.empty())
return 1;
return ERR_AGAIN;
const std::string& fn_s = pending_events.front();
strcpy_s(fn, PATH_MAX, fn_s.c_str());
pending_events.pop_front();
return 0;
return ERR_OK;
}

View File

@ -556,7 +556,7 @@ __HrLoadAllImportsForDll(LPCSTR szDll) {
*/
static int wdll_shutdown()
static LibError wdll_shutdown()
{
PUnloadInfo pui;
@ -579,7 +579,7 @@ static int wdll_shutdown()
// changes __puiHead!
}
return 0;
return ERR_OK;
}

View File

@ -5,10 +5,10 @@ extern void wdll_add_notify(DllLoadNotify*);
struct DllLoadNotify
{
const char* dll_name;
int(*func)(void);
LibError (*func)(void);
DllLoadNotify* next;
DllLoadNotify(const char* _dll_name, int(*_func)(void))
DllLoadNotify(const char* _dll_name, LibError (*_func)(void))
{
dll_name = _dll_name;
func = _func;

View File

@ -31,7 +31,7 @@ typedef __int64 INT64;
typedef float FLOAT;
typedef const char* LPCSTR;
typedef void* HANDLE;
typedef int(*PROC)(void);
typedef int (*PROC)(void);
#define DECLARE_HANDLE(name) typedef HANDLE name
DECLARE_HANDLE(HDC);
DECLARE_HANDLE(HGLRC);

View File

@ -26,6 +26,44 @@
char win_sys_dir[MAX_PATH+1];
char win_exe_dir[MAX_PATH+1];
// only call after a Win32 function indicates failure.
static LibError LibError_from_GLE()
{
switch(GetLastError())
{
case ERROR_OUTOFMEMORY:
return ERR_NO_MEM;
case ERROR_INVALID_PARAMETER:
return ERR_INVALID_PARAM;
case ERROR_INSUFFICIENT_BUFFER:
return ERR_BUF_SIZE;
case ERROR_ACCESS_DENIED:
return ERR_FILE_ACCESS;
case ERROR_FILE_NOT_FOUND:
return ERR_FILE_NOT_FOUND;
case ERROR_PATH_NOT_FOUND:
return ERR_PATH_NOT_FOUND;
default:
return ERR_FAIL;
}
UNREACHABLE;
}
// return the LibError equivalent of GetLastError(), or ERR_FAIL if
// there's no equal.
// you should SetLastError(0) before calling whatever will set ret
// to make sure we do not return any stale errors.
LibError LibError_from_win32(DWORD ret)
{
return (ret != FALSE)? ERR_OK : LibError_from_GLE();
}
//-----------------------------------------------------------------------------
//
@ -86,7 +124,7 @@ void win_free(void* p)
// be placed beyond the table start/end by the linker, since the linker's
// ordering WRT other source files' data is undefined within a segment.
typedef int(*_PIFV)(void);
typedef LibError (*_PIFV)(void);
// pointers to start and end of function tables.
// note: COFF tosses out empty segments, so we have to put in one value

View File

@ -438,7 +438,7 @@ extern void win_free(void* p);
// to be called via WIN_REGISTER_FUNC, and then restore the previous segment
// with #pragma data_seg() .
#define WIN_REGISTER_FUNC(func) static int func(void); static int(*p##func)(void) = func
#define WIN_REGISTER_FUNC(func) static LibError func(void); static LibError (*p##func)(void) = func
#define WIN_CALLBACK_PRE_LIBC(group) ".LIB$WC" #group
#define WIN_CALLBACK_PRE_MAIN(group) ".LIB$WI" #group
@ -450,6 +450,13 @@ extern void win_free(void* p);
#define WIN_RESTORE_LAST_ERROR STMT(if(last_err__ != 0 && GetLastError() == 0) SetLastError(last_err__););
// return the LibError equivalent of GetLastError(), or ERR_FAIL if
// there's no equal.
// you should SetLastError(0) before calling whatever will set ret
// to make sure we do not return any stale errors.
extern LibError LibError_from_win32(DWORD ret);
extern char win_sys_dir[MAX_PATH+1];
extern char win_exe_dir[MAX_PATH+1];

View File

@ -624,7 +624,7 @@ int mprotect(void* addr, size_t len, int prot)
// called when flags & MAP_ANONYMOUS
static int mmap_mem(void* start, size_t len, int prot, int flags, int fd, void** pp)
static LibError mmap_mem(void* start, size_t len, int prot, int flags, int fd, void** pp)
{
// sanity checks. we don't care about these but enforce them to
// ensure callers are compatible with mmap.
@ -648,7 +648,7 @@ debug_assert(ok); // todo4
ok = VirtualFree(start, len, MEM_DECOMMIT);
debug_assert(ok);
*pp = 0;
return 0;
return ERR_OK;
}
}
@ -659,7 +659,7 @@ debug_assert(ok);
if(!p)
return ERR_NO_MEM;
*pp = p;
return 0;
return ERR_OK;
}
@ -667,7 +667,7 @@ debug_assert(ok);
// CreateFileMapping / MapViewOfFile. they only support read-only,
// read/write and copy-on-write, so we dumb it down to that and later
// set the correct (and more restrictive) permission via mprotect.
static int mmap_file_access(int prot, int flags, DWORD& flProtect, DWORD& dwAccess)
static LibError mmap_file_access(int prot, int flags, DWORD& flProtect, DWORD& dwAccess)
{
// assume read-only; other cases handled below.
flProtect = PAGE_READONLY;
@ -696,11 +696,11 @@ static int mmap_file_access(int prot, int flags, DWORD& flProtect, DWORD& dwAcce
}
}
return 0;
return ERR_OK;
}
static int mmap_file(void* start, size_t len, int prot, int flags,
static LibError mmap_file(void* start, size_t len, int prot, int flags,
int fd, off_t ofs, void** pp)
{
debug_assert(fd != -1); // handled by mmap_mem
@ -744,14 +744,14 @@ static int mmap_file(void* start, size_t len, int prot, int flags,
WIN_RESTORE_LAST_ERROR;
*pp = p;
return 0;
return ERR_OK;
}
void* mmap(void* start, size_t len, int prot, int flags, int fd, off_t ofs)
{
void* p;
int err;
LibError err;
if(flags & MAP_ANONYMOUS)
err = mmap_mem(start, len, prot, flags, fd, &p);
else

View File

@ -114,7 +114,7 @@ static const uint MAX_DTORS = 4;
static struct
{
pthread_key_t key;
void(*dtor)(void*);
void (*dtor)(void*);
}
dtors[MAX_DTORS];
@ -203,7 +203,7 @@ again:
for(uint i = 0; i < MAX_DTORS; i++)
{
// is slot #i in use?
void(*dtor)(void*) = dtors[i].dtor;
void (*dtor)(void*) = dtors[i].dtor;
if(!dtor)
continue;
@ -242,7 +242,7 @@ again:
// c) we therefore use static data protected by a critical section.
static struct FuncAndArg
{
void*(*func)(void*);
void* (*func)(void*);
void* arg;
}
func_and_arg;
@ -251,7 +251,7 @@ func_and_arg;
// bridge calling conventions required by _beginthreadex and POSIX.
static unsigned __stdcall thread_start(void* UNUSED(param))
{
void*(*func)(void*) = func_and_arg.func;
void* (*func)(void*) = func_and_arg.func;
void* arg = func_and_arg.arg;
win_unlock(WPTHREAD_CS);
@ -270,7 +270,7 @@ static unsigned __stdcall thread_start(void* UNUSED(param))
}
int pthread_create(pthread_t* thread_id, const void* UNUSED(attr), void*(*func)(void*), void* arg)
int pthread_create(pthread_t* thread_id, const void* UNUSED(attr), void* (*func)(void*), void* arg)
{
win_lock(WPTHREAD_CS);
func_and_arg.func = func;

View File

@ -61,7 +61,7 @@ typedef unsigned int pthread_t;
extern pthread_t pthread_self(void);
extern int pthread_getschedparam(pthread_t thread, int* policy, struct sched_param* param);
extern int pthread_setschedparam(pthread_t thread, int policy, const struct sched_param* param);
extern int pthread_create(pthread_t* thread, const void* attr, void*(*func)(void*), void* arg);
extern int pthread_create(pthread_t* thread, const void* attr, void* (*func)(void*), void* arg);
extern int pthread_cancel(pthread_t thread);
extern int pthread_join(pthread_t thread, void** value_ptr);

View File

@ -82,7 +82,7 @@ static u16 cur_ramp[3][256];
// ramp: 8.8 fixed point
static int calc_gamma_ramp(float gamma, u16* ramp)
static LibError calc_gamma_ramp(float gamma, u16* ramp)
{
// assume identity if invalid
if(gamma <= 0.0f)
@ -93,7 +93,7 @@ static int calc_gamma_ramp(float gamma, u16* ramp)
{
for(u16 i = 0; i < 256; i++)
ramp[i] = (i << 8);
return 0;
return ERR_OK;
}
const double inv_gamma = 1.0 / gamma;
@ -106,7 +106,7 @@ static int calc_gamma_ramp(float gamma, u16* ramp)
ramp[i] = fp_to_u16(pow(frac, inv_gamma));
}
return 0;
return ERR_OK;
}
@ -1106,10 +1106,10 @@ int SDL_SemWait(SDL_sem* sem)
// warnings in VC2005, so we coerce values directly.
cassert(sizeof(pthread_t) == sizeof(SDL_Thread*));
SDL_Thread* SDL_CreateThread(int(*func)(void*), void* param)
SDL_Thread* SDL_CreateThread(int (*func)(void*), void* param)
{
pthread_t thread = 0;
if(pthread_create(&thread, 0, (void*(*)(void*))func, param) < 0)
if(pthread_create(&thread, 0, (void* (*)(void*))func, param) < 0)
return 0;
return *(SDL_Thread**)&thread;
}
@ -1154,7 +1154,7 @@ inline void* SDL_GL_GetProcAddress(const char* name)
//-----------------------------------------------------------------------------
// init/shutdown
static int wsdl_init()
static LibError wsdl_init()
{
hInst = GetModuleHandle(0);
@ -1170,8 +1170,8 @@ static int wsdl_init()
// to avoid the OS opening a console on startup (ugly). that means
// stdout isn't associated with a lowio handle; _close ends up
// getting called with fd = -1. oh well, nothing we can do.
FILE* ret = freopen(path, "wt", stdout);
if(!ret)
FILE* f = freopen(path, "wt", stdout);
if(!f)
debug_warn("stdout freopen failed");
#if CONFIG_PARANOIA
@ -1182,11 +1182,11 @@ static int wsdl_init()
enable_kbd_hook(true);
return 0;
return ERR_OK;
}
static int wsdl_shutdown()
static LibError wsdl_shutdown()
{
is_shutdown = true;
@ -1200,7 +1200,7 @@ static int wsdl_shutdown()
enable_kbd_hook(false);
return 0;
return ERR_OK;
}

View File

@ -97,7 +97,7 @@ extern void SDL_DestroySemaphore(SDL_sem*);
extern int SDL_SemPost(SDL_sem*);
extern int SDL_SemWait(SDL_sem* sem);
extern SDL_Thread* SDL_CreateThread(int(*)(void*), void*);
extern SDL_Thread* SDL_CreateThread(int (*)(void*), void*);
extern int SDL_KillThread(SDL_Thread*);

View File

@ -46,7 +46,7 @@ static int dll_refs;
// called from delay loader the first time a wsock function is called
// (shortly before the actual wsock function is called).
static int wsock_init()
static LibError wsock_init()
{
hWs2_32Dll = LoadLibrary("ws2_32.dll");
@ -58,14 +58,14 @@ static int wsock_init()
debug_warn("WSAStartup failed");
}
return 0;
return ERR_OK;
}
WDLL_LOAD_NOTIFY("ws2_32", wsock_init);
static int wsock_shutdown()
static LibError wsock_shutdown()
{
// call WSACleanup if DLL was used
// (this way is easier to understand than ONCE in loop below)
@ -77,7 +77,7 @@ static int wsock_shutdown()
while(dll_refs-- > 0)
FreeLibrary(hWs2_32Dll);
return 0;
return ERR_OK;
}

View File

@ -111,13 +111,13 @@ static HWND get_app_main_window()
static POINTS dlg_client_origin;
static POINTS dlg_prev_client_size;
const int ANCHOR_LEFT = 0x01;
const int ANCHOR_RIGHT = 0x02;
const int ANCHOR_TOP = 0x04;
const int ANCHOR_BOTTOM = 0x08;
const int ANCHOR_ALL = 0x0f;
static const uint ANCHOR_LEFT = 0x01;
static const uint ANCHOR_RIGHT = 0x02;
static const uint ANCHOR_TOP = 0x04;
static const uint ANCHOR_BOTTOM = 0x08;
static const uint ANCHOR_ALL = 0x0f;
static void dlg_resize_control(HWND hDlg, int dlg_item, int dx,int dy, int anchors)
static void dlg_resize_control(HWND hDlg, int dlg_item, int dx,int dy, uint anchors)
{
HWND hControl = GetDlgItem(hDlg, dlg_item);
RECT r;
@ -189,7 +189,7 @@ struct DialogParams
};
static int CALLBACK error_dialog_proc(HWND hDlg, unsigned int msg, WPARAM wParam, LPARAM lParam)
static INT_PTR CALLBACK error_dialog_proc(HWND hDlg, unsigned int msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
@ -345,24 +345,25 @@ ErrorReaction sys_display_error(const wchar_t* text, int flags)
//-----------------------------------------------------------------------------
// "copy" text into the clipboard. replaces previous contents.
int sys_clipboard_set(const wchar_t* text)
LibError sys_clipboard_set(const wchar_t* text)
{
int err = -1;
const HWND new_owner = 0;
// MSDN: passing 0 requests the current task be granted ownership;
// there's no need to pass our window handle.
if(!OpenClipboard(new_owner))
return err;
return ERR_FAIL;
EmptyClipboard();
err = 0;
LibError err = ERR_FAIL;
{
const size_t len = wcslen(text);
HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, (len+1) * sizeof(wchar_t));
if(!hMem)
{
err = ERR_NO_MEM;
goto fail;
}
wchar_t* copy = (wchar_t*)GlobalLock(hMem);
if(copy)
@ -372,7 +373,8 @@ int sys_clipboard_set(const wchar_t* text)
GlobalUnlock(hMem);
if(SetClipboardData(CF_UNICODETEXT, hMem) != 0)
err = 0; // success
err = ERR_OK;
}
}
fail:
@ -422,10 +424,10 @@ wchar_t* sys_clipboard_get()
// frees memory used by <copy>, which must have been returned by
// sys_clipboard_get. see note above.
int sys_clipboard_free(wchar_t* copy)
LibError sys_clipboard_free(wchar_t* copy)
{
free(copy);
return 0;
return ERR_OK;
}
@ -464,7 +466,7 @@ static HCURSOR HCURSOR_from_ptr(void* p)
// return: negative error code, or 0 on success. cursor is filled with
// a pointer and undefined on failure. it must be sys_cursor_free-ed
// when no longer needed.
int sys_cursor_create(uint w, uint h, void* bgra_img,
LibError sys_cursor_create(uint w, uint h, void* bgra_img,
uint hx, uint hy, void** cursor)
{
// MSDN says selecting this HBITMAP into a DC is slower since we use
@ -492,17 +494,17 @@ int sys_cursor_create(uint w, uint h, void* bgra_img,
DeleteObject(hbmColour);
if(!hIcon) // not INVALID_HANDLE_VALUE
return -1;
return ERR_FAIL;
*cursor = ptr_from_HICON(hIcon);
return 0;
return ERR_OK;
}
// replaces the current system cursor with the one indicated. need only be
// called once per cursor; pass 0 to restore the default.
int sys_cursor_set(void* cursor)
LibError sys_cursor_set(void* cursor)
{
// restore default cursor.
if(!cursor)
@ -511,17 +513,17 @@ int sys_cursor_set(void* cursor)
(void)SetCursor(HCURSOR_from_ptr(cursor));
// return value (previous cursor) is useless.
return 0;
return ERR_OK;
}
// destroys the indicated cursor and frees its resources. if it is
// currently the system cursor, the default cursor is restored first.
int sys_cursor_free(void* cursor)
LibError sys_cursor_free(void* cursor)
{
// bail now to prevent potential confusion below; there's nothing to do.
if(!cursor)
return 0;
return ERR_OK;
// if the cursor being freed is active, restore the default arrow
// (just for safety).
@ -529,7 +531,7 @@ int sys_cursor_free(void* cursor)
WARN_ERR(sys_cursor_set(0));
BOOL ok = DestroyIcon(HICON_from_ptr(cursor));
return ok? 0 : -1;
return LibError_from_win32(ok);
}
@ -540,21 +542,21 @@ int sys_cursor_free(void* cursor)
// OS-specific backend for error_description_r.
// NB: it is expected to be rare that OS return/error codes are actually
// seen by user code, but we still translate them for completeness.
int sys_error_description_r(int err, char* buf, size_t max_chars)
LibError sys_error_description_r(int err, char* buf, size_t max_chars)
{
// not in our range (Win32 error numbers are positive)
if(err < 0)
return -1;
return ERR_FAIL;
const LPCVOID source = 0; // ignored (we're not using FROM_HMODULE etc.)
const DWORD lang_id = 0; // look for neutral, then current locale
va_list* args = 0; // we don't care about "inserts"
DWORD ret = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, source, (DWORD)err,
DWORD chars_output = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, source, (DWORD)err,
lang_id, buf, (DWORD)max_chars, args);
if(!ret)
return -1;
debug_assert(ret < max_chars); // ret = #chars output
return 0;
if(!chars_output)
return ERR_FAIL;
debug_assert(chars_output < max_chars);
return ERR_OK;
}
@ -584,10 +586,10 @@ wchar_t* sys_get_module_filename(void* addr, wchar_t* path)
// store full path to the current executable.
// returns 0 or a negative error code.
// useful for determining installation directory, e.g. for VFS.
inline int sys_get_executable_name(char* n_path, size_t buf_size)
inline LibError sys_get_executable_name(char* n_path, size_t buf_size)
{
DWORD nbytes = GetModuleFileName(0, n_path, (DWORD)buf_size);
return nbytes? 0 : -1;
return nbytes? ERR_OK : ERR_FAIL;
}
@ -609,7 +611,7 @@ static int CALLBACK browse_cb(HWND hWnd, unsigned int msg, LPARAM UNUSED(lParam)
// stores its full path in the given buffer, which must hold at least
// PATH_MAX chars.
// returns 0 on success or a negative error code.
int sys_pick_directory(char* path, size_t buf_size)
LibError sys_pick_directory(char* path, size_t buf_size)
{
// bring up dialog; set starting directory to current working dir.
WARN_IF_FALSE(GetCurrentDirectory((DWORD)buf_size, path));
@ -631,7 +633,7 @@ int sys_pick_directory(char* path, size_t buf_size)
p_malloc->Free(pidl);
p_malloc->Release();
return ok? 0 : -1;
return LibError_from_win32(ok);
}
@ -643,16 +645,16 @@ int sys_pick_directory(char* path, size_t buf_size)
// return 0 on success or a negative error code on failure
// (e.g. if OS is preventing us from running on some CPUs).
// called from ia32.cpp get_cpu_count
int sys_on_each_cpu(void(*cb)())
LibError sys_on_each_cpu(void (*cb)())
{
const HANDLE hProcess = GetCurrentProcess();
DWORD process_affinity, system_affinity;
if(!GetProcessAffinityMask(hProcess, &process_affinity, &system_affinity))
return -1;
return ERR_FAIL;
// our affinity != system affinity: OS is limiting the CPUs that
// this process can run on. fail (cannot call back for each CPU).
if(process_affinity != system_affinity)
return -1;
return ERR_FAIL;
for(DWORD cpu_bit = 1; cpu_bit != 0 && cpu_bit <= process_affinity; cpu_bit *= 2)
{
@ -675,5 +677,5 @@ int sys_on_each_cpu(void(*cb)())
// restore to original value
SetProcessAffinityMask(hProcess, process_affinity);
return 0;
return ERR_OK;
}

View File

@ -156,7 +156,7 @@ static inline void unlock(void)
// in case there are unforeseen problems with one of them.
// order of preference (due to resolution and speed): TSC, QPC, GTC.
// split out of reset_impl so we can just return when impl is chosen.
static int choose_impl()
static LibError choose_impl()
{
bool safe;
#define SAFETY_OVERRIDE(impl)\
@ -195,7 +195,7 @@ static int choose_impl()
hrt_impl = HRT_TSC;
hrt_nominal_freq = cpu_freq;
hrt_res = (1.0 / hrt_nominal_freq);
return 0;
return ERR_OK;
}
}
#endif // TSC
@ -254,7 +254,7 @@ static int choose_impl()
hrt_impl = HRT_QPC;
hrt_nominal_freq = (double)qpc_freq;
hrt_res = (1.0 / hrt_nominal_freq);
return 0;
return ERR_OK;
}
}
#endif // QPC
@ -275,13 +275,13 @@ static int choose_impl()
DWORD timer_period; // [hectonanoseconds]
if(GetSystemTimeAdjustment(&adj, &timer_period, &adj_disabled))
hrt_res = (timer_period / 1e7);
return 0;
return ERR_OK;
}
debug_warn("no safe timer found!");
hrt_impl = HRT_NONE;
hrt_nominal_freq = -1.0;
return -1;
return ERR_FAIL;
}
@ -364,7 +364,7 @@ static double time_lk()
//
// don't want to saddle timer module with the problem of initializing
// us on first call - it wouldn't otherwise need to be thread-safe.
static int reset_impl_lk()
static LibError reset_impl_lk()
{
HRTImpl old_impl = hrt_impl;
@ -390,7 +390,7 @@ static int reset_impl_lk()
hrt_cal_ticks = ticks_lk();
}
return 0;
return ERR_OK;
}
@ -455,23 +455,20 @@ unlock();
// the timer may jump after doing so.
// call with HRT_DEFAULT, HRT_NONE to re-evaluate implementation choice
// after system info becomes available.
static int hrt_override_impl(HRTOverride ovr, HRTImpl impl)
static LibError hrt_override_impl(HRTOverride ovr, HRTImpl impl)
{
if((ovr != HRT_DISABLE && ovr != HRT_FORCE && ovr != HRT_DEFAULT) ||
(impl != HRT_TSC && impl != HRT_QPC && impl != HRT_GTC && impl != HRT_NONE))
{
debug_warn("invalid ovr or impl param");
return -1;
}
CHECK_ERR(ERR_INVALID_PARAM);
lock();
overrides[impl] = ovr;
reset_impl_lk();
LibError ret = reset_impl_lk();
unlock();
return 0;
return ret;
}
@ -594,34 +591,34 @@ static void* calibration_thread(void* UNUSED(data))
}
static inline int init_calibration_thread()
static inline LibError init_calibration_thread()
{
sem_init(&exit_flag, 0, 0);
pthread_create(&thread, 0, calibration_thread, 0);
return 0;
return ERR_OK;
}
static inline int shutdown_calibration_thread()
static inline LibError shutdown_calibration_thread()
{
sem_post(&exit_flag);
pthread_join(thread, 0);
sem_destroy(&exit_flag);
return 0;
return ERR_OK;
}
static int hrt_init()
static LibError hrt_init()
{
// no lock needed - calibration thread hasn't yet been created
reset_impl_lk();
RETURN_ERR(reset_impl_lk());
return init_calibration_thread();
}
static int hrt_shutdown()
static LibError hrt_shutdown()
{
// don't take a lock here! race condition:
// 1) calibration_thread is about to call clock_gettime
@ -735,18 +732,18 @@ static i64 time_ns()
}
static int wtime_init()
static LibError wtime_init()
{
hrt_init();
// first call latches start times
time_ns();
return 0;
return ERR_OK;
}
static int wtime_shutdown()
static LibError wtime_shutdown()
{
return hrt_shutdown();
}

View File

@ -31,4 +31,6 @@ typedef unsigned int PS_uint;
# error "check size_t and SIZE_MAX - too small?"
#endif
enum LibError;
#endif // #ifndef __TYPES_H__