# SwEng (reduce full recompiles by splitting up master error header)

- error codes now accessed as ERR::NO_MEM, INFO::OK etc.
- no more X-macros => the above are now recognized by visual assist
- error codes are defined by the module originating them (lib_errors has
some generic ones)
  => no full rebuild when adding some
- error descriptions are now in C++ files => can be changed without full
rebuild

added AT_STARTUP in lib.h.

This was SVN commit r4374.
This commit is contained in:
janwas 2006-09-22 13:19:40 +00:00
parent 05aadf1f12
commit 871cdb6ef9
123 changed files with 1784 additions and 1486 deletions

View File

@ -25,6 +25,7 @@
#include "lib/posix.h" // PROT_* constants for da_set_prot
#include "lib/sysdep/cpu.h" // CAS
#include "byte_order.h"
#include "lib/res/file/file_io.h" // IO_EOF
#include "allocators.h"
@ -58,7 +59,7 @@ static inline size_t round_up_to_page(size_t size)
static inline LibError LibError_from_mmap(void* ret, bool warn_if_failed = true)
{
if(ret != MAP_FAILED)
return INFO_OK;
return INFO::OK;
return LibError_from_errno(warn_if_failed);
}
@ -91,7 +92,7 @@ static LibError mem_commit(u8* p, size_t size, int prot)
{
if(prot == PROT_NONE)
// not allowed - it would be misinterpreted by mmap.
WARN_RETURN(ERR_INVALID_PARAM);
WARN_RETURN(ERR::INVALID_PARAM);
errno = 0;
void* ret = mmap(p, size, prot, mmap_flags|MAP_FIXED, -1, 0);
@ -162,7 +163,7 @@ const int DA_NOT_OUR_MEM = 0x40000000;
static LibError validate_da(DynArray* da)
{
if(!da)
WARN_RETURN(ERR_INVALID_PARAM);
WARN_RETURN(ERR::INVALID_PARAM);
u8* const base = da->base;
const size_t max_size_pa = da->max_size_pa;
const size_t cur_size = da->cur_size;
@ -170,21 +171,21 @@ static LibError validate_da(DynArray* da)
const int prot = da->prot;
if(debug_is_pointer_bogus(base))
WARN_RETURN(ERR_1);
WARN_RETURN(ERR::_1);
// note: don't check if base is page-aligned -
// might not be true for 'wrapped' mem regions.
// if(!is_page_multiple((uintptr_t)base))
// WARN_RETURN(ERR_2);
// WARN_RETURN(ERR::_2);
if(!is_page_multiple(max_size_pa))
WARN_RETURN(ERR_3);
WARN_RETURN(ERR::_3);
if(cur_size > max_size_pa)
WARN_RETURN(ERR_4);
WARN_RETURN(ERR::_4);
if(pos > cur_size || pos > max_size_pa)
WARN_RETURN(ERR_5);
WARN_RETURN(ERR::_5);
if(prot & ~(PROT_READ|PROT_WRITE|PROT_EXEC|DA_NOT_OUR_MEM))
WARN_RETURN(ERR_6);
WARN_RETURN(ERR::_6);
return INFO_OK;
return INFO::OK;
}
#define CHECK_DA(da) RETURN_ERR(validate_da(da))
@ -213,7 +214,7 @@ LibError da_alloc(DynArray* da, size_t max_size)
da->prot = PROT_READ|PROT_WRITE;
da->pos = 0;
CHECK_DA(da);
return INFO_OK;
return INFO::OK;
}
@ -238,7 +239,7 @@ LibError 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 INFO_OK;
return INFO::OK;
}
@ -267,7 +268,7 @@ LibError da_free(DynArray* da)
// da_free is supposed to be called even in the above case.
if(!was_wrapped)
RETURN_ERR(mem_release(p, size));
return INFO_OK;
return INFO::OK;
}
@ -285,7 +286,7 @@ LibError da_set_size(DynArray* da, size_t new_size)
CHECK_DA(da);
if(da->prot & DA_NOT_OUR_MEM)
WARN_RETURN(ERR_LOGIC);
WARN_RETURN(ERR::LOGIC);
// determine how much to add/remove
const size_t cur_size_pa = round_up_to_page(da->cur_size);
@ -296,7 +297,7 @@ LibError da_set_size(DynArray* da, size_t new_size)
// note: do not complain - some allocators (e.g. file_cache)
// egitimately use up all available space.
if(new_size_pa > da->max_size_pa)
return ERR_LIMIT; // NOWARN
return ERR::LIMIT; // NOWARN
u8* end = da->base + cur_size_pa;
// expanding
@ -310,7 +311,7 @@ LibError da_set_size(DynArray* da, size_t new_size)
da->cur_size = new_size;
CHECK_DA(da);
return INFO_OK;
return INFO::OK;
}
@ -330,7 +331,7 @@ LibError da_reserve(DynArray* da, size_t size)
if(da->pos + size > da->cur_size)
return da_set_size(da, da->cur_size + expand_amount);
return INFO_OK;
return INFO::OK;
}
@ -350,13 +351,13 @@ LibError da_set_prot(DynArray* da, int prot)
// somewhat more subtle: POSIX mprotect requires the memory have been
// mmap-ed, which it probably wasn't here.
if(da->prot & DA_NOT_OUR_MEM)
WARN_RETURN(ERR_LOGIC);
WARN_RETURN(ERR::LOGIC);
da->prot = prot;
RETURN_ERR(mem_protect(da->base, da->cur_size, prot));
CHECK_DA(da);
return INFO_OK;
return INFO::OK;
}
@ -373,11 +374,11 @@ 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)
WARN_RETURN(ERR_EOF);
WARN_RETURN(ERR::IO_EOF);
memcpy2(data, da->base+da->pos, size);
da->pos += size;
return INFO_OK;
return INFO::OK;
}
@ -395,7 +396,7 @@ LibError da_append(DynArray* da, const void* data, size_t size)
RETURN_ERR(da_reserve(da, size));
memcpy2(da->base+da->pos, data, size);
da->pos += size;
return INFO_OK;
return INFO::OK;
}
@ -456,7 +457,7 @@ LibError pool_create(Pool* p, size_t max_size, size_t el_size)
p->el_size = round_up(el_size, ALIGN);
p->freelist = 0;
RETURN_ERR(da_alloc(&p->da, max_size));
return INFO_OK;
return INFO::OK;
}
@ -623,13 +624,13 @@ LibError bucket_create(Bucket* b, size_t el_size)
// cause next bucket_alloc to retry the allocation
b->pos = BUCKET_SIZE;
b->num_buckets = 0;
WARN_RETURN(ERR_NO_MEM);
WARN_RETURN(ERR::NO_MEM);
}
*(u8**)b->bucket = 0; // terminate list
b->pos = round_up(sizeof(u8*), ALIGN);
b->num_buckets = 1;
return INFO_OK;
return INFO::OK;
}
@ -829,7 +830,7 @@ void* single_calloc(void* storage, volatile uintptr_t* in_use_flag, size_t size)
p = malloc(size);
if(!p)
{
WARN_ERR(ERR_NO_MEM);
WARN_ERR(ERR::NO_MEM);
return 0;
}
}

View File

@ -526,7 +526,7 @@ private:
if(da_alloc(&da, sizeof(T)) < 0)
{
fail:
WARN_ERR(ERR_NO_MEM);
WARN_ERR(ERR::NO_MEM);
return;
}
if(da_set_size(&da, sizeof(T)) < 0)

View File

@ -27,6 +27,7 @@
#include "lib.h"
#include "posix.h"
#include "lib/res/file/file.h" // FILE_ACCESS
#include "lib/sysdep/cpu.h" // CAS
// some functions here are called from within mmgr; disable its hooks
// so that our allocations don't cause infinite recursion.
@ -37,6 +38,20 @@
#include "debug.h"
AT_STARTUP(\
error_setDescription(ERR::SYM_NO_STACK_FRAMES_FOUND, "No stack frames found");\
error_setDescription(ERR::SYM_UNRETRIEVABLE_STATIC, "Value unretrievable (stored in external module)");\
error_setDescription(ERR::SYM_UNRETRIEVABLE_REG, "Value unretrievable (stored in register)");\
error_setDescription(ERR::SYM_TYPE_INFO_UNAVAILABLE, "Error getting type_info");\
error_setDescription(ERR::SYM_INTERNAL_ERROR, "Exception raised while processing a symbol");\
error_setDescription(ERR::SYM_UNSUPPORTED, "Symbol type not (fully) supported");\
error_setDescription(ERR::SYM_CHILD_NOT_FOUND, "Symbol does not have the given child");\
error_setDescription(ERR::SYM_NESTING_LIMIT, "Symbol nesting too deep or infinite recursion");\
error_setDescription(ERR::SYM_SINGLE_SYMBOL_LIMIT, "Symbol has produced too much output");\
error_setDescription(INFO::SYM_SUPPRESS_OUTPUT, "Symbol was suppressed");\
)
// needed when writing crashlog
static const size_t LOG_CHARS = 16384;
wchar_t debug_log[LOG_CHARS];
@ -219,7 +234,7 @@ LibError debug_write_crashlog(const wchar_t* text)
// avoid potential infinite loop if an error occurs here.
static uintptr_t in_progress;
if(!CAS(&in_progress, 0, 1))
return ERR_REENTERED; // NOWARN
return ERR::REENTERED; // NOWARN
// note: we go through some gyrations here (strcpy+strcat) to avoid
// dependency on file code (path_append).
@ -230,7 +245,7 @@ LibError debug_write_crashlog(const wchar_t* text)
if(!f)
{
in_progress = 0;
WARN_RETURN(ERR_FILE_ACCESS);
WARN_RETURN(ERR::FILE_ACCESS);
}
fputwc(0xfeff, f); // BOM
@ -244,7 +259,7 @@ LibError debug_write_crashlog(const wchar_t* text)
fclose(f);
in_progress = 0;
return INFO_OK;
return INFO::OK;
}
@ -272,7 +287,7 @@ static const char* symbol_string_build(void* symbol, const char* name, const cha
string_buf = (char*)malloc(STRING_BUF_SIZE);
if(!string_buf)
{
WARN_ERR(ERR_NO_MEM);
WARN_ERR(ERR::NO_MEM);
return 0;
}
string_buf_pos = string_buf;
@ -282,7 +297,7 @@ static const char* symbol_string_build(void* symbol, const char* name, const cha
char* string = string_buf_pos;
if(string + STRING_MAX >= string_buf + STRING_BUF_SIZE)
{
WARN_ERR(ERR_LIMIT);
WARN_ERR(ERR::LIMIT);
return 0;
}
@ -402,7 +417,7 @@ static void symbol_string_add_to_cache(const char* string, void* symbol)
// hash table is completely full (guard against infinite loop below).
// if this happens, the string won't be cached - nothing serious.
if(total_symbols >= MAX_SYMBOLS)
WARN_ERR_RETURN(ERR_LIMIT);
WARN_ERR_RETURN(ERR::LIMIT);
total_symbols++;
// find Symbol slot in hash table
@ -539,11 +554,11 @@ const wchar_t* debug_error_message_build(
char description_buf[100] = {'?'};
LibError errno_equiv = LibError_from_errno(false);
if(errno_equiv != ERR_FAIL) // meaningful translation
if(errno_equiv != ERR::FAIL) // meaningful translation
error_description_r(errno_equiv, description_buf, ARRAY_SIZE(description_buf));
char os_error[100];
if(sys_error_description_r(0, os_error, ARRAY_SIZE(os_error)) != INFO_OK)
if(sys_error_description_r(0, os_error, ARRAY_SIZE(os_error)) != INFO::OK)
strcpy_s(os_error, ARRAY_SIZE(os_error), "?");
static const wchar_t fmt[] =
@ -568,14 +583,14 @@ const wchar_t* debug_error_message_build(
if(!context)
skip += 2; // skip debug_error_message_build and debug_display_error
LibError ret = debug_dump_stack(pos, chars_left, skip, context);
if(ret == ERR_REENTERED)
if(ret == ERR::REENTERED)
{
wcscpy_s(pos, chars_left,
L"(cannot start a nested stack trace; what probably happened is that "
L"an debug_assert/debug_warn/CHECK_ERR fired during the current trace.)"
);
}
else if(ret != INFO_OK)
else if(ret != INFO::OK)
{
swprintf(pos, chars_left,
L"(error while dumping stack: %hs)",
@ -719,16 +734,16 @@ static bool should_skip_this_error(LibError err)
// to share code between assert and error skip mechanism, we treat the former as
// an error. choose the code such that no one would want to warn of it.
static const LibError assert_err = INFO_OK;
static const LibError assert_err = INFO::OK;
void debug_skip_next_assert()
{
debug_skip_next_err(INFO_OK);
debug_skip_next_err(INFO::OK);
}
static bool should_skip_this_assert()
{
return should_skip_this_error(INFO_OK);
return should_skip_this_error(INFO::OK);
}

View File

@ -290,7 +290,7 @@ extern void debug_wprintf_mem(const wchar_t* fmt, ...);
* @param text description of the error (including stack trace);
* typically generated by debug_error_message_build.
*
* @return LibError; ERR_REENTERED if reentered via recursion or
* @return LibError; ERR::REENTERED if reentered via recursion or
* multithreading (not allowed since an infinite loop may result).
**/
extern LibError debug_write_crashlog(const wchar_t* text);
@ -461,7 +461,7 @@ enum DbgBreakType
* for simplicity, the length (range of bytes to be checked) is derived
* from addr's alignment, and is typically 1 machine word.
* @param type the type of access to watch for (see DbgBreakType)
* @return LibError; ERR_LIMIT if no more breakpoints are available
* @return LibError; ERR::LIMIT if no more breakpoints are available
* (they are a limited resource - only 4 on IA-32).
**/
extern LibError debug_set_break(void* addr, DbgBreakType type);
@ -477,6 +477,31 @@ extern LibError debug_remove_all_breaks();
// symbol access
//-----------------------------------------------------------------------------
namespace ERR
{
const LibError SYM_NO_STACK_FRAMES_FOUND = -100400;
const LibError SYM_UNRETRIEVABLE_STATIC = -100401;
const LibError SYM_UNRETRIEVABLE_REG = -100402;
const LibError SYM_TYPE_INFO_UNAVAILABLE = -100403;
const LibError SYM_INTERNAL_ERROR = -100404;
const LibError SYM_UNSUPPORTED = -100405;
const LibError SYM_CHILD_NOT_FOUND = -100406;
// this limit is to prevent infinite recursion.
const LibError SYM_NESTING_LIMIT = -100407;
// this limit is to prevent large symbols (e.g. arrays or linked lists)
// from taking up all available output space.
const LibError SYM_SINGLE_SYMBOL_LIMIT = -100408;
}
namespace INFO
{
// 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.
const LibError SYM_SUPPRESS_OUTPUT = +100809;
}
/**
* maximum number of characters (including trailing \0) written to
* user's buffers by debug_resolve_symbol.
@ -499,7 +524,7 @@ const size_t DBG_FILE_LEN = 100;
*
* note: all of the output parameters are optional; we pass back as much
* information as is available and desired.
* @return LibError; INFO_OK iff any information was successfully
* @return LibError; INFO::OK iff any information was successfully
* retrieved and stored.
**/
extern LibError debug_resolve_symbol(void* ptr_of_interest, char* sym_name, char* file, int* line);
@ -516,7 +541,7 @@ extern LibError debug_resolve_symbol(void* ptr_of_interest, char* sym_name, char
* @param context platform-specific representation of execution state
* (e.g. Win32 CONTEXT). if not NULL, tracing starts there; this is useful
* for exceptions. otherwise, tracing starts from the current call stack.
* @return LibError; ERR_REENTERED if reentered via recursion or
* @return LibError; ERR::REENTERED if reentered via recursion or
* multithreading (not allowed since static data is used).
**/
extern LibError debug_dump_stack(wchar_t* buf, size_t max_chars, uint skip, void* context);

View File

@ -29,6 +29,13 @@
#include "debug_stl.h"
#include "lib.h" // match_wildcard
AT_STARTUP(\
error_setDescription(ERR::STL_CNT_UNKNOWN, "Unknown STL container type_name");\
error_setDescription(ERR::STL_CNT_INVALID, "Container type is known but contents are invalid");\
)
// used in debug_stl_simplify_name.
// note: strcpy is safe because replacement happens in-place and
// src is longer than dst (otherwise, we wouldn't be replacing).
@ -650,7 +657,7 @@ LibError debug_stl_get_container_info(const char* type_name, const u8* p, size_t
// 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 ERR_FAIL;
return ERR::FAIL;
#endif
bool handled = false, valid = false;
@ -699,10 +706,10 @@ LibError debug_stl_get_container_info(const char* type_name, const u8* p, size_t
// note: do not raise warnings - these can happen for new
// STL classes or if the debuggee's memory is corrupted.
if(!handled)
return ERR_STL_CNT_UNKNOWN; // NOWARN
return ERR::STL_CNT_UNKNOWN; // NOWARN
if(!valid)
return ERR_STL_CNT_INVALID; // NOWARN
return INFO_OK;
return ERR::STL_CNT_INVALID; // NOWARN
return INFO::OK;
}
#endif

View File

@ -23,6 +23,15 @@
#ifndef DEBUG_STL_H_INCLUDED
#define DEBUG_STL_H_INCLUDED
namespace ERR
{
const LibError STL_CNT_UNKNOWN = -100500;
// likely causes: not yet initialized or memory corruption.
const LibError STL_CNT_INVALID = -100501;
}
/**
* reduce complicated STL symbol names to human-readable form.
*
@ -64,7 +73,7 @@ const size_t DEBUG_STL_MAX_ITERATOR_SIZE = 64;
* @param el_iterator out; callback function that acts as an iterator
* @param it_mem out; buffer holding the iterator state. must be
* at least DEBUG_STL_MAX_ITERATOR_SIZE bytes.
* @return LibError (ERR_STL_*)
* @return LibError (ERR::STL_*)
**/
extern LibError debug_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);

View File

@ -29,6 +29,7 @@
#include "lib.h"
#include "input.h"
#include "sdl.h"
#include "lib/res/file/file.h"
const uint MAX_HANDLERS = 8;
static InHandler handler_stack[MAX_HANDLERS];
@ -39,7 +40,7 @@ void in_add_handler(InHandler handler)
debug_assert(handler);
if(handler_stack_top >= MAX_HANDLERS)
WARN_ERR_RETURN(ERR_LIMIT);
WARN_ERR_RETURN(ERR::LIMIT);
handler_stack[handler_stack_top++] = handler;
}
@ -105,13 +106,13 @@ LibError in_record(const char* fn)
f = fopen(fn, "wb");
if(!f)
WARN_RETURN(ERR_FILE_ACCESS);
WARN_RETURN(ERR::FILE_ACCESS);
fwrite(&game_ticks, sizeof(u32), 1, f);
state = RECORD;
return INFO_OK;
return INFO::OK;
}
@ -124,7 +125,7 @@ LibError in_playback(const char* fn)
f = fopen(fn, "rb");
if(!f)
WARN_RETURN(ERR_TNODE_NOT_FOUND);
WARN_RETURN(ERR::FILE_ACCESS);
u32 rec_start_time;
fread(&rec_start_time, sizeof(u32), 1, f);
@ -135,7 +136,7 @@ LibError in_playback(const char* fn)
state = PLAYBACK;
return INFO_OK;
return INFO::OK;
}

View File

@ -27,11 +27,6 @@
#include "lib/sdl_fwd.h"
#ifdef __cplusplus
extern "C" {
#endif
// input handler return values.
enum InReaction
{
@ -60,9 +55,4 @@ extern LibError in_record(const char* fn);
extern LibError in_playback(const char* fn);
extern void in_stop(void);
#ifdef __cplusplus
}
#endif
#endif // #ifndef INPUT_H__

View File

@ -194,7 +194,7 @@ uint rand(uint min_inclusive, uint max_exclusive)
// huge interval or min >= max
if(range == 0 || range > XRAND_MAX)
{
WARN_ERR(ERR_INVALID_PARAM);
WARN_ERR(ERR::INVALID_PARAM);
return 0;
}

View File

@ -74,6 +74,16 @@ const size_t KiB = 1ul << 10;
const size_t MiB = 1ul << 20;
const size_t GiB = 1ul << 30;
// generate a symbol containing the line number of the macro invocation.
// used to give a unique name (per file) to types made by cassert.
// we can't prepend __FILE__ to make it globally unique - the filename
// may be enclosed in quotes. PASTE3_HIDDEN__ is needed to make sure
// __LINE__ is expanded correctly.
#define PASTE3_HIDDEN__(a, b, c) a ## b ## c
#define PASTE3__(a, b, c) PASTE3_HIDDEN__(a, b, c)
#define UID__ PASTE3__(LINE_, __LINE__, _)
#define UID2__ PASTE3__(LINE_, __LINE__, _2)
//-----------------------------------------------------------------------------
// code-generating macros
@ -131,6 +141,20 @@ STMT(\
)
/**
* execute the code passed as a parameter before main is entered.
*
* WARNING: if the source file containing this is not directly referenced
* from anywhere, linkers may discard that object file (unless linking
* statically). see http://www.cbloom.com/3d/techdocs/more_coding.txt
**/
#define AT_STARTUP(code__)\
static struct UID__\
{\
UID__() { code__; }\
} UID2__;\
/**
* C++ new wrapper: allocates an instance of the given type and stores a
* pointer to it. sets pointer to 0 on allocation failure.
@ -284,15 +308,6 @@ switch(x % 2)
//-----------------------------------------------------------------------------
// cassert
// generate a symbol containing the line number of the macro invocation.
// used to give a unique name (per file) to types made by cassert.
// we can't prepend __FILE__ to make it globally unique - the filename
// may be enclosed in quotes. need the 2 macro expansions to make sure
// __LINE__ is expanded correctly.
#define MAKE_UID2__(l) LINE_ ## l
#define MAKE_UID1__(l) MAKE_UID2__(l)
#define UID__ MAKE_UID1__(__LINE__)
/**
* compile-time debug_assert. causes a compile error if the expression
* evaluates to zero/false.

View File

@ -34,20 +34,44 @@
#include <stdlib.h> // abs
#include <errno.h>
static const char* LibError_description(LibError err)
{
// not in our range
const int ierr = abs((int)err);
if(!(ERR_MIN <= ierr && ierr < ERR_MAX))
return 0;
switch(err)
struct LibErrorAssociation
{
const char* description_;
int errno_equivalent_;
LibErrorAssociation()
: description_(0), errno_equivalent_(-1) {}
void setDescription(const char* description)
{
#define ERR(err, id, str) case id: return str;
#include "lib_errors.h"
default: return "Unknown error";
debug_assert(description_ == 0); // not already set
description_ = description;
}
UNREACHABLE;
void setEquivalent(int errno_equivalent)
{
debug_assert(errno_equivalent_ == -1); // not already set
errno_equivalent_ = errno_equivalent;
}
};
typedef std::map<LibError, LibErrorAssociation> LibErrorAssociations;
// wrapper required because error_set* is called from AT_STARTUP
// (potentially before our static map is constructed)
static LibErrorAssociations& associations()
{
static LibErrorAssociations associations_;
return associations_;
};
void error_setDescription(LibError err, const char* description)
{
associations()[err].setDescription(description);
}
void error_setEquivalent(LibError err, int errno_equivalent)
{
associations()[err].setEquivalent(errno_equivalent);
}
@ -58,47 +82,44 @@ static const char* LibError_description(LibError err)
char* error_description_r(LibError err, char* buf, size_t max_chars)
{
// lib error
const char* str = LibError_description(err);
if(str)
LibErrorAssociations::iterator it = associations().find(err);
if(it != associations().end())
{
// <err> was one of our error codes (chosen so as not to conflict
// with any others), so we're done.
strcpy_s(buf, max_chars, str);
}
// unknown
else
{
snprintf(buf, max_chars, "Unknown error (%d, 0x%X)", err, err);
const LibErrorAssociation& a = it->second;
if(a.description_)
{
strcpy_s(buf, max_chars, a.description_);
return buf;
}
}
// unknown
snprintf(buf, max_chars, "Unknown error (%d, 0x%X)", err, err);
return buf;
}
// return the LibError equivalent of errno, or ERR_FAIL if there's no equal.
// return the LibError equivalent of errno, or ERR::FAIL if there's no equal.
// only call after a POSIX function indicates failure.
// raises a warning (avoids having to on each call site).
LibError LibError_from_errno(bool warn_if_failed)
{
LibError err;
switch(errno)
LibError ret = ERR::FAIL;
LibErrorAssociations::iterator it;
for(it = associations().begin(); it != associations().end(); ++it)
{
case ENOMEM: err = ERR_NO_MEM; break;
case EINVAL: err = ERR_INVALID_PARAM; break;
case ENOSYS: err = ERR_NOT_IMPLEMENTED; break;
case ENOENT: err = ERR_TNODE_NOT_FOUND; break;
case EACCES: err = ERR_FILE_ACCESS; break;
case EIO: err = ERR_IO; break;
case ENAMETOOLONG: err = ERR_PATH_LENGTH; break;
default: err = ERR_FAIL; break;
const LibErrorAssociation& a = it->second;
if(a.errno_equivalent_ == errno)
{
ret = it->first;
break;
}
}
if(warn_if_failed)
DEBUG_WARN_ERR(err);
return err;
DEBUG_WARN_ERR(ret);
return ret;
}
// translate the return value of any POSIX function into LibError.
@ -109,7 +130,7 @@ LibError LibError_from_posix(int ret, bool warn_if_failed)
{
debug_assert(ret == 0 || ret == -1);
if(ret == 0)
return INFO_OK;
return INFO::OK;
return LibError_from_errno(warn_if_failed);
}
@ -118,25 +139,21 @@ LibError LibError_from_posix(int ret, bool warn_if_failed)
// does not assign to errno (this simplifies code by allowing direct return)
static int return_errno_from_LibError(LibError err)
{
switch(err)
LibErrorAssociations::iterator it = associations().find(err);
if(it != associations().end())
{
case ERR_NO_MEM: return ENOMEM;
case ERR_INVALID_PARAM: return EINVAL;
case ERR_NOT_IMPLEMENTED: return ENOSYS;
case ERR_TNODE_NOT_FOUND: return ENOENT;
case ERR_FILE_ACCESS: return EACCES;
case ERR_IO: return EIO;
case ERR_PATH_LENGTH: return ENAMETOOLONG;
const LibErrorAssociation& a = it->second;
if(a.errno_equivalent_ != -1)
return a.errno_equivalent_;
}
// somewhat of a quandary: the set of errnos in wposix.h doesn't
// have an "unknown error". we pick EPERM because we don't expect
// that to come up often otherwise.
default: return EPERM;
}
return EPERM;
}
// set errno to the equivalent of <err>. used in wposix - underlying
// functions return LibError but must be translated to errno at
// e.g. the mmap interface level. higher-level code that calls mmap will
@ -145,3 +162,68 @@ void LibError_set_errno(LibError err)
{
errno = return_errno_from_LibError(err);
}
//-----------------------------------------------------------------------------
AT_STARTUP(\
/* INFO::OK doesn't really need a string because calling error_description_r(0) should never happen, but go the safe route. */\
error_setDescription(INFO::OK, "(but return value was 0 which indicates success)");\
error_setDescription(ERR::FAIL, "Function failed (no details available)");\
\
error_setDescription(INFO::CB_CONTINUE, "Continue (not an error)");\
error_setDescription(INFO::SKIPPED, "Skipped (not an error)");\
error_setDescription(INFO::CANNOT_HANDLE, "Cannot handle (not an error)");\
error_setDescription(INFO::ALL_COMPLETE, "All complete (not an error)");\
error_setDescription(INFO::ALREADY_EXISTS, "Already exists (not an error)");\
\
error_setDescription(ERR::LOGIC, "Logic error in code");\
error_setDescription(ERR::TIMED_OUT, "Timed out");\
error_setDescription(ERR::REENTERED, "Single-call function was reentered");\
error_setDescription(ERR::CORRUPTED, "File/memory data is corrupted");\
\
error_setDescription(ERR::INVALID_PARAM, "Invalid function argument");\
error_setDescription(ERR::INVALID_HANDLE, "Invalid Handle (argument)");\
error_setDescription(ERR::BUF_SIZE, "Buffer argument too small");\
error_setDescription(ERR::AGAIN, "Try again later");\
error_setDescription(ERR::LIMIT, "Fixed limit exceeded");\
error_setDescription(ERR::NO_SYS, "OS doesn't provide a required API");\
error_setDescription(ERR::NOT_IMPLEMENTED, "Feature currently not implemented");\
error_setDescription(ERR::NOT_SUPPORTED, "Feature isn't and won't be supported");\
error_setDescription(ERR::NO_MEM, "Not enough memory");\
\
error_setDescription(ERR::_1, "Case 1");\
error_setDescription(ERR::_2, "Case 2");\
error_setDescription(ERR::_3, "Case 3");\
error_setDescription(ERR::_4, "Case 4");\
error_setDescription(ERR::_5, "Case 5");\
error_setDescription(ERR::_6, "Case 6");\
error_setDescription(ERR::_7, "Case 7");\
error_setDescription(ERR::_8, "Case 8");\
error_setDescription(ERR::_9, "Case 9");\
error_setDescription(ERR::_11, "Case 11");\
error_setDescription(ERR::_12, "Case 12");\
error_setDescription(ERR::_13, "Case 13");\
error_setDescription(ERR::_14, "Case 14");\
error_setDescription(ERR::_15, "Case 15");\
error_setDescription(ERR::_16, "Case 16");\
error_setDescription(ERR::_17, "Case 17");\
error_setDescription(ERR::_18, "Case 18");\
error_setDescription(ERR::_19, "Case 19");\
error_setDescription(ERR::_21, "Case 21");\
error_setDescription(ERR::_22, "Case 22");\
error_setDescription(ERR::_23, "Case 23");\
error_setDescription(ERR::_24, "Case 24");\
error_setDescription(ERR::_25, "Case 25");\
error_setDescription(ERR::_26, "Case 26");\
error_setDescription(ERR::_27, "Case 27");\
error_setDescription(ERR::_28, "Case 28");\
error_setDescription(ERR::_29, "Case 29");\
)
AT_STARTUP(\
error_setEquivalent(ERR::NO_MEM, ENOMEM);\
error_setEquivalent(ERR::INVALID_PARAM, EINVAL);\
error_setEquivalent(ERR::NOT_IMPLEMENTED, ENOSYS);\
)

View File

@ -25,6 +25,7 @@
Error handling system
Introduction
------------
@ -32,6 +33,7 @@ This module defines error codes, translates them to/from other systems
(e.g. errno), provides several macros that simplify returning errors /
checking if a function failed, and associates codes with descriptive text.
Why Error Codes?
----------------
@ -39,6 +41,7 @@ To convey information about what failed, the alternatives are unique
integral codes and direct pointers to descriptive text. Both occupy the
same amount of space, but codes are easier to internationalize.
Method of Propagating Errors
----------------------------
@ -67,6 +70,7 @@ exceptions when checking call sites and propagating errors becomes tedious.
However, inter-module boundaries should always return error codes for
interoperability with other languages.
Simplifying Call-Site Checking
------------------------------
@ -77,7 +81,7 @@ macros to simplify this task: function calls can be wrapped in an
Consider the following example:
LibError ret = doWork();
if(ret != INFO_OK) { warnUser(ret); return ret; }
if(ret != INFO::OK) { warnUser(ret); return ret; }
This can be replaced by:
CHECK_ERR(doWork());
@ -87,16 +91,17 @@ allows warning the user whenever an error occurs.
Thus, no errors can be swept under the carpet by failing to
check return value or catch(...) all exceptions.
When to warn the user?
----------------------
When a function fails, there are 2 places we can raise a warning:
as soon as the error condition is known, or in the higher-level caller.
The former is the WARN_RETURN(ERR_FAIL) approach, while the latter
The former is the WARN_RETURN(ERR::FAIL) approach, while the latter
corresponds to the example above.
We prefer the former because it is easier to ensure that all
possible return paths have been covered: search for all "return ERR_*"
possible return paths have been covered: search for all "return ERR::*"
that are not followed by a "// NOWARN" comment. Also, the latter approach
raises the question of where exactly to issue the warning.
Clearly API-level routines must raise the warning, but sometimes they will
@ -115,35 +120,50 @@ without warning, and having their callers take care of that.
which caller of the validator failed anyway.
Validator functions should therefore also use WARN_RETURN.
Numbering Scheme
----------------
Each module header defines its own error codes to avoid a full rebuild
whenever a new obscure code is added.
Error codes start at -100000 (warnings are positive, but reserves a
negative value; absolute values are unique). This avoids collisions
with all known error code schemes.
Each header gets 100 possible values; the tens value may be
used to denote groups within that header.
The subsystem is denoted by the ten-thousands digit: 1 for file,
2 for other resources (e.g. textures), 3 for sysdep, ..
To summarize: +/-1SHHCC (S=subsystem, HH=header, CC=code number)
Notes:
- file is called lib_errors.h because 0ad has another errors.cpp and
the MS linker isn't smart enough to deal with object files
of the same name but in different paths.
- the first part of this file is a normal header; the second contains
X macros and is only active if ERR is defined (i.e. someone is
including this header for the purpose of using them).
- unfortunately Intellisense isn't smart enough to pick up the
ERR_* definitions. This is the price of automatically associating
descriptive text with the error code.
**/
#ifndef ERRORS_H__
#define ERRORS_H__
// limits on the errors defined above (used by error_description_r)
#define ERR_MIN 100000
#define ERR_MAX 120000
// note: this loses compiler type safety (being able to prevent
// return 1 when a LibError is the return value), but allows splitting
// up the error namespace into separate headers.
// Lint's 'strong type' checking can be used to find errors.
typedef long LibError;
// define error codes.
enum LibError {
#define ERR(err, id, str) id = err,
#include "lib_errors.h"
// necessary because the enum would otherwise end with a comma
// (which is often tolerated but not standards compliant).
// note: we cannot rely on this being the last value (in case the
// ERR x-macros aren't arranged in order), so don't use as such.
LIB_ERROR_DUMMY
};
/**
* associate textual description with an error code.
*
* @param err LibError to be associate with. if it already has a
* description, a warning will be generated.
* @param description string. Must remain valid until end of program.
**/
extern void error_setDescription(LibError err, const char* description);
/**
* generate textual description of an error code.
@ -164,6 +184,17 @@ extern char* error_description_r(LibError err, char* buf, size_t max_chars);
// note: other conversion routines (e.g. to/from Win32) are implemented in
// the corresponding modules to keep this header portable.
/**
* associate POSIX errno with an error code.
*
* @param err LibError to be associate with. if it already has a
* equivalent, a warning will be generated.
* @param errno (as defined by POSIX)
**/
extern void error_setEquivalent(LibError err, int errno_);
/**
* translate errno to LibError.
*
@ -171,9 +202,9 @@ extern char* error_description_r(LibError err, char* buf, size_t max_chars);
* errno may otherwise still be set from another error cause.
*
* @param warn_if_failed if set, raise a warning when returning an error
* (i.e. ERR_*, but not INFO_OK). this avoids having to wrap all
* (i.e. ERR::*, but not INFO::OK). this avoids having to wrap all
* call sites in WARN_ERR etc.
* @return LibError equivalent of errno, or ERR_FAIL if there's no equal.
* @return LibError equivalent of errno, or ERR::FAIL if there's no equal.
**/
extern LibError LibError_from_errno(bool warn_if_failed = true);
@ -189,10 +220,10 @@ extern LibError LibError_from_errno(bool warn_if_failed = true);
* @param ret return value of a POSIX function: 0 indicates success,
* -1 is error.
* @param warn_if_failed if set, raise a warning when returning an error
* (i.e. ERR_*, but not INFO_OK). this avoids having to wrap all
* (i.e. ERR::*, but not INFO::OK). this avoids having to wrap all
* call sites in WARN_ERR etc.
* @return INFO_OK if the POSIX function succeeded, else the LibError
* equivalent of errno, or ERR_FAIL if there's no equal.
* @return INFO::OK if the POSIX function succeeded, else the LibError
* equivalent of errno, or ERR::FAIL if there's no equal.
**/
extern LibError LibError_from_posix(int ret, bool warn_if_failed = true);
@ -318,7 +349,7 @@ STMT(\
{\
debug_warn("FYI: WARN_RETURN_IF_FALSE reports that a function failed."\
"feel free to ignore or suppress this warning.");\
return ERR_FAIL;\
return ERR::FAIL;\
}\
)
@ -326,7 +357,7 @@ STMT(\
#define RETURN_IF_FALSE(ok)\
STMT(\
if(!(ok))\
return ERR_FAIL;\
return ERR::FAIL;\
)
// if ok evaluates to false or FALSE, warn user.
@ -338,37 +369,52 @@ STMT(\
)
#endif // #ifndef ERRORS_H__
//-----------------------------------------------------------------------------
#ifdef ERR
// X macros: error code, symbolic name in code, user-visible string.
// error code is usually negative; positive denotes warnings.
// if negative, absolute value must be within [ERR_MIN, ERR_MAX).
// INFO_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, INFO_OK, "(but return value was 0 which indicates success)")
ERR(-1, ERR_FAIL, "Function failed (no details available)")
namespace INFO
{
const LibError OK = 0;
// note: these values are > 100 to allow multiplexing them with
// coroutine return values, which return completion percentage.
ERR(101, INFO_CB_CONTINUE, "1 (not an error)")
// these are all basically the same thing
ERR(102, INFO_CANNOT_HANDLE, "2 (not an error)")
ERR(103, INFO_NO_REPLACE, "3 (not an error)")
ERR(104, INFO_SKIPPED, "4 (not an error)")
ERR(105, INFO_ALL_COMPLETE, "5 (not an error)")
ERR(106, INFO_ALREADY_EXISTS, "6 (not an error)")
ERR(-100000, ERR_LOGIC, "Logic error in code")
ERR(-100001, ERR_TIMED_OUT, "Timed out")
ERR(-100002, ERR_REENTERED, "Single-call function was reentered")
ERR(-100010, ERR_STRING_NOT_TERMINATED, "Invalid string (no 0 terminator found in buffer)")
// function is a callback and indicates that it can (but need not
// necessarily) be called again.
const LibError CB_CONTINUE = +100000;
// notify caller that nothing was done.
const LibError SKIPPED = +100001;
// function is incapable of doing the requested task with the given inputs.
// this implies SKIPPED, but also conveys a bit more information.
const LibError CANNOT_HANDLE = +100002;
// function is meant to be called repeatedly, and now indicates that
// all jobs are complete.
const LibError ALL_COMPLETE = +100003;
// (returned e.g. when inserting into container)
const LibError ALREADY_EXISTS = +100004;
}
namespace ERR
{
const LibError FAIL = -1;
// general
const LibError LOGIC = -100010;
const LibError TIMED_OUT = -100011;
const LibError REENTERED = -100012;
const LibError CORRUPTED = -100013;
// function arguments
const LibError INVALID_PARAM = -100020;
const LibError INVALID_HANDLE = -100021;
const LibError BUF_SIZE = -100022;
// system limitations
const LibError AGAIN = -100030;
const LibError LIMIT = -100031;
const LibError NO_SYS = -100032;
const LibError NOT_IMPLEMENTED = -100033;
const LibError NOT_SUPPORTED = -100034;
const LibError NO_MEM = -100035;
// 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
@ -379,133 +425,34 @@ ERR(-100010, ERR_STRING_NOT_TERMINATED, "Invalid string (no 0 terminator found i
// 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")
const LibError _1 = -100101;
const LibError _2 = -100102;
const LibError _3 = -100103;
const LibError _4 = -100104;
const LibError _5 = -100105;
const LibError _6 = -100106;
const LibError _7 = -100107;
const LibError _8 = -100108;
const LibError _9 = -100109;
const LibError _11 = -100111;
const LibError _12 = -100112;
const LibError _13 = -100113;
const LibError _14 = -100114;
const LibError _15 = -100115;
const LibError _16 = -100116;
const LibError _17 = -100117;
const LibError _18 = -100118;
const LibError _19 = -100119;
const LibError _21 = -100121;
const LibError _22 = -100122;
const LibError _23 = -100123;
const LibError _24 = -100124;
const LibError _25 = -100125;
const LibError _26 = -100126;
const LibError _27 = -100127;
const LibError _28 = -100128;
const LibError _29 = -100129;
// function arguments
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")
} // namespace ERR
// system limitations
ERR(-100240, ERR_AGAIN, "Try again later")
ERR(-100241, ERR_LIMIT, "Fixed limit exceeded")
ERR(-100242, ERR_NO_SYS, "OS doesn't provide a required API")
ERR(-100243, ERR_NOT_IMPLEMENTED, "Feature currently not implemented")
ERR(-100244, ERR_NOT_SUPPORTED, "Feature isn't and won't be supported")
// memory
ERR(-100260, ERR_NO_MEM, "Not enough memory")
ERR(-100261, ERR_ALLOC_NOT_FOUND, "Not a valid allocated address")
ERR(-100262, ERR_MEM_OVERWRITTEN, "Wrote to memory outside valid allocation")
// file + vfs
// .. path
ERR(-100300, ERR_PATH_LENGTH, "Path exceeds PATH_MAX characters")
ERR(-100301, ERR_PATH_EMPTY, "Path is an empty string")
ERR(-100302, ERR_PATH_NOT_RELATIVE, "Path is not relative")
ERR(-100303, ERR_PATH_NON_PORTABLE, "Path contains OS-specific dir separator")
ERR(-100304, ERR_PATH_NON_CANONICAL, "Path contains unsupported .. or ./")
ERR(-100305, ERR_PATH_COMPONENT_SEPARATOR, "Path component contains dir separator")
// .. tree node
ERR(-100310, ERR_TNODE_NOT_FOUND, "File/directory not found")
ERR(-100311, ERR_TNODE_WRONG_TYPE, "Using a directory as file or vice versa")
// .. open
ERR(-100320, ERR_FILE_ACCESS, "Insufficient access rights to open file")
// .. enum
ERR(-100330, ERR_DIR_END, "End of directory reached (no more files)")
// .. IO
ERR(-100340, ERR_IO, "Error during IO")
ERR(-100341, ERR_EOF, "Reading beyond end of file")
// .. mount
ERR(-100350, ERR_ALREADY_MOUNTED, "Directory (tree) already mounted")
ERR(-100351, ERR_NOT_MOUNTED, "Specified directory is not mounted")
ERR(-100352, ERR_INVALID_MOUNT_TYPE, "Invalid mount type (memory corruption?)")
ERR(-100353, ERR_ROOT_DIR_ALREADY_SET, "Attempting to set FS root dir more than once")
// .. misc
ERR(-100360, ERR_UNKNOWN_CMETHOD, "Unknown/unsupported compression method")
ERR(-100361, ERR_IS_COMPRESSED, "Invalid operation for a compressed file")
ERR(-100362, ERR_NOT_MAPPED, "File was not mapped")
ERR(-100363, ERR_NOT_IN_CACHE, "[Internal] Entry not found in cache")
ERR(-100364, ERR_TRACE_EMPTY, "No valid entries in trace")
// file format
ERR(-100400, ERR_UNKNOWN_FORMAT, "Unknown file format")
ERR(-100401, ERR_INCOMPLETE_HEADER, "File header not completely read")
ERR(-100402, ERR_CORRUPTED, "File data is corrupted")
// texture
ERR(-100500, ERR_TEX_FMT_INVALID, "Invalid/unsupported texture format")
ERR(-100501, ERR_TEX_INVALID_COLOR_TYPE, "Invalid color type")
ERR(-100502, ERR_TEX_NOT_8BIT_PRECISION, "Not 8-bit channel precision")
ERR(-100503, ERR_TEX_INVALID_LAYOUT, "Unsupported texel layout, e.g. right-to-left")
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, INFO_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")
ERR(-100601, ERR_CPU_UNKNOWN_OPCODE, "Disassembly failed")
ERR(-100602, ERR_CPU_RESTRICTED_AFFINITY, "Cannot set desired CPU affinity")
// shaders
ERR(-100700, ERR_SHDR_CREATE, "Shader creation failed")
ERR(-100701, ERR_SHDR_COMPILE, "Shader compile failed")
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")
ERR(-100804, ERR_SYM_INTERNAL_ERROR, "Exception raised while processing a symbol")
ERR(-100805, ERR_SYM_UNSUPPORTED, "Symbol type not (fully) supported")
ERR(-100806, ERR_SYM_CHILD_NOT_FOUND, "Symbol does not have the given child")
// .. this limit is to prevent infinite recursion.
ERR(-100807, 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(-100808, ERR_SYM_SINGLE_SYMBOL_LIMIT, "Symbol has produced too much output")
// .. 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(+100809, INFO_SYM_SUPPRESS_OUTPUT, "Symbol was suppressed")
// 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")
// timer
ERR(-101000, ERR_TIMER_NO_SAFE_IMPL, "No safe time source available")
#undef ERR
#endif // #ifdef ERR
#endif // #ifndef ERRORS_H__

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.
// code (currently only ERR::NO_MEM) is returned, the list can't be used.
LibError lfl_init(LFList* list)
{
// make sure a TLS slot has been allocated for this thread.
@ -443,12 +443,12 @@ LibError lfl_init(LFList* list)
if(!tls)
{
list->head = (void*)-1; // 'poison' prevents further use
return ERR_NO_MEM;
return ERR::NO_MEM;
}
list->head = 0;
atomic_add(&active_data_structures, 1);
return INFO_OK;
return INFO::OK;
}
@ -624,7 +624,7 @@ LibError lfl_erase(LFList* list, uintptr_t key)
retry:
// not found in list - abort.
if(!list_lookup(list, key, pos))
return ERR_FAIL;
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
@ -640,7 +640,7 @@ retry:
// call list_lookup to ensure # non-released nodes < # threads.
else
list_lookup(list, key, pos);
return INFO_OK;
return INFO::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.
// code (currently only ERR::NO_MEM) is returned, the hash can't be used.
LibError lfh_init(LFHash* hash, size_t num_entries)
{
hash->tbl = 0;
@ -678,12 +678,12 @@ LibError lfh_init(LFHash* hash, size_t num_entries)
if(!is_pow2((long)num_entries))
{
debug_warn("lfh_init: size must be power of 2");
return ERR_INVALID_PARAM;
return ERR::INVALID_PARAM;
}
hash->tbl = (LFList*)malloc(sizeof(LFList) * num_entries);
if(!hash->tbl)
return ERR_NO_MEM;
return ERR::NO_MEM;
hash->mask = (uint)num_entries-1;
for(int i = 0; i < (int)num_entries; i++)
@ -694,11 +694,11 @@ LibError lfh_init(LFHash* hash, size_t num_entries)
// failed - free all and bail
for(int j = 0; j < i; j++)
lfl_free(&hash->tbl[j]);
return ERR_NO_MEM;
return ERR::NO_MEM;
}
}
return INFO_OK;
return INFO::OK;
}

View File

@ -112,7 +112,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.
// code (currently only ERR::NO_MEM) is returned, the list can't be used.
extern LibError lfl_init(LFList* list);
// call when list is no longer needed; should no longer hold any references.
@ -144,7 +144,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.
// code (currently only ERR::NO_MEM) is returned, the hash can't be used.
extern LibError lfh_init(LFHash* hash, size_t num_entries);
// call when hash is no longer needed; should no longer hold any references.

View File

@ -22,6 +22,13 @@
#include "precompiled.h"
AT_STARTUP(\
error_setDescription(ERR::MEM_ALLOC_NOT_FOUND, "Not a valid allocated address");\
error_setDescription(ERR::MEM_OVERWRITTEN, "Wrote to memory outside valid allocation");\
)
// for easy removal in release builds, so that we don't cause any overhead.
// note that any application calls to our functions must be removed also,
// but this is preferable to stubbing them out here ("least surprise").
@ -242,7 +249,7 @@ static Alloc* alloc_new()
freelist = (Alloc*)calloc(256, sizeof(Alloc));
if(!freelist)
{
debug_assert(0 && "mmgr: failed to allocate freelist (out of memory)");
DEBUG_WARN_ERR(ERR::NO_MEM);
return 0;
}
@ -848,7 +855,7 @@ static bool alloc_is_valid(const Alloc* a)
else
log("[!] alloc_is_valid encountered an exception - something may be very wrong!\n");
log_this_alloc(a);
debug_assert(0 && "Memory over/underrun detected by mmgr");
DEBUG_WARN_ERR(ERR::MEM_OVERWRITTEN);
}
return intact;
}
@ -881,13 +888,13 @@ static bool validate_all()
// enable MMGR_VALIDATE_ALL, trigger this condition again,
// and check the log for the last successful operation. the problem
// will have occurred between then and now.
DEBUG_WARN_ERR(ERR_CORRUPTED);
DEBUG_WARN_ERR(ERR::CORRUPTED);
log("[!] Memory tracking hash table corrupt!\n");
}
if(params.num_invalid)
{
DEBUG_WARN_ERR(ERR_MEM_OVERWRITTEN);
DEBUG_WARN_ERR(ERR::MEM_OVERWRITTEN);
log("[!] %d allocations are corrupt\n", params.num_invalid);
return false;
}
@ -1047,7 +1054,7 @@ void* alloc_dbg(size_t user_size, AllocType type, const char* file, int line, co
void* p = malloc(size);
if(!p)
{
DEBUG_WARN_ERR(ERR_NO_MEM);
DEBUG_WARN_ERR(ERR::NO_MEM);
log("[!] Allocation failed (out of memory)\n");
goto fail;
}
@ -1114,9 +1121,8 @@ void free_dbg(const void* user_p, AllocType type, const char* file, int line, co
Alloc* a = allocs_find(user_p);
if(!a)
{
// you tried to free a pointer mmgr didn't allocate
debug_assert(0 && "mmgr tried to free a pointer mmgr didn't allocate");
log("[!] mmgr_free: not allocated by this memory manager\n");
DEBUG_WARN_ERR(ERR::ALLOC_NOT_FOUND);
goto fail;
}
// .. overrun? (note: alloc_is_valid already asserts if invalid)
@ -1197,7 +1203,7 @@ void* realloc_dbg(const void* user_p, size_t user_size, AllocType type, const ch
{
// you called realloc for a pointer mmgr didn't allocate
log("[!] realloc: wasn't previously allocated\n");
debug_assert(0 && "realloc was called for a pointer mmgr didn't allocate");
DEBUG_WARN_ERR(ERR::MEM_ALLOC_NOT_FOUND);
goto fail;
}
// .. the owner wasn't compiled with mmgr.h

View File

@ -105,6 +105,13 @@ good luck!
#ifndef MMGR_H__
#define MMGR_H__
namespace ERR
{
const LibError MEM_ALLOC_NOT_FOUND = -100200;
const LibError MEM_OVERWRITTEN = -100201;
}
// provide for completely disabling the memory manager
// (e.g. when using other debug packages)
//
@ -115,7 +122,6 @@ good luck!
#include "lib/types.h"
//
// optional additional checks, enabled via mmgr_set_options.
// these slow down the application; see 'digging deeper' in documentation.

View File

@ -348,14 +348,14 @@ LibError ogl_get_gfx_info()
// can fail if OpenGL not yet initialized,
// or if called between glBegin and glEnd.
if(!vendor || !renderer || !version)
WARN_RETURN(ERR_AGAIN);
WARN_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 INFO_OK;
return INFO::OK;
}

View File

@ -23,10 +23,6 @@
#ifndef __OGL_H__
#define __OGL_H__
#ifdef __cplusplus
extern "C" {
#endif
#if OS_WIN
// wgl.h is a private header and should only be included from here.
// if this isn't defined, it'll complain.
@ -193,9 +189,4 @@ extern void oglSquelchError(GLenum err_to_ignore);
**/
extern void oglInit(void);
#ifdef __cplusplus
}
#endif
#endif // #ifndef __OGL_H__

View File

@ -29,6 +29,18 @@
#include "path_util.h"
AT_STARTUP(\
error_setDescription(ERR::PATH_LENGTH, "Path exceeds PATH_MAX characters");\
error_setDescription(ERR::PATH_EMPTY, "Path is an empty string");\
error_setDescription(ERR::PATH_NOT_RELATIVE, "Path is not relative");\
error_setDescription(ERR::PATH_NON_PORTABLE, "Path contains OSspecific dir separator");\
error_setDescription(ERR::PATH_NON_CANONICAL, "Path contains unsupported .. or ./");\
error_setDescription(ERR::PATH_COMPONENT_SEPARATOR, "Path component contains dir separator");\
\
error_setEquivalent(ERR::PATH_LENGTH, ENAMETOOLONG);\
)
static inline bool is_dir_sep(char c)
{
if(c == '/' || c == DIR_SEP)
@ -69,13 +81,13 @@ bool path_is_subpath(const char* s1, const char* s2)
}
// if path is invalid, return a descriptive error code, otherwise INFO_OK.
// if path is invalid, return a descriptive error code, otherwise INFO::OK.
LibError path_validate(const char* path)
{
// disallow "/", because it would create a second 'root' (with name = "").
// root dir is "".
if(path[0] == '/')
WARN_RETURN(ERR_PATH_NOT_RELATIVE);
WARN_RETURN(ERR::PATH_NOT_RELATIVE);
// scan each char in path string; count length.
int c = 0; // current char; used for .. detection
@ -87,35 +99,35 @@ LibError path_validate(const char* path)
// whole path is too long
if(path_len >= PATH_MAX)
WARN_RETURN(ERR_PATH_LENGTH);
WARN_RETURN(ERR::PATH_LENGTH);
// disallow:
// - ".." (prevent going above the VFS root dir)
// - "./" (security hole when mounting and not supported on Windows).
// allow "/.", because CVS backup files include it.
if(last_c == '.' && (c == '.' || c == '/'))
WARN_RETURN(ERR_PATH_NON_CANONICAL);
WARN_RETURN(ERR::PATH_NON_CANONICAL);
// disallow OS-specific dir separators
if(c == '\\' || c == ':')
WARN_RETURN(ERR_PATH_NON_PORTABLE);
WARN_RETURN(ERR::PATH_NON_PORTABLE);
// end of string, no errors encountered
if(c == '\0')
break;
}
return INFO_OK;
return INFO::OK;
}
// if name is invalid, return a descriptive error code, otherwise INFO_OK.
// if name is invalid, return a descriptive error code, otherwise INFO::OK.
// (name is a path component, i.e. that between directory separators)
LibError path_component_validate(const char* name)
{
// disallow empty strings
if(*name == '\0')
WARN_RETURN(ERR_PATH_EMPTY);
WARN_RETURN(ERR::PATH_EMPTY);
for(;;)
{
@ -124,14 +136,14 @@ LibError path_component_validate(const char* name)
// disallow *any* dir separators (regardless of which
// platform we're on).
if(c == '\\' || c == ':' || c == '/')
WARN_RETURN(ERR_PATH_COMPONENT_SEPARATOR);
WARN_RETURN(ERR::PATH_COMPONENT_SEPARATOR);
// end of string, no errors encountered
if(c == '\0')
break;
}
return INFO_OK;
return INFO::OK;
}
@ -175,7 +187,7 @@ LibError path_append(char* dst, const char* path1, const char* path2, uint flags
}
if(total_len > PATH_MAX)
WARN_RETURN(ERR_PATH_LENGTH);
WARN_RETURN(ERR::PATH_LENGTH);
strcpy(dst, path1); // safe
dst += len1;
@ -185,20 +197,20 @@ LibError path_append(char* dst, const char* path1, const char* path2, uint flags
if(need_terminator)
strcpy(dst+len2, "/"); // safe
return INFO_OK;
return INFO::OK;
}
// strip <remove> from the start of <src>, prepend <replace>,
// and write to <dst>.
// returns ERR_FAIL (without warning!) if the beginning of <src> doesn't
// returns ERR::FAIL (without warning!) if the beginning of <src> doesn't
// match <remove>.
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 ERR_FAIL; // NOWARN
return ERR::FAIL; // NOWARN
// if removing will leave a separator at beginning of src, remove it
// (example: "a/b"; removing "a" would yield "/b")
@ -208,7 +220,7 @@ LibError path_replace(char* dst, const char* src, const char* remove, const char
// prepend replace.
RETURN_ERR(path_append(dst, replace, start));
return INFO_OK;
return INFO::OK;
}
@ -329,7 +341,7 @@ LibError path_foreach_component(const char* path_org, PathComponentCb cb, void*
LibError ret = cb(cur_component, is_dir, ctx);
// callback wants to abort - return its value.
if(ret != INFO_CB_CONTINUE)
if(ret != INFO::CB_CONTINUE)
return ret;
// filename is by definition the last component. abort now
@ -344,7 +356,7 @@ LibError path_foreach_component(const char* path_org, PathComponentCb cb, void*
cur_component = slash+1;
}
return INFO_OK;
return INFO::OK;
}
@ -366,7 +378,7 @@ LibError path_package_set_dir(PathPackage* pp, const char* dir)
// -1 allows for trailing DIR_SEP that will be added if not
// already present.
if(strcpy_s(pp->path, ARRAY_SIZE(pp->path)-1, dir) != 0)
WARN_RETURN(ERR_PATH_LENGTH);
WARN_RETURN(ERR::PATH_LENGTH);
size_t len = strlen(pp->path);
// add directory separator if not already present
// .. but only check this if dir != "" (=> len-1 is safe)
@ -386,7 +398,7 @@ LibError path_package_set_dir(PathPackage* pp, const char* dir)
pp->end = pp->path+len;
pp->chars_left = ARRAY_SIZE(pp->path)-len;
return INFO_OK;
return INFO::OK;
}
@ -395,5 +407,5 @@ LibError path_package_set_dir(PathPackage* pp, const char* dir)
LibError path_package_append_file(PathPackage* pp, const char* path)
{
CHECK_ERR(strcpy_s(pp->end, pp->chars_left, path));
return INFO_OK;
return INFO::OK;
}

View File

@ -35,10 +35,22 @@
#include "posix.h" // PATH_MAX
namespace ERR
{
const LibError PATH_LENGTH = -100300;
const LibError PATH_EMPTY = -100301;
const LibError PATH_NOT_RELATIVE = -100302;
const LibError PATH_NON_PORTABLE = -100303;
const LibError PATH_NON_CANONICAL = -100304;
const LibError PATH_COMPONENT_SEPARATOR = -100305;
}
/**
* check if path is valid. (see source for criteria)
*
* @return LibError (ERR_PATH_* or INFO_OK)
* @return LibError (ERR::PATH_* or INFO::OK)
**/
extern LibError path_validate(const char* path);
@ -50,7 +62,7 @@ extern LibError path_validate(const char* path);
/**
* check if name is valid. (see source for criteria)
*
* @return LibError (ERR_PATH_* or INFO_OK)
* @return LibError (ERR::PATH_* or INFO::OK)
**/
extern LibError path_component_validate(const char* name);
@ -106,7 +118,7 @@ extern LibError path_append(char* dst, const char* path1, const char* path2,
* @param remove substring to remove; must match (case-sensitive) the
* start of src.
* @param replace string to prepend to output after stripping <remove>.
* @return LibError; ERR_FAIL (without warning!) if <src> doesn't
* @return LibError; ERR::FAIL (without warning!) if <src> doesn't
* match <remove>.
**/
extern LibError path_replace(char* dst, const char* src, const char* remove, const char* replace);
@ -170,9 +182,9 @@ extern const char* path_extension(const char* fn);
* rationale: a bool isn't as nice as a flag or enum, but vfs_tree already
* has TNodeType and we don't want to expose that or create a new one.
* @param ctx: context parameter that was passed to path_foreach_component.
* @return LibError; INFO_CB_CONTINUE to continue operation normally;
* @return LibError; INFO::CB_CONTINUE to continue operation normally;
* anything else will cause path_foreach_component to abort immediately and
* return that. no need to 'abort' (e.g. return INFO_OK) after a filename is
* return that. no need to 'abort' (e.g. return INFO::OK) after a filename is
* encountered - that's taken care of automatically.
**/
typedef LibError (*PathComponentCb)(const char* component, bool is_dir, void* ctx);

View File

@ -56,6 +56,7 @@
//
#include "lib/types.h"
#include "lib/lib_errors.h"
#include "lib/string_s.h" // CRT secure string
#include "lib/sysdep/sysdep.h"
#include "lib/debug.h" // (sysdep.h pulls in debug.h)

View File

@ -44,6 +44,12 @@
// uses file_* and inf_*.
// - file mapping
AT_STARTUP(\
error_setDescription(ERR::IS_COMPRESSED, "Invalid operation for a compressed file");\
)
///////////////////////////////////////////////////////////////////////////////
//
// lookup_*: file lookup
@ -121,7 +127,7 @@ static LibError Archive_reload(Archive* a, const char* fn, Handle)
RETURN_ERR(zip_populate_archive(&a->f, a));
a->is_loaded = 1;
return INFO_OK;
return INFO::OK;
}
static LibError Archive_validate(const Archive* a)
@ -129,15 +135,15 @@ static LibError Archive_validate(const Archive* a)
RETURN_ERR(file_validate(&a->f));
if(debug_is_pointer_bogus(a->ents))
WARN_RETURN(ERR_1);
WARN_RETURN(ERR::_1);
return INFO_OK;
return INFO::OK;
}
static LibError Archive_to_string(const Archive* a, char* buf)
{
snprintf(buf, H_STRING_LEN, "(%u files)", a->num_files);
return INFO_OK;
return INFO::OK;
}
@ -169,7 +175,7 @@ static LibError archive_get_file_info(Archive* a, const char* fn, uintptr_t meme
if(memento)
{
ent = (ArchiveEntry*)memento;
return INFO_OK;
return INFO::OK;
}
else
{
@ -178,11 +184,11 @@ static LibError archive_get_file_info(Archive* a, const char* fn, uintptr_t meme
if(a->ents[i].atom_fn == atom_fn)
{
ent = &a->ents[i];
return INFO_OK;
return INFO::OK;
}
}
WARN_RETURN(ERR_TNODE_NOT_FOUND);
WARN_RETURN(ERR::TNODE_NOT_FOUND);
}
@ -207,11 +213,11 @@ LibError archive_enum(const Handle ha, const FileCB cb, const uintptr_t user)
s.st_mtime = ent->mtime;
const uintptr_t memento = (uintptr_t)ent;
LibError ret = cb(ent->atom_fn, &s, memento, user);
if(ret != INFO_CB_CONTINUE)
if(ret != INFO::CB_CONTINUE)
return ret;
}
return INFO_OK;
return INFO::OK;
}
@ -222,8 +228,8 @@ LibError archive_allocate_entries(Archive* a, size_t num_entries)
debug_assert(a->ents == 0); // must not have been allocated yet
a->ents = (ArchiveEntry*)mem_alloc(num_entries * sizeof(ArchiveEntry), 32);
if(!a->ents)
WARN_RETURN(ERR_NO_MEM);
return INFO_OK;
WARN_RETURN(ERR::NO_MEM);
return INFO::OK;
}
@ -235,7 +241,7 @@ LibError archive_allocate_entries(Archive* a, size_t num_entries)
LibError archive_add_file(Archive* a, const ArchiveEntry* ent)
{
a->ents[a->num_files++] = *ent;
return INFO_OK;
return INFO::OK;
}
@ -290,7 +296,7 @@ LibError afile_stat(Handle ha, const char* fn, struct stat* s)
s->st_size = ent->ucsize;
s->st_mtime = ent->mtime;
return INFO_OK;
return INFO::OK;
}
@ -299,16 +305,16 @@ LibError afile_stat(Handle ha, const char* fn, struct stat* s)
LibError afile_validate(const File* f)
{
if(!f)
WARN_RETURN(ERR_INVALID_PARAM);
WARN_RETURN(ERR::INVALID_PARAM);
const ArchiveFile* af = (const ArchiveFile*)f->opaque;
UNUSED2(af);
// note: don't check af->ha - it may be freed at shutdown before
// its files. TODO: revisit once dependency support is added.
if(!f->size)
WARN_RETURN(ERR_1);
WARN_RETURN(ERR::_1);
// note: af->ctx is 0 if file is not compressed.
return INFO_OK;
return INFO::OK;
}
#define CHECK_AFILE(f) RETURN_ERR(afile_validate(f))
@ -322,7 +328,7 @@ LibError afile_open(const Handle ha, const char* fn, uintptr_t memento, uint fla
memset(f, 0, sizeof(*f));
if(flags & FILE_WRITE)
WARN_RETURN(ERR_IS_COMPRESSED);
WARN_RETURN(ERR::IS_COMPRESSED);
H_DEREF(ha, Archive, a);
@ -345,7 +351,7 @@ LibError afile_open(const Handle ha, const char* fn, uintptr_t memento, uint fla
{
ctx = comp_alloc(CT_DECOMPRESSION, ent->method);
if(!ctx)
WARN_RETURN(ERR_NO_MEM);
WARN_RETURN(ERR::NO_MEM);
}
f->flags = flags;
@ -359,7 +365,7 @@ LibError afile_open(const Handle ha, const char* fn, uintptr_t memento, uint fla
af->ctx = ctx;
af->is_mapped = 0;
CHECK_AFILE(f);
return INFO_OK;
return INFO::OK;
}
@ -371,7 +377,7 @@ LibError afile_close(File* f)
// other File fields don't need to be freed/cleared
comp_free(af->ctx);
af->ctx = 0;
return INFO_OK;
return INFO::OK;
}
@ -415,7 +421,7 @@ LibError afile_io_issue(File* f, off_t user_ofs, size_t max_output_size, void* u
ArchiveFileIo* aio = (ArchiveFileIo*)io->opaque;
aio->io = io_allocator.alloc();
if(!aio->io)
WARN_RETURN(ERR_NO_MEM);
WARN_RETURN(ERR::NO_MEM);
// not compressed; we'll just read directly from the archive file.
// no need to clamp to EOF - that's done already by the VFS.
@ -441,12 +447,12 @@ LibError afile_io_issue(File* f, off_t user_ofs, size_t max_output_size, void* u
void* cbuf = mem_alloc(csize, 4*KiB);
if(!cbuf)
WARN_RETURN(ERR_NO_MEM);
WARN_RETURN(ERR::NO_MEM);
RETURN_ERR(file_io_issue(&a->f, cofs, csize, cbuf, aio->io));
af->last_cofs += (off_t)csize;
return INFO_OK;
return INFO::OK;
}
@ -489,7 +495,7 @@ LibError afile_io_wait(FileIo* io, void*& buf, size_t& size)
size = raw_size;
}
return INFO_OK;
return INFO::OK;
}
@ -507,10 +513,10 @@ LibError afile_io_validate(const FileIo* io)
{
ArchiveFileIo* aio = (ArchiveFileIo*)io->opaque;
if(debug_is_pointer_bogus(aio->user_buf))
WARN_RETURN(ERR_1);
WARN_RETURN(ERR::_1);
// <ctx> and <max_output_size> have no invariants we could check.
RETURN_ERR(file_io_validate(aio->io));
return INFO_OK;
return INFO::OK;
}
@ -544,11 +550,11 @@ public:
debug_assert(ucsize <= ucsize_left);
ucsize_left -= ucsize;
LibError ret = INFO_CB_CONTINUE;
LibError ret = INFO::CB_CONTINUE;
if(user_cb)
ret = user_cb(user_cb_ctx, ucblock, ucsize, bytes_processed);
if(ucsize_left == 0)
ret = INFO_OK;
ret = INFO::OK;
return ret;
}
@ -667,7 +673,7 @@ LibError afile_map(File* f, void*& p, size_t& size)
// mapping compressed files doesn't make sense because the
// compression algorithm is unspecified - disallow it.
if(is_compressed(af))
WARN_RETURN(ERR_IS_COMPRESSED);
WARN_RETURN(ERR::IS_COMPRESSED);
// note: we mapped the archive in archive_open, but unmapped it
// in the meantime to save memory in case it wasn't going to be mapped.
@ -681,7 +687,7 @@ LibError afile_map(File* f, void*& p, size_t& size)
size = f->size;
af->is_mapped = 1;
return INFO_OK;
return INFO::OK;
}
@ -698,7 +704,7 @@ LibError afile_unmap(File* f)
// make sure archive mapping refcount remains balanced:
// don't allow multiple|"false" unmaps.
if(!af->is_mapped)
WARN_RETURN(ERR_NOT_MAPPED);
WARN_RETURN(ERR::FILE_NOT_MAPPED);
af->is_mapped = 0;
H_DEREF(af->ha, Archive, a);

View File

@ -28,6 +28,10 @@
#include "file.h" // FileCB for afile_enum
#include "compression.h" // CompressionMethod
namespace ERR
{
const LibError IS_COMPRESSED = -110400;
}
// note: filenames are case-insensitive.
@ -199,7 +203,7 @@ struct ArchiveEntry
// successively called for each valid file in the archive,
// passing the complete path and <user>.
// return INFO_CB_CONTINUE to continue calling; anything else will cause
// 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

View File

@ -76,7 +76,7 @@ static LibError compress_cb(uintptr_t cb_ctx, const void* block, size_t size, si
if(p->attempt_compress)
(void)comp_feed(p->ctx, block, size);
return INFO_CB_CONTINUE;
return INFO::CB_CONTINUE;
}
@ -123,7 +123,7 @@ static LibError read_and_compress_file(const char* atom_fn, uintptr_t ctx,
// even less safe.
// we thus skip 0-length files to avoid confusing them with dirs.
if(!ucsize)
return INFO_SKIPPED;
return INFO::SKIPPED;
const bool attempt_compress = !file_type_is_uncompressible(atom_fn);
if(attempt_compress)
@ -179,7 +179,7 @@ static LibError read_and_compress_file(const char* atom_fn, uintptr_t ctx,
// note: no need to free cdata - it is owned by the
// compression context and can be reused.
return INFO_OK;
return INFO::OK;
}
@ -195,7 +195,7 @@ LibError archive_build_init(const char* P_archive_filename, Filenames V_fns,
for(ab->num_files = 0; ab->V_fns[ab->num_files]; ab->num_files++) {}
ab->i = 0;
return INFO_OK;
return INFO::OK;
}
@ -210,7 +210,7 @@ int archive_build_continue(ArchiveBuildState* ab)
break;
ArchiveEntry ent; void* file_contents; FileIOBuf buf;
if(read_and_compress_file(V_fn, ab->ctx, ent, file_contents, buf) == INFO_OK)
if(read_and_compress_file(V_fn, ab->ctx, ent, file_contents, buf) == INFO::OK)
{
(void)zip_archive_add_file(ab->za, &ent, file_contents);
(void)file_buf_free(buf);
@ -226,7 +226,7 @@ int archive_build_continue(ArchiveBuildState* ab)
comp_free(ab->ctx); ab->ctx = 0;
(void)zip_archive_finish(ab->za);
return INFO_OK;
return INFO::OK;
}
@ -251,7 +251,7 @@ LibError archive_build(const char* P_archive_filename, Filenames V_fns)
{
int ret = archive_build_continue(&ab);
RETURN_ERR(ret);
if(ret == INFO_OK)
return INFO_OK;
if(ret == INFO::OK)
return INFO::OK;
}
}

View File

@ -29,6 +29,13 @@
#include "lib/allocators.h"
#include "lib/timer.h"
#include "compression.h"
#include "file_io.h" // IO_EOF
AT_STARTUP(\
error_setDescription(ERR::COMPRESSION_UNKNOWN_METHOD, "Unknown/unsupported compression method");\
)
// provision for removing all ZLib code (all inflate calls will fail).
// used for checking DLL dependency; might also simulate corrupt Zip files.
@ -66,17 +73,17 @@ static LibError LibError_from_zlib(int zlib_err, bool warn_if_failed = true)
switch(zlib_err)
{
case Z_OK:
return INFO_OK;
return INFO::OK;
case Z_STREAM_END:
err = ERR_EOF; break;
err = ERR::IO_EOF; break;
case Z_MEM_ERROR:
err = ERR_NO_MEM; break;
err = ERR::NO_MEM; break;
case Z_DATA_ERROR:
err = ERR_CORRUPTED; break;
err = ERR::CORRUPTED; break;
case Z_STREAM_ERROR:
err = ERR_INVALID_PARAM; break;
err = ERR::INVALID_PARAM; break;
default:
err = ERR_FAIL; break;
err = ERR::FAIL; break;
}
if(warn_if_failed)
@ -112,7 +119,7 @@ public:
{
next_out = 0;
avail_out = 0;
return INFO_OK;
return INFO::OK;
}
virtual LibError alloc_output(size_t in_size) = 0;
@ -186,7 +193,7 @@ public:
{
void* cdata_copy = malloc(buf.csize);
if(!cdata_copy)
WARN_RETURN(ERR_NO_MEM);
WARN_RETURN(ERR::NO_MEM);
memcpy2(cdata_copy, buf.cdata, buf.csize);
buf.cdata = (const u8*)cdata_copy;
}
@ -255,7 +262,7 @@ protected:
// .. need to allocate anew
out_mem = mem_alloc(alloc_size, 32*KiB);
if(!out_mem)
WARN_RETURN(ERR_NO_MEM);
WARN_RETURN(ERR::NO_MEM);
out_mem_size = alloc_size;
have_out_mem:
@ -266,7 +273,7 @@ have_out_mem:
next_out = out_mem;
avail_out = out_mem_size;
return INFO_OK;
return INFO::OK;
}
}; // class Compressor
@ -339,10 +346,10 @@ public:
{
size_t required_size = (size_t)deflateBound(&zs, (uLong)in_size);
RETURN_ERR(alloc_output_impl(required_size));
return INFO_OK;
return INFO::OK;
}
else
WARN_RETURN(ERR_LOGIC);
WARN_RETURN(ERR::LOGIC);
}
@ -396,7 +403,7 @@ public:
*out = zs.next_out - zs.total_out;
*out_size = zs.total_out;
return INFO_OK;
return INFO::OK;
}
@ -443,7 +450,7 @@ uintptr_t comp_alloc(ContextType type, CompressionMethod method)
#endif
default:
compressor_allocator.release(c_mem);
WARN_ERR(ERR_UNKNOWN_CMETHOD);
WARN_ERR(ERR::COMPRESSION_UNKNOWN_METHOD);
return 0;
}

View File

@ -24,6 +24,13 @@
#ifndef COMPRESSION_H__
#define COMPRESSION_H__
namespace ERR
{
const LibError COMPRESSION_UNKNOWN_METHOD = -110300;
}
enum ContextType
{
CT_COMPRESSION,

View File

@ -36,6 +36,14 @@
#include <string>
AT_STARTUP(\
error_setDescription(ERR::FILE_ACCESS, "Insufficient access rights to open file");\
error_setDescription(ERR::DIR_END, "End of directory reached (no more files)");\
error_setDescription(ERR::FILE_NOT_MAPPED, "File was not mapped");\
\
error_setEquivalent(ERR::FILE_ACCESS, EACCES);\
)
// rationale for aio, instead of only using mmap:
// - parallelism: instead of just waiting for the transfer to complete,
// other work can be done in the meantime.
@ -80,7 +88,7 @@ static SingleAllocator<PathPackage> pp_allocator;
// prepare to iterate (once) over entries in the given directory.
// if INFO_OK is returned, <d> is ready for subsequent dir_next_ent calls and
// if INFO::OK is returned, <d> is ready for subsequent dir_next_ent calls and
// must be freed via dir_close.
LibError dir_open(const char* P_path, DirIterator* di)
{
@ -102,7 +110,7 @@ LibError dir_open(const char* P_path, DirIterator* di)
pdi->pp = pp_allocator.alloc();
if(!pdi->pp)
WARN_RETURN(ERR_NO_MEM);
WARN_RETURN(ERR::NO_MEM);
errno = 0;
pdi->os_dir = opendir(n_path);
@ -110,12 +118,12 @@ LibError dir_open(const char* P_path, DirIterator* di)
return LibError_from_errno();
(void)path_package_set_dir(pdi->pp, n_path);
return INFO_OK;
return INFO::OK;
}
// return ERR_DIR_END if all entries have already been returned once,
// another negative error code, or INFO_OK on success, in which case <ent>
// return ERR::DIR_END if all entries have already been returned once,
// another negative error code, or INFO::OK on success, in which case <ent>
// describes the next (order is unspecified) directory entry.
LibError dir_next_ent(DirIterator* di, DirEnt* ent)
{
@ -128,7 +136,7 @@ get_another_entry:
{
// no error, just no more entries to return
if(!errno)
return ERR_DIR_END; // NOWARN
return ERR::DIR_END; // NOWARN
return LibError_from_errno();
}
@ -167,7 +175,7 @@ get_another_entry:
ent->size = s.st_size;
ent->mtime = s.st_mtime;
ent->name = name;
return INFO_OK;
return INFO::OK;
}
@ -181,7 +189,7 @@ LibError dir_close(DirIterator* di)
errno = 0;
if(closedir(pdi->os_dir) < 0)
return LibError_from_errno();
return INFO_OK;
return INFO::OK;
}
@ -193,7 +201,7 @@ LibError dir_create(const char* P_path, mode_t mode)
struct stat s;
int ret = stat(N_path, &s);
if(ret == 0)
return INFO_ALREADY_EXISTS;
return INFO::ALREADY_EXISTS;
errno = 0;
ret = mkdir(N_path, mode);
@ -219,27 +227,27 @@ LibError dir_delete(const char* P_path)
{
DirEnt ent;
ret = dir_next_ent(&di, &ent);
if(ret == ERR_DIR_END)
if(ret == ERR::DIR_END)
break;
if(ret != INFO_OK) goto fail;
if(ret != INFO::OK) goto fail;
if(DIRENT_IS_DIR(&ent))
{
char P_subdir[PATH_MAX];
ret = path_append(P_subdir, P_path, ent.name);
if(ret != INFO_OK) goto fail;
if(ret != INFO::OK) goto fail;
ret = dir_delete(P_subdir);
if(ret != INFO_OK) goto fail;
if(ret != INFO::OK) goto fail;
}
else
{
ret = path_package_append_file(&N_pp, ent.name);
if(ret != INFO_OK) goto fail;
if(ret != INFO::OK) goto fail;
errno = 0;
int posix_ret = unlink(N_pp.path);
ret = LibError_from_posix(posix_ret);
if(ret != INFO_OK) goto fail;
if(ret != INFO::OK) goto fail;
}
}
@ -281,7 +289,7 @@ bool file_exists(const char* fn)
{
struct stat s;
const bool warn_if_failed = false;
return file_stat_impl(fn, &s, warn_if_failed) == INFO_OK;
return file_stat_impl(fn, &s, warn_if_failed) == INFO::OK;
}
@ -346,17 +354,17 @@ int file_fd_from_PosixFile(File* f)
LibError file_validate(const File* f)
{
if(!f)
WARN_RETURN(ERR_INVALID_PARAM);
WARN_RETURN(ERR::INVALID_PARAM);
const PosixFile* pf = (PosixFile*)f->opaque;
if(pf->fd < 0)
WARN_RETURN(ERR_1);
WARN_RETURN(ERR::_1);
// mapped but refcount is invalid
else if((pf->mapping != 0) ^ (pf->map_refs != 0))
WARN_RETURN(ERR_2);
WARN_RETURN(ERR::_2);
// note: don't check atom_fn - that complains at the end of
// file_open if flags & FILE_DONT_SET_FN and has no benefit, really.
return INFO_OK;
return INFO::OK;
}
@ -366,7 +374,7 @@ LibError file_open(const char* P_fn, uint flags, File* f)
memset(f, 0, sizeof(*f));
if(flags > FILE_FLAG_ALL)
WARN_RETURN(ERR_INVALID_PARAM);
WARN_RETURN(ERR::INVALID_PARAM);
char N_fn[PATH_MAX];
RETURN_ERR(file_make_full_native_path(P_fn, N_fn));
@ -383,7 +391,7 @@ LibError file_open(const char* P_fn, uint flags, File* f)
// get file size
struct stat s;
if(stat(N_fn, &s) < 0)
WARN_RETURN(ERR_TNODE_NOT_FOUND);
WARN_RETURN(ERR::TNODE_NOT_FOUND);
size = s.st_size;
// note: despite increased overhead, the AIO read method is still
@ -397,7 +405,7 @@ LibError file_open(const char* P_fn, uint flags, File* f)
// make sure <N_fn> is a regular file
if(!S_ISREG(s.st_mode))
WARN_RETURN(ERR_TNODE_WRONG_TYPE);
WARN_RETURN(ERR::TNODE_WRONG_TYPE);
}
#if OS_WIN
@ -413,7 +421,7 @@ LibError file_open(const char* P_fn, uint flags, File* f)
int fd = open(N_fn, oflag, S_IRWXO|S_IRWXU|S_IRWXG);
if(fd < 0)
WARN_RETURN(ERR_FILE_ACCESS);
WARN_RETURN(ERR::FILE_ACCESS);
f->flags = flags;
f->size = size;
@ -426,7 +434,7 @@ LibError file_open(const char* P_fn, uint flags, File* f)
pf->fd = fd;
CHECK_FILE(f);
return INFO_OK;
return INFO::OK;
}
@ -459,7 +467,7 @@ LibError file_close(File* f)
if(f->flags & FILE_WRITE)
file_cache_invalidate(f->atom_fn);
return INFO_OK;
return INFO::OK;
}
@ -500,7 +508,7 @@ LibError file_map(File* f, void*& p, size_t& size)
{
// prevent overflow; if we have this many refs, should find out why.
if(pf->map_refs >= MAX_MAP_REFS)
WARN_RETURN(ERR_LIMIT);
WARN_RETURN(ERR::LIMIT);
pf->map_refs++;
goto have_mapping;
}
@ -510,7 +518,7 @@ LibError 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 ERR_FAIL; // NOWARN
return ERR::FAIL; // NOWARN
errno = 0;
pf->mapping = mmap(0, f->size, prot, MAP_PRIVATE, pf->fd, (off_t)0);
@ -522,7 +530,7 @@ LibError file_map(File* f, void*& p, size_t& size)
have_mapping:
p = pf->mapping;
size = f->size;
return INFO_OK;
return INFO::OK;
}
@ -539,11 +547,11 @@ LibError file_unmap(File* f)
// file is not currently mapped
if(pf->map_refs == 0)
WARN_RETURN(ERR_NOT_MAPPED);
WARN_RETURN(ERR::FILE_NOT_MAPPED);
// still more than one reference remaining - done.
if(--pf->map_refs > 0)
return INFO_OK;
return INFO::OK;
// no more references: remove the mapping
void* p = pf->mapping;
@ -565,7 +573,7 @@ LibError file_init()
// convenience
file_sector_size = sys_max_sector_size();
return INFO_OK;
return INFO::OK;
}
LibError file_shutdown()
@ -573,5 +581,5 @@ LibError file_shutdown()
stats_dump();
path_shutdown();
file_io_shutdown();
return INFO_OK;
return INFO::OK;
}

View File

@ -26,6 +26,14 @@
#include "lib/posix.h" // struct stat
namespace ERR
{
const LibError FILE_ACCESS = -110000;
const LibError FILE_NOT_MAPPED = -110001;
const LibError DIR_END = -110002;
}
extern LibError file_init();
// used by vfs_redirector to call various file objects' methods.
@ -37,7 +45,7 @@ struct FileProvider_VTbl;
// for external libraries that require the real filename.
//
// replaces '/' with platform's directory separator and vice versa.
// verifies path length < PATH_MAX (otherwise return ERR_PATH_LENGTH).
// verifies path length < PATH_MAX (otherwise return ERR::PATH_LENGTH).
//
// relative paths (relative to root dir)
@ -137,12 +145,12 @@ struct DirEnt
#define DIRENT_IS_DIR(p_ent) ((p_ent)->size == -1)
// prepare to iterate (once) over entries in the given directory.
// if INFO_OK is returned, <d> is ready for subsequent dir_next_ent calls and
// if INFO::OK is returned, <d> is ready for subsequent dir_next_ent calls and
// must be freed via dir_close.
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 INFO_OK on success, in which case <ent>
// return ERR::DIR_END if all entries have already been returned once,
// another negative error code, or INFO::OK on success, in which case <ent>
// describes the next (order is unspecified) directory entry.
extern LibError dir_next_ent(DirIterator* d, DirEnt* ent);
@ -170,7 +178,7 @@ extern LibError file_get_sorted_dirents(const char* P_path, DirEnts& dirents);
// called by file_enum for each entry in the directory.
// name doesn't include path!
// return INFO_CB_CONTINUE to continue calling; anything else will cause
// 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, uintptr_t memento, const uintptr_t user);
@ -322,122 +330,8 @@ extern LibError file_validate(const File* f);
extern LibError file_cache_invalidate(const char* fn);
//
// asynchronous IO
//
#include "file_io.h"
// this is a thin wrapper on top of the system AIO calls.
// IOs are carried out exactly as requested - there is no caching or
// alignment done here. rationale: see source.
// again chosen for nice alignment; each user checks if big enough.
const size_t FILE_IO_OPAQUE_SIZE = 28;
struct FileIo
{
const FileProvider_VTbl* type;
u8 opaque[FILE_IO_OPAQUE_SIZE];
};
// queue the IO; it begins after the previous ones (if any) complete.
//
// rationale: this interface is more convenient than implicitly advancing a
// file pointer because archive.cpp often accesses random offsets.
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);
// wait for the given IO to complete. passes back its buffer and size.
extern LibError file_io_wait(FileIo* io, void*& p, size_t& size);
// indicates the IO's buffer is no longer needed and frees that memory.
extern LibError file_io_discard(FileIo* io);
extern LibError file_io_validate(const FileIo* io);
//
// synchronous IO
//
extern size_t file_sector_size;
// called by file_io after a block IO has completed.
// *bytes_processed must be set; file_io will return the sum of these values.
// example: when reading compressed data and decompressing in the callback,
// indicate #bytes decompressed.
// return value: INFO_CB_CONTINUE to continue calling; anything else:
// abort immediately and return that.
// note: in situations where the entire IO is not split into blocks
// (e.g. when reading from cache or not using AIO), this is still called but
// for the entire IO. we do not split into fake blocks because it is
// advantageous (e.g. for decompressors) to have all data at once, if available
// anyway.
typedef LibError (*FileIOCB)(uintptr_t ctx, const void* block, size_t size, size_t* bytes_processed);
typedef const u8* FileIOBuf;
FileIOBuf* const FILE_BUF_TEMP = (FileIOBuf*)1;
const FileIOBuf FILE_BUF_ALLOC = (FileIOBuf)2;
enum FileBufFlags
{
// indicates the buffer will not be freed immediately
// (i.e. before the next buffer alloc) as it normally should.
// this flag serves to suppress a warning and better avoid fragmentation.
// caller sets this when FILE_LONG_LIVED is specified.
//
// also used by file_cache_retrieve because it may have to
// 'reactivate' the buffer (transfer from cache to extant list),
// which requires knowing whether the buffer is long-lived or not.
FB_LONG_LIVED = 1,
// statistics (e.g. # buffer allocs) should not be updated.
// (useful for simulation, e.g. trace_entry_causes_io)
FB_NO_STATS = 2,
// file_cache_retrieve should not update item credit.
// (useful when just looking up buffer given atom_fn)
FB_NO_ACCOUNTING = 4,
// memory will be allocated from the heap, not the (limited) file cache.
// this makes sense for write buffers that are never used again,
// because we avoid having to displace some other cached items.
FB_FROM_HEAP = 8
};
// allocate a new buffer of <size> bytes (possibly more due to internal
// fragmentation). never returns 0.
// <atom_fn>: owner filename (buffer is intended to be used for data from
// this file).
extern FileIOBuf file_buf_alloc(size_t size, const char* atom_fn, uint fb_flags = 0);
// mark <buf> as no longer needed. if its reference count drops to 0,
// it will be removed from the extant list. if it had been added to the
// cache, it remains there until evicted in favor of another buffer.
extern LibError file_buf_free(FileIOBuf buf, uint fb_flags = 0);
// transfer <size> bytes, starting at <ofs>, to/from the given file.
// (read or write access was chosen at file-open time).
//
// if non-NULL, <cb> is called for each block transferred, passing <ctx>.
// it returns how much data was actually transferred, or a negative error
// code (in which case we abort the transfer and return that value).
// the callback mechanism is useful for user progress notification or
// processing data while waiting for the next I/O to complete
// (quasi-parallel, without the complexity of threads).
//
// return number of bytes transferred (see above), or a negative error code.
extern ssize_t file_io(File* f, off_t ofs, size_t size, FileIOBuf* pbuf, FileIOCB cb = 0, uintptr_t ctx = 0);
extern ssize_t file_read_from_cache(const char* atom_fn, off_t ofs, size_t size,
FileIOBuf* pbuf, FileIOCB cb, uintptr_t ctx);
//
// memory mapping

View File

@ -1048,7 +1048,7 @@ FileIOBuf file_buf_alloc(size_t size, const char* atom_fn, uint fb_flags)
{
buf = (FileIOBuf)page_aligned_alloc(size);
if(!buf)
WARN_ERR(ERR_NO_MEM);
WARN_ERR(ERR::NO_MEM);
}
else
buf = cache_alloc(size);
@ -1070,7 +1070,7 @@ LibError file_buf_free(FileIOBuf buf, uint fb_flags)
const bool from_heap = (fb_flags & FB_FROM_HEAP) != 0;
if(!buf)
return INFO_OK;
return INFO::OK;
size_t size; const char* atom_fn;
bool actually_removed = extant_bufs.find_and_remove(buf, size, atom_fn);
@ -1107,7 +1107,7 @@ free_immediately:
stats_buf_free();
trace_notify_free(atom_fn, size);
return INFO_OK;
return INFO::OK;
}
@ -1137,7 +1137,7 @@ LibError file_buf_set_real_fn(FileIOBuf buf, const char* atom_fn)
// note: removing and reinserting would be easiest, but would
// mess up the epoch field.
extant_bufs.replace_owner(buf, atom_fn);
return INFO_OK;
return INFO::OK;
}
@ -1171,7 +1171,7 @@ LibError file_cache_add(FileIOBuf buf, size_t size, const char* atom_fn,
debug_assert(buf);
if(!file_cache_would_add(size, atom_fn, file_flags))
return INFO_SKIPPED;
return INFO::SKIPPED;
// assign cost
uint cost = 1;
@ -1182,7 +1182,7 @@ LibError file_cache_add(FileIOBuf buf, size_t size, const char* atom_fn,
file_cache.add(atom_fn, buf, size, cost);
return INFO_OK;
return INFO::OK;
}
@ -1247,7 +1247,7 @@ LibError file_cache_invalidate(const char* P_fn)
free_padded_buf(cached_buf, size);
}
return INFO_OK;
return INFO::OK;
}

View File

@ -57,7 +57,7 @@ const size_t FILE_BLOCK_SIZE = 32*KiB;
// helper routine used by functions that call back to a FileIOCB.
//
// bytes_processed is 0 if return value != { INFO_OK, INFO_CB_CONTINUE }
// bytes_processed is 0 if return value != { INFO::OK, INFO::CB_CONTINUE }
// note: don't abort if = 0: zip callback may not actually
// output anything if passed very little data.
extern LibError file_io_call_back(const void* block, size_t size,
@ -65,7 +65,7 @@ extern LibError file_io_call_back(const void* block, size_t size,
// retrieve the next (order is unspecified) dir entry matching <filter>.
// return 0 on success, ERR_DIR_END if no matching entry was found,
// return 0 on success, ERR::DIR_END if no matching entry was found,
// or a negative error code on failure.
// filter values:
// - 0: anything;
@ -74,7 +74,7 @@ extern LibError file_io_call_back(const void* block, size_t size,
// - <pattern>: any file whose name matches; ? and * wildcards are allowed.
//
// note that the directory entries are only scanned once; after the
// end is reached (-> ERR_DIR_END returned), no further entries can
// end is reached (-> ERR::DIR_END returned), no further entries can
// be retrieved, even if filter changes (which shouldn't happen - see impl).
//
// rationale: we do not sort directory entries alphabetically here.

View File

@ -31,6 +31,14 @@
#include "file_internal.h"
AT_STARTUP(\
error_setDescription(ERR::IO, "Error during IO");\
error_setDescription(ERR::IO_EOF, "Reading beyond end of file");\
\
error_setEquivalent(ERR::IO, EIO);\
)
//-----------------------------------------------------------------------------
// async I/O
//-----------------------------------------------------------------------------
@ -106,7 +114,7 @@ LibError file_io_issue(File* f, off_t ofs, size_t size, void* p, FileIo* io)
// check params
CHECK_FILE(f);
if(!size || !p || !io)
WARN_RETURN(ERR_INVALID_PARAM);
WARN_RETURN(ERR::INVALID_PARAM);
const bool is_write = (f->flags & FILE_WRITE) != 0;
PosixFileIo* pio = (PosixFileIo*)io;
@ -130,7 +138,7 @@ LibError file_io_issue(File* f, off_t ofs, size_t size, void* p, FileIo* io)
aiocb* cb = aiocb_allocator.alloc();
pio->cb = cb;
if(!cb)
WARN_RETURN(ERR_NO_MEM);
WARN_RETURN(ERR::NO_MEM);
memset(cb, 0, sizeof(*cb));
// send off async read/write request
@ -150,7 +158,7 @@ LibError file_io_issue(File* f, off_t ofs, size_t size, void* p, FileIo* io)
const BlockId disk_pos = block_cache_make_id(f->atom_fn, ofs);
stats_io_check_seek(disk_pos);
return INFO_OK;
return INFO::OK;
}
@ -166,7 +174,7 @@ int file_io_has_completed(FileIo* io)
if(ret == 0)
return 1;
WARN_RETURN(ERR_FAIL);
WARN_RETURN(ERR::FAIL);
}
@ -197,7 +205,7 @@ LibError file_io_wait(FileIo* io, void*& p, size_t& size)
p = (void*)cb->aio_buf; // cast from volatile void*
size = bytes_transferred;
return INFO_OK;
return INFO::OK;
}
@ -207,7 +215,7 @@ LibError file_io_discard(FileIo* io)
memset(pio->cb, 0, sizeof(aiocb)); // prevent further use.
aiocb_allocator.free_(pio->cb);
pio->cb = 0;
return INFO_OK;
return INFO::OK;
}
@ -218,13 +226,13 @@ LibError file_io_validate(const FileIo* io)
// >= 0x100 is not necessarily bogus, but suspicious.
// this also catches negative values.
if((uint)cb->aio_fildes >= 0x100)
WARN_RETURN(ERR_1);
WARN_RETURN(ERR::_1);
if(debug_is_pointer_bogus((void*)cb->aio_buf))
WARN_RETURN(ERR_2);
WARN_RETURN(ERR::_2);
if(cb->aio_lio_opcode != LIO_WRITE && cb->aio_lio_opcode != LIO_READ && cb->aio_lio_opcode != LIO_NOP)
WARN_RETURN(ERR_3);
WARN_RETURN(ERR::_3);
// all other aiocb fields have no invariants we could check.
return INFO_OK;
return INFO::OK;
}
@ -253,7 +261,7 @@ size_t file_sector_size;
// helper routine used by functions that call back to a FileIOCB.
//
// bytes_processed is 0 if return value != { INFO_OK, INFO_CB_CONTINUE }
// bytes_processed is 0 if return value != { INFO::OK, INFO::CB_CONTINUE }
// note: don't abort if = 0: zip callback may not actually
// output anything if passed very little data.
LibError file_io_call_back(const void* block, size_t size,
@ -266,7 +274,7 @@ LibError file_io_call_back(const void* block, size_t size,
stats_cb_finish();
// failed - reset byte count in case callback didn't
if(ret != INFO_OK && ret != INFO_CB_CONTINUE)
if(ret != INFO::OK && ret != INFO::CB_CONTINUE)
bytes_processed = 0;
CHECK_ERR(ret); // user might not have raised a warning; make sure
@ -276,7 +284,7 @@ LibError file_io_call_back(const void* block, size_t size,
else
{
bytes_processed = size;
return INFO_CB_CONTINUE;
return INFO::CB_CONTINUE;
}
}
@ -297,22 +305,22 @@ LibError file_io_get_buf(FileIOBuf* pbuf, size_t size,
// reading into temp buffers - ok.
if(!is_write && temp && cb != 0)
return INFO_OK;
return INFO::OK;
// reading and want buffer allocated.
if(!is_write && alloc)
{
*pbuf = file_buf_alloc(size, atom_fn, fb_flags);
if(!*pbuf) // very unlikely (size totally bogus or cache hosed)
WARN_RETURN(ERR_NO_MEM);
return INFO_OK;
WARN_RETURN(ERR::NO_MEM);
return INFO::OK;
}
// writing from user-specified buffer - ok
if(is_write && user)
return INFO_OK;
return INFO::OK;
WARN_RETURN(ERR_INVALID_PARAM);
WARN_RETURN(ERR::INVALID_PARAM);
}
@ -389,7 +397,7 @@ class IOManager
{
dst_mem = malloc(size);
if(!dst_mem)
WARN_RETURN(ERR_NO_MEM);
WARN_RETURN(ERR::NO_MEM);
dst = dst_mem;
}
else
@ -436,7 +444,7 @@ class IOManager
// but cut off at EOF (necessary to prevent IO error).
const off_t bytes_left = f->size - start_ofs;
if(bytes_left < 0)
WARN_RETURN(ERR_EOF);
WARN_RETURN(ERR::IO_EOF);
size = MIN(size, (size_t)bytes_left);
// and round back up to sector size.
@ -446,7 +454,7 @@ class IOManager
RETURN_ERR(file_io_get_buf(pbuf, size, f->atom_fn, f->flags, cb));
return INFO_OK;
return INFO::OK;
}
void issue(IOSlot& slot)
@ -474,7 +482,7 @@ class IOManager
LibError ret = file_io_issue(f, ofs, issue_size, buf, &slot.io);
// transfer failed - loop will now terminate after
// waiting for all pending transfers to complete.
if(ret != INFO_OK)
if(ret != INFO::OK)
err = ret;
}
@ -529,11 +537,11 @@ class IOManager
void process(IOSlot& slot, void* block, size_t block_size, FileIOCB cb, uintptr_t ctx)
{
if(err == INFO_CB_CONTINUE)
if(err == INFO::CB_CONTINUE)
{
size_t bytes_processed;
err = file_io_call_back(block, block_size, cb, ctx, bytes_processed);
if(err == INFO_CB_CONTINUE || err == INFO_OK)
if(err == INFO::CB_CONTINUE || err == INFO::OK)
total_processed += bytes_processed;
// else: processing failed.
// loop will now terminate after waiting for all
@ -558,7 +566,7 @@ again:
{
// data remaining to transfer, and no error:
// start transferring next block.
if(total_issued < size && err == INFO_CB_CONTINUE && queue.size() < MAX_PENDING_IOS)
if(total_issued < size && err == INFO::CB_CONTINUE && queue.size() < MAX_PENDING_IOS)
{
queue.push_back(IOSlot());
IOSlot& slot = queue.back();
@ -601,7 +609,7 @@ public:
total_issued = 0;
total_transferred = 0;
total_processed = 0;
err = INFO_CB_CONTINUE;
err = INFO::CB_CONTINUE;
}
// now we read the file in 64 KiB chunks, N-buffered.
@ -626,7 +634,7 @@ public:
file_buf_add_padding(org_buf, size, ofs_misalign);
}
if(err != INFO_CB_CONTINUE && err != INFO_OK)
if(err != INFO::CB_CONTINUE && err != INFO::OK)
return (ssize_t)err;
return bytes_transferred;
}

View File

@ -23,9 +23,138 @@
#ifndef FILE_IO_H__
#define FILE_IO_H__
struct FileProvider_VTbl;
struct File;
namespace ERR
{
const LibError IO = -110100;
const LibError IO_EOF = -110101;
}
extern void file_io_init();
extern void file_io_shutdown();
//
// asynchronous IO
//
// this is a thin wrapper on top of the system AIO calls.
// IOs are carried out exactly as requested - there is no caching or
// alignment done here. rationale: see source.
// again chosen for nice alignment; each user checks if big enough.
const size_t FILE_IO_OPAQUE_SIZE = 28;
struct FileIo
{
const FileProvider_VTbl* type;
u8 opaque[FILE_IO_OPAQUE_SIZE];
};
// queue the IO; it begins after the previous ones (if any) complete.
//
// rationale: this interface is more convenient than implicitly advancing a
// file pointer because archive.cpp often accesses random offsets.
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);
// wait for the given IO to complete. passes back its buffer and size.
extern LibError file_io_wait(FileIo* io, void*& p, size_t& size);
// indicates the IO's buffer is no longer needed and frees that memory.
extern LibError file_io_discard(FileIo* io);
extern LibError file_io_validate(const FileIo* io);
//
// synchronous IO
//
extern size_t file_sector_size;
// called by file_io after a block IO has completed.
// *bytes_processed must be set; file_io will return the sum of these values.
// example: when reading compressed data and decompressing in the callback,
// indicate #bytes decompressed.
// return value: INFO::CB_CONTINUE to continue calling; anything else:
// abort immediately and return that.
// note: in situations where the entire IO is not split into blocks
// (e.g. when reading from cache or not using AIO), this is still called but
// for the entire IO. we do not split into fake blocks because it is
// advantageous (e.g. for decompressors) to have all data at once, if available
// anyway.
typedef LibError (*FileIOCB)(uintptr_t ctx, const void* block, size_t size, size_t* bytes_processed);
typedef const u8* FileIOBuf;
FileIOBuf* const FILE_BUF_TEMP = (FileIOBuf*)1;
const FileIOBuf FILE_BUF_ALLOC = (FileIOBuf)2;
enum FileBufFlags
{
// indicates the buffer will not be freed immediately
// (i.e. before the next buffer alloc) as it normally should.
// this flag serves to suppress a warning and better avoid fragmentation.
// caller sets this when FILE_LONG_LIVED is specified.
//
// also used by file_cache_retrieve because it may have to
// 'reactivate' the buffer (transfer from cache to extant list),
// which requires knowing whether the buffer is long-lived or not.
FB_LONG_LIVED = 1,
// statistics (e.g. # buffer allocs) should not be updated.
// (useful for simulation, e.g. trace_entry_causes_io)
FB_NO_STATS = 2,
// file_cache_retrieve should not update item credit.
// (useful when just looking up buffer given atom_fn)
FB_NO_ACCOUNTING = 4,
// memory will be allocated from the heap, not the (limited) file cache.
// this makes sense for write buffers that are never used again,
// because we avoid having to displace some other cached items.
FB_FROM_HEAP = 8
};
// allocate a new buffer of <size> bytes (possibly more due to internal
// fragmentation). never returns 0.
// <atom_fn>: owner filename (buffer is intended to be used for data from
// this file).
extern FileIOBuf file_buf_alloc(size_t size, const char* atom_fn, uint fb_flags = 0);
// mark <buf> as no longer needed. if its reference count drops to 0,
// it will be removed from the extant list. if it had been added to the
// cache, it remains there until evicted in favor of another buffer.
extern LibError file_buf_free(FileIOBuf buf, uint fb_flags = 0);
// transfer <size> bytes, starting at <ofs>, to/from the given file.
// (read or write access was chosen at file-open time).
//
// if non-NULL, <cb> is called for each block transferred, passing <ctx>.
// it returns how much data was actually transferred, or a negative error
// code (in which case we abort the transfer and return that value).
// the callback mechanism is useful for user progress notification or
// processing data while waiting for the next I/O to complete
// (quasi-parallel, without the complexity of threads).
//
// return number of bytes transferred (see above), or a negative error code.
extern ssize_t file_io(File* f, off_t ofs, size_t size, FileIOBuf* pbuf, FileIOCB cb = 0, uintptr_t ctx = 0);
extern ssize_t file_read_from_cache(const char* atom_fn, off_t ofs, size_t size,
FileIOBuf* pbuf, FileIOCB cb, uintptr_t ctx);
extern LibError file_io_get_buf(FileIOBuf* pbuf, size_t size,
const char* atom_fn, uint file_flags, FileIOCB cb);

View File

@ -22,7 +22,7 @@ LibError file_get_sorted_dirents(const char* P_path, DirEnts& dirents)
for(;;)
{
LibError ret = dir_next_ent(&d, &ent);
if(ret == ERR_DIR_END)
if(ret == ERR::DIR_END)
break;
RETURN_ERR(ret);
@ -33,7 +33,7 @@ LibError file_get_sorted_dirents(const char* P_path, DirEnts& dirents)
std::sort(dirents.begin(), dirents.end(), dirent_less);
(void)dir_close(&d);
return INFO_OK;
return INFO::OK;
}
@ -55,8 +55,8 @@ LibError file_get_sorted_dirents(const char* P_path, DirEnts& dirents)
// of converting from/to native path (we just give 'em the dirent name).
LibError file_enum(const char* P_path, const FileCB cb, const uintptr_t user)
{
LibError stat_err = INFO_OK; // first error encountered by stat()
LibError cb_err = INFO_OK; // first error returned by cb
LibError stat_err = INFO::OK; // first error encountered by stat()
LibError cb_err = INFO::OK; // first error returned by cb
DirEnts dirents;
RETURN_ERR(file_get_sorted_dirents(P_path, dirents));
@ -75,14 +75,14 @@ LibError file_enum(const char* P_path, const FileCB cb, const uintptr_t user)
s.st_size = dirent.size;
s.st_mtime = dirent.mtime;
LibError ret = cb(dirent.name, &s, memento, user);
if(ret != INFO_CB_CONTINUE)
if(ret != INFO::CB_CONTINUE)
{
cb_err = ret; // first error (since we now abort)
break;
}
}
if(cb_err != INFO_OK)
if(cb_err != INFO::OK)
return cb_err;
return stat_err;
}
@ -90,7 +90,7 @@ LibError file_enum(const char* P_path, const FileCB cb, const uintptr_t user)
// retrieve the next (order is unspecified) dir entry matching <filter>.
// return 0 on success, ERR_DIR_END if no matching entry was found,
// return 0 on success, ERR::DIR_END if no matching entry was found,
// or a negative error code on failure.
// filter values:
// - 0: anything;
@ -99,7 +99,7 @@ LibError file_enum(const char* P_path, const FileCB cb, const uintptr_t user)
// - <pattern>: any file whose name matches; ? and * wildcards are allowed.
//
// note that the directory entries are only scanned once; after the
// end is reached (-> ERR_DIR_END returned), no further entries can
// end is reached (-> ERR::DIR_END returned), no further entries can
// be retrieved, even if filter changes (which shouldn't happen - see impl).
//
// rationale: we do not sort directory entries alphabetically here.
@ -154,7 +154,7 @@ LibError dir_filtered_next_ent(DirIterator* di, DirEnt* ent, const char* filter)
}
}
return INFO_OK;
return INFO::OK;
}
@ -234,7 +234,7 @@ LibError vfs_dir_enum(const char* start_path, uint flags, const char* user_filte
}
while(!dir_queue.empty());
return INFO_OK;
return INFO::OK;
}
@ -271,7 +271,7 @@ void next_numbered_filename(const char* fn_fmt,
Handle hd = vfs_dir_open(dir);
if(hd > 0)
{
while(vfs_dir_next_ent(hd, &ent, 0) == INFO_OK)
while(vfs_dir_next_ent(hd, &ent, 0) == INFO::OK)
{
if(!DIRENT_IS_DIR(&ent) && sscanf(ent.name, name_fmt, &num) == 1)
max_num = MAX(num, max_num);
@ -282,9 +282,9 @@ void next_numbered_filename(const char* fn_fmt,
else
{
DirIterator it;
if(dir_open(dir, &it) == INFO_OK)
if(dir_open(dir, &it) == INFO::OK)
{
while(dir_next_ent(&it, &ent) == INFO_OK)
while(dir_next_ent(&it, &ent) == INFO::OK)
if(!DIRENT_IS_DIR(&ent) && sscanf(ent.name, name_fmt, &num) == 1)
max_num = MAX(num, max_num);
(void)dir_close(&it);

View File

@ -30,6 +30,11 @@
#include "lib/allocators.h"
AT_STARTUP(\
error_setDescription(ERR::ROOT_DIR_ALREADY_SET, "Attempting to set FS root dir more than once");\
)
// path types:
// p_*: posix (e.g. mount object name or for open())
// v_*: vfs (e.g. mount point)
@ -45,7 +50,6 @@
// file ::= name
// name ::= [^/]
enum Conversion
{
TO_NATIVE,
@ -69,7 +73,7 @@ static LibError convert_path(char* dst, const char* src, Conversion conv = TO_NA
{
len++;
if(len >= PATH_MAX)
WARN_RETURN(ERR_PATH_LENGTH);
WARN_RETURN(ERR::PATH_LENGTH);
char c = *s++;
@ -80,7 +84,7 @@ static LibError convert_path(char* dst, const char* src, Conversion conv = TO_NA
// end of string - done
if(c == '\0')
return INFO_OK;
return INFO::OK;
}
}
@ -129,7 +133,7 @@ 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)
WARN_RETURN(ERR_TNODE_NOT_FOUND);
WARN_RETURN(ERR::TNODE_NOT_FOUND);
return convert_path(path, n_full_path+n_root_dir_len, TO_PORTABLE);
}
@ -156,7 +160,7 @@ LibError file_set_root_dir(const char* argv0, const char* rel_path)
// are likely bogus.
static bool already_attempted;
if(already_attempted)
WARN_RETURN(ERR_ROOT_DIR_ALREADY_SET);
WARN_RETURN(ERR::ROOT_DIR_ALREADY_SET);
already_attempted = true;
// get full path to executable
@ -185,7 +189,7 @@ LibError 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 INFO_OK;
return INFO::OK;
}
@ -233,7 +237,7 @@ const char* file_make_unique_fn_copy(const char* P_fn)
unique_fn = (const char*)pool_alloc(&atom_pool, fn_len+1);
if(!unique_fn)
{
DEBUG_WARN_ERR(ERR_NO_MEM);
DEBUG_WARN_ERR(ERR::NO_MEM);
return 0;
}
memcpy2((void*)unique_fn, P_fn, fn_len);

View File

@ -25,6 +25,13 @@
#include "lib/lib.h"
namespace ERR
{
const LibError ROOT_DIR_ALREADY_SET = -110200;
}
#define VFS_PATH_IS_DIR(path) (*path == '\0' || path[strlen(path)-1] == '/')
struct NextNumberedFilenameInfo

View File

@ -28,6 +28,12 @@
#include "lib/sysdep/cpu.h"
#include "file_internal.h"
AT_STARTUP(\
error_setDescription(ERR::TRACE_EMPTY, "No valid entries in trace");\
)
static uintptr_t trace_initialized; // set via CAS
static Pool trace_pool;
@ -70,20 +76,20 @@ static LibError trace_add(TraceOp op, const char* P_fn, size_t size,
{
trace_init();
if(!trace_enabled)
return INFO_OK;
return INFO::OK;
if(timestamp == 0.0)
timestamp = get_time();
TraceEntry* t = (TraceEntry*)pool_alloc(&trace_pool, 0);
if(!t)
return ERR_LIMIT; // NOWARN
return ERR::LIMIT; // NOWARN
t->timestamp = timestamp;
t->atom_fn = file_make_unique_fn_copy(P_fn);
t->size = size;
t->op = op;
t->flags = flags;
return INFO_OK;
return INFO::OK;
}
static void trace_get_raw_ents(const TraceEntry*& ents, size_t& num_ents)
@ -238,7 +244,7 @@ static void write_entry(FILE* f, const TraceEntry* ent)
LibError trace_write_to_file(const char* trace_filename)
{
if(!trace_enabled)
return INFO_SKIPPED;
return INFO::SKIPPED;
char N_fn[PATH_MAX];
RETURN_ERR(file_make_full_native_path(trace_filename, N_fn));
@ -247,7 +253,7 @@ LibError trace_write_to_file(const char* trace_filename)
// several trace runs per file.
FILE* f = fopen(N_fn, "at");
if(!f)
WARN_RETURN(ERR_FILE_ACCESS);
WARN_RETURN(ERR::FILE_ACCESS);
write_entry(f, &delimiter_entry);
@ -259,7 +265,7 @@ LibError trace_write_to_file(const char* trace_filename)
write_entry(f, ent);
(void)fclose(f);
return INFO_OK;
return INFO::OK;
}
@ -271,7 +277,7 @@ LibError trace_read_from_file(const char* trace_filename, Trace* t)
RETURN_ERR(file_make_full_native_path(trace_filename, N_fn));
FILE* f = fopen(N_fn, "rt");
if(!f)
WARN_RETURN(ERR_TNODE_NOT_FOUND);
WARN_RETURN(ERR::TNODE_NOT_FOUND);
// we use trace_add, which is the same mechanism called by trace_notify*;
// therefore, tracing needs to be enabled.
@ -306,7 +312,7 @@ LibError trace_read_from_file(const char* trace_filename, Trace* t)
// storage in trace pool exhausted. must abort to avoid later
// adding delimiters for items that weren't actually stored
// into the pool.
if(ret == ERR_LIMIT)
if(ret == ERR::LIMIT)
break;
}
}
@ -320,9 +326,9 @@ LibError trace_read_from_file(const char* trace_filename, Trace* t)
trace_enabled = false;
if(t->total_ents == 0)
WARN_RETURN(ERR_TRACE_EMPTY);
WARN_RETURN(ERR::TRACE_EMPTY);
return INFO_OK;
return INFO::OK;
}
@ -346,7 +352,7 @@ void trace_gen_random(size_t num_entries)
struct stat s;
LibError ret = vfs_stat(atom_fn, &s);
// ought to apply due to vfs_exists above.
debug_assert(ret == INFO_OK && S_ISREG(s.st_mode));
debug_assert(ret == INFO::OK && S_ISREG(s.st_mode));
size = s.st_size;
break;
@ -402,7 +408,7 @@ bool trace_entry_causes_io(const TraceEntry* ent)
// since TO_FREE below uses the cache to find out which
// buffer was allocated for atom_fn, we have to free it manually.
// see note above.
if(ret == INFO_SKIPPED)
if(ret == INFO::SKIPPED)
(void)file_buf_free(buf, fb_flags);
return true;
}
@ -474,6 +480,6 @@ LibError trace_run(const char* trace_filename, uint flags)
trace_clear();
return INFO_OK;
return INFO::OK;
}

View File

@ -24,6 +24,11 @@
#ifndef TRACE_H__
#define TRACE_H__
namespace ERR
{
const LibError TRACE_EMPTY = -110500;
}
extern void trace_enable(bool want_enabled);
extern void trace_shutdown();

View File

@ -119,15 +119,15 @@ static LibError VDir_reload(VDir* vd, const char* V_dir_path, Handle UNUSED(hvd)
RETURN_ERR(xdir_open(V_dir_path, &vd->di));
vd->di_valid = 1;
return INFO_OK;
return INFO::OK;
}
static LibError VDir_validate(const VDir* vd)
{
// note: <di> is mostly opaque and cannot be validated.
if(vd->di.filter && !isprint(vd->di.filter[0]))
WARN_RETURN(ERR_1);
return INFO_OK;
WARN_RETURN(ERR::_1);
return INFO::OK;
}
static LibError VDir_to_string(const VDir* vd, char* buf)
@ -138,7 +138,7 @@ static LibError VDir_to_string(const VDir* vd, char* buf)
if(!filter)
filter = "*";
snprintf(buf, H_STRING_LEN, "(\"%s\")", filter);
return INFO_OK;
return INFO::OK;
}
@ -160,7 +160,7 @@ 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,
// return 0 on success, ERR::DIR_END if no matching entry was found,
// or a negative error code on failure.
// filter values:
// - 0: anything;
@ -169,7 +169,7 @@ LibError vfs_dir_close(Handle& hd)
// - <pattern>: any file whose name matches; ? and * wildcards are allowed.
//
// note that the directory entries are only scanned once; after the
// end is reached (-> ERR_DIR_END returned), no further entries can
// end is reached (-> ERR::DIR_END returned), no further entries can
// be retrieved, even if filter changes (which shouldn't happen - see impl).
//
// rationale: we do not sort directory entries alphabetically here.
@ -275,7 +275,7 @@ static LibError VFile_reload(VFile* vf, const char* V_path, Handle)
// 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(xfile_is_open(&vf->f))
return INFO_OK;
return INFO::OK;
TFile* tf;
uint lf = (flags & FILE_WRITE)? LF_CREATE_MISSING : 0;
@ -300,20 +300,20 @@ static LibError VFile_reload(VFile* vf, const char* V_path, Handle)
vf->is_valid = 1;
vf->tf = tf;
return INFO_OK;
return INFO::OK;
}
static LibError VFile_validate(const VFile* vf)
{
// <ofs> doesn't have any invariant we can check.
RETURN_ERR(xfile_validate(&vf->f));
return INFO_OK;
return INFO::OK;
}
static LibError VFile_to_string(const VFile* UNUSED(vf), char* buf)
{
strcpy(buf, ""); // safe
return INFO_OK;
return INFO::OK;
}
@ -418,8 +418,8 @@ LibError vfs_load(const char* V_fn, FileIOBuf& buf, size_t& size,
// we don't care if the cb has "had enough" or whether it would
// accept more data - this is all it gets and we need to
// translate return value to avoid confusing callers.
if(ret == INFO_CB_CONTINUE)
ret = INFO_OK;
if(ret == INFO::CB_CONTINUE)
ret = INFO::OK;
size = actual_size;
return ret;
}
@ -448,7 +448,7 @@ LibError vfs_load(const char* V_fn, FileIOBuf& buf, size_t& size,
stats_cache(CR_MISS, size, atom_fn);
(void)vfs_close(hf);
return INFO_OK;
return INFO::OK;
}
@ -519,17 +519,17 @@ static LibError VIo_reload(VIo* vio, const char* UNUSED(fn), Handle UNUSED(h))
static LibError VIo_validate(const VIo* vio)
{
if(vio->hf < 0)
WARN_RETURN(ERR_21);
WARN_RETURN(ERR::_21);
// <size> doesn't have any invariant we can check.
if(debug_is_pointer_bogus(vio->buf))
WARN_RETURN(ERR_22);
WARN_RETURN(ERR::_22);
return xfile_io_validate(&vio->io);
}
static LibError VIo_to_string(const VIo* vio, char* buf)
{
snprintf(buf, H_STRING_LEN, "buf=%p size=%d", vio->buf, vio->size);
return INFO_OK;
return INFO::OK;
}
@ -621,7 +621,7 @@ static LibError reload_without_rebuild(const char* fn)
RETURN_ERR(h_reload(fn));
return INFO_OK;
return INFO::OK;
}
@ -696,7 +696,7 @@ LibError vfs_reload_changed_files()
// get next notification
char N_path[PATH_MAX];
LibError ret = dir_get_changed_file(N_path);
if(ret == ERR_AGAIN) // none available; done.
if(ret == ERR::AGAIN) // none available; done.
break;
RETURN_ERR(ret);
@ -726,7 +726,7 @@ LibError vfs_reload_changed_files()
for(uint i = 0; i < num_pending; i++)
RETURN_ERR(reload_without_rebuild(pending_reloads[i]));
return INFO_OK;
return INFO::OK;
}

View File

@ -300,7 +300,7 @@ extern Handle vfs_dir_open(const char* V_dir_path);
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,
// return 0 on success, ERR::DIR_END if no matching entry was found,
// or a negative error code on failure.
// filter values:
// - 0: anything;
@ -309,7 +309,7 @@ extern LibError vfs_dir_close(Handle& hd);
// - <pattern>: any file whose name matches; ? and * wildcards are allowed.
//
// note that the directory entries are only scanned once; after the
// end is reached (-> ERR_DIR_END returned), no further entries can
// end is reached (-> ERR::DIR_END returned), no further entries can
// be retrieved, even if filter changes (which shouldn't happen - see impl).
//
// see also the definition of DirEnt in file.h.

View File

@ -33,6 +33,7 @@
#include <algorithm>
#include <ctime>
// location of a file: either archive or a real directory.
// not many instances => don't worry about efficiency.
struct Mount
@ -184,7 +185,7 @@ LibError mount_realpath(const char* V_path, const Mount* m, char* P_real_path)
if(P_len != 0 && P_real_path[P_len-1] == '/')
P_real_path[P_len-1] = '\0';
return INFO_OK;
return INFO::OK;
}
@ -264,7 +265,7 @@ static LibError afile_cb(const char* atom_fn, const struct stat* s, uintptr_t me
WARN_ERR(tree_add_file(td, name, m, s->st_size, s->st_mtime, memento));
vfs_opt_notify_non_loose_file(atom_fn);
return INFO_CB_CONTINUE;
return INFO::CB_CONTINUE;
}
@ -278,7 +279,7 @@ static bool archive_less(Handle hza1, Handle hza2)
typedef std::vector<Handle> Archives;
typedef Archives::const_iterator ArchiveCIt;
// return value is INFO_OK iff archives != 0 and the file should not be
// return value is INFO::OK iff archives != 0 and the file should not be
// added to VFS (e.g. because it is an archive).
static LibError enqueue_archive(const char* name, const char* P_archive_dir, Archives* archives)
{
@ -286,7 +287,7 @@ static LibError enqueue_archive(const char* name, const char* P_archive_dir, Arc
// 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;
return INFO::SKIPPED;
// get complete path for archive_open.
// this doesn't (need to) work for subdirectories of the mounted td!
@ -301,30 +302,30 @@ static LibError enqueue_archive(const char* name, const char* P_archive_dir, Arc
// .. special case: <name> is recognizable as a Zip file but is
// invalid and can't be opened. avoid adding it to
// archive list and/or VFS.
if(archive == ERR_CORRUPTED)
if(archive == ERR::CORRUPTED)
goto do_not_add_to_VFS_or_list;
RETURN_ERR(archive);
archives->push_back(archive);
// avoid also adding the archive file itself to VFS.
// (when caller sees INFO_OK, they skip the file)
// (when caller sees INFO::OK, they skip the file)
do_not_add_to_VFS_or_list:
return INFO_OK;
return INFO::OK;
}
static LibError mount_archive(TDir* td, const Mount& m)
{
ZipCBParams params(td, &m);
archive_enum(m.archive, afile_cb, (uintptr_t)&params);
return INFO_OK;
return INFO::OK;
}
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 INFO_OK;
return INFO::OK;
std::sort(archives->begin(), archives->end(), archive_less);
@ -339,7 +340,7 @@ static LibError mount_archives(TDir* td, Archives* archives, const Mount* mount)
mount_archive(td, m);
}
return INFO_OK;
return INFO::OK;
}
@ -373,7 +374,7 @@ static LibError enqueue_dir(TDir* parent_td, const char* name,
{
// caller doesn't want us to enqueue subdirectories; bail.
if(!dir_queue)
return INFO_OK;
return INFO::OK;
// skip versioning system directories - this avoids cluttering the
// VFS with hundreds of irrelevant files.
@ -381,7 +382,7 @@ static LibError 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 INFO_OK;
return INFO::OK;
// prepend parent path to get complete pathname.
char P_path[PATH_MAX];
@ -392,7 +393,7 @@ static LibError 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, P_path));
return INFO_OK;
return INFO::OK;
}
@ -426,10 +427,10 @@ static LibError add_ent(TDir* td, DirEnt* ent, const char* P_parent_path, const
// 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) == INFO_OK)
if(enqueue_archive(name, m->P_name.c_str(), archives) == INFO::OK)
// return value indicates this file shouldn't be added to VFS
// (see enqueue_archive)
return INFO_OK;
return INFO::OK;
// notify archive builder that this file could be archived but
// currently isn't; if there are too many of these, archive will be
@ -468,7 +469,7 @@ static LibError 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 != INFO_OK)
if(err != INFO::OK)
break;
err = add_ent(td, &ent, P_path, m, dir_queue, archives);
@ -476,7 +477,7 @@ static LibError populate_dir(TDir* td, const char* P_path, const Mount* m,
}
WARN_ERR(dir_close(&d));
return INFO_OK;
return INFO::OK;
}
@ -494,7 +495,7 @@ static LibError populate_dir(TDir* td, const char* P_path, const Mount* m,
// every single file to see if it's an archive (slow!).
static LibError mount_dir_tree(TDir* td, const Mount& m)
{
LibError err = INFO_OK;
LibError err = INFO::OK;
// add_ent fills these queues with dirs/archives if the corresponding
// flags are set.
@ -517,7 +518,7 @@ static LibError mount_dir_tree(TDir* td, const Mount& m)
const char* P_path = dir_queue.front().path.c_str();
LibError ret = populate_dir(td, P_path, &m, pdir_queue, parchives, m.flags);
if(err == INFO_OK)
if(err == INFO::OK)
err = ret;
// prevent searching for archives in subdirectories (slow!). this
@ -532,7 +533,7 @@ static LibError 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 INFO_OK;
return INFO::OK;
}
@ -605,7 +606,7 @@ static LibError remount(const Mount& m)
case MT_FILE:
return mount_dir_tree(td, m);
default:
WARN_RETURN(ERR_INVALID_MOUNT_TYPE);
WARN_RETURN(ERR::MOUNT_INVALID_TYPE);
}
}
@ -646,14 +647,14 @@ LibError vfs_mount(const char* V_mount_point, const char* P_real_path, uint flag
for(MountIt it = mounts.begin(); it != mounts.end(); ++it)
{
if(path_is_subpath(P_real_path, it->P_name.c_str()))
WARN_RETURN(ERR_ALREADY_MOUNTED);
WARN_RETURN(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, "."))
WARN_RETURN(ERR_PATH_NON_CANONICAL);
WARN_RETURN(ERR::PATH_NON_CANONICAL);
// (count this as "init" to obviate a separate timer)
stats_vfs_init_start();
@ -674,7 +675,7 @@ LibError mount_rebuild()
{
tree_clear();
remount_all();
return INFO_OK;
return INFO::OK;
}
@ -712,7 +713,7 @@ LibError vfs_unmount(const char* P_name)
std::bind2nd(Mount::equal_to(), P_name));
// none were removed - need to complain so that the caller notices.
if(last == end)
WARN_RETURN(ERR_TNODE_NOT_FOUND);
WARN_RETURN(ERR::TNODE_NOT_FOUND);
// trim list and actually remove 'invalidated' entries.
mounts.erase(last, end);
@ -738,11 +739,11 @@ LibError mount_make_vfs_path(const char* P_path, char* V_path)
const char* remove = m.P_name.c_str();
const char* replace = m.V_mount_point.c_str();
if(path_replace(V_path, P_path, remove, replace) == INFO_OK)
return INFO_OK;
if(path_replace(V_path, P_path, remove, replace) == INFO::OK)
return INFO::OK;
}
WARN_RETURN(ERR_TNODE_NOT_FOUND);
WARN_RETURN(ERR::TNODE_NOT_FOUND);
}
@ -799,11 +800,11 @@ LibError vfs_set_write_target(const char* P_target_dir)
if(!strcmp(m.P_name.c_str(), P_target_dir))
{
write_target = &m;
return INFO_OK;
return INFO::OK;
}
}
WARN_RETURN(ERR_NOT_MOUNTED);
WARN_RETURN(ERR::NOT_MOUNTED);
}
@ -812,7 +813,7 @@ LibError vfs_set_write_target(const char* P_target_dir)
LibError set_mount_to_write_target(TFile* tf)
{
if(!write_target)
WARN_RETURN(ERR_NOT_MOUNTED);
WARN_RETURN(ERR::NOT_MOUNTED);
tfile_set_mount(tf, write_target);
@ -822,7 +823,7 @@ LibError set_mount_to_write_target(TFile* tf)
// opened for writing, which will change these values anyway.
tree_update_file(tf, 0, 0);
return INFO_OK;
return INFO::OK;
}
@ -866,12 +867,12 @@ LibError mount_attach_real_dir(RealDir* rd, const char* P_path, const Mount* m,
// note: do not cause this function to return an error if
// something goes wrong - this step is basically optional.
char N_path[PATH_MAX];
if(file_make_full_native_path(P_path, N_path) == INFO_OK)
if(file_make_full_native_path(P_path, N_path) == INFO::OK)
(void)dir_add_watch(N_path, &rd->watch);
}
#endif
return INFO_OK;
return INFO::OK;
}
@ -892,7 +893,7 @@ LibError mount_create_real_dir(const char* V_path, const Mount* m)
debug_assert(VFS_PATH_IS_DIR(V_path));
if(!m || m == MULTIPLE_MOUNTINGS || m->type != MT_FILE)
return INFO_OK;
return INFO::OK;
char P_path[PATH_MAX];
RETURN_ERR(mount_realpath(V_path, m, P_path));
@ -905,5 +906,5 @@ LibError mount_populate(TDir* td, RealDir* rd)
{
UNUSED2(td);
UNUSED2(rd);
return INFO_OK;
return INFO::OK;
}

View File

@ -30,11 +30,20 @@ struct Mount; // must come before vfs_tree.h
#include "zip.h"
#include "vfs_tree.h"
namespace ERR
{
const LibError ALREADY_MOUNTED = -110700;
const LibError NOT_MOUNTED = -110701;
const LibError MOUNT_INVALID_TYPE = -110702;
}
extern void mount_init();
extern void mount_shutdown();
// If it was possible to forward-declare enums in gcc, this one wouldn't be in
// If it were possible to forward-declare enums in GCC, this one wouldn't be in
// the header. Don't use.
enum MountType
{
@ -49,7 +58,7 @@ enum MountType
//
// accessor routines that obviate the need to access Mount fields directly:
// accessors that obviate the need to access Mount fields directly:
//
extern bool mount_is_archivable(const Mount* m);

View File

@ -170,7 +170,7 @@ public:
// note: use this instead of resize because FileNode doesn't have
// a default ctor. NB: this is how resize is implemented anyway.
file_nodes.erase(file_nodes.begin() + MAX_IDS, file_nodes.end());
WARN_ERR(ERR_LIMIT);
WARN_ERR(ERR::LIMIT);
}
}
};
@ -294,7 +294,7 @@ class ConnectionBuilder
// note: this happens when trace contains by now
// deleted or unarchivable files.
TFile* tf;
if(tree_lookup(te->atom_fn, &tf) == INFO_OK)
if(tree_lookup(te->atom_fn, &tf) == INFO::OK)
if(is_archivable(tf))
add_connection(connections, te->atom_fn);
}
@ -320,7 +320,7 @@ public:
add_connections_from_runs(t, connections);
return INFO_OK;
return INFO::OK;
}
};
@ -578,13 +578,13 @@ static LibError vfs_opt_init(const char* trace_filename, const char* archive_fn_
// bail if we shouldn't rebuild the archive.
if(!force_build && !should_rebuild_main_archive(trace_filename, existing_archives))
return INFO_SKIPPED;
return INFO::SKIPPED;
// build 'graph' (nodes only) of all files that must be added.
FileNodes file_nodes;
FileGatherer gatherer(file_nodes);
if(file_nodes.empty())
WARN_RETURN(ERR_DIR_END);
WARN_RETURN(ERR::DIR_END);
// scan nodes and add them to filename->FileId mapping.
id_mgr.init(&file_nodes);
@ -602,14 +602,14 @@ static LibError vfs_opt_init(const char* trace_filename, const char* archive_fn_
Filenames V_fns = &fn_vector[0];
RETURN_ERR(archive_build_init(archive_fn, V_fns, &ab));
return INFO_OK;
return INFO::OK;
}
static int vfs_opt_continue()
{
int ret = archive_build_continue(&ab);
if(ret == INFO_OK)
if(ret == INFO::OK)
{
// do NOT delete source files! some apps might want to
// keep them (e.g. for source control), or name them differently.
@ -659,11 +659,11 @@ static bool should_build_mini_archive(const char* UNUSED(mini_archive_fn_fmt))
static LibError build_mini_archive(const char* mini_archive_fn_fmt)
{
if(!should_build_mini_archive(mini_archive_fn_fmt))
return INFO_SKIPPED;
return INFO::SKIPPED;
Filenames V_fns = (Filenames)malloc((loose_files.size()+1) * sizeof(const char*));
if(!V_fns)
WARN_RETURN(ERR_NO_MEM);
WARN_RETURN(ERR::NO_MEM);
std::copy(loose_files.begin(), loose_files.end(), &V_fns[0]);
V_fns[loose_files.size()] = 0; // terminator
@ -674,7 +674,7 @@ static LibError build_mini_archive(const char* mini_archive_fn_fmt)
next_numbered_filename(mini_archive_fn_fmt, &nfi, mini_archive_fn, use_vfs);
RETURN_ERR(archive_build(mini_archive_fn, V_fns));
return INFO_OK;
return INFO::OK;
}
@ -697,11 +697,11 @@ int vfs_opt_auto_build(const char* trace_filename,
const char* archive_fn_fmt, const char* mini_archive_fn_fmt, bool force_build)
{
if(state == NOP)
return INFO_ALL_COMPLETE;
return INFO::ALL_COMPLETE;
if(state == DECIDE_IF_BUILD)
{
if(vfs_opt_init(trace_filename, archive_fn_fmt, force_build) != INFO_SKIPPED)
if(vfs_opt_init(trace_filename, archive_fn_fmt, force_build) != INFO::SKIPPED)
state = IN_PROGRESS;
else
{
@ -709,7 +709,7 @@ int vfs_opt_auto_build(const char* trace_filename,
RETURN_ERR(build_mini_archive(mini_archive_fn_fmt));
state = NOP;
return INFO_OK; // "finished"
return INFO::OK; // "finished"
}
}
@ -717,7 +717,7 @@ int vfs_opt_auto_build(const char* trace_filename,
{
int ret = vfs_opt_continue();
// just finished
if(ret == INFO_OK)
if(ret == INFO::OK)
state = NOP;
return ret;
}
@ -731,7 +731,7 @@ LibError vfs_opt_rebuild_main_archive(const char* trace_filename, const char* ar
{
int ret = vfs_opt_auto_build(trace_filename, archive_fn_fmt, 0, true);
RETURN_ERR(ret);
if(ret == INFO_OK)
return INFO_OK;
if(ret == INFO::OK)
return INFO::OK;
}
}

View File

@ -51,7 +51,7 @@ LibError file_open_vfs(const char* V_path, uint flags, TFile* tf,
RETURN_ERR(file_open(N_path, flags|FILE_DONT_SET_FN, f));
// file_open didn't set fc.atom_fn due to FILE_DONT_SET_FN.
f->atom_fn = file_make_unique_fn_copy(V_path);
return INFO_OK;
return INFO::OK;
}
static const FileProvider_VTbl archive_vtbl =
@ -96,10 +96,10 @@ static const FileProvider_VTbl tree_vtbl =
static LibError vtbl_validate(const FileProvider_VTbl* vtbl)
{
if(!vtbl)
WARN_RETURN(ERR_INVALID_PARAM);
WARN_RETURN(ERR::INVALID_PARAM);
if(vtbl->magic != vtbl_magic)
WARN_RETURN(ERR_CORRUPTED);
return INFO_OK;
WARN_RETURN(ERR::CORRUPTED);
return INFO::OK;
}
#define CHECK_VTBL(type) RETURN_ERR(vtbl_validate(type))
@ -163,7 +163,7 @@ const FileProvider_VTbl* vtbl = (c == 'F')? &file_vtbl : &archive_vtbl;
// note: don't assign these unless we succeed to avoid the
// false impression that all is well.
f->type = vtbl;
return INFO_OK;
return INFO::OK;
}
LibError xfile_close(File* f)
@ -173,7 +173,7 @@ LibError xfile_close(File* f)
// the dtor after reload fails.
// note: this takes care of checking the vtbl.
if(!xfile_is_open(f))
return INFO_OK;
return INFO::OK;
LibError ret = f->type->file_close(f);
f->type = 0;
return ret;

View File

@ -34,6 +34,14 @@
#include "file_internal.h"
AT_STARTUP(\
error_setDescription(ERR::TNODE_NOT_FOUND, "File/directory not found");\
error_setDescription(ERR::TNODE_WRONG_TYPE, "Using a directory as file or vice versa");\
\
error_setEquivalent(ERR::TNODE_NOT_FOUND, ENOENT);\
)
// we add/cancel directory watches from the VFS mount code for convenience -
// it iterates through all subdirectories anyway (*) and provides storage for
// a key to identify the watch (obviates separate TDir -> watch mapping).
@ -253,7 +261,7 @@ RealDir rd; // HACK; removeme
// pool, but that "can't happen" and is OK because pool is big enough.
void* mem = node_alloc();
if(!mem)
WARN_RETURN(ERR_NO_MEM);
WARN_RETURN(ERR::NO_MEM);
TNode* node;
#include "lib/nommgr.h"
if(type == NT_FILE)
@ -265,7 +273,7 @@ RealDir rd; // HACK; removeme
children.insert(name, node);
*pnode = node;
return INFO_OK;
return INFO::OK;
}
LibError find_and_add(const char* name, TNodeType type, TNode** pnode, const Mount* m = 0)
@ -275,10 +283,10 @@ RealDir rd; // HACK; removeme
{
// wrong type (dir vs. file)
if(node->type != type)
WARN_RETURN(ERR_TNODE_WRONG_TYPE);
WARN_RETURN(ERR::TNODE_WRONG_TYPE);
*pnode = node;
return INFO_ALREADY_EXISTS;
return INFO::ALREADY_EXISTS;
}
return add(name, type, pnode, m);
@ -426,15 +434,15 @@ static LibError lookup_cb(const char* component, bool is_dir, void* ctx)
else
// complaining is left to callers; vfs_exists must be
// able to fail quietly.
return ERR_TNODE_NOT_FOUND; // NOWARN
return ERR::TNODE_NOT_FOUND; // NOWARN
}
if(p->node->type != type)
WARN_RETURN(ERR_TNODE_WRONG_TYPE);
WARN_RETURN(ERR::TNODE_WRONG_TYPE);
if(is_dir)
p->td = (TDir*)p->node;
return INFO_CB_CONTINUE;
return INFO::CB_CONTINUE;
}
static LibError lookup(TDir* td, const char* path, uint flags, TNode** pnode)
@ -447,7 +455,7 @@ static LibError lookup(TDir* td, const char* path, uint flags, TNode** pnode)
// success.
*pnode = p.node;
return INFO_OK;
return INFO::OK;
}
@ -550,11 +558,11 @@ LibError tree_add_file(TDir* td, const char* name,
TNode* node;
LibError ret = td->find_and_add(name, NT_FILE, &node);
RETURN_ERR(ret);
if(ret == INFO_ALREADY_EXISTS)
if(ret == INFO::ALREADY_EXISTS)
{
TFile* tf = (TFile*)node;
if(!mount_should_replace(tf->m, m, tf->size, size, tf->mtime, mtime))
return INFO_ALREADY_EXISTS;
return INFO::ALREADY_EXISTS;
stats_vfs_file_remove(tf->size);
}
@ -567,7 +575,7 @@ LibError tree_add_file(TDir* td, const char* name,
stats_vfs_file_add(size);
set_most_recent_if_newer(mtime);
return INFO_OK;
return INFO::OK;
}
@ -576,7 +584,7 @@ LibError tree_add_dir(TDir* td, const char* name, TDir** ptd)
TNode* node;
RETURN_ERR(td->find_and_add(name, NT_DIR, &node));
*ptd = (TDir*)node;
return INFO_OK;
return INFO::OK;
}
@ -585,14 +593,14 @@ LibError tree_lookup_dir(const char* V_path, TDir** ptd, uint flags)
{
// path is not a directory; TDir::lookup might return a file node
if(!VFS_PATH_IS_DIR(V_path))
WARN_RETURN(ERR_TNODE_WRONG_TYPE);
WARN_RETURN(ERR::TNODE_WRONG_TYPE);
TDir* td = (flags & LF_START_DIR)? *ptd : tree_root;
TNode* node;
CHECK_ERR(lookup(td, V_path, flags, &node));
// directories should exist, so warn if this fails
*ptd = (TDir*)node;
return INFO_OK;
return INFO::OK;
}
@ -600,13 +608,13 @@ LibError tree_lookup(const char* V_path, TFile** pfile, uint flags)
{
// path is not a file; TDir::lookup might return a directory node
if(VFS_PATH_IS_DIR(V_path))
WARN_RETURN(ERR_TNODE_WRONG_TYPE);
WARN_RETURN(ERR::TNODE_WRONG_TYPE);
TNode* node;
LibError ret = lookup(tree_root, V_path, flags, &node);
RETURN_ERR(ret);
*pfile = (TFile*)node;
return INFO_OK;
return INFO::OK;
}
@ -626,13 +634,13 @@ static LibError add_path_cb(const char* component, bool is_dir, void* ctx)
// should only be called for directory paths, so complain if not dir.
if(!is_dir)
WARN_RETURN(ERR_TNODE_WRONG_TYPE);
WARN_RETURN(ERR::TNODE_WRONG_TYPE);
TNode* node;
RETURN_ERR(p->td->find_and_add(component, NT_DIR, &node, p->m));
p->td = (TDir*)node;
return INFO_CB_CONTINUE;
return INFO::CB_CONTINUE;
}
// iterate over all components in V_dir_path (must reference a directory,
@ -647,7 +655,7 @@ LibError tree_add_path(const char* V_dir_path, const Mount* m, TDir** ptd)
AddPathCbParams p(m);
RETURN_ERR(path_foreach_component(V_dir_path, add_path_cb, &p));
*ptd = p.td;
return INFO_OK;
return INFO::OK;
}
@ -682,7 +690,7 @@ LibError tree_dir_open(const char* V_dir_path, DirIterator* di)
// we need to prevent modifications to this directory while an iterator is
// active, otherwise entries may be skipped or no longer valid addresses
// accessed. blocking other threads is much more convenient for callers
// than having to check for ERR_AGAIN on every call, so we use a mutex
// than having to check for ERR::AGAIN on every call, so we use a mutex
// instead of a simple refcount. we don't bother with fine-grained locking
// (e.g. per directory or read/write locks) because it would result in
// more overhead (we have hundreds of directories) and is unnecessary.
@ -691,7 +699,7 @@ LibError tree_dir_open(const char* V_dir_path, DirIterator* di)
tdi->it = td->begin();
tdi->end = td->end();
tdi->td = td;
return INFO_OK;
return INFO::OK;
}
@ -700,7 +708,7 @@ LibError tree_dir_next_ent(DirIterator* di, DirEnt* ent)
TreeDirIterator* tdi = (TreeDirIterator*)di->opaque;
if(tdi->it == tdi->end)
return ERR_DIR_END; // NOWARN
return ERR::DIR_END; // NOWARN
const TNode* node = *(tdi->it++);
ent->name = node->name;
@ -725,7 +733,7 @@ LibError tree_dir_next_ent(DirIterator* di, DirEnt* ent)
debug_warn("invalid TNode type");
}
return INFO_OK;
return INFO::OK;
}
@ -735,7 +743,7 @@ LibError tree_dir_close(DirIterator* UNUSED(d))
// 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 INFO_OK;
return INFO::OK;
}
@ -780,7 +788,7 @@ LibError tree_stat(const TFile* tf, struct stat* s)
s->st_size = tf->size;
s->st_mtime = tf->mtime;
return INFO_OK;
return INFO::OK;
}

View File

@ -30,6 +30,13 @@ class TDir;
#include "vfs_mount.h" // Mount
namespace ERR
{
const LibError TNODE_NOT_FOUND = -110600;
// attemped to treat a file as directory or vice versa.
const LibError TNODE_WRONG_TYPE = -110601;
}
// establish a root node and prepare node_allocator for use.
extern void tree_init();
@ -73,7 +80,7 @@ enum TreeLookupFlags
// a higher-priority file of the same name already exists
// (used by VFile_reload when opening for writing).
//
// output params are only valid if INFO_OK is returned.
// output params are only valid if INFO::OK is returned.
extern LibError tree_lookup(const char* path, TFile** ptf, uint flags = 0);
// starting at VFS root, traverse <path> and pass back information
@ -87,7 +94,7 @@ extern LibError tree_lookup(const char* path, TFile** ptf, uint flags = 0);
// <path> can be to a file or dir (in which case it must end in '/',
// to make sure the last component is treated as a directory).
//
// output params are only valid if INFO_OK is returned.
// output params are only valid if INFO::OK is returned.
extern LibError tree_lookup_dir(const char* V_path, TDir** ptd, uint flags = 0);

View File

@ -30,6 +30,7 @@
#include "lib/allocators.h"
#include "lib/timer.h"
#include "file_internal.h"
#include "lib/res/res.h"
// safe downcasters: cast from any integral type to u32 or u16;
@ -127,7 +128,7 @@ static ZipCompressionMethod zip_method_for(CompressionMethod method)
case CM_DEFLATE:
return ZIP_CM_DEFLATE;
default:
WARN_ERR(ERR_UNKNOWN_CMETHOD);
WARN_ERR(ERR::COMPRESSION_UNKNOWN_METHOD);
return ZIP_CM_NONE;
}
}
@ -142,7 +143,7 @@ static CompressionMethod method_for_zip_method(ZipCompressionMethod zip_method)
case ZIP_CM_DEFLATE:
return CM_DEFLATE;
default:
WARN_ERR(ERR_UNKNOWN_CMETHOD);
WARN_ERR(ERR::COMPRESSION_UNKNOWN_METHOD);
return CM_UNSUPPORTED;
}
}
@ -366,7 +367,7 @@ static const u8* za_find_id(const u8* buf, size_t size, const void* start, u32 m
// search for ECDR in the last <max_scan_amount> bytes of the file.
// if found, fill <dst_ecdr> with a copy of the (little-endian) ECDR and
// return INFO_OK, otherwise IO error or ERR_CORRUPTED.
// return INFO::OK, otherwise IO error or ERR::CORRUPTED.
static LibError za_find_ecdr(File* f, size_t max_scan_amount, ECDR* dst_ecdr_le)
{
// don't scan more than the entire file
@ -381,13 +382,13 @@ static LibError za_find_ecdr(File* f, size_t max_scan_amount, ECDR* dst_ecdr_le)
debug_assert(bytes_read == (ssize_t)scan_amount);
// look for ECDR in buffer
LibError ret = ERR_CORRUPTED;
LibError ret = ERR::CORRUPTED;
const u8* start = (const u8*)buf;
const ECDR* ecdr_le = (const ECDR*)za_find_id(start, bytes_read, start, ecdr_magic, ECDR_SIZE);
if(ecdr_le)
{
*dst_ecdr_le = *ecdr_le;
ret = INFO_OK;
ret = INFO::OK;
}
file_buf_free(buf);
@ -407,24 +408,24 @@ completely_bogus:
// note: the VFS blindly opens files when mounting; it needs to open
// all archives, but doesn't know their extension (e.g. ".pk3").
// therefore, do not warn user.
return ERR_UNKNOWN_FORMAT; // NOWARN
return ERR::RES_UNKNOWN_FORMAT; // NOWARN
}
ECDR ecdr_le;
// expected case: ECDR at EOF; no file comment (=> we only need to
// read 512 bytes)
LibError ret = za_find_ecdr(f, ECDR_SIZE, &ecdr_le);
if(ret == INFO_OK)
if(ret == INFO::OK)
{
have_ecdr:
ecdr_decompose(&ecdr_le, cd_entries, cd_ofs, cd_size);
return INFO_OK;
return INFO::OK;
}
// last resort: scan last 66000 bytes of file
// (the Zip archive comment field - up to 64k - may follow ECDR).
// if the zip file is < 66000 bytes, scan the whole file.
ret = za_find_ecdr(f, 66000u, &ecdr_le);
if(ret == INFO_OK)
if(ret == INFO::OK)
goto have_ecdr;
// both ECDR scans failed - this is not a valid Zip file.
@ -441,19 +442,19 @@ have_ecdr:
// the Zip file is mostly valid but lacking an ECDR. (can happen if
// user hard-exits while building an archive)
// notes:
// - return ERR_CORRUPTED so VFS will not include this file.
// - return ERR::CORRUPTED so VFS will not include this file.
// - we could work around this by scanning all LFHs, but won't bother
// because it'd be slow.
// - do not warn - the corrupt archive will be deleted on next
// successful archive builder run anyway.
return ERR_CORRUPTED; // NOWARN
return ERR::CORRUPTED; // NOWARN
}
// analyse an opened Zip file; call back into archive.cpp to
// populate the Archive object with a list of the files it contains.
// returns INFO_OK on success, ERR_CORRUPTED if file is recognizable as
// a Zip file but invalid, otherwise ERR_UNKNOWN_FORMAT or IO error.
// returns INFO::OK on success, ERR::CORRUPTED if file is recognizable as
// a Zip file but invalid, otherwise ERR::RES_UNKNOWN_FORMAT or IO error.
//
// fairly slow - must read Central Directory from disk
// (size ~= 60 bytes*num_files); observed time ~= 80ms.
@ -472,7 +473,7 @@ LibError zip_populate_archive(File* f, Archive* a)
RETURN_ERR(file_io(f, cd_ofs, cd_size, &buf));
// iterate through Central Directory
LibError ret = INFO_OK;
LibError ret = INFO::OK;
const CDFH* cdfh = (const CDFH*)buf;
size_t ofs_to_next_cdfh = 0;
for(uint i = 0; i < cd_entries; i++)
@ -482,7 +483,7 @@ LibError zip_populate_archive(File* f, Archive* a)
cdfh = (CDFH*)za_find_id((const u8*)buf, cd_size, (const u8*)cdfh, cdfh_magic, CDFH_SIZE);
if(!cdfh) // no (further) CDFH found:
{
ret = ERR_CORRUPTED;
ret = ERR::CORRUPTED;
break;
}
@ -495,7 +496,7 @@ LibError zip_populate_archive(File* f, Archive* a)
if(ae.csize && ae.ucsize)
{
ret = archive_add_file(a, &ae);
if(ret != INFO_OK)
if(ret != INFO::OK)
break;
}
}
@ -531,7 +532,7 @@ static LibError lfh_copier_cb(uintptr_t ctx, const void* block, size_t size, siz
p->lfh_bytes_remaining -= size;
*bytes_processed = size;
return INFO_CB_CONTINUE;
return INFO::CB_CONTINUE;
}
@ -603,10 +604,10 @@ LibError zip_archive_create(const char* zip_filename, ZipArchive** pza)
ZipArchive* za = za_mgr.alloc();
if(!za)
WARN_RETURN(ERR_NO_MEM);
WARN_RETURN(ERR::NO_MEM);
*za = za_copy;
*pza = za;
return INFO_OK;
return INFO::OK;
}
@ -639,14 +640,14 @@ LibError zip_archive_add_file(ZipArchive* za, const ArchiveEntry* ae, void* file
const size_t prev_pos = za->cdfhs.da.pos;
CDFH_Package* p = (CDFH_Package*)pool_alloc(&za->cdfhs, CDFH_SIZE+fn_len);
if(!p)
WARN_RETURN(ERR_NO_MEM);
WARN_RETURN(ERR::NO_MEM);
const size_t slack = za->cdfhs.da.pos-prev_pos - (CDFH_SIZE+fn_len);
cdfh_assemble(&p->cdfh, ae->method, ae->mtime, ae->crc, ae->csize, ae->ucsize, fn_len, slack, lfh_ofs);
memcpy2(p->fn, ae->atom_fn, fn_len);
za->cd_entries++;
return INFO_OK;
return INFO::OK;
}
@ -661,7 +662,7 @@ LibError zip_archive_finish(ZipArchive* za)
// write out both to the archive file in one burst)
ECDR* ecdr = (ECDR*)pool_alloc(&za->cdfhs, ECDR_SIZE);
if(!ecdr)
WARN_RETURN(ERR_NO_MEM);
WARN_RETURN(ERR::NO_MEM);
ecdr_assemble(ecdr, za->cd_entries, za->cur_file_size, cd_size);
FileIOBuf buf = za->cdfhs.da.base;
@ -670,5 +671,5 @@ LibError zip_archive_finish(ZipArchive* za)
(void)file_close(&za->f);
(void)pool_destroy(&za->cdfhs);
za_mgr.release(za);
return INFO_OK;
return INFO::OK;
}

View File

@ -30,8 +30,8 @@ struct ArchiveEntry;
// analyse an opened Zip file; call back into archive.cpp to
// populate the Archive object with a list of the files it contains.
// returns INFO_OK on success, ERR_CORRUPTED if file is recognizable as
// a Zip file but invalid, otherwise ERR_UNKNOWN_FORMAT or IO error.
// returns INFO::OK on success, ERR::CORRUPTED if file is recognizable as
// a Zip file but invalid, otherwise ERR::RES_UNKNOWN_FORMAT or IO error.
//
// fairly slow - must read Central Directory from disk
// (size ~= 60 bytes*num_files); observed time ~= 80ms.

View File

@ -121,7 +121,7 @@ public:
(void)ogl_tex_set_filter(ht, GL_NEAREST);
(void)ogl_tex_upload(ht);
return INFO_OK;
return INFO::OK;
}
void destroy()
@ -155,10 +155,10 @@ public:
{
const uint A = 128; // no cursor is expected to get this big
if(w > A || h > A || hotspotx > A || hotspoty > A)
WARN_RETURN(ERR_1);
WARN_RETURN(ERR::_1);
if(ht < 0)
WARN_RETURN(ERR_2);
return INFO_OK;
WARN_RETURN(ERR::_2);
return INFO::OK;
}
};
@ -214,13 +214,13 @@ static LibError Cursor_reload(Cursor* c, const char* name, Handle)
{
LibError err=c->gl_cursor.create(filename, hotspotx, hotspoty);
if (err == INFO_OK)
if (err == INFO::OK)
c->gl_sys_cursor = load_empty_sys_cursor();
return err;
}
return INFO_OK;
return INFO::OK;
}
static LibError Cursor_validate(const Cursor* c)
@ -230,14 +230,14 @@ static LibError Cursor_validate(const Cursor* c)
if(!c->sys_cursor)
RETURN_ERR(c->gl_cursor.validate());
return INFO_OK;
return INFO::OK;
}
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 INFO_OK;
return INFO::OK;
}
@ -268,7 +268,7 @@ LibError cursor_draw(const char* name, int x, int y)
if(!name)
{
WARN_ERR(sys_cursor_set(0));
return INFO_OK;
return INFO::OK;
}
Handle hc = cursor_load(name);
@ -287,5 +287,5 @@ LibError cursor_draw(const char* name, int x, int y)
}
(void)cursor_free(hc);
return INFO_OK;
return INFO::OK;
}

View File

@ -22,6 +22,15 @@
#define LOG_CATEGORY "shaders"
AT_STARTUP(\
error_setDescription(ERR::SHDR_CREATE, "Shader creation failed");\
error_setDescription(ERR::SHDR_COMPILE, "Shader compile failed");\
error_setDescription(ERR::SHDR_NO_SHADER, "Invalid shader reference");\
error_setDescription(ERR::SHDR_LINK, "Shader linking failed");\
error_setDescription(ERR::SHDR_NO_PROGRAM, "Invalid shader program reference");\
)
// Convert a shader object type into a descriptive string.
// If the type enum is not known, the given buffer is used as scratch space
// to format the type number. If buf is null, a generic string is returned.
@ -84,10 +93,10 @@ static void Ogl_Shader_init(Ogl_Shader* shdr, va_list args)
// So, how can we inform the "parent object" (i.e. the program object) of our change?
static LibError Ogl_Shader_reload(Ogl_Shader* shdr, const char* filename, Handle UNUSED(h))
{
LibError err = ERR_FAIL;
LibError err = ERR::FAIL;
if (shdr->id)
return INFO_OK;
return INFO::OK;
FileIOBuf file;
size_t file_size;
@ -106,7 +115,7 @@ static LibError Ogl_Shader_reload(Ogl_Shader* shdr, const char* filename, Handle
// bad code.
oglCheck();
err = ERR_SHDR_CREATE;
err = ERR::SHDR_CREATE;
goto fail_fileloaded;
}
@ -143,12 +152,12 @@ static LibError Ogl_Shader_reload(Ogl_Shader* shdr, const char* filename, Handle
filename,
shader_type_to_string(shdr->type, typenamebuf, ARRAY_SIZE(typenamebuf)));
err = ERR_SHDR_COMPILE;
err = ERR::SHDR_COMPILE;
goto fail_shadercreated;
}
(void)file_buf_free(file);
return INFO_OK;
return INFO::OK;
fail_shadercreated:
pglDeleteObjectARB(shdr->id);
@ -173,13 +182,13 @@ static void Ogl_Shader_dtor(Ogl_Shader* shdr)
static LibError Ogl_Shader_validate(const Ogl_Shader* UNUSED(shdr))
{
// TODO
return INFO_OK;
return INFO::OK;
}
static LibError Ogl_Shader_to_string(const Ogl_Shader* UNUSED(shdr), char* buf)
{
snprintf(buf, H_STRING_LEN, "");
return INFO_OK;
return INFO::OK;
}
@ -208,11 +217,11 @@ LibError ogl_shader_attach(GLhandleARB program, Handle& h)
H_DEREF(h, Ogl_Shader, shdr);
if (!shdr->id)
WARN_RETURN(ERR_SHDR_NO_SHADER);
WARN_RETURN(ERR::SHDR_NO_SHADER);
pglAttachObjectARB(program, shdr->id);
return INFO_OK;
return INFO::OK;
}
@ -252,7 +261,7 @@ static LibError do_load_shader(
{
LOG(ERROR, LOG_CATEGORY, "%hs: Missing attribute \"type\" in element \"Shader\".",
filename);
WARN_RETURN(ERR_CORRUPTED);
WARN_RETURN(ERR::CORRUPTED);
}
GLenum shadertype = string_to_shader_type(Type.c_str());
@ -261,7 +270,7 @@ static LibError do_load_shader(
{
LOG(ERROR, LOG_CATEGORY, "%hs: Unknown shader type \"%hs\" (valid are: VERTEX_SHADER, FRAGMENT_SHADER).",
filename, Type.c_str());
WARN_RETURN(ERR_CORRUPTED);
WARN_RETURN(ERR::CORRUPTED);
}
CStr Name = Shader.getText();
@ -269,7 +278,7 @@ static LibError do_load_shader(
if (!Name.Length())
{
LOG(ERROR, LOG_CATEGORY, "%hs: Missing shader name.", filename);
WARN_RETURN(ERR_CORRUPTED);
WARN_RETURN(ERR::CORRUPTED);
}
Handle hshader = ogl_shader_load(Name.c_str(), shadertype);
@ -283,7 +292,7 @@ static LibError do_load_shader(
// TODO: How will this work with automatic reload?
ogl_shader_free(hshader);
return INFO_OK;
return INFO::OK;
}
@ -291,7 +300,7 @@ static LibError do_load_shader(
static LibError Ogl_Program_reload(Ogl_Program* p, const char* filename, Handle h)
{
if (p->id)
return INFO_OK;
return INFO::OK;
oglCheck();
@ -302,12 +311,12 @@ static LibError Ogl_Program_reload(Ogl_Program* p, const char* filename, Handle
// here, but it may still help spot bad code.
oglCheck();
WARN_RETURN(ERR_SHDR_CREATE);
WARN_RETURN(ERR::SHDR_CREATE);
}
CXeromyces XeroFile;
if (XeroFile.Load(filename) != PSRETURN_OK)
WARN_RETURN(ERR_CORRUPTED); // more informative error message?
WARN_RETURN(ERR::CORRUPTED); // more informative error message?
// Define all the elements and attributes used in the XML file
#define EL(x) int el_##x = XeroFile.getElementID(#x)
@ -321,7 +330,7 @@ static LibError Ogl_Program_reload(Ogl_Program* p, const char* filename, Handle
if (Root.getNodeName() != el_program)
{
LOG(ERROR, LOG_CATEGORY, "%hs: XML root was not \"Program\".", filename);
WARN_RETURN(ERR_CORRUPTED);
WARN_RETURN(ERR::CORRUPTED);
}
XMBElementList RootChildren = Root.getChildNodes();
@ -343,7 +352,7 @@ static LibError Ogl_Program_reload(Ogl_Program* p, const char* filename, Handle
{
LOG(ERROR, LOG_CATEGORY, "%hs: Only \"Shader\" may be child of \"Shaders\".",
filename);
WARN_RETURN(ERR_CORRUPTED);
WARN_RETURN(ERR::CORRUPTED);
}
RETURN_ERR(do_load_shader(p, filename, h, XeroFile, Shader));
@ -374,10 +383,10 @@ static LibError Ogl_Program_reload(Ogl_Program* p, const char* filename, Handle
if (!linked)
{
debug_printf("Link failed for %hs\n", filename);
WARN_RETURN(ERR_SHDR_LINK);
WARN_RETURN(ERR::SHDR_LINK);
}
return INFO_OK;
return INFO::OK;
}
@ -394,13 +403,13 @@ static void Ogl_Program_dtor(Ogl_Program* p)
static LibError Ogl_Program_validate(const Ogl_Program* UNUSED(p))
{
// TODO
return INFO_OK;
return INFO::OK;
}
static LibError Ogl_Program_to_string(const Ogl_Program* UNUSED(p), char* buf)
{
snprintf(buf, H_STRING_LEN, "");
return INFO_OK;
return INFO::OK;
}
@ -428,18 +437,18 @@ LibError ogl_program_use(Handle h)
if (!h)
{
pglUseProgramObjectARB(0);
return INFO_OK;
return INFO::OK;
}
Ogl_Program* p = H_USER_DATA(h, Ogl_Program);
if (!p || !p->id)
{
pglUseProgramObjectARB(0);
WARN_RETURN(ERR_INVALID_HANDLE);
WARN_RETURN(ERR::INVALID_HANDLE);
}
pglUseProgramObjectARB(p->id);
return INFO_OK;
return INFO::OK;
}

View File

@ -16,6 +16,16 @@
#include "lib/types.h"
#include "lib/ogl.h"
namespace ERR
{
const LibError SHDR_CREATE = -120200;
const LibError SHDR_COMPILE = -120201;
const LibError SHDR_NO_SHADER = -120202;
const LibError SHDR_LINK = -120203;
const LibError SHDR_NO_PROGRAM = -120204;
}
/*
Encapsulate shader objects into handles, which transparently enables sharing
of shader source files between programs as well as reloading shaders at

View File

@ -409,7 +409,7 @@ 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 INFO_OK;
return INFO::OK;
// if we don't already have the texture in memory (*), load from file.
// * this happens if the texture is "wrapped".
@ -424,7 +424,7 @@ static LibError OglTex_reload(OglTex* ot, const char* fn, Handle h)
if(ot->flags & OT_NEED_AUTO_UPLOAD)
(void)ogl_tex_upload(h);
return INFO_OK;
return INFO::OK;
}
static LibError OglTex_validate(const OglTex* ot)
@ -438,41 +438,41 @@ static LibError OglTex_validate(const OglTex* ot)
GLsizei h = (GLsizei)ot->t.h;
// .. == 0; texture file probably not loaded successfully.
if(w == 0 || h == 0)
WARN_RETURN(ERR_11);
WARN_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)
WARN_RETURN(ERR_12);
WARN_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))
WARN_RETURN(ERR_13);
WARN_RETURN(ERR::_13);
// texture state
if(!filter_valid(ot->state.filter))
WARN_RETURN(ERR_14);
WARN_RETURN(ERR::_14);
if(!wrap_valid(ot->state.wrap))
WARN_RETURN(ERR_15);
WARN_RETURN(ERR::_15);
// misc
if(!q_flags_valid(ot->q_flags))
WARN_RETURN(ERR_16);
WARN_RETURN(ERR::_16);
if(ot->tmu >= 128) // unexpected that there will ever be this many
WARN_RETURN(ERR_17);
WARN_RETURN(ERR::_17);
if(ot->flags > OT_ALL_FLAGS)
WARN_RETURN(ERR_18);
WARN_RETURN(ERR::_18);
// .. note: don't check ot->fmt and ot->int_fmt - they aren't set
// until during ogl_tex_upload.
return INFO_OK;
return INFO::OK;
}
static LibError OglTex_to_string(const OglTex* ot, char* buf)
{
snprintf(buf, H_STRING_LEN, "id=%d", ot->id);
return INFO_OK;
return INFO::OK;
}
@ -578,14 +578,14 @@ LibError ogl_tex_set_filter(Handle ht, GLint filter)
H_DEREF(ht, OglTex, ot);
if(!filter_valid(filter))
WARN_RETURN(ERR_INVALID_PARAM);
WARN_RETURN(ERR::INVALID_PARAM);
if(ot->state.filter != filter)
{
warn_if_uploaded(ht, ot);
ot->state.filter = filter;
}
return INFO_OK;
return INFO::OK;
}
@ -598,14 +598,14 @@ LibError ogl_tex_set_wrap(Handle ht, GLint wrap)
H_DEREF(ht, OglTex, ot);
if(!wrap_valid(wrap))
WARN_RETURN(ERR_INVALID_PARAM);
WARN_RETURN(ERR::INVALID_PARAM);
if(ot->state.wrap != wrap)
{
warn_if_uploaded(ht, ot);
ot->state.wrap = wrap;
}
return INFO_OK;
return INFO::OK;
}
@ -690,7 +690,7 @@ static LibError get_mipmaps(Tex* t, GLint filter, uint q_flags, int* plevels_to_
*plevels_to_skip = TEX_BASE_LEVEL_ONLY;
if(!need_mipmaps)
return INFO_OK;
return INFO::OK;
// image already contains pregenerated mipmaps; we need do nothing.
// this is the nicest case, because they are fastest to load
@ -713,7 +713,7 @@ static LibError get_mipmaps(Tex* t, GLint filter, uint q_flags, int* plevels_to_
// 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 ERR_FAIL; // NOWARN
return ERR::FAIL; // NOWARN
// image is uncompressed and we're on an old OpenGL implementation;
// we will generate mipmaps in software.
else
@ -735,7 +735,7 @@ static LibError get_mipmaps(Tex* t, GLint filter, uint q_flags, int* plevels_to_
*plevels_to_skip = log2(reduce);
}
return INFO_OK;
return INFO::OK;
}
@ -806,7 +806,7 @@ LibError ogl_tex_upload(const Handle ht, GLenum fmt_ovr, uint q_flags_ovr, GLint
// upload already happened; no work to do.
// (this also happens if a cached texture is "loaded")
if(ot->flags & OT_IS_UPLOADED)
return INFO_OK;
return INFO::OK;
debug_assert(ot->flags & OT_TEX_VALID);
@ -851,7 +851,7 @@ LibError ogl_tex_upload(const Handle ht, GLenum fmt_ovr, uint q_flags_ovr, GLint
ot->flags &= ~OT_TEX_VALID;
}
return INFO_OK;
return INFO::OK;
}
@ -871,7 +871,7 @@ LibError ogl_tex_get_size(Handle ht, uint* w, uint* h, uint* bpp)
*h = ot->t.h;
if(bpp)
*bpp = ot->t.bpp;
return INFO_OK;
return INFO::OK;
}
@ -890,7 +890,7 @@ LibError ogl_tex_get_format(Handle ht, uint* flags, GLenum* fmt)
debug_warn("hasn't been defined yet!");
*fmt = ot->fmt;
}
return INFO_OK;
return INFO::OK;
}
@ -906,7 +906,7 @@ LibError ogl_tex_get_data(Handle ht, void** p)
H_DEREF(ht, OglTex, ot);
*p = tex_get_data(&ot->t);
return INFO_OK;
return INFO::OK;
}
@ -935,7 +935,7 @@ LibError ogl_tex_bind(Handle ht, uint unit)
if(ht == 0)
{
glDisable(GL_TEXTURE_2D);
return INFO_OK;
return INFO::OK;
}
// if this fails, the texture unit's state remains unchanged.
@ -951,7 +951,7 @@ LibError ogl_tex_bind(Handle ht, uint unit)
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, ot->id);
return INFO_OK;
return INFO::OK;
}

View File

@ -34,6 +34,18 @@
#include "tex_codec.h"
AT_STARTUP(\
error_setDescription(ERR::TEX_FMT_INVALID, "Invalid/unsupported texture format");\
error_setDescription(ERR::TEX_INVALID_COLOR_TYPE, "Invalid color type");\
error_setDescription(ERR::TEX_NOT_8BIT_PRECISION, "Not 8bit channel precision");\
error_setDescription(ERR::TEX_INVALID_LAYOUT, "Unsupported texel layout, e.g. righttoleft");\
error_setDescription(ERR::TEX_COMPRESSED, "Unsupported texture compression");\
error_setDescription(WARN::TEX_INVALID_DATA, "Warning: invalid texel data encountered");\
error_setDescription(ERR::TEX_INVALID_SIZE, "Texture size is incorrect");\
error_setDescription(INFO::TEX_CODEC_CANNOT_HANDLE, "Texture codec cannot handle the given format");\
)
//-----------------------------------------------------------------------------
// validation
//-----------------------------------------------------------------------------
@ -52,25 +64,25 @@ LibError 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)
WARN_RETURN(ERR_1);
WARN_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)
WARN_RETURN(ERR_2);
WARN_RETURN(ERR::_2);
// flags
// .. DXT value
const uint dxt = t->flags & TEX_DXT;
if(dxt != 0 && dxt != 1 && dxt != DXT1A && dxt != 3 && dxt != 5)
WARN_RETURN(ERR_3);
WARN_RETURN(ERR::_3);
// .. orientation
const uint orientation = t->flags & TEX_ORIENTATION;
if(orientation == (TEX_BOTTOM_UP|TEX_TOP_DOWN))
WARN_RETURN(ERR_4);
WARN_RETURN(ERR::_4);
return INFO_OK;
return INFO::OK;
}
#define CHECK_TEX(t) RETURN_ERR(tex_validate(t))
@ -88,22 +100,22 @@ LibError tex_validate_plain_format(uint bpp, uint flags)
const bool mipmaps = (flags & TEX_MIPMAPS) != 0;
if(dxt || mipmaps)
WARN_RETURN(ERR_TEX_FMT_INVALID);
WARN_RETURN(ERR::TEX_FMT_INVALID);
// grey must be 8bpp without alpha, or it's invalid.
if(grey)
{
if(bpp == 8 && !alpha)
return INFO_OK;
WARN_RETURN(ERR_TEX_FMT_INVALID);
return INFO::OK;
WARN_RETURN(ERR::TEX_FMT_INVALID);
}
if(bpp == 24 && !alpha)
return INFO_OK;
return INFO::OK;
if(bpp == 32 && alpha)
return INFO_OK;
return INFO::OK;
WARN_RETURN(ERR_TEX_FMT_INVALID);
WARN_RETURN(ERR::TEX_FMT_INVALID);
}
@ -241,20 +253,20 @@ static LibError add_mipmaps(Tex* t, uint w, uint h, uint bpp,
// go to the trouble of implementing image scaling because
// the only place this is used (ogl_tex_upload) requires POT anyway.
if(!is_pow2(w) || !is_pow2(h))
WARN_RETURN(ERR_TEX_INVALID_SIZE);
WARN_RETURN(ERR::TEX_INVALID_SIZE);
t->flags |= TEX_MIPMAPS; // must come before tex_img_size!
const size_t mipmap_size = tex_img_size(t);
Handle hm;
const u8* mipmap_data = (const u8*)mem_alloc(mipmap_size, 4*KiB, 0, &hm);
if(!mipmap_data)
WARN_RETURN(ERR_NO_MEM);
WARN_RETURN(ERR::NO_MEM);
CreateLevelData cld = { bpp/8, w, h, (const u8*)new_data, data_size };
tex_util_foreach_mipmap(w, h, bpp, mipmap_data, 0, 1, create_level, &cld);
mem_free_h(t->hm);
t->hm = hm;
t->ofs = 0;
return INFO_OK;
return INFO::OK;
}
@ -287,12 +299,12 @@ 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 INFO_TEX_CODEC_CANNOT_HANDLE;
return INFO::TEX_CODEC_CANNOT_HANDLE;
// .. data is not in "plain" format
RETURN_ERR(tex_validate_plain_format(bpp, flags));
// .. nothing to do
if(!transforms)
return INFO_OK;
return INFO::OK;
// allocate copy of the image data.
// rationale: L1 cache is typically A2 => swapping in-place with a
@ -304,7 +316,7 @@ TIMER_ACCRUE(tc_plain_transform);
Handle hm;
void* new_data = mem_alloc(data_size, 4*KiB, 0, &hm);
if(!new_data)
WARN_RETURN(ERR_NO_MEM);
WARN_RETURN(ERR::NO_MEM);
memcpy2(new_data, data, data_size);
// setup row source/destination pointers (simplifies outer loop)
@ -372,7 +384,7 @@ TIMER_ACCRUE(tc_plain_transform);
RETURN_ERR(add_mipmaps(t, w, h, bpp, new_data, data_size));
CHECK_TEX(t);
return INFO_OK;
return INFO::OK;
}
@ -392,16 +404,16 @@ LibError tex_transform(Tex* t, uint transforms)
remaining_transforms = target_flags ^ t->flags;
// we're finished (all required transforms have been done)
if(remaining_transforms == 0)
return INFO_OK;
return INFO::OK;
LibError ret = tex_codec_transform(t, remaining_transforms);
if(ret != INFO_OK)
if(ret != INFO::OK)
break;
}
// last chance
RETURN_ERR(plain_transform(t, remaining_transforms));
return INFO_OK;
return INFO::OK;
}
@ -487,7 +499,7 @@ bool tex_is_known_extension(const char* filename)
{
const TexCodecVTbl* dummy;
// found codec for it => known extension
if(tex_codec_for_filename(filename, &dummy) == INFO_OK)
if(tex_codec_for_filename(filename, &dummy) == INFO::OK)
return true;
return false;
@ -527,7 +539,7 @@ LibError 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 INFO_OK;
return INFO::OK;
}
@ -616,10 +628,10 @@ LibError tex_decode(const u8* data, size_t data_size, MEM_DTOR dtor, Tex* t)
// make sure the entire header is available
const size_t min_hdr_size = c->hdr_size(0);
if(data_size < min_hdr_size)
WARN_RETURN(ERR_INCOMPLETE_HEADER);
WARN_RETURN(ERR::RES_INCOMPLETE_HEADER);
const size_t hdr_size = c->hdr_size(data);
if(data_size < hdr_size)
WARN_RETURN(ERR_INCOMPLETE_HEADER);
WARN_RETURN(ERR::RES_INCOMPLETE_HEADER);
// wrap pointer into a Handle; required for Tex.hm.
// rationale: a Handle protects the texture memory from being
@ -642,16 +654,16 @@ LibError tex_decode(const u8* data, size_t data_size, MEM_DTOR dtor, Tex* t)
// sanity checks
if(!t->w || !t->h || t->bpp > 32)
WARN_RETURN(ERR_TEX_FMT_INVALID);
WARN_RETURN(ERR::TEX_FMT_INVALID);
// .. note: can't use data_size - decode may have decompressed the image.
size_t hm_size;
(void)mem_get_ptr(t->hm, &hm_size);
if(hm_size < t->ofs + tex_img_size(t))
WARN_RETURN(ERR_TEX_INVALID_SIZE);
WARN_RETURN(ERR::TEX_INVALID_SIZE);
flip_to_global_orientation(t);
return INFO_OK;
return INFO::OK;
}
@ -679,7 +691,7 @@ LibError tex_encode(Tex* t, const char* fn, DynArray* da)
WARN_RETURN(err);
}
return INFO_OK;
return INFO::OK;
}
@ -709,7 +721,7 @@ LibError tex_load(const char* fn, Tex* t, uint file_flags)
// wasn't compressed) or was replaced by a new buffer for the image data.
CHECK_TEX(t);
return INFO_OK;
return INFO::OK;
}
@ -722,7 +734,7 @@ LibError tex_write(Tex* t, const char* fn)
RETURN_ERR(tex_encode(t, fn, &da));
// write to disk
LibError ret = INFO_OK;
LibError ret = INFO::OK;
{
const size_t sector_aligned_size = round_up(da.cur_size, file_sector_size);
(void)da_set_size(&da, sector_aligned_size);

View File

@ -102,6 +102,28 @@ library and IO layer. Read and write are zero-copy.
#include "lib/res/handle.h"
namespace ERR
{
const LibError TEX_FMT_INVALID = -120100;
const LibError TEX_INVALID_COLOR_TYPE = -120101;
const LibError TEX_NOT_8BIT_PRECISION = -120102;
const LibError TEX_INVALID_LAYOUT = -120103;
const LibError TEX_COMPRESSED = -120104;
const LibError TEX_INVALID_SIZE = -120105;
}
namespace WARN
{
const LibError TEX_INVALID_DATA = +120106;
}
namespace INFO
{
const LibError TEX_CODEC_CANNOT_HANDLE = +120107;
}
/**
* flags describing the pixel format. these are to be interpreted as
* deviations from "plain" format, i.e. uncompressed RGB.

View File

@ -58,7 +58,7 @@ struct BmpHeader
static LibError bmp_transform(Tex* UNUSED(t), uint UNUSED(transforms))
{
return INFO_TEX_CODEC_CANNOT_HANDLE;
return INFO::TEX_CODEC_CANNOT_HANDLE;
}
@ -112,13 +112,13 @@ static LibError bmp_decode(DynArray* restrict da, Tex* restrict t)
// sanity checks
if(compress != BI_RGB)
WARN_RETURN(ERR_TEX_COMPRESSED);
WARN_RETURN(ERR::TEX_COMPRESSED);
t->w = w;
t->h = h;
t->bpp = bpp;
t->flags = flags;
return INFO_OK;
return INFO::OK;
}

View File

@ -50,7 +50,7 @@ int tex_codec_register(TexCodecVTbl* c)
// find codec that recognizes the desired output file extension,
// or return ERR_UNKNOWN_FORMAT if unknown.
// or return ERR::RES_UNKNOWN_FORMAT if unknown.
// note: does not raise a warning because it is used by
// tex_is_known_extension.
LibError tex_codec_for_filename(const char* fn, const TexCodecVTbl** c)
@ -60,10 +60,10 @@ LibError tex_codec_for_filename(const char* fn, const TexCodecVTbl** c)
{
// we found it
if((*c)->is_ext(ext))
return INFO_OK;
return INFO::OK;
}
return ERR_UNKNOWN_FORMAT; // NOWARN
return ERR::RES_UNKNOWN_FORMAT; // NOWARN
}
@ -72,16 +72,16 @@ LibError tex_codec_for_header(const u8* file, size_t file_size, const TexCodecVT
{
// we guarantee at least 4 bytes for is_hdr to look at
if(file_size < 4)
WARN_RETURN(ERR_INCOMPLETE_HEADER);
WARN_RETURN(ERR::RES_INCOMPLETE_HEADER);
for(*c = codecs; *c; *c = (*c)->next)
{
// we found it
if((*c)->is_hdr(file))
return INFO_OK;
return INFO::OK;
}
WARN_RETURN(ERR_UNKNOWN_FORMAT);
WARN_RETURN(ERR::RES_UNKNOWN_FORMAT);
}
@ -98,17 +98,17 @@ const TexCodecVTbl* tex_codec_next(const TexCodecVTbl* prev_codec)
LibError tex_codec_transform(Tex* t, uint transforms)
{
LibError ret = INFO_TEX_CODEC_CANNOT_HANDLE;
LibError ret = INFO::TEX_CODEC_CANNOT_HANDLE;
// find codec that understands the data, and transform
for(const TexCodecVTbl* c = codecs; c; c = c->next)
{
LibError err = c->transform(t, transforms);
// success
if(err == INFO_OK)
return INFO_OK;
if(err == INFO::OK)
return INFO::OK;
// something went wrong
else if(err != INFO_TEX_CODEC_CANNOT_HANDLE)
else if(err != INFO::TEX_CODEC_CANNOT_HANDLE)
{
ret = err;
debug_warn("codec indicates error");
@ -150,7 +150,7 @@ LibError tex_codec_alloc_rows(const u8* data, size_t h, size_t pitch,
rows = (RowArray)malloc(h * sizeof(RowPtr));
if(!rows)
WARN_RETURN(ERR_NO_MEM);
WARN_RETURN(ERR::NO_MEM);
// determine start position and direction
RowPtr pos = flip? data+pitch*(h-1) : data;
@ -164,7 +164,7 @@ LibError tex_codec_alloc_rows(const u8* data, size_t h, size_t pitch,
}
debug_assert(pos == end);
return INFO_OK;
return INFO::OK;
}
@ -175,5 +175,5 @@ LibError tex_codec_write(Tex* t, uint transforms, const void* hdr, size_t hdr_si
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 INFO_OK;
return INFO::OK;
}

View File

@ -165,7 +165,7 @@ extern int tex_codec_register(TexCodecVTbl* c);
* @param fn filename; only the extension (that after '.') is used.
* case-insensitive.
* @param c (out) vtbl of responsible codec
* @return LibError; ERR_UNKNOWN_FORMAT (without warning, because this is
* @return LibError; ERR::RES_UNKNOWN_FORMAT (without warning, because this is
* called by tex_is_known_extension) if no codec indicates they can
* handle the given extension.
**/
@ -178,7 +178,7 @@ extern LibError tex_codec_for_filename(const char* fn, const TexCodecVTbl** c);
* (first 4 bytes of) header.
* @param data_size [bytes]
* @param c (out) vtbl of responsible codec
* @return LibError; ERR_UNKNOWN_FORMAT if no codec indicates they can
* @return LibError; ERR::RES_UNKNOWN_FORMAT if no codec indicates they can
* handle the given format (header).
**/
extern LibError tex_codec_for_header(const u8* data, size_t data_size, const TexCodecVTbl** c);

View File

@ -23,7 +23,6 @@
#include "precompiled.h"
#include "lib/byte_order.h"
#include "lib/res/mem.h"
#include "tex_codec.h"
// NOTE: the convention is bottom-up for DDS, but there's no way to tell.
@ -289,7 +288,7 @@ static LibError s3tc_decompress(Tex* t)
const size_t out_size = tex_img_size(t) * out_bpp / t->bpp;
void* out_data = mem_alloc(out_size, 64*KiB, 0, &hm);
if(!out_data)
WARN_RETURN(ERR_NO_MEM);
WARN_RETURN(ERR::NO_MEM);
const uint s3tc_block_size = (dxt == 3 || dxt == 5)? 16 : 8;
S3tcDecompressInfo di = { dxt, s3tc_block_size, out_bpp/8, (u8*)out_data };
@ -301,7 +300,7 @@ static LibError s3tc_decompress(Tex* t)
t->ofs = 0;
t->bpp = out_bpp;
t->flags &= ~TEX_DXT;
return INFO_OK;
return INFO::OK;
}
@ -416,7 +415,7 @@ static LibError decode_pf(const DDPIXELFORMAT* pf, uint* bpp_, uint* flags_)
// check struct size
if(read_le32(&pf->dwSize) != sizeof(DDPIXELFORMAT))
WARN_RETURN(ERR_TEX_INVALID_SIZE);
WARN_RETURN(ERR::TEX_INVALID_SIZE);
// determine type
const u32 pf_flags = read_le32(&pf->dwFlags);
@ -452,7 +451,7 @@ static LibError decode_pf(const DDPIXELFORMAT* pf, uint* bpp_, uint* flags_)
// we do not allow any weird orderings that require runtime work.
// instead, the artists must export with the correct settings.
unsupported_component_ordering:
WARN_RETURN(ERR_TEX_FMT_INVALID);
WARN_RETURN(ERR::TEX_FMT_INVALID);
}
RETURN_ERR(tex_validate_plain_format(bpp, flags));
@ -483,16 +482,16 @@ static LibError decode_pf(const DDPIXELFORMAT* pf, uint* bpp_, uint* flags_)
break;
default:
WARN_RETURN(ERR_TEX_FMT_INVALID);
WARN_RETURN(ERR::TEX_FMT_INVALID);
}
}
// .. neither uncompressed nor compressed - invalid
else
WARN_RETURN(ERR_TEX_FMT_INVALID);
WARN_RETURN(ERR::TEX_FMT_INVALID);
*bpp_ = bpp;
*flags_ = flags;
return INFO_OK;
return INFO::OK;
}
@ -505,7 +504,7 @@ static LibError decode_sd(const DDSURFACEDESC2* sd, uint* w_, uint* h_,
{
// check header size
if(read_le32(&sd->dwSize) != sizeof(*sd))
WARN_RETURN(ERR_CORRUPTED);
WARN_RETURN(ERR::CORRUPTED);
// flags (indicate which fields are valid)
const u32 sd_flags = read_le32(&sd->dwFlags);
@ -513,14 +512,14 @@ static LibError decode_sd(const DDSURFACEDESC2* sd, uint* w_, uint* h_,
// note: we can't guess dimensions - the image may not be square.
const u32 sd_req_flags = DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT;
if((sd_flags & sd_req_flags) != sd_req_flags)
WARN_RETURN(ERR_INCOMPLETE_HEADER);
WARN_RETURN(ERR::RES_INCOMPLETE_HEADER);
// image dimensions
const u32 h = read_le32(&sd->dwHeight);
const u32 w = read_le32(&sd->dwWidth);
// .. not padded to S3TC block size
if(w % 4 || h % 4)
WARN_RETURN(ERR_TEX_INVALID_SIZE);
WARN_RETURN(ERR::TEX_INVALID_SIZE);
// pixel format
uint bpp, flags;
@ -532,12 +531,12 @@ static LibError decode_sd(const DDSURFACEDESC2* sd, uint* w_, uint* h_,
if(sd_flags & DDSD_PITCH)
{
if(sd_pitch_or_size != round_up(pitch, 4))
WARN_RETURN(ERR_CORRUPTED);
WARN_RETURN(ERR::CORRUPTED);
}
if(sd_flags & DDSD_LINEARSIZE)
{
if(sd_pitch_or_size != pitch*h)
WARN_RETURN(ERR_CORRUPTED);
WARN_RETURN(ERR::CORRUPTED);
}
// note: both flags set would be invalid; no need to check for that,
// though, since one of the above tests would fail.
@ -551,7 +550,7 @@ static LibError decode_sd(const DDSURFACEDESC2* sd, uint* w_, uint* h_,
// mipmap chain is incomplete
// note: DDS includes the base level in its count, hence +1.
if(mipmap_count != log2(MAX(w,h))+1)
WARN_RETURN(ERR_TEX_FMT_INVALID);
WARN_RETURN(ERR::TEX_FMT_INVALID);
flags |= TEX_MIPMAPS;
}
}
@ -561,7 +560,7 @@ static LibError decode_sd(const DDSURFACEDESC2* sd, uint* w_, uint* h_,
{
const u32 depth = read_le32(&sd->dwDepth);
if(depth)
WARN_RETURN(ERR_NOT_IMPLEMENTED);
WARN_RETURN(ERR::NOT_IMPLEMENTED);
}
// check caps
@ -580,7 +579,7 @@ static LibError decode_sd(const DDSURFACEDESC2* sd, uint* w_, uint* h_,
*h_ = h;
*bpp_ = bpp;
*flags_ = flags;
return INFO_OK;
return INFO::OK;
}
@ -618,15 +617,15 @@ static LibError dds_decode(DynArray* restrict da, Tex* restrict t)
t->h = h;
t->bpp = bpp;
t->flags = flags;
return INFO_OK;
return INFO::OK;
}
static LibError dds_encode(Tex* restrict UNUSED(t), DynArray* restrict UNUSED(da))
{
// note: do not return ERR_NOT_IMPLEMENTED et al. because that would
// 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 INFO_TEX_CODEC_CANNOT_HANDLE;
return INFO::TEX_CODEC_CANNOT_HANDLE;
}
@ -640,13 +639,13 @@ static LibError dds_transform(Tex* t, uint transforms)
if(dxt && transform_dxt)
{
RETURN_ERR(s3tc_decompress(t));
return INFO_OK;
return INFO::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 INFO_TEX_CODEC_CANNOT_HANDLE;
return INFO::TEX_CODEC_CANNOT_HANDLE;
}

View File

@ -23,7 +23,7 @@
#ifndef TEX_INTERNAL_H__
#define TEX_INTERNAL_H__
#include "../mem.h" // MEM_DTOR
#include "lib/res/res.h" // error codes and mem.h
#include "lib/allocators.h" // DynArray
/**

View File

@ -422,7 +422,7 @@ JpgErrorMgr::JpgErrorMgr(j_common_ptr cinfo)
static LibError jpg_transform(Tex* UNUSED(t), uint UNUSED(transforms))
{
return INFO_TEX_CODEC_CANNOT_HANDLE;
return INFO::TEX_CODEC_CANNOT_HANDLE;
}
@ -478,7 +478,7 @@ static LibError jpg_decode_impl(DynArray* da,
const size_t img_size = pitch * h; // for allow_rows
u8* img = (u8*)mem_alloc(img_size, 64*KiB, 0, &img_hm);
if(!img)
WARN_RETURN(ERR_NO_MEM);
WARN_RETURN(ERR::NO_MEM);
// read rows
RETURN_ERR(tex_codec_alloc_rows(img, h, pitch, TEX_TOP_DOWN, 0, rows));
@ -499,9 +499,9 @@ static LibError jpg_decode_impl(DynArray* da,
// mem data source.
(void)jpeg_finish_decompress(cinfo);
LibError ret = INFO_OK;
LibError ret = INFO::OK;
if(cinfo->err->num_warnings != 0)
ret = WARN_TEX_INVALID_DATA;
ret = WARN::TEX_INVALID_DATA;
// store image info
// .. transparently switch handles - free the old (compressed)
@ -560,9 +560,9 @@ static LibError jpg_encode_impl(Tex* t,
jpeg_finish_compress(cinfo);
LibError ret = INFO_OK;
LibError ret = INFO::OK;
if(cinfo->err->num_warnings != 0)
ret = WARN_TEX_INVALID_DATA;
ret = WARN::TEX_INVALID_DATA;
return ret;
}
@ -606,7 +606,7 @@ static LibError jpg_decode(DynArray* restrict da, Tex* restrict t)
JpgErrorMgr jerr((j_common_ptr)&cinfo);
if(setjmp(jerr.call_site))
{
err = ERR_FAIL;
err = ERR::FAIL;
goto fail;
}
@ -642,7 +642,7 @@ static LibError jpg_encode(Tex* restrict t, DynArray* restrict da)
JpgErrorMgr jerr((j_common_ptr)&cinfo);
if(setjmp(jerr.call_site))
{
err = ERR_FAIL;
err = ERR::FAIL;
goto fail;
}

View File

@ -88,7 +88,7 @@ static void io_flush(png_structp UNUSED(png_ptr))
static LibError png_transform(Tex* UNUSED(t), uint UNUSED(transforms))
{
return INFO_TEX_CODEC_CANNOT_HANDLE;
return INFO::TEX_CODEC_CANNOT_HANDLE;
}
@ -119,14 +119,14 @@ static LibError png_decode_impl(DynArray* da,
// make sure format is acceptable
if(bit_depth != 8)
WARN_RETURN(ERR_TEX_NOT_8BIT_PRECISION);
WARN_RETURN(ERR::TEX_NOT_8BIT_PRECISION);
if(colour_type & PNG_COLOR_MASK_PALETTE)
WARN_RETURN(ERR_TEX_INVALID_COLOR_TYPE);
WARN_RETURN(ERR::TEX_INVALID_COLOR_TYPE);
const size_t img_size = pitch * h;
u8* img = (u8*)mem_alloc(img_size, 64*KiB, 0, &img_hm);
if(!img)
WARN_RETURN(ERR_NO_MEM);
WARN_RETURN(ERR::NO_MEM);
RETURN_ERR(tex_codec_alloc_rows(img, h, pitch, TEX_TOP_DOWN, 0, rows));
@ -146,7 +146,7 @@ static LibError png_decode_impl(DynArray* da,
t->bpp = bpp;
t->flags = flags;
return INFO_OK;
return INFO::OK;
}
@ -189,7 +189,7 @@ static LibError 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 INFO_OK;
return INFO::OK;
}
@ -221,7 +221,7 @@ static LibError png_decode(DynArray* restrict da, Tex* restrict t)
{
TIMER_ACCRUE(tc_png_decode);
LibError err = ERR_FAIL;
LibError err = ERR::FAIL;
// freed when ret is reached:
png_structp png_ptr = 0;
png_infop info_ptr = 0;
@ -262,7 +262,7 @@ ret:
// limitation: palette images aren't supported
static LibError png_encode(Tex* restrict t, DynArray* restrict da)
{
LibError err = ERR_FAIL;
LibError err = ERR::FAIL;
// freed when ret is reached:
png_structp png_ptr = 0;
png_infop info_ptr = 0;

View File

@ -65,7 +65,7 @@ TgaHeader;
static LibError tga_transform(Tex* UNUSED(t), uint UNUSED(transforms))
{
return INFO_TEX_CODEC_CANNOT_HANDLE;
return INFO::TEX_CODEC_CANNOT_HANDLE;
}
@ -132,13 +132,13 @@ static LibError tga_decode(DynArray* restrict da, Tex* restrict t)
// .. storing right-to-left is just stupid;
// we're not going to bother converting it.
if(desc & TGA_RIGHT_TO_LEFT)
WARN_RETURN(ERR_TEX_INVALID_LAYOUT);
WARN_RETURN(ERR::TEX_INVALID_LAYOUT);
t->w = w;
t->h = h;
t->bpp = bpp;
t->flags = flags;
return INFO_OK;
return INFO::OK;
}

View File

@ -65,7 +65,7 @@ static LibError UniFont_reload(UniFont* f, const char* fn, Handle UNUSED(h))
{
// already loaded
if(f->ht > 0)
return INFO_OK;
return INFO::OK;
f->glyphs_id = new glyphmap_id;
f->glyphs_size = new glyphmap_size;
@ -85,7 +85,7 @@ static LibError UniFont_reload(UniFont* f, const char* fn, Handle UNUSED(h))
int Version;
FNTStream >> Version;
if (Version != 100) // Make sure this is from a recent version of the font builder
WARN_RETURN(ERR_UNKNOWN_FORMAT);
WARN_RETURN(ERR::RES_UNKNOWN_FORMAT);
int TextureWidth, TextureHeight;
FNTStream >> TextureWidth >> TextureHeight;
@ -102,7 +102,7 @@ static LibError UniFont_reload(UniFont* f, const char* fn, Handle UNUSED(h))
f->ListBase = glGenLists(NumGlyphs);
if (f->ListBase == 0) // My Voodoo2 drivers didn't support display lists (although I'd be surprised if they got this far)
WARN_RETURN(ERR_FAIL);
WARN_RETURN(ERR::FAIL);
// [cumulative for 12: 256ms]
for (int i = 0; i < NumGlyphs; ++i)
@ -166,28 +166,28 @@ static LibError UniFont_reload(UniFont* f, const char* fn, Handle UNUSED(h))
f->ht = ht;
return INFO_OK;
return INFO::OK;
}
static LibError UniFont_validate(const UniFont* f)
{
if(f->ht < 0)
WARN_RETURN(ERR_1);
WARN_RETURN(ERR::_1);
if(debug_is_pointer_bogus(f->glyphs_id) || debug_is_pointer_bogus(f->glyphs_size))
WARN_RETURN(ERR_2);
WARN_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)
WARN_RETURN(ERR_3);
WARN_RETURN(ERR::_3);
if(f->ListBase == 0 || f->ListBase > 1000000) // suspicious
WARN_RETURN(ERR_4);
return INFO_OK;
WARN_RETURN(ERR::_4);
return INFO::OK;
}
static LibError UniFont_to_string(const UniFont* UNUSED(f), char* buf)
{
snprintf(buf, H_STRING_LEN, "");
return INFO_OK;
return INFO::OK;
}
@ -211,7 +211,7 @@ LibError unifont_bind(const Handle h)
glListBase(f->ListBase);
BoundGlyphs = f->glyphs_id;
return INFO_OK;
return INFO::OK;
}
@ -311,11 +311,11 @@ LibError unifont_stringsize(const Handle h, const wchar_t* text, int& width, int
if (it == f->glyphs_size->end()) // Missing the missing glyph symbol - give up
{
debug_warn("Missing the missing glyph in a unifont!\n");
return INFO_OK;
return INFO::OK;
}
width += it->second; // Add the character's advance distance
}
return INFO_OK;
return INFO::OK;
}

View File

@ -289,11 +289,11 @@ static LibError alloc_idx(i32& idx, HDATA*& hd)
// add another
// .. too many already: IDX_BITS must be increased.
if(last_in_use >= hdata_cap)
WARN_RETURN(ERR_LIMIT);
WARN_RETURN(ERR::LIMIT);
idx = last_in_use+1; // just incrementing idx would start it at 1
hd = h_data_from_idx(idx);
if(!hd)
WARN_RETURN(ERR_NO_MEM);
WARN_RETURN(ERR::NO_MEM);
// can't fail for any other reason - idx is checked above.
{ // VC6 goto fix
bool is_unused = !hd->tag;
@ -313,7 +313,7 @@ have_idx:;
if(idx > last_in_use)
last_in_use = idx;
return INFO_OK;
return INFO::OK;
}
@ -321,7 +321,7 @@ static LibError free_idx(i32 idx)
{
if(first_free == -1 || idx < first_free)
first_free = idx;
return INFO_OK;
return INFO::OK;
}
@ -351,7 +351,7 @@ static Handle key_find(uintptr_t key, H_Type type, KeyRemoveFlag remove_option =
{
Key2Idx* key2idx = key2idx_wrapper.get();
if(!key2idx)
WARN_RETURN(ERR_NO_MEM);
WARN_RETURN(ERR::NO_MEM);
// initial return value: "not found at all, or it's of the
// wrong type". the latter happens when called by h_alloc to
@ -441,7 +441,7 @@ static void fn_store(HDATA* hd, const char* fn)
hd->fn = (const char*)malloc(size);
// still failed - bail (avoid strcpy to 0)
if(!hd->fn)
WARN_ERR_RETURN(ERR_NO_MEM);
WARN_ERR_RETURN(ERR::NO_MEM);
}
memcpy2((void*)hd->fn, fn, size); // faster than strcpy
@ -488,7 +488,7 @@ static void warn_if_invalid(HDATA* hd)
// have the resource validate its user_data
LibError err = vtbl->validate(hd->user);
debug_assert(err == INFO_OK);
debug_assert(err == INFO::OK);
// make sure empty space in control block isn't touched
// .. but only if we're not storing a filename there
@ -509,13 +509,13 @@ static void warn_if_invalid(HDATA* hd)
static LibError type_validate(H_Type type)
{
if(!type)
WARN_RETURN(ERR_INVALID_PARAM);
WARN_RETURN(ERR::INVALID_PARAM);
if(type->user_size > HDATA_USER_SIZE)
WARN_RETURN(ERR_LIMIT);
WARN_RETURN(ERR::LIMIT);
if(type->name == 0)
WARN_RETURN(ERR_INVALID_PARAM);
WARN_RETURN(ERR::INVALID_PARAM);
return INFO_OK;
return INFO::OK;
}
@ -545,7 +545,7 @@ static Handle reuse_existing_handle(uintptr_t key, H_Type type, uint flags)
HDATA* hd = h_data_tag_type(h, type);
// too many references - increase REF_BITS
if(hd->refs == REF_MAX)
WARN_RETURN(ERR_LIMIT);
WARN_RETURN(ERR::LIMIT);
hd->refs++;
@ -567,7 +567,7 @@ static Handle reuse_existing_handle(uintptr_t key, H_Type type, uint flags)
static LibError call_init_and_reload(Handle h, H_Type type, HDATA* hd, const char* fn, va_list* init_args)
{
LibError err = INFO_OK;
LibError err = INFO::OK;
H_VTbl* vtbl = type; // exact same thing but for clarity
// init
@ -581,12 +581,12 @@ static LibError call_init_and_reload(Handle h, H_Type type, HDATA* hd, const cha
try
{
err = vtbl->reload(hd->user, fn, h);
if(err == INFO_OK)
if(err == INFO::OK)
warn_if_invalid(hd);
}
catch(std::bad_alloc)
{
err = ERR_NO_MEM;
err = ERR::NO_MEM;
}
}
@ -694,7 +694,7 @@ static LibError 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 INFO_OK;
return INFO::OK;
// actually release the resource (call dtor, free control block).
@ -732,7 +732,7 @@ static LibError h_free_idx(i32 idx, HDATA* hd)
free_idx(idx);
return INFO_OK;
return INFO::OK;
}
@ -751,10 +751,10 @@ LibError 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 INFO_OK;
return INFO::OK;
// this was a valid handle but was probably freed in the meantime.
// complain because this probably indicates a bug somewhere.
WARN_RETURN(ERR_INVALID_HANDLE);
WARN_RETURN(ERR::INVALID_HANDLE);
}
return h_free_idx(idx, hd);
@ -802,7 +802,7 @@ LibError h_reload(const char* fn)
// must not continue - some resources not backed by files have
// key = 0 and reloading those would be disastrous.
if(!fn)
WARN_RETURN(ERR_INVALID_PARAM);
WARN_RETURN(ERR::INVALID_PARAM);
const u32 key = fnv_hash(fn);
@ -818,7 +818,7 @@ LibError h_reload(const char* fn)
hd->type->dtor(hd->user);
}
LibError ret = INFO_OK;
LibError ret = INFO::OK;
// now reload all affected handles
for(i32 i = 0; i <= last_in_use; i++)
@ -863,7 +863,7 @@ LibError h_force_free(Handle h, H_Type type)
// require valid index; ignore tag; type checked below.
HDATA* hd = h_data_no_tag(h);
if(!hd || hd->type != type)
WARN_RETURN(ERR_INVALID_HANDLE);
WARN_RETURN(ERR::INVALID_HANDLE);
u32 idx = h_idx(h);
hd->keep_open = 0;
hd->refs = 0;
@ -904,7 +904,7 @@ int h_get_refcnt(Handle h)
{
HDATA* hd = h_data_tag(h);
if(!hd)
WARN_RETURN(ERR_INVALID_PARAM);
WARN_RETURN(ERR::INVALID_PARAM);
// if there are no refs, how did the caller manage to keep a Handle?!
if(!hd->refs)

View File

@ -137,7 +137,7 @@ static LibError Type_reload(Res1* r, const char* filename, Handle);
r->data = malloc(100);
if(!r->data)
WARN_RETURN(ERR_NO_MEM);
WARN_RETURN(ERR::NO_MEM);
// (read contents of <filename> into r->data)
return 0;
}
@ -191,9 +191,9 @@ static LibError Type_validate(const Res1* r);
{
const int permissible_flags = 0x01;
if(debug_is_pointer_bogus(r->data))
WARN_RETURN(ERR_1);
WARN_RETURN(ERR::_1);
if(r->flags & ~permissible_flags)
WARN_RETURN(ERR_2);
WARN_RETURN(ERR::_2);
return 0;
}
@ -359,12 +359,12 @@ typedef H_VTbl* H_Type;
// note: don't use STMT - var decl must be visible to "caller"
#define H_DEREF(h, type, var)\
/* h already indicates an error - return immediately to pass back*/\
/* that specific error, rather than only ERR_INVALID_HANDLE*/\
/* that specific error, rather than only ERR::INVALID_HANDLE*/\
if(h < 0)\
WARN_RETURN((LibError)h);\
type* const var = H_USER_DATA(h, type);\
if(!var)\
WARN_RETURN(ERR_INVALID_HANDLE);
WARN_RETURN(ERR::INVALID_HANDLE);
// all functions check the passed tag (part of the handle) and type against

View File

@ -74,7 +74,7 @@ static Handle find_alloc(void* target_raw_p, It* out_it = 0)
{
Ptr2H* ptr2h = ptr2h_wrapper.get();
if(!ptr2h)
WARN_RETURN(ERR_NO_MEM);
WARN_RETURN(ERR::NO_MEM);
// early out optimization (don't pay for full subset check)
It it = ptr2h->find(target_raw_p);
@ -182,20 +182,20 @@ static void Mem_dtor(Mem* m)
static LibError Mem_reload(Mem* m, const char* UNUSED(fn), Handle hm)
{
set_alloc(m->raw_p, hm);
return INFO_OK;
return INFO::OK;
}
static LibError Mem_validate(const Mem* m)
{
if(debug_is_pointer_bogus(m->p))
WARN_RETURN(ERR_1);
WARN_RETURN(ERR::_1);
if(!m->size)
WARN_RETURN(ERR_2);
WARN_RETURN(ERR::_2);
if(m->raw_p && m->raw_p > m->p)
WARN_RETURN(ERR_3);
WARN_RETURN(ERR::_3);
if(m->raw_size && m->raw_size < m->size)
WARN_RETURN(ERR_4);
return INFO_OK;
WARN_RETURN(ERR::_4);
return INFO::OK;
}
static LibError Mem_to_string(const Mem* m, char* buf)
@ -210,7 +210,7 @@ static LibError 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 INFO_OK;
return INFO::OK;
}
@ -253,7 +253,7 @@ LibError mem_free_h(Handle& hm)
LibError mem_free_p(void*& p)
{
if(!p)
return INFO_OK;
return INFO::OK;
Handle hm;
{
@ -263,7 +263,7 @@ LibError mem_free_p(void*& p)
p = 0;
if(hm <= 0)
WARN_RETURN(ERR_ALLOC_NOT_FOUND);
WARN_RETURN(ERR::MEM_ALLOC_NOT_FOUND);
return mem_free_h(hm);
}
@ -274,7 +274,7 @@ LibError mem_free_p(void*& p)
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)
{
if(!p || !size)
WARN_RETURN(ERR_INVALID_PARAM);
WARN_RETURN(ERR::INVALID_PARAM);
SCOPED_LOCK;
@ -318,7 +318,7 @@ LibError mem_assign_user(Handle hm, void* user_p, size_t user_size)
m->p = user_p;
m->size = user_size;
return INFO_OK;
return INFO::OK;
}
*/
@ -328,7 +328,7 @@ LibError mem_assign_user(Handle hm, void* user_p, size_t user_size)
void* mem_alloc(size_t size, const size_t align, uint flags, Handle* phm)
{
if(phm)
*phm = ERR_NO_MEM;
*phm = ERR::NO_MEM;
#ifdef NDEBUG
void* owner = 0;
@ -420,7 +420,7 @@ LibError mem_get(Handle hm, u8** pp, size_t* psize)
if(psize)
*psize = m->size;
// leave hm locked
return INFO_OK;
return INFO::OK;
}

View File

@ -27,10 +27,6 @@
#include "handle.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef void (*MEM_DTOR)(void* p, size_t size, uintptr_t ctx);
// mem_alloc flags
@ -63,10 +59,4 @@ extern void mem_shutdown(void);
#ifdef __cplusplus
}
#endif
#endif // #ifndef MEM_H__

30
source/lib/res/res.cpp Normal file
View File

@ -0,0 +1,30 @@
/**
* =========================================================================
* File : res.cpp
* Project : 0 A.D.
* Description :
*
* @author Jan.Wassenberg@stud.uni-karlsruhe.de
* =========================================================================
*/
/*
* Copyright (c) 2004-2005 Jan Wassenberg
*
* Redistribution and/or modification are also permitted under the
* terms of the GNU General Public License as published by the
* Free Software Foundation (version 2 or later, at your option).
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
#include "precompiled.h"
#include "res.h"
AT_STARTUP(\
error_setDescription(ERR::RES_UNKNOWN_FORMAT, "Unknown file format");\
error_setDescription(ERR::RES_INCOMPLETE_HEADER, "File header not completely read");\
)

View File

@ -1,6 +1,18 @@
#ifndef INCLUDED_RES
#define INCLUDED_RES
// common headers needed by lib/res code
#include "h_mgr.h"
#include "lib/res/file/vfs.h"
#include "lib/path_util.h"
#include "mem.h"
namespace ERR
{
const LibError RES_UNKNOWN_FORMAT = -120000;
const LibError RES_INCOMPLETE_HEADER = -120001;
}
#endif // #ifndef INCLUDED_RES

View File

@ -176,7 +176,7 @@ LibError snd_dev_set(const char * 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 INFO_OK;
return INFO::OK;
// store name (need to copy it, since alc_init is called later,
// and it must then still be valid)
@ -189,7 +189,7 @@ LibError snd_dev_set(const char * alc_new_dev_name)
{
// already using default device - done. (don't re-init)
if(alc_dev_name == 0)
return INFO_OK;
return INFO::OK;
alc_dev_name = 0;
}
@ -226,7 +226,7 @@ static void alc_shutdown()
*/
static LibError alc_init()
{
LibError ret = INFO_OK;
LibError ret = INFO::OK;
#if WIN_LOADLIBRARY_HACK
HMODULE dlls[3];
@ -268,7 +268,7 @@ static LibError 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 = ERR_FAIL;
ret = ERR::FAIL;
}
// make note of which sound device is actually being used
@ -332,7 +332,7 @@ static void al_listener_latch()
LibError snd_set_master_gain(float gain)
{
if(gain < 0)
WARN_RETURN(ERR_INVALID_PARAM);
WARN_RETURN(ERR::INVALID_PARAM);
al_listener_gain = gain;
@ -340,7 +340,7 @@ LibError snd_set_master_gain(float gain)
// position will get sent too.
// this isn't called often, so we don't care.
return INFO_OK;
return INFO::OK;
}
@ -555,7 +555,7 @@ LibError snd_set_max_voices(uint limit)
if(!al_src_allocated || limit < al_src_allocated)
{
al_src_cap = limit;
return INFO_OK;
return INFO::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
@ -563,7 +563,7 @@ LibError snd_set_max_voices(uint limit)
// 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 INFO_OK;
return INFO::OK;
}
@ -585,7 +585,7 @@ static LibError al_init()
{
// only take action on first call, OR when re-initializing.
if(al_initialized)
return INFO_OK;
return INFO::OK;
RETURN_ERR(alc_init());
@ -595,7 +595,7 @@ static LibError al_init()
al_src_init();
al_listener_latch();
return INFO_OK;
return INFO::OK;
}
@ -639,7 +639,7 @@ 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 INFO_OK;
return INFO::OK;
// re-init (stops all currently playing sounds)
al_shutdown();
@ -673,10 +673,10 @@ static const char * devs;
LibError snd_dev_prepare_enum()
{
if(alcIsExtensionPresent(0, (ALCchar*)"ALC_ENUMERATION_EXT") != AL_TRUE)
WARN_RETURN(ERR_NO_SYS);
WARN_RETURN(ERR::NO_SYS);
devs = (const char*)alcGetString(0, ALC_DEVICE_SPECIFIER);
return INFO_OK;
return INFO::OK;
}
@ -781,11 +781,11 @@ static void * io_buf_alloc()
{
// no buffer allocated
if(!io_bufs)
WARN_ERR(ERR_NO_MEM);
WARN_ERR(ERR::NO_MEM);
// too many streams - can't happen (tm) because
// stream_open enforces MAX_STREAMS.
else
WARN_ERR(ERR_LIMIT);
WARN_ERR(ERR::LIMIT);
return 0;
}
@ -839,16 +839,16 @@ struct Stream
static LibError stream_issue(Stream * s)
{
if(s->active_ios >= MAX_IOS)
return INFO_OK;
return INFO::OK;
void * buf = io_buf_alloc();
if(!buf)
WARN_RETURN(ERR_NO_MEM);
WARN_RETURN(ERR::NO_MEM);
Handle h = vfs_io_issue(s->hf, STREAM_BUF_SIZE, buf);
RETURN_ERR(h);
s->ios[s->active_ios++] = h;
return INFO_OK;
return INFO::OK;
}
@ -859,19 +859,19 @@ static LibError stream_issue(Stream * s)
* @param data pointer to buffer
* @param size [bytes]
* @return LibError; if the first pending IO hasn't completed,
* ERR_AGAIN (not an error).
* ERR::AGAIN (not an error).
*/
static LibError stream_buf_get(Stream * s, void*& data, size_t& size)
{
if(s->active_ios == 0)
WARN_RETURN(ERR_EOF);
WARN_RETURN(ERR::IO_EOF);
Handle hio = s->ios[0];
// has it finished? if not, bail.
int is_complete = vfs_io_has_completed(hio);
RETURN_ERR(is_complete);
if(is_complete == 0)
return ERR_AGAIN; // NOWARN
return ERR::AGAIN; // NOWARN
// get its buffer.
// no delay, since vfs_io_has_completed == 1
@ -879,7 +879,7 @@ static LibError stream_buf_get(Stream * s, void*& data, size_t& size)
// (next stream_buf_discard will free this buffer)
s->last_buf = data;
return INFO_OK;
return INFO::OK;
}
@ -926,7 +926,7 @@ static LibError stream_open(Stream * s, const char * fn)
{
// bail because we wouldn't have enough IO buffers for all
if(active_streams >= MAX_STREAMS)
WARN_RETURN(ERR_LIMIT);
WARN_RETURN(ERR::LIMIT);
active_streams++;
s->hf = vfs_open(fn);
@ -935,7 +935,7 @@ static LibError stream_open(Stream * s, const char * fn)
for(int i = 0; i < MAX_IOS; i++)
RETURN_ERR(stream_issue(s));
return INFO_OK;
return INFO::OK;
}
@ -948,7 +948,7 @@ static LibError stream_open(Stream * s, const char * fn)
*/
static LibError stream_close(Stream * s)
{
LibError ret = INFO_OK;
LibError ret = INFO::OK;
LibError err;
// for each pending IO:
@ -958,7 +958,7 @@ static LibError stream_close(Stream * s)
void * data; size_t size; // unused
do
err = stream_buf_get(s, data, size);
while(err == ERR_AGAIN);
while(err == ERR::AGAIN);
if(err < 0 && ret == 0)
ret = err;
@ -987,9 +987,9 @@ static LibError stream_close(Stream * s)
static LibError stream_validate(const Stream * s)
{
if(s->active_ios > MAX_IOS)
WARN_RETURN(ERR_1);
WARN_RETURN(ERR::_1);
// <last_buf> has no invariant we could check.
return INFO_OK;
return INFO::OK;
}
@ -1091,7 +1091,7 @@ static LibError SndData_reload(SndData * sd, const char * fn, Handle hsd)
if(ogg_supported == -1)
ogg_supported = alIsExtensionPresent((ALubyte*)"AL_EXT_vorbis")? 1 : 0;
if(!ogg_supported)
WARN_RETURN(ERR_NO_SYS);
WARN_RETURN(ERR::NO_SYS);
sd->al_fmt = AL_FORMAT_VORBIS_EXT;
sd->al_freq = 0;
@ -1101,7 +1101,7 @@ static LibError SndData_reload(SndData * sd, const char * fn, Handle hsd)
}
// .. unknown extension
else
WARN_RETURN(ERR_UNKNOWN_FORMAT);
WARN_RETURN(ERR::RES_UNKNOWN_FORMAT);
// note: WAV is no longer supported. writing our own loader is infeasible
// due to a seriously watered down spec with many incompatible variants.
@ -1113,11 +1113,11 @@ static LibError 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)
WARN_RETURN(ERR_NOT_SUPPORTED);
WARN_RETURN(ERR::NOT_SUPPORTED);
RETURN_ERR(stream_open(&sd->s, fn));
sd->is_valid = 1;
return INFO_OK;
return INFO::OK;
}
// else: clip
@ -1162,29 +1162,29 @@ else
(void)file_buf_free(file);
return INFO_OK;
return INFO::OK;
}
static LibError SndData_validate(const SndData * sd)
{
if(sd->al_fmt == 0)
WARN_RETURN(ERR_11);
WARN_RETURN(ERR::_11);
if((uint)sd->al_freq > 100000) // suspicious
WARN_RETURN(ERR_12);
WARN_RETURN(ERR::_12);
if(sd->al_buf == 0)
WARN_RETURN(ERR_13);
WARN_RETURN(ERR::_13);
if(sd->is_stream)
RETURN_ERR(stream_validate(&sd->s));
return INFO_OK;
return INFO::OK;
}
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 INFO_OK;
return INFO::OK;
}
@ -1289,15 +1289,15 @@ static void hsd_list_free_all()
* @param hsd Handle to SndData.
* @param al_buf buffer name.
* @return LibError, most commonly:
* INFO_OK = buffer has been returned; more are expected to be available.
* ERR_EOF = buffer has been returned but is the last one
* INFO::OK = buffer has been returned; more are expected to be available.
* ERR::IO_EOF = buffer has been returned but is the last one
* (end of file reached)
* ERR_AGAIN = no buffer returned yet; still streaming in ATM.
* ERR::AGAIN = no buffer returned yet; still streaming in ATM.
* call back later.
*/
static LibError snd_data_buf_get(Handle hsd, ALuint& al_buf)
{
LibError err = INFO_OK;
LibError err = INFO::OK;
// in case H_DEREF fails
al_buf = 0;
@ -1308,7 +1308,7 @@ static LibError snd_data_buf_get(Handle hsd, ALuint& al_buf)
if(!sd->is_stream)
{
al_buf = sd->al_buf;
return ERR_EOF; // NOWARN
return ERR::IO_EOF; // NOWARN
}
// stream:
@ -1317,8 +1317,8 @@ static LibError snd_data_buf_get(Handle hsd, ALuint& al_buf)
void * data;
size_t size;
err = stream_buf_get(&sd->s, data, size);
if(err == ERR_AGAIN)
return ERR_AGAIN; // NOWARN
if(err == ERR::AGAIN)
return ERR::AGAIN; // NOWARN
RETURN_ERR(err);
// .. yes: pass to OpenAL and discard IO buffer.
@ -1328,12 +1328,12 @@ static LibError snd_data_buf_get(Handle hsd, ALuint& al_buf)
// .. try to issue the next IO.
// if EOF reached, indicate al_buf is the last that will be returned.
err = stream_issue(&sd->s);
if(err == ERR_EOF)
return ERR_EOF; // NOWARN
if(err == ERR::IO_EOF)
return ERR::IO_EOF; // NOWARN
RETURN_ERR(err);
// al_buf valid and next IO issued successfully.
return INFO_OK;
return INFO::OK;
}
@ -1351,11 +1351,11 @@ static LibError snd_data_buf_free(Handle hsd, ALuint al_buf)
// clip: no-op (caller will later release hsd reference;
// when hsd actually unloads, sd->al_buf will be freed).
if(!sd->is_stream)
return INFO_OK;
return INFO::OK;
// stream: we had allocated an additional buffer, so free it now.
al_buf_free(al_buf);
return INFO_OK;
return INFO::OK;
}
@ -1577,7 +1577,7 @@ static LibError VSrc_reload(VSrc * vs, const char * fn, Handle hvs)
// must load OpenAL so that snd_data_load can check for OGG extension.
LibError err = snd_init();
// .. don't complain if sound is disabled; fail silently.
if(err == ERR_AGAIN)
if(err == ERR::AGAIN)
return err;
// .. catch genuine errors during init.
RETURN_ERR(err);
@ -1625,29 +1625,29 @@ static LibError VSrc_reload(VSrc * vs, const char * fn, Handle hvs)
vs->hsd = snd_data_load(snd_fn, is_stream);
RETURN_ERR(vs->hsd);
return INFO_OK;
return INFO::OK;
}
static LibError VSrc_validate(const VSrc * vs)
{
// al_src can legitimately be 0 (if vs is low-pri)
if(vs->flags & ~VS_ALL_FLAGS)
WARN_RETURN(ERR_1);
WARN_RETURN(ERR::_1);
// no limitations on <pos>
if(!(0.0f <= vs->gain && vs->gain <= 1.0f))
WARN_RETURN(ERR_2);
WARN_RETURN(ERR::_2);
if(!(0.0f < vs->pitch && vs->pitch <= 1.0f))
WARN_RETURN(ERR_3);
WARN_RETURN(ERR::_3);
if(*(u8*)&vs->loop > 1 || *(u8*)&vs->relative > 1)
WARN_RETURN(ERR_4);
WARN_RETURN(ERR::_4);
// <static_pri> and <cur_pri> have no invariant we could check.
return INFO_OK;
return INFO::OK;
}
static LibError VSrc_to_string(const VSrc * vs, char * buf)
{
snprintf(buf, H_STRING_LEN, "al_src = %d", vs->al_src);
return INFO_OK;
return INFO::OK;
}
@ -1665,7 +1665,7 @@ static LibError VSrc_to_string(const VSrc * vs, char * buf)
* or loaded immediately.
* @return Handle or LibError on failure
*/
Handle snd_open(const char * snd_fn, bool is_stream)
Handle snd_open(const char* snd_fn, bool is_stream)
{
uint flags = 0;
if(is_stream)
@ -1797,7 +1797,7 @@ static void vsrc_free(VSrc * vs) { snd_free(vs->hvs); }
static LibError list_free_all()
{
list_foreach(vsrc_free);
return INFO_OK;
return INFO::OK;
}
@ -1873,14 +1873,14 @@ static double snd_update_time;
static LibError vsrc_update(VSrc * vs)
{
if(!vs->al_src)
return INFO_OK;
return INFO::OK;
FadeRet ret = fade(vs->fade, snd_update_time, vs->gain);
// auto-free after fadeout.
if(ret == FADE_TO_0_FINISHED)
{
vsrc_free(vs);
return INFO_OK; // don't continue - <vs> has been freed.
return INFO::OK; // don't continue - <vs> has been freed.
}
// fade in progress; latch current gain value.
else if(ret == FADE_CHANGED)
@ -1898,7 +1898,7 @@ static LibError vsrc_update(VSrc * vs)
if(num_queued == 0)
{
snd_free(vs->hvs);
return INFO_OK;
return INFO::OK;
}
}
// can still read from SndData
@ -1917,20 +1917,20 @@ static LibError vsrc_update(VSrc * vs)
ALuint al_buf;
ret = snd_data_buf_get(vs->hsd, al_buf);
// these 2 are legit (see above); otherwise, bail.
if(ret != ERR_AGAIN && ret != ERR_EOF)
if(ret != ERR::AGAIN && ret != ERR::IO_EOF)
RETURN_ERR(ret);
alSourceQueueBuffers(vs->al_src, 1, &al_buf);
al_check("vsrc_update alSourceQueueBuffers");
}
while(to_fill-- && ret == INFO_OK);
while(to_fill-- && ret == INFO::OK);
// SndData has reported that no further buffers are available.
if(ret == ERR_EOF)
if(ret == ERR::IO_EOF)
vs->flags |= VS_EOF;
}
return INFO_OK;
return INFO::OK;
}
@ -1939,19 +1939,19 @@ static LibError vsrc_update(VSrc * vs)
* called by snd_play and voice management.
*
* @param VSrc*
* @return LibError (ERR_FAIL if no AL source is available)
* @return LibError (ERR::FAIL if no AL source is available)
*/
static LibError vsrc_grant(VSrc * vs)
{
// already playing - bail
if(vs->al_src)
return INFO_OK;
return INFO::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 ERR_FAIL; // NOWARN
return ERR::FAIL; // NOWARN
// OpenAL docs don't specify default values, so initialize everything
// ourselves to be sure. note: alSourcefv param is not const.
@ -1970,7 +1970,7 @@ static LibError vsrc_grant(VSrc * vs)
alSourcePlay(vs->al_src);
AL_CHECK;
return INFO_OK;
return INFO::OK;
}
@ -1986,7 +1986,7 @@ static LibError vsrc_reclaim(VSrc * vs)
{
// don't own a source - bail.
if(!vs->al_src)
return ERR_FAIL; // NOWARN
return ERR::FAIL; // NOWARN
alSourceStop(vs->al_src);
AL_CHECK;
@ -1996,7 +1996,7 @@ static LibError vsrc_reclaim(VSrc * vs)
vsrc_deque_finished_bufs(vs);
al_src_free(vs->al_src);
return INFO_OK;
return INFO::OK;
}
@ -2031,7 +2031,7 @@ LibError snd_play(Handle hvs, 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 INFO_OK;
return INFO::OK;
}
@ -2055,7 +2055,7 @@ LibError snd_set_pos(Handle hvs, float x, float y, float z, bool relative)
vs->relative = relative;
vsrc_latch(vs);
return INFO_OK;
return INFO::OK;
}
@ -2076,18 +2076,18 @@ LibError snd_set_gain(Handle hvs, float gain)
H_DEREF(hvs, VSrc, vs);
if(!(0.0f <= gain && gain <= 1.0f))
WARN_RETURN(ERR_INVALID_PARAM);
WARN_RETURN(ERR::INVALID_PARAM);
// if fading, gain changes would be overridden during the next
// snd_update. attempting this indicates a logic error. we abort to
// avoid undesired jumps in gain that might surprise (and deafen) user.
if(fade_is_active(vs->fade))
WARN_RETURN(ERR_LOGIC);
WARN_RETURN(ERR::LOGIC);
vs->gain = gain;
vsrc_latch(vs);
return INFO_OK;
return INFO::OK;
}
@ -2107,12 +2107,12 @@ LibError snd_set_pitch(Handle hvs, float pitch)
H_DEREF(hvs, VSrc, vs);
if(!(0.0f < pitch && pitch <= 1.0f))
WARN_RETURN(ERR_INVALID_PARAM);
WARN_RETURN(ERR::INVALID_PARAM);
vs->pitch = pitch;
vsrc_latch(vs);
return INFO_OK;
return INFO::OK;
}
@ -2140,7 +2140,7 @@ LibError snd_set_loop(Handle hvs, bool loop)
vs->loop = loop;
vsrc_latch(vs);
return INFO_OK;
return INFO::OK;
}
@ -2180,7 +2180,7 @@ LibError snd_fade(Handle hvs, float initial_gain, float final_gain,
if(type != FT_LINEAR && type != FT_EXPONENTIAL && type != FT_S_CURVE &&
type != FT_ABORT)
WARN_RETURN(ERR_INVALID_PARAM);
WARN_RETURN(ERR::INVALID_PARAM);
// special case - set initial value to current gain (see above).
if(initial_gain < 0.0f)
@ -2198,7 +2198,7 @@ LibError snd_fade(Handle hvs, float initial_gain, float final_gain,
(void)fade(fi, cur_time, vs->gain);
vsrc_latch(vs);
return INFO_OK;
return INFO::OK;
}
@ -2288,7 +2288,7 @@ static LibError vm_update()
list_foreach(reclaim, first_unimportant, 0);
list_foreach(grant, 0, first_unimportant);
return INFO_OK;
return INFO::OK;
}
@ -2312,7 +2312,7 @@ LibError 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 INFO_OK;
return INFO::OK;
if(pos)
al_listener_set_pos(pos, dir, up);
@ -2323,7 +2323,7 @@ LibError snd_update(const float * pos, const float * dir, const float * up)
snd_update_time = get_time(); // see decl
list_foreach((void (*)(VSrc*))vsrc_update);
return INFO_OK;
return INFO::OK;
}
@ -2334,13 +2334,13 @@ static bool snd_disabled = false;
* extra layer on top of al_init that allows 'disabling' sound.
* called from each snd_open.
*
* @return LibError from al_init, or ERR_AGAIN if sound disabled
* @return LibError from al_init, or ERR::AGAIN if sound disabled
*/
static inline LibError snd_init()
{
// (note: each VSrc_reload and therefore snd_open will fail)
if(snd_disabled)
return ERR_AGAIN; // NOWARN
return ERR::AGAIN; // NOWARN
return al_init();
}
@ -2370,11 +2370,11 @@ LibError snd_disable(bool disabled)
{
if(al_initialized)
debug_warn("already initialized => disable is pointless");
return INFO_OK;
return INFO::OK;
}
else
return snd_init();
// note: won't return ERR_AGAIN, since snd_disabled == false
// note: won't return ERR::AGAIN, since snd_disabled == false
}

View File

@ -186,7 +186,7 @@ extern bool self_test_active;
#include <cxxtest/TestSuite.h>
#define TS_ASSERT_OK(expr) TS_ASSERT_EQUALS((expr), INFO_OK)
#define TS_ASSERT_OK(expr) TS_ASSERT_EQUALS((expr), INFO::OK)
#define TS_ASSERT_STR_EQUALS(str1, str2) TS_ASSERT_EQUALS(std::string(str1), std::string(str2))
#endif // #ifndef SELF_TEST_H__

View File

@ -28,6 +28,15 @@
#include "posix.h" // SIZE_MAX
// we were included from wstring_s.cpp; skip all stuff that
// must only be done once.
#ifndef WSTRING_S
AT_STARTUP(\
error_setDescription(ERR::STRING_NOT_TERMINATED, "Invalid string (no 0 terminator found in buffer)")\
)
#endif
// written against http://std.dkuug.dk/jtc1/sc22/wg14/www/docs/n1031.pdf .
// optimized for size - e.g. strcpy calls strncpy with n = SIZE_MAX.
@ -117,10 +126,10 @@ int tncpy_s(tchar* dst, size_t max_dst_chars, const tchar* src, size_t max_src_c
// the MS implementation returns EINVAL and allows dst = 0 if
// max_dst_chars = max_src_chars = 0. no mention of this in
// 3.6.2.1.1, so don't emulate that behavior.
ENFORCE(dst != 0, ERR_INVALID_PARAM, EINVAL);
ENFORCE(max_dst_chars != 0, ERR_INVALID_PARAM, ERANGE);
ENFORCE(dst != 0, ERR::INVALID_PARAM, EINVAL);
ENFORCE(max_dst_chars != 0, ERR::INVALID_PARAM, ERANGE);
*dst = '\0'; // in case src ENFORCE is triggered
ENFORCE(src != 0, ERR_INVALID_PARAM, EINVAL);
ENFORCE(src != 0, ERR::INVALID_PARAM, EINVAL);
WARN_IF_PTR_LEN(max_dst_chars);
WARN_IF_PTR_LEN(max_src_chars);
@ -143,7 +152,7 @@ int tncpy_s(tchar* dst, size_t max_dst_chars, const tchar* src, size_t max_src_c
if(max_dst_chars <= max_src_chars)
{
*dst = '\0';
ENFORCE(0, ERR_BUF_SIZE, ERANGE);
ENFORCE(0, ERR::BUF_SIZE, ERANGE);
}
// .. source: success, but still need to null-terminate the destination.
*p = '\0';
@ -167,8 +176,8 @@ int tcpy_s(tchar* dst, size_t max_dst_chars, const tchar* src)
// 0 is returned to indicate success and that <dst> is null-terminated.
int tncat_s(tchar* dst, size_t max_dst_chars, const tchar* src, size_t max_src_chars)
{
ENFORCE(dst != 0, ERR_INVALID_PARAM, EINVAL);
ENFORCE(max_dst_chars != 0, ERR_INVALID_PARAM, ERANGE);
ENFORCE(dst != 0, ERR::INVALID_PARAM, EINVAL);
ENFORCE(max_dst_chars != 0, ERR::INVALID_PARAM, ERANGE);
// src is checked in tncpy_s
// WARN_IF_PTR_LEN not necessary: both max_dst_chars and max_src_chars
@ -178,7 +187,7 @@ int tncat_s(tchar* dst, size_t max_dst_chars, const tchar* src, size_t max_src_c
if(dst_len == max_dst_chars)
{
*dst = '\0';
ENFORCE(0, ERR_STRING_NOT_TERMINATED, ERANGE);
ENFORCE(0, ERR::STRING_NOT_TERMINATED, ERANGE);
}
tchar* const end = dst+dst_len;

View File

@ -26,6 +26,12 @@
#include "posix_types.h" // size_t
#include "config.h"
namespace ERR
{
const LibError STRING_NOT_TERMINATED = -100600;
}
// only declare these functions if using our implementation
// (otherwise, we risk incompatibilities)
#if !HAVE_STRING_S

View File

@ -29,6 +29,14 @@
# include "lib/sysdep/ia32.h"
#endif
AT_STARTUP(\
error_setDescription(ERR::CPU_FEATURE_MISSING, "This CPU doesn't support a required feature");\
error_setDescription(ERR::CPU_UNKNOWN_OPCODE, "Disassembly failed");\
error_setDescription(ERR::CPU_RESTRICTED_AFFINITY, "Cannot set desired CPU affinity");\
)
char cpu_type[CPU_TYPE_LEN] = "";
double cpu_freq = 0.f;

View File

@ -23,9 +23,13 @@
#ifndef CPU_H__
#define CPU_H__
#ifdef __cplusplus
extern "C" {
#endif
namespace ERR
{
const LibError CPU_FEATURE_MISSING = -130000;
const LibError CPU_UNKNOWN_OPCODE = -130001;
const LibError CPU_RESTRICTED_AFFINITY = -130002;
}
const size_t CPU_TYPE_LEN = 49; // IA32 processor brand string is <= 48 chars
@ -36,7 +40,7 @@ extern double cpu_freq;
// -1 if detect not yet called, or cannot be determined:
extern int cpus; // # packages (i.e. sockets; > 1 => SMP system)
extern "C" int cpus; // # packages (i.e. sockets; > 1 => SMP system)
extern int cpu_ht_units; // degree of hyperthreading, typically 2
extern int cpu_cores; // cores per package, typically 2
@ -56,7 +60,7 @@ extern void get_mem_status(void);
// atomic "compare and swap". compare the machine word at <location> against
// <expected>; if not equal, return false; otherwise, overwrite it with
// <new_value> and return true.
extern bool CAS_(uintptr_t* location, uintptr_t expected, uintptr_t new_value);
extern "C" bool CAS_(uintptr_t* location, uintptr_t expected, uintptr_t new_value);
// this is often used for pointers, so the macro coerces parameters to
// uinptr_t. invalid usage unfortunately also goes through without warnings.
@ -64,12 +68,12 @@ extern bool CAS_(uintptr_t* location, uintptr_t expected, uintptr_t new_value);
// similar mishaps, the implementation verifies <location> is a valid pointer.
#define CAS(l,o,n) CAS_((uintptr_t*)l, (uintptr_t)o, (uintptr_t)n)
extern void atomic_add(intptr_t* location, intptr_t increment);
extern "C" void atomic_add(intptr_t* location, intptr_t increment);
// enforce strong memory ordering.
extern void mfence();
extern "C" void mfence();
extern void serialize();
extern "C" void serialize();
// Win32 CONTEXT field abstraction
@ -84,8 +88,4 @@ extern void serialize();
# define SP_ Esp
#endif
#ifdef __cplusplus
}
#endif
#endif // #ifndef CPU_H__

View File

@ -32,7 +32,7 @@ char gfx_drv_ver[GFX_DRV_VER_LEN] = "";
int gfx_mem = -1; // [MiB]; approximate
extern "C" LibError ogl_get_gfx_info();
extern LibError ogl_get_gfx_info();
// detect graphics card and set the above information.
void gfx_detect()

View File

@ -23,10 +23,6 @@
#ifndef GFX_H__
#define GFX_H__
#ifdef __cplusplus
extern "C" {
#endif
const size_t GFX_CARD_LEN = 128;
/**
* description of graphics card.
@ -63,7 +59,7 @@ extern void gfx_detect(void);
* @param xres, yres (optional out) resolution [pixels]
* @param bpp (optional out) bits per pixel
* @param freq (optional out) vertical refresh rate [Hz]
* @return LibError; INFO_OK unless: some information was requested
* @return LibError; INFO::OK unless: some information was requested
* (i.e. pointer is non-NULL) but cannot be returned.
* on failure, the outputs are all left unchanged (they are
* assumed initialized to defaults)
@ -83,9 +79,4 @@ extern LibError gfx_get_video_mode(int* xres, int* yres, int* bpp, int* freq);
**/
extern LibError gfx_get_monitor_size(int& width_mm, int& height_mm);
#ifdef __cplusplus
}
#endif
#endif // #ifndef GFX_H__

View File

@ -43,8 +43,10 @@
#error ia32.cpp needs inline assembly support!
#endif
extern "C" {
// set by ia32_init, referenced by ia32_memcpy (asm)
extern "C" u32 ia32_memcpy_size_mask = 0;
extern u32 ia32_memcpy_size_mask = 0;
void ia32_init()
{
@ -616,7 +618,7 @@ void ia32_get_cpu_info()
// checks if there is an IA-32 CALL instruction right before ret_addr.
// returns INFO_OK if so and ERR_FAIL if not.
// returns INFO::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.
@ -637,13 +639,13 @@ LibError ia32_get_call_target(void* ret_addr, void** target)
if(len >= 5 && c[-5] == 0xE8)
{
*target = (u8*)ret_addr + *(i32*)(c-4);
return INFO_OK;
return INFO::OK;
}
// CALL r/m32 (FF /2)
// .. CALL [r32 + r32*s] => FF 14 SIB
if(len >= 3 && c[-3] == 0xFF && c[-2] == 0x14)
return INFO_OK;
return INFO::OK;
// .. CALL [disp32] => FF 15 disp32
if(len >= 6 && c[-6] == 0xFF && c[-5] == 0x15)
{
@ -653,26 +655,28 @@ LibError ia32_get_call_target(void* ret_addr, void** target)
// even if the pointer is 0, it's better to pass its value on
// (may help in tracking down memory corruption)
*target = *(void**)addr_of_target;
return INFO_OK;
return INFO::OK;
}
// .. CALL [r32] => FF 00-3F(!14/15)
if(len >= 2 && c[-2] == 0xFF && c[-1] < 0x40 && c[-1] != 0x14 && c[-1] != 0x15)
return INFO_OK;
return INFO::OK;
// .. CALL [r32 + r32*s + disp8] => FF 54 SIB disp8
if(len >= 4 && c[-4] == 0xFF && c[-3] == 0x54)
return INFO_OK;
return INFO::OK;
// .. CALL [r32 + disp8] => FF 50-57(!54) disp8
if(len >= 3 && c[-3] == 0xFF && (c[-2] & 0xF8) == 0x50 && c[-2] != 0x54)
return INFO_OK;
return INFO::OK;
// .. CALL [r32 + r32*s + disp32] => FF 94 SIB disp32
if(len >= 7 && c[-7] == 0xFF && c[-6] == 0x94)
return INFO_OK;
return INFO::OK;
// .. CALL [r32 + disp32] => FF 90-97(!94) disp32
if(len >= 6 && c[-6] == 0xFF && (c[-5] & 0xF8) == 0x90 && c[-5] != 0x94)
return INFO_OK;
return INFO::OK;
// .. CALL r32 => FF D0-D7
if(len >= 2 && c[-2] == 0xFF && (c[-1] & 0xF8) == 0xD0)
return INFO_OK;
return INFO::OK;
WARN_RETURN(ERR_CPU_UNKNOWN_OPCODE);
WARN_RETURN(ERR::CPU_UNKNOWN_OPCODE);
}
} // extern "C"

View File

@ -143,7 +143,7 @@ extern void ia32_get_current_context(void* pcontext);
extern void ia32_asm_init();
// checks if there is an IA-32 CALL instruction right before ret_addr.
// returns INFO_OK if so and ERR_FAIL if not.
// returns INFO::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.

View File

@ -23,11 +23,6 @@
#ifndef SND_H__
#define SND_H__
#ifdef __cplusplus
extern "C" {
#endif
const size_t SND_CARD_LEN = 128;
/**
* description of sound card.
@ -45,9 +40,4 @@ extern char snd_drv_ver[SND_DRV_VER_LEN];
**/
extern void snd_detect(void);
#ifdef __cplusplus
}
#endif
#endif // #ifndef SND_H__

View File

@ -78,11 +78,6 @@
#endif
#ifdef __cplusplus
extern "C" {
#endif
//-----------------------------------------------------------------------------
// C99 / SUSv3 emulation where needed
//-----------------------------------------------------------------------------
@ -149,9 +144,7 @@ extern void* alloca(size_t size);
// Some systems have C99 support but in C++ they provide only std::isfinite
// and not isfinite. C99 specifies that isfinite is a macro, so we can use
// #ifndef and define it if it's not there already.
// Since sysdep.h will normally be included before cmath is, we need to load
// cmath first to let it define/undef that macro. (That's awkward here inside
// the 'extern "C"', so it's included at the top of this file.)
// We've included <cmath> above to make sure it defines that macro.
# ifndef isfinite
# define isfinite std::isfinite
# define isnan std::isnan
@ -236,7 +229,7 @@ extern LibError sys_clipboard_free(wchar_t* copy);
// it is no longer needed and can be freed after this call returns.
// hotspot (hx,hy) is the offset from its upper-left corner to the
// position where mouse clicks are registered.
// cursor is only valid when INFO_OK is returned; in that case, it must be
// cursor is only valid when INFO::OK is returned; in that case, it must be
// sys_cursor_free-ed when no longer needed.
extern LibError sys_cursor_create(uint w, uint h, void* bgra_img,
uint hx, uint hy, void** cursor);
@ -360,11 +353,6 @@ extern size_t sys_max_sector_size();
#endif
#ifdef __cplusplus
}
#endif
//-----------------------------------------------------------------------------
// STL_HASH_MAP, STL_HASH_MULTIMAP, STL_HASH_SET
//-----------------------------------------------------------------------------

View File

@ -601,7 +601,7 @@ static LibError wdll_shutdown()
// changes __puiHead!
}
return INFO_OK;
return INFO::OK;
}

View File

@ -46,14 +46,14 @@ static LibError get_ver(const char* module_path, char* out_ver, size_t out_ver_l
wchar_t buf[1000];
swprintf(buf, 1000, L"path: %hs; GLE: %08X", module_path, GetLastError());
DISPLAY_ERROR(buf);
return ERR_FAIL;
// WARN_RETURN(ERR_FAIL);
return ERR::FAIL;
// WARN_RETURN(ERR::FAIL);
}
void* buf = malloc(ver_size);
if(!buf)
WARN_RETURN(ERR_NO_MEM);
WARN_RETURN(ERR::NO_MEM);
LibError ret = ERR_FAIL; // single point of exit (for free())
LibError ret = ERR::FAIL; // single point of exit (for free())
if(GetFileVersionInfo(module_path, 0, ver_size, buf))
{
@ -69,7 +69,7 @@ static LibError get_ver(const char* module_path, char* out_ver, size_t out_ver_l
if(VerQueryValue(buf, subblock, (void**)&in_ver, &in_ver_len))
{
strcpy_s(out_ver, out_ver_len, in_ver);
ret = INFO_OK;
ret = INFO::OK;
}
}
}
@ -106,7 +106,7 @@ LibError dll_list_add(const char* name)
{
// not be called before dll_list_init or after failure
if(!dll_list_pos)
WARN_RETURN(ERR_LOGIC);
WARN_RETURN(ERR::LOGIC);
// some driver names are stored in the registry without .dll extension.
// if necessary, copy to new buffer and add it there.
@ -141,11 +141,11 @@ LibError dll_list_add(const char* name)
if(len > 0)
{
dll_list_pos += len;
return INFO_OK;
return INFO::OK;
}
// didn't fit; complain
sprintf(dll_list_pos, "..."); // (room was reserved above)
dll_list_pos = 0; // poison pill, prevent further calls
WARN_RETURN(ERR_BUF_SIZE);
WARN_RETURN(ERR::BUF_SIZE);
}

View File

@ -169,7 +169,7 @@ int type_size(TCHAR type, int length)
return 0;
}
extern "C" int vsnprintf2(TCHAR* buffer, size_t count, const TCHAR* format, va_list argptr)
int vsnprintf2(TCHAR* buffer, size_t count, const TCHAR* format, va_list argptr)
{
/*

View File

@ -207,7 +207,7 @@ static HANDLE aio_h_get(const int fd)
static LibError aio_h_set(const int fd, const HANDLE h)
{
if(fd < 0)
WARN_RETURN(ERR_INVALID_PARAM);
WARN_RETURN(ERR::INVALID_PARAM);
lock();
@ -220,7 +220,7 @@ static LibError aio_h_set(const int fd, const HANDLE h)
HANDLE* hs2 = (HANDLE*)realloc(aio_hs, size2*sizeof(HANDLE));
if(!hs2)
{
err = ERR_NO_MEM;
err = ERR::NO_MEM;
goto fail;
}
// don't assign directly from realloc -
@ -242,13 +242,13 @@ static LibError aio_h_set(const int fd, const HANDLE h)
// already set
if(aio_hs[fd] != INVALID_HANDLE_VALUE)
{
err = ERR_LOGIC;
err = ERR::LOGIC;
goto fail;
}
// setting invalid handle
if(!is_valid_file_handle(h))
{
err = ERR_TNODE_WRONG_TYPE;
err = ERR::INVALID_HANDLE;
goto fail;
}
}
@ -256,7 +256,7 @@ static LibError aio_h_set(const int fd, const HANDLE h)
aio_hs[fd] = h;
unlock();
return INFO_OK;
return INFO::OK;
fail:
unlock();
@ -435,7 +435,7 @@ static LibError req_free(Req* r)
{
debug_assert(r->cb != 0 && "req_free: not currently in use");
r->cb = 0;
return INFO_OK;
return INFO::OK;
}
@ -596,7 +596,7 @@ static int aio_rw(struct aiocb* cb)
ok = TRUE;
// .. translate from Win32 result code to POSIX
LibError err = LibError_from_win32(ok);
if(err == INFO_OK)
if(err == INFO::OK)
ret = 0;
LibError_set_errno(err);
@ -797,7 +797,7 @@ int aio_fsync(int, struct aiocb*)
static LibError waio_init()
{
req_init();
return INFO_OK;
return INFO::OK;
}
@ -805,5 +805,5 @@ static LibError waio_shutdown()
{
req_cleanup();
aio_h_cleanup();
return INFO_OK;
return INFO::OK;
}

View File

@ -117,7 +117,7 @@ LibError win_get_cpu_info()
check_speedstep();
return INFO_OK;
return INFO::OK;
}
@ -136,11 +136,11 @@ LibError sys_on_each_cpu(void (*cb)())
const HANDLE hProcess = GetCurrentProcess();
DWORD process_affinity, system_affinity;
if(!GetProcessAffinityMask(hProcess, &process_affinity, &system_affinity))
WARN_RETURN(ERR_FAIL);
WARN_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)
WARN_RETURN(ERR_CPU_RESTRICTED_AFFINITY);
WARN_RETURN(ERR::CPU_RESTRICTED_AFFINITY);
for(DWORD cpu_bit = 1; cpu_bit != 0 && cpu_bit <= process_affinity; cpu_bit *= 2)
{
@ -150,7 +150,7 @@ LibError sys_on_each_cpu(void (*cb)())
// .. and do so.
if(!SetProcessAffinityMask(hProcess, process_affinity))
{
WARN_ERR(ERR_CPU_RESTRICTED_AFFINITY);
WARN_ERR(ERR::CPU_RESTRICTED_AFFINITY);
continue;
}
@ -163,7 +163,7 @@ LibError sys_on_each_cpu(void (*cb)())
// restore to original value
SetProcessAffinityMask(hProcess, process_affinity);
return INFO_OK;
return INFO::OK;
}
@ -309,19 +309,19 @@ LibError prof_start()
const DWORD access = THREAD_GET_CONTEXT|THREAD_SUSPEND_RESUME;
HANDLE hThread = OpenThread(access, FALSE, GetCurrentThreadId());
if(hThread == INVALID_HANDLE_VALUE)
WARN_RETURN(ERR_FAIL);
WARN_RETURN(ERR::FAIL);
prof_target_thread = hThread;
sem_init(&exit_flag, 0, 0);
pthread_create(&thread, 0, prof_thread_func, 0);
return INFO_OK;
return INFO::OK;
}
LibError prof_shutdown()
{
WARN_IF_FALSE(CloseHandle(prof_target_thread));
return INFO_OK;
return INFO::OK;
}

View File

@ -210,7 +210,7 @@ static LibError call_while_suspended(WhileSuspendedFunc func, void* user_arg)
const DWORD access = THREAD_GET_CONTEXT|THREAD_SET_CONTEXT|THREAD_SUSPEND_RESUME;
HANDLE hThread = OpenThread(access, FALSE, GetCurrentThreadId());
if(hThread == INVALID_HANDLE_VALUE)
WARN_RETURN(ERR_FAIL);
WARN_RETURN(ERR::FAIL);
WhileSuspendedParam param = { hThread, func, user_arg };
@ -264,7 +264,7 @@ static const uint MAX_BREAKPOINTS = 4;
static LibError brk_disable_all_in_ctx(BreakInfo* UNUSED(bi), CONTEXT* context)
{
context->Dr7 &= ~brk_all_local_enables;
return INFO_OK;
return INFO::OK;
}
@ -284,7 +284,7 @@ static LibError brk_enable_in_ctx(BreakInfo* bi, CONTEXT* context)
if((context->Dr7 & LE) == 0)
goto have_reg;
}
WARN_RETURN(ERR_LIMIT);
WARN_RETURN(ERR::LIMIT);
have_reg:
// store breakpoint address in debug register.
@ -340,7 +340,7 @@ have_reg:
context->Dr7 |= LE;
brk_all_local_enables |= LE;
return INFO_OK;
return INFO::OK;
}
@ -354,7 +354,7 @@ static LibError brk_do_request(HANDLE hThread, void* arg)
CONTEXT context;
context.ContextFlags = CONTEXT_DEBUG_REGISTERS;
if(!GetThreadContext(hThread, &context))
WARN_RETURN(ERR_FAIL);
WARN_RETURN(ERR::FAIL);
#if CPU_IA32
if(bi->want_all_disabled)
@ -366,10 +366,10 @@ static LibError brk_do_request(HANDLE hThread, void* arg)
#endif
if(!SetThreadContext(hThread, &context))
WARN_RETURN(ERR_FAIL);
WARN_RETURN(ERR::FAIL);
RETURN_ERR(ret);
return INFO_OK;
return INFO::OK;
}
@ -378,7 +378,7 @@ static LibError brk_do_request(HANDLE hThread, void* arg)
// for simplicity, the length (range of bytes to be checked) is
// 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.
// return ERR::LIMIT if none are available.
LibError debug_set_break(void* p, DbgBreakType type)
{
lock();
@ -739,7 +739,7 @@ static LibError wdbg_init(void)
pAddVectoredExceptionHandler(TRUE, vectored_exception_handler);
#endif
return INFO_OK;
return INFO::OK;
}

View File

@ -23,10 +23,6 @@
#ifndef WDBG_H__
#define WDBG_H__
#ifdef __cplusplus
extern "C" {
#endif
#if HAVE_MS_ASM
# define debug_break() __asm { int 3 }
#else
@ -36,8 +32,4 @@ extern "C" {
// internal use only:
extern void wdbg_set_thread_name(const char* name);
#ifdef __cplusplus
}
#endif
#endif // #ifndef WDBG_H__

View File

@ -93,7 +93,7 @@ static LibError sym_init()
// don't use pthread_once because we need to return success/error code.
static uintptr_t already_initialized = 0;
if(!CAS(&already_initialized, 0, 1))
return INFO_OK;
return INFO::OK;
hProcess = GetCurrentProcess();
@ -120,7 +120,7 @@ static LibError sym_init()
IMAGE_NT_HEADERS* header = ImageNtHeader((void*)mod_base);
machine = header->FileHeader.Machine;
return INFO_OK;
return INFO::OK;
}
@ -128,7 +128,7 @@ static LibError sym_init()
static LibError sym_shutdown()
{
SymCleanup(hProcess);
return INFO_OK;
return INFO::OK;
}
@ -209,7 +209,7 @@ static LibError debug_resolve_symbol_lk(void* ptr_of_interest, char* sym_name, c
}
}
return (successes != 0)? INFO_OK : ERR_FAIL;
return (successes != 0)? INFO::OK : ERR::FAIL;
}
// read and return symbol information for the given address. all of the
@ -284,21 +284,21 @@ static LibError ia32_walk_stack(STACKFRAME64* sf)
void* prev_ip = (void*)sf->AddrPC .Offset;
void* prev_ret = (void*)sf->AddrReturn.Offset;
if(!debug_is_stack_ptr(prev_fp))
WARN_RETURN(ERR_11);
WARN_RETURN(ERR::_11);
if(prev_ip && !debug_is_code_ptr(prev_ip))
WARN_RETURN(ERR_12);
WARN_RETURN(ERR::_12);
if(prev_ret && !debug_is_code_ptr(prev_ret))
WARN_RETURN(ERR_13);
WARN_RETURN(ERR::_13);
// read stack frame
void* fp = ((void**)prev_fp)[0];
void* ret_addr = ((void**)prev_fp)[1];
if(!fp)
return INFO_ALL_COMPLETE;
return INFO::ALL_COMPLETE;
if(!debug_is_stack_ptr(fp))
WARN_RETURN(ERR_14);
WARN_RETURN(ERR::_14);
if(!debug_is_code_ptr(ret_addr))
WARN_RETURN(ERR_15);
WARN_RETURN(ERR::_15);
void* target;
LibError err = ia32_get_call_target(ret_addr, &target);
@ -310,7 +310,7 @@ static LibError ia32_walk_stack(STACKFRAME64* sf)
sf->AddrPC .Offset = (DWORD64)target;
sf->AddrReturn.Offset = (DWORD64)ret_addr;
return INFO_OK;
return INFO::OK;
}
#endif // #if CPU_IA32 && !CONFIG_OMIT_FP
@ -318,7 +318,7 @@ static LibError ia32_walk_stack(STACKFRAME64* sf)
// called for each stack frame found by walk_stack, passing information
// about the frame and <user_arg>.
// return INFO_CB_CONTINUE to continue, anything else to stop immediately
// return INFO::CB_CONTINUE to continue, anything else to stop immediately
// and return that value to walk_stack's caller.
//
// rationale: we can't just pass function's address to the callback -
@ -396,7 +396,7 @@ static LibError walk_stack(StackFrameCallback cb, void* user_arg = 0, uint skip
sf.AddrStack.Mode = AddrModeFlat;
// for each stack frame found:
LibError ret = ERR_SYM_NO_STACK_FRAMES_FOUND;
LibError ret = ERR::SYM_NO_STACK_FRAMES_FOUND;
for(;;)
{
// rationale:
@ -425,13 +425,13 @@ static LibError walk_stack(StackFrameCallback cb, void* user_arg = 0, uint skip
0, SymFunctionTableAccess64, SymGetModuleBase64, 0);
// note: don't use LibError_from_win32 because it raises a warning,
// and this "fails" commonly (when no stack frames are left).
err = ok? INFO_OK : ERR_FAIL;
err = ok? INFO::OK : ERR::FAIL;
#endif
// no more frames found - abort. note: also test FP because
// StackWalk64 sometimes erroneously reports success.
void* fp = (void*)(uintptr_t)sf.AddrFrame.Offset;
if(err != INFO_OK || !fp)
if(err != INFO::OK || !fp)
return ret;
if(skip)
@ -442,8 +442,8 @@ static LibError walk_stack(StackFrameCallback cb, void* user_arg = 0, uint skip
ret = cb(&sf, user_arg);
// callback is allowing us to continue
if(ret == INFO_CB_CONTINUE)
ret = INFO_OK; // make sure this is never returned
if(ret == INFO::CB_CONTINUE)
ret = INFO::OK; // make sure this is never returned
// callback reports it's done; stop calling it and return that value.
// (can be either success or failure)
else
@ -466,7 +466,7 @@ static LibError nth_caller_cb(const STACKFRAME64* sf, void* user_arg)
// return its address
*pfunc = (void*)sf->AddrPC.Offset;
return INFO_OK;
return INFO::OK;
}
@ -487,7 +487,7 @@ void* debug_get_nth_caller(uint skip, void* pcontext)
LibError err = walk_stack(nth_caller_cb, &func, skip, (const CONTEXT*)pcontext);
unlock();
return (err == INFO_OK)? func : 0;
return (err == INFO::OK)? func : 0;
}
@ -534,7 +534,7 @@ static wchar_t* out_pos;
// new position exceeds the limit and aborts if so.
// slight wrinkle: since we don't want each level of UDTs to successively
// realize the limit has been hit and display the error message, we
// return ERR_SYM_SINGLE_SYMBOL_LIMIT once and thereafter INFO_SYM_SUPPRESS_OUTPUT.
// return ERR::SYM_SINGLE_SYMBOL_LIMIT once and thereafter INFO::SYM_SUPPRESS_OUTPUT.
//
// * example: local variables, as opposed to child symbols in a UDT.
static wchar_t* out_latched_pos;
@ -619,15 +619,15 @@ static void out_latch_pos()
static LibError out_check_limit()
{
if(out_have_warned_of_limit)
return INFO_SYM_SUPPRESS_OUTPUT;
return INFO::SYM_SUPPRESS_OUTPUT;
if(out_pos - out_latched_pos > 3000) // ~30 lines
{
out_have_warned_of_limit = true;
return ERR_SYM_SINGLE_SYMBOL_LIMIT; // NOWARN
return ERR::SYM_SINGLE_SYMBOL_LIMIT; // NOWARN
}
// no limit hit, proceed normally
return INFO_OK;
return INFO::OK;
}
//----------------------------------------------------------------------------
@ -731,22 +731,22 @@ static void dump_error(LibError err, const u8* p)
case 0:
// no error => no output
break;
case ERR_SYM_SINGLE_SYMBOL_LIMIT:
case ERR::SYM_SINGLE_SYMBOL_LIMIT:
out(L"(too much output; skipping to next top-level symbol)");
break;
case ERR_SYM_UNRETRIEVABLE_STATIC:
case ERR::SYM_UNRETRIEVABLE_STATIC:
out(L"(unavailable - located in another module)");
break;
case ERR_SYM_UNRETRIEVABLE_REG:
case ERR::SYM_UNRETRIEVABLE_REG:
out(L"(unavailable - stored in register %s)", string_for_register((CV_HREG_e)(uintptr_t)p));
break;
case ERR_SYM_TYPE_INFO_UNAVAILABLE:
case ERR::SYM_TYPE_INFO_UNAVAILABLE:
out(L"(unavailable - type info request failed (GLE=%d))", GetLastError());
break;
case ERR_SYM_INTERNAL_ERROR:
case ERR::SYM_INTERNAL_ERROR:
out(L"(unavailable - internal error)\r\n");
break;
case INFO_SYM_SUPPRESS_OUTPUT:
case INFO::SYM_SUPPRESS_OUTPUT:
// not an error; do not output anything. handled by caller.
break;
default:
@ -761,10 +761,10 @@ static LibError dump_string(const u8* p, size_t el_size)
{
// not char or wchar_t string
if(el_size != sizeof(char) && el_size != sizeof(wchar_t))
return INFO_CANNOT_HANDLE;
return INFO::CANNOT_HANDLE;
// not text
if(!is_string(p, el_size))
return INFO_CANNOT_HANDLE;
return INFO::CANNOT_HANDLE;
wchar_t buf[512];
if(el_size == sizeof(wchar_t))
@ -783,7 +783,7 @@ static LibError dump_string(const u8* p, size_t el_size)
}
out(L"\"%s\"", buf);
return INFO_OK;
return INFO::OK;
}
@ -827,7 +827,7 @@ static LibError dump_sequence(DebugIterator el_iterator, void* internal,
el_p = el_iterator(internal, el_size);
LibError ret = dump_string(el_p, el_size);
if(ret == INFO_OK)
if(ret == INFO::OK)
return ret;
}
@ -850,20 +850,20 @@ static LibError dump_sequence(DebugIterator el_iterator, void* internal,
// there was no output for this child; undo its indentation (if any),
// skip everything below and proceed with the next child.
if(err == INFO_SYM_SUPPRESS_OUTPUT)
if(err == INFO::SYM_SUPPRESS_OUTPUT)
{
if(!fits_on_one_line)
UNINDENT;
continue;
}
dump_error(err, el_p); // nop if err == INFO_OK
dump_error(err, el_p); // nop if err == INFO::OK
// add separator unless this is the last element (can't just
// erase below due to additional "...").
if(i != num_elements_to_show-1)
out(fits_on_one_line? L", " : L"\r\n");
if(err == ERR_SYM_SINGLE_SYMBOL_LIMIT)
if(err == ERR::SYM_SINGLE_SYMBOL_LIMIT)
break;
} // for each child
@ -874,7 +874,7 @@ static LibError dump_sequence(DebugIterator el_iterator, void* internal,
state.level--;
if(fits_on_one_line)
out(L" }");
return INFO_OK;
return INFO::OK;
}
@ -904,7 +904,7 @@ static LibError determine_symbol_address(DWORD id, DWORD UNUSED(type_id), const
DWORD data_kind;
if(!SymGetTypeInfo(hProcess, mod_base, id, TI_GET_DATAKIND, &data_kind))
WARN_RETURN(ERR_SYM_TYPE_INFO_UNAVAILABLE);
WARN_RETURN(ERR::SYM_TYPE_INFO_UNAVAILABLE);
switch(data_kind)
{
// SymFromIndex will fail
@ -912,12 +912,12 @@ static LibError determine_symbol_address(DWORD id, DWORD UNUSED(type_id), const
// pp is already correct (udt_dump_normal retrieved the offset;
// we do it that way so we can check it against the total
// UDT size for safety).
return INFO_OK;
return INFO::OK;
// this symbol is defined as static in another module =>
// there's nothing we can do.
case DataIsStaticMember:
return ERR_SYM_UNRETRIEVABLE_STATIC; // NOWARN
return ERR::SYM_UNRETRIEVABLE_STATIC; // NOWARN
// ok; will handle below
case DataIsLocal:
@ -939,7 +939,7 @@ static LibError determine_symbol_address(DWORD id, DWORD UNUSED(type_id), const
SYMBOL_INFO_PACKAGEW2 sp;
SYMBOL_INFOW* sym = &sp.si;
if(!SymFromIndexW(hProcess, mod_base, id, sym))
WARN_RETURN(ERR_SYM_TYPE_INFO_UNAVAILABLE);
WARN_RETURN(ERR::SYM_TYPE_INFO_UNAVAILABLE);
DWORD addrofs = 0;
ULONG64 addr2 = 0;
@ -980,14 +980,14 @@ fp_rel:
{
in_register:
*pp = (const u8*)(uintptr_t)sym->Register;
return ERR_SYM_UNRETRIEVABLE_REG; // NOWARN
return ERR::SYM_UNRETRIEVABLE_REG; // NOWARN
}
*pp = (const u8*)addr;
debug_printf("SYM| %ws at %p flags=%X dk=%d sym->addr=%I64X addrofs=%X addr2=%I64X ofs2=%X\n", sym->Name, *pp, sym->Flags, data_kind, sym->Address, addrofs, addr2, ofs2);
return INFO_OK;
return INFO::OK;
}
@ -1004,18 +1004,18 @@ static LibError dump_sym_array(DWORD type_id, const u8* p, DumpState state)
{
ULONG64 size_ = 0;
if(!SymGetTypeInfo(hProcess, mod_base, type_id, TI_GET_LENGTH, &size_))
WARN_RETURN(ERR_SYM_TYPE_INFO_UNAVAILABLE);
WARN_RETURN(ERR::SYM_TYPE_INFO_UNAVAILABLE);
const size_t size = (size_t)size_;
// get element count and size
DWORD el_type_id = 0;
if(!SymGetTypeInfo(hProcess, mod_base, type_id, TI_GET_TYPEID, &el_type_id))
WARN_RETURN(ERR_SYM_TYPE_INFO_UNAVAILABLE);
WARN_RETURN(ERR::SYM_TYPE_INFO_UNAVAILABLE);
// .. workaround: TI_GET_COUNT returns total struct size for
// arrays-of-struct. therefore, calculate as size / el_size.
ULONG64 el_size_;
if(!SymGetTypeInfo(hProcess, mod_base, el_type_id, TI_GET_LENGTH, &el_size_))
WARN_RETURN(ERR_SYM_TYPE_INFO_UNAVAILABLE);
WARN_RETURN(ERR::SYM_TYPE_INFO_UNAVAILABLE);
const size_t el_size = (size_t)el_size_;
debug_assert(el_size != 0);
const size_t num_elements = size/el_size;
@ -1031,10 +1031,10 @@ static LibError dump_sym_base_type(DWORD type_id, const u8* p, DumpState state)
{
DWORD base_type;
if(!SymGetTypeInfo(hProcess, mod_base, type_id, TI_GET_BASETYPE, &base_type))
WARN_RETURN(ERR_SYM_TYPE_INFO_UNAVAILABLE);
WARN_RETURN(ERR::SYM_TYPE_INFO_UNAVAILABLE);
ULONG64 size_ = 0;
if(!SymGetTypeInfo(hProcess, mod_base, type_id, TI_GET_LENGTH, &size_))
WARN_RETURN(ERR_SYM_TYPE_INFO_UNAVAILABLE);
WARN_RETURN(ERR::SYM_TYPE_INFO_UNAVAILABLE);
const size_t size = (size_t)size_;
// single out() call. note: we pass a single u64 for all sizes,
@ -1153,7 +1153,7 @@ display_as_hex:
case btBit:
case btBSTR:
case btHresult:
return ERR_SYM_UNSUPPORTED; // NOWARN
return ERR::SYM_UNSUPPORTED; // NOWARN
}
out(fmt, data);
@ -1167,7 +1167,7 @@ display_as_hex:
out(L" ('%hc')", c);
}
return INFO_OK;
return INFO::OK;
}
@ -1177,14 +1177,14 @@ static LibError dump_sym_base_class(DWORD type_id, const u8* p, DumpState state)
{
DWORD base_class_type_id;
if(!SymGetTypeInfo(hProcess, mod_base, type_id, TI_GET_TYPEID, &base_class_type_id))
WARN_RETURN(ERR_SYM_TYPE_INFO_UNAVAILABLE);
WARN_RETURN(ERR::SYM_TYPE_INFO_UNAVAILABLE);
// this is a virtual base class. we can't display those because it'd
// require reading the VTbl, which is difficult given lack of documentation
// and just not worth it.
DWORD vptr_ofs;
if(SymGetTypeInfo(hProcess, mod_base, type_id, TI_GET_VIRTUALBASEPOINTEROFFSET, &vptr_ofs))
return ERR_SYM_UNSUPPORTED; // NOWARN
return ERR::SYM_UNSUPPORTED; // NOWARN
return dump_sym(base_class_type_id, p, state);
@ -1199,7 +1199,7 @@ static LibError dump_sym_data(DWORD id, const u8* p, DumpState state)
// display name (of variable/member)
const wchar_t* name;
if(!SymGetTypeInfo(hProcess, mod_base, id, TI_GET_SYMNAME, &name))
WARN_RETURN(ERR_SYM_TYPE_INFO_UNAVAILABLE);
WARN_RETURN(ERR::SYM_TYPE_INFO_UNAVAILABLE);
out(L"%s = ", name);
LocalFree((HLOCAL)name);
@ -1208,7 +1208,7 @@ static LibError dump_sym_data(DWORD id, const u8* p, DumpState state)
// get type_id and address
DWORD type_id;
if(!SymGetTypeInfo(hProcess, mod_base, id, TI_GET_TYPEID, &type_id))
WARN_RETURN(ERR_SYM_TYPE_INFO_UNAVAILABLE);
WARN_RETURN(ERR::SYM_TYPE_INFO_UNAVAILABLE);
RETURN_ERR(determine_symbol_address(id, type_id, &p));
// display value recursively
@ -1216,7 +1216,7 @@ static LibError dump_sym_data(DWORD id, const u8* p, DumpState state)
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
return ERR_SYM_INTERNAL_ERROR; // NOWARN
return ERR::SYM_INTERNAL_ERROR; // NOWARN
}
}
@ -1227,7 +1227,7 @@ static LibError dump_sym_enum(DWORD type_id, const u8* p, DumpState UNUSED(state
{
ULONG64 size_ = 0;
if(!SymGetTypeInfo(hProcess, mod_base, type_id, TI_GET_LENGTH, &size_))
WARN_RETURN(ERR_SYM_TYPE_INFO_UNAVAILABLE);
WARN_RETURN(ERR::SYM_TYPE_INFO_UNAVAILABLE);
const size_t size = (size_t)size_;
const i64 enum_value = movsx_64le(p, size);
@ -1235,10 +1235,10 @@ static LibError dump_sym_enum(DWORD type_id, const u8* p, DumpState UNUSED(state
// get array of child symbols (enumerants).
DWORD num_children;
if(!SymGetTypeInfo(hProcess, mod_base, type_id, TI_GET_CHILDRENCOUNT, &num_children))
WARN_RETURN(ERR_SYM_TYPE_INFO_UNAVAILABLE);
WARN_RETURN(ERR::SYM_TYPE_INFO_UNAVAILABLE);
TI_FINDCHILDREN_PARAMS2 fcp(num_children);
if(!SymGetTypeInfo(hProcess, mod_base, type_id, TI_FINDCHILDREN, &fcp))
WARN_RETURN(ERR_SYM_TYPE_INFO_UNAVAILABLE);
WARN_RETURN(ERR::SYM_TYPE_INFO_UNAVAILABLE);
num_children = fcp.p.Count; // was truncated to MAX_CHILDREN
const DWORD* children = fcp.p.ChildId;
@ -1254,7 +1254,7 @@ static LibError dump_sym_enum(DWORD type_id, const u8* p, DumpState UNUSED(state
// already pulled in by e.g. OpenGL anyway.
VARIANT v;
if(!SymGetTypeInfo(hProcess, mod_base, child_data_id, TI_GET_VALUE, &v))
WARN_RETURN(ERR_SYM_TYPE_INFO_UNAVAILABLE);
WARN_RETURN(ERR::SYM_TYPE_INFO_UNAVAILABLE);
if(VariantChangeType(&v, &v, 0, VT_I8) != S_OK)
continue;
@ -1263,10 +1263,10 @@ static LibError dump_sym_enum(DWORD type_id, const u8* p, DumpState UNUSED(state
{
const wchar_t* name;
if(!SymGetTypeInfo(hProcess, mod_base, child_data_id, TI_GET_SYMNAME, &name))
WARN_RETURN(ERR_SYM_TYPE_INFO_UNAVAILABLE);
WARN_RETURN(ERR::SYM_TYPE_INFO_UNAVAILABLE);
out(L"%s", name);
LocalFree((HLOCAL)name);
return INFO_OK;
return INFO::OK;
}
}
@ -1275,7 +1275,7 @@ static LibError dump_sym_enum(DWORD type_id, const u8* p, DumpState UNUSED(state
// note: could goto here after a SGTI fails, but we fail instead
// to make sure those errors are noticed.
out(L"%I64d", enum_value);
return INFO_OK;
return INFO::OK;
}
@ -1284,7 +1284,7 @@ static LibError dump_sym_enum(DWORD type_id, const u8* p, DumpState UNUSED(state
static LibError dump_sym_function(DWORD UNUSED(type_id), const u8* UNUSED(p),
DumpState UNUSED(state))
{
return INFO_SYM_SUPPRESS_OUTPUT;
return INFO::SYM_SUPPRESS_OUTPUT;
}
@ -1300,9 +1300,9 @@ static LibError dump_sym_function_type(DWORD UNUSED(type_id), const u8* p, DumpS
LibError err = debug_resolve_symbol_lk((void*)p, name, 0, 0);
out(L"0x%p", p);
if(err == INFO_OK)
if(err == INFO::OK)
out(L" (%hs)", name);
return INFO_OK;
return INFO::OK;
}
@ -1340,7 +1340,7 @@ static LibError dump_sym_pointer(DWORD type_id, const u8* p, DumpState state)
{
ULONG64 size_ = 0;
if(!SymGetTypeInfo(hProcess, mod_base, type_id, TI_GET_LENGTH, &size_))
WARN_RETURN(ERR_SYM_TYPE_INFO_UNAVAILABLE);
WARN_RETURN(ERR::SYM_TYPE_INFO_UNAVAILABLE);
const size_t size = (size_t)size_;
// read+output pointer's value.
@ -1350,13 +1350,13 @@ static LibError dump_sym_pointer(DWORD type_id, const u8* p, DumpState state)
// bail if it's obvious the pointer is bogus
// (=> can't display what it's pointing to)
if(debug_is_pointer_bogus(p))
return INFO_OK;
return INFO::OK;
// avoid duplicates and circular references
if(ptr_already_visited(p))
{
out(L" (see above)");
return INFO_OK;
return INFO::OK;
}
// display what the pointer is pointing to.
@ -1366,11 +1366,11 @@ static LibError dump_sym_pointer(DWORD type_id, const u8* p, DumpState state)
// the responsible dump_sym* will erase "->", leaving only address.
out(L" -> ");
if(!SymGetTypeInfo(hProcess, mod_base, type_id, TI_GET_TYPEID, &type_id))
WARN_RETURN(ERR_SYM_TYPE_INFO_UNAVAILABLE);
WARN_RETURN(ERR::SYM_TYPE_INFO_UNAVAILABLE);
// prevent infinite recursion just to be safe (shouldn't happen)
if(state.indirection >= MAX_INDIRECTION)
WARN_RETURN(ERR_SYM_NESTING_LIMIT);
WARN_RETURN(ERR::SYM_NESTING_LIMIT);
state.indirection++;
return dump_sym(type_id, p, state);
}
@ -1382,7 +1382,7 @@ static LibError dump_sym_pointer(DWORD type_id, const u8* p, DumpState state)
static LibError dump_sym_typedef(DWORD type_id, const u8* p, DumpState state)
{
if(!SymGetTypeInfo(hProcess, mod_base, type_id, TI_GET_TYPEID, &type_id))
WARN_RETURN(ERR_SYM_TYPE_INFO_UNAVAILABLE);
WARN_RETURN(ERR::SYM_TYPE_INFO_UNAVAILABLE);
return dump_sym(type_id, p, state);
}
@ -1416,19 +1416,19 @@ static LibError udt_get_child_type(const wchar_t* child_name,
// .. its type information is what we want.
DWORD type_id;
if(!SymGetTypeInfo(hProcess, mod_base, child_id, TI_GET_TYPEID, &type_id))
WARN_RETURN(ERR_SYM_TYPE_INFO_UNAVAILABLE);
WARN_RETURN(ERR::SYM_TYPE_INFO_UNAVAILABLE);
ULONG64 size;
if(!SymGetTypeInfo(hProcess, mod_base, child_id, TI_GET_LENGTH, &size))
WARN_RETURN(ERR_SYM_TYPE_INFO_UNAVAILABLE);
WARN_RETURN(ERR::SYM_TYPE_INFO_UNAVAILABLE);
*el_type_id = type_id;
*el_size = (size_t)size;
return INFO_OK;
return INFO::OK;
}
// (happens if called for containers that are treated as STL but are not)
return ERR_SYM_CHILD_NOT_FOUND; // NOWARN
return ERR::SYM_CHILD_NOT_FOUND; // NOWARN
}
@ -1439,13 +1439,13 @@ static LibError udt_dump_std(const wchar_t* wtype_name, const u8* p, size_t size
// not a C++ standard library object; can't handle it.
if(wcsncmp(wtype_name, L"std::", 5) != 0)
return INFO_CANNOT_HANDLE;
return INFO::CANNOT_HANDLE;
// check for C++ objects that should be displayed via udt_dump_normal.
// STL containers are special-cased and the rest (apart from those here)
// are ignored, because for the most part they are spew.
if(!wcsncmp(wtype_name, L"std::pair", 9))
return INFO_CANNOT_HANDLE;
return INFO::CANNOT_HANDLE;
// convert to char since debug_stl doesn't support wchar_t.
char ctype_name[DBG_SYMBOL_LEN];
@ -1456,14 +1456,14 @@ static LibError udt_dump_std(const wchar_t* wtype_name, const u8* p, size_t size
DWORD el_type_id;
size_t el_size;
err = udt_get_child_type(L"value_type", num_children, children, &el_type_id, &el_size);
if(err != INFO_OK)
if(err != INFO::OK)
goto not_valid_container;
// .. get iterator and # elements
size_t el_count;
DebugIterator el_iterator;
u8 it_mem[DEBUG_STL_MAX_ITERATOR_SIZE];
err = debug_stl_get_container_info(ctype_name, p, size, el_size, &el_count, &el_iterator, it_mem);
if(err != INFO_OK)
if(err != INFO::OK)
goto not_valid_container;
return dump_sequence(el_iterator, it_mem, el_count, el_type_id, el_size, state);
not_valid_container:
@ -1475,13 +1475,13 @@ not_valid_container:
// it's a non-STL C++ stdlib object. wasn't handled by the
// special case above, so we just display its simplified type name
// (the contents are usually spew).
if(err == ERR_SYM_CHILD_NOT_FOUND)
if(err == ERR::SYM_CHILD_NOT_FOUND)
text = "";
// .. not one of the containers we can analyse.
if(err == ERR_STL_CNT_UNKNOWN)
if(err == ERR::STL_CNT_UNKNOWN)
text = "unsupported ";
// .. container of a known type but contents are invalid.
if(err == ERR_STL_CNT_INVALID)
if(err == ERR::STL_CNT_INVALID)
text = "uninitialized/invalid ";
// .. some other error encountered
else
@ -1490,7 +1490,7 @@ not_valid_container:
text = buf;
}
out(L"(%hs%hs)", text, debug_stl_simplify_name(ctype_name));
return INFO_OK;
return INFO::OK;
}
@ -1547,7 +1547,7 @@ static LibError udt_dump_suppressed(const wchar_t* type_name, const u8* UNUSED(p
DumpState state, ULONG UNUSED(num_children), const DWORD* UNUSED(children))
{
if(!udt_should_suppress(type_name))
return INFO_CANNOT_HANDLE;
return INFO::CANNOT_HANDLE;
// the data symbol is pointer-to-UDT. since we won't display its
// contents, leave only the pointer's value.
@ -1558,7 +1558,7 @@ static LibError udt_dump_suppressed(const wchar_t* type_name, const u8* UNUSED(p
// (otherwise, lack of output may be taken for an error)
out(L" (..)");
return INFO_OK;
return INFO::OK;
}
@ -1603,7 +1603,7 @@ static LibError udt_dump_normal(const wchar_t* type_name, const u8* p, size_t si
// prevent infinite recursion just to be safe (shouldn't happen)
if(state.level >= MAX_LEVEL)
WARN_RETURN(ERR_SYM_NESTING_LIMIT);
WARN_RETURN(ERR::SYM_NESTING_LIMIT);
state.level++;
out(fits_on_one_line? L"{ " : L"\r\n");
@ -1628,7 +1628,7 @@ static LibError udt_dump_normal(const wchar_t* type_name, const u8* p, size_t si
// there was no output for this child; undo its indentation (if any),
// skip everything below and proceed with the next child.
if(err == INFO_SYM_SUPPRESS_OUTPUT)
if(err == INFO::SYM_SUPPRESS_OUTPUT)
{
if(!fits_on_one_line)
UNINDENT;
@ -1636,10 +1636,10 @@ static LibError udt_dump_normal(const wchar_t* type_name, const u8* p, size_t si
}
displayed_anything = true;
dump_error(err, el_p); // nop if err == INFO_OK
dump_error(err, el_p); // nop if err == INFO::OK
out(fits_on_one_line? L", " : L"\r\n");
if(err == ERR_SYM_SINGLE_SYMBOL_LIMIT)
if(err == ERR::SYM_SINGLE_SYMBOL_LIMIT)
break;
} // for each child
@ -1649,7 +1649,7 @@ static LibError udt_dump_normal(const wchar_t* type_name, const u8* p, size_t si
{
out_erase(2); // "{ " or "\r\n"
out(L"(%s)", type_name);
return INFO_OK;
return INFO::OK;
}
// remove trailing comma separator
@ -1661,7 +1661,7 @@ static LibError udt_dump_normal(const wchar_t* type_name, const u8* p, size_t si
out(L" }");
}
return INFO_OK;
return INFO::OK;
}
@ -1669,37 +1669,37 @@ static LibError dump_sym_udt(DWORD type_id, const u8* p, DumpState state)
{
ULONG64 size_ = 0;
if(!SymGetTypeInfo(hProcess, mod_base, type_id, TI_GET_LENGTH, &size_))
WARN_RETURN(ERR_SYM_TYPE_INFO_UNAVAILABLE);
WARN_RETURN(ERR::SYM_TYPE_INFO_UNAVAILABLE);
const size_t size = (size_t)size_;
// get array of child symbols (members/functions/base classes).
DWORD num_children;
if(!SymGetTypeInfo(hProcess, mod_base, type_id, TI_GET_CHILDRENCOUNT, &num_children))
WARN_RETURN(ERR_SYM_TYPE_INFO_UNAVAILABLE);
WARN_RETURN(ERR::SYM_TYPE_INFO_UNAVAILABLE);
TI_FINDCHILDREN_PARAMS2 fcp(num_children);
if(!SymGetTypeInfo(hProcess, mod_base, type_id, TI_FINDCHILDREN, &fcp))
WARN_RETURN(ERR_SYM_TYPE_INFO_UNAVAILABLE);
WARN_RETURN(ERR::SYM_TYPE_INFO_UNAVAILABLE);
num_children = fcp.p.Count; // was truncated to MAX_CHILDREN
const DWORD* children = fcp.p.ChildId;
const wchar_t* type_name;
if(!SymGetTypeInfo(hProcess, mod_base, type_id, TI_GET_SYMNAME, &type_name))
WARN_RETURN(ERR_SYM_TYPE_INFO_UNAVAILABLE);
WARN_RETURN(ERR::SYM_TYPE_INFO_UNAVAILABLE);
LibError ret;
// note: order is important (e.g. STL special-case must come before
// suppressing UDTs, which tosses out most other C++ stdlib classes)
ret = udt_dump_std (type_name, p, size, state, num_children, children);
if(ret != INFO_CANNOT_HANDLE)
if(ret != INFO::CANNOT_HANDLE)
goto done;
ret = udt_dump_suppressed(type_name, p, size, state, num_children, children);
if(ret != INFO_CANNOT_HANDLE)
if(ret != INFO::CANNOT_HANDLE)
goto done;
ret = udt_dump_normal (type_name, p, size, state, num_children, children);
if(ret != INFO_CANNOT_HANDLE)
if(ret != INFO::CANNOT_HANDLE)
goto done;
done:
@ -1714,7 +1714,7 @@ done:
static LibError dump_sym_vtable(DWORD UNUSED(type_id), const u8* UNUSED(p), DumpState UNUSED(state))
{
// unsupported (vtable internals are undocumented; too much work).
return INFO_SYM_SUPPRESS_OUTPUT;
return INFO::SYM_SUPPRESS_OUTPUT;
}
@ -1726,11 +1726,11 @@ static LibError dump_sym_unknown(DWORD type_id, const u8* UNUSED(p), DumpState U
// redundant (already done in dump_sym), but this is rare.
DWORD type_tag;
if(!SymGetTypeInfo(hProcess, mod_base, type_id, TI_GET_SYMTAG, &type_tag))
WARN_RETURN(ERR_SYM_TYPE_INFO_UNAVAILABLE);
WARN_RETURN(ERR::SYM_TYPE_INFO_UNAVAILABLE);
debug_printf("SYM| unknown tag: %d\n", type_tag);
out(L"(unknown symbol type)");
return INFO_OK;
return INFO::OK;
}
@ -1745,7 +1745,7 @@ static LibError dump_sym(DWORD type_id, const u8* p, DumpState state)
DWORD type_tag;
if(!SymGetTypeInfo(hProcess, mod_base, type_id, TI_GET_SYMTAG, &type_tag))
WARN_RETURN(ERR_SYM_TYPE_INFO_UNAVAILABLE);
WARN_RETURN(ERR::SYM_TYPE_INFO_UNAVAILABLE);
switch(type_tag)
{
case SymTagArrayType:
@ -1794,7 +1794,7 @@ static BOOL CALLBACK dump_sym_cb(SYMBOL_INFO* sym, ULONG UNUSED(size), void* UNU
INDENT;
LibError err = dump_sym(sym->Index, p, state);
dump_error(err, p);
if(err == INFO_SYM_SUPPRESS_OUTPUT)
if(err == INFO::SYM_SUPPRESS_OUTPUT)
UNINDENT;
else
out(L"\r\n");
@ -1834,7 +1834,7 @@ static LibError dump_frame_cb(const STACKFRAME64* sf, void* UNUSED(user_arg))
char func_name[DBG_SYMBOL_LEN]; char file[DBG_FILE_LEN]; int line;
LibError ret = debug_resolve_symbol_lk(func, func_name, file, &line);
if(ret == INFO_OK)
if(ret == INFO::OK)
{
// don't trace back further than the app's entry point
// (no one wants to see this frame). checking for the
@ -1842,7 +1842,7 @@ static LibError dump_frame_cb(const STACKFRAME64* sf, void* UNUSED(user_arg))
// an alternative would be to check if module=kernel32, but
// that would cut off callbacks as well.
if(!strcmp(func_name, "_BaseProcessStart@4"))
return INFO_OK;
return INFO::OK;
out(L"%hs (%hs:%d)\r\n", func_name, file, line);
}
@ -1862,7 +1862,7 @@ static LibError dump_frame_cb(const STACKFRAME64* sf, void* UNUSED(user_arg))
// should be used.
out(L"\r\n");
return INFO_CB_CONTINUE;
return INFO::CB_CONTINUE;
}
@ -1870,7 +1870,7 @@ LibError debug_dump_stack(wchar_t* buf, size_t max_chars, uint skip, void* pcont
{
static uintptr_t already_in_progress;
if(!CAS(&already_in_progress, 0, 1))
return ERR_REENTERED; // NOWARN
return ERR::REENTERED; // NOWARN
lock();
out_init(buf, max_chars);
@ -1940,7 +1940,7 @@ static LibError wdbg_sym_init()
HMODULE hKernel32Dll = GetModuleHandle("kernel32.dll");
*(void**)&pRtlCaptureContext = GetProcAddress(hKernel32Dll, "RtlCaptureContext");
return INFO_OK;
return INFO::OK;
}

View File

@ -168,7 +168,7 @@ static LibError wdir_watch_shutdown()
delete it->second;
watches.clear();
return INFO_OK;
return INFO::OK;
}
@ -185,7 +185,7 @@ static Watch* find_watch(intptr_t reqnum)
// better to use a cached string from rel_chdir - secure
LibError dir_add_watch(const char* dir, intptr_t* _reqnum)
{
LibError err = ERR_FAIL;
LibError err = ERR::FAIL;
WIN_SAVE_LAST_ERROR; // Create*
intptr_t reqnum;
@ -268,7 +268,7 @@ LibError dir_add_watch(const char* dir, intptr_t* _reqnum)
}
done:
err = INFO_OK;
err = INFO::OK;
*_reqnum = reqnum;
fail:
@ -280,17 +280,17 @@ fail:
LibError dir_cancel_watch(const intptr_t reqnum)
{
if(reqnum <= 0)
WARN_RETURN(ERR_INVALID_PARAM);
WARN_RETURN(ERR::INVALID_PARAM);
Watch* w = find_watch(reqnum);
// watches[reqnum] is invalid - big trouble
if(!w)
WARN_RETURN(ERR_FAIL);
WARN_RETURN(ERR::FAIL);
// we're freeing a reference - done.
debug_assert(w->refs >= 1);
if(--w->refs != 0)
return INFO_OK;
return INFO::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.
@ -375,7 +375,7 @@ static void get_packet()
// if a file change notification is pending, store its filename in <fn> and
// return INFO_OK; otherwise, return ERR_AGAIN ('none currently pending') or
// return INFO::OK; otherwise, return ERR::AGAIN ('none currently pending') or
// a negative error code.
// <fn> must hold at least PATH_MAX chars.
LibError dir_get_changed_file(char* fn)
@ -385,11 +385,11 @@ LibError dir_get_changed_file(char* fn)
// nothing to return; call again later.
if(pending_events.empty())
return ERR_AGAIN; // NOWARN
return ERR::AGAIN; // NOWARN
const std::string& fn_s = pending_events.front();
strcpy_s(fn, PATH_MAX, fn_s.c_str());
pending_events.pop_front();
return INFO_OK;
return INFO::OK;
}

View File

@ -45,7 +45,7 @@ LibError gfx_get_video_mode(int* xres, int* yres, int* bpp, int* freq)
// dm.dmDriverExtra already set to 0 by memset
if(!EnumDisplaySettingsA(0, ENUM_CURRENT_SETTINGS, &dm))
WARN_RETURN(ERR_FAIL);
WARN_RETURN(ERR::FAIL);
if(dm.dmFields & (DWORD)DM_PELSWIDTH && xres)
*xres = (int)dm.dmPelsWidth;
@ -56,7 +56,7 @@ LibError gfx_get_video_mode(int* xres, int* yres, int* bpp, int* freq)
if(dm.dmFields & (DWORD)DM_DISPLAYFREQUENCY && freq)
*freq = (int)dm.dmDisplayFrequency;
return INFO_OK;
return INFO::OK;
}
@ -69,7 +69,7 @@ LibError gfx_get_monitor_size(int& width_mm, int& height_mm)
width_mm = GetDeviceCaps(dc, HORZSIZE);
height_mm = GetDeviceCaps(dc, VERTSIZE);
ReleaseDC(0, dc);
return INFO_OK;
return INFO::OK;
}
@ -93,7 +93,7 @@ static LibError import_EnumDisplayDevices()
// so this resource leak is unavoidable.
}
return pEnumDisplayDevicesA? INFO_OK : ERR_FAIL;
return pEnumDisplayDevicesA? INFO::OK : ERR::FAIL;
}
@ -120,12 +120,12 @@ static LibError win_get_gfx_card()
if(dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
{
strcpy_s(gfx_card, ARRAY_SIZE(gfx_card), (const char*)dd.DeviceString);
return INFO_OK;
return INFO::OK;
}
}
}
WARN_RETURN(ERR_FAIL);
WARN_RETURN(ERR::FAIL);
}
@ -134,7 +134,7 @@ static LibError win_get_gfx_drv_ver()
{
// don't overwrite existing information
if(gfx_drv_ver[0] != '\0')
return INFO_SKIPPED;
return INFO::SKIPPED;
// rationale:
// - we could easily determine the 2d driver via EnumDisplaySettings,
@ -153,7 +153,7 @@ static LibError win_get_gfx_drv_ver()
// gfx_card which one is correct; we thus avoid driver-specific
// name checks and reporting incorrectly.
LibError ret = ERR_FAIL; // single point of exit (for RegCloseKey)
LibError ret = ERR::FAIL; // single point of exit (for RegCloseKey)
DWORD i;
char drv_name[MAX_PATH+1];
@ -162,7 +162,7 @@ static LibError 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)
WARN_RETURN(ERR_FAIL);
WARN_RETURN(ERR::FAIL);
// for each subkey (i.e. set of installed OpenGL drivers):
for(i = 0; ; i++)
@ -214,5 +214,5 @@ LibError win_get_gfx_info()
// don't exit before trying both
RETURN_ERR(err1);
RETURN_ERR(err2);
return INFO_OK;
return INFO::OK;
}

View File

@ -45,21 +45,22 @@ static LibError LibError_from_GLE(bool warn_if_failed = true)
switch(GetLastError())
{
case ERROR_OUTOFMEMORY:
err = ERR_NO_MEM; break;
err = ERR::NO_MEM; break;
case ERROR_INVALID_PARAMETER:
err = ERR_INVALID_PARAM; break;
err = ERR::INVALID_PARAM; break;
case ERROR_INSUFFICIENT_BUFFER:
err = ERR_BUF_SIZE; break;
err = ERR::BUF_SIZE; break;
/*/*
case ERROR_ACCESS_DENIED:
err = ERR_FILE_ACCESS; break;
err = ERR::FILE_ACCESS; break;
case ERROR_FILE_NOT_FOUND:
case ERROR_PATH_NOT_FOUND:
err = ERR_TNODE_NOT_FOUND; break;
err = ERR::TNODE_NOT_FOUND; break;
*/
default:
err = ERR_FAIL; break;
err = ERR::FAIL; break;
}
if(warn_if_failed)
@ -68,14 +69,14 @@ static LibError LibError_from_GLE(bool warn_if_failed = true)
}
// return the LibError equivalent of GetLastError(), or ERR_FAIL if
// 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, bool warn_if_failed)
{
if(ret != FALSE)
return INFO_OK;
return INFO::OK;
return LibError_from_GLE(warn_if_failed);
}

View File

@ -452,7 +452,7 @@ 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
// 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.

View File

@ -99,7 +99,7 @@ no_aio:
// warn now, so that we notice why so many are open.
#ifndef NDEBUG
if(fd > 256)
WARN_ERR(ERR_LIMIT);
WARN_ERR(ERR::LIMIT);
#endif
return fd;
@ -626,7 +626,7 @@ static LibError mmap_mem(void* start, size_t len, int prot, int flags, int fd, v
*pp = 0;
// make sure *pp won't be misinterpreted as an error
cassert(MAP_FAILED != 0);
return INFO_OK;
return INFO::OK;
}
}
@ -634,9 +634,9 @@ static LibError mmap_mem(void* start, size_t len, int prot, int flags, int fd, v
DWORD flProtect = win32_prot(prot);
void* p = VirtualAlloc(start, len, flAllocationType, flProtect);
if(!p)
WARN_RETURN(ERR_NO_MEM);
WARN_RETURN(ERR::NO_MEM);
*pp = p;
return INFO_OK;
return INFO::OK;
}
@ -669,11 +669,11 @@ static LibError mmap_file_access(int prot, int flags, DWORD& flProtect, DWORD& d
// definitely illegal according to POSIX and some man pages
// say exactly one must be set, so abort.
default:
WARN_RETURN(ERR_INVALID_PARAM);
WARN_RETURN(ERR::INVALID_PARAM);
}
}
return INFO_OK;
return INFO::OK;
}
@ -686,7 +686,7 @@ static LibError mmap_file(void* start, size_t len, int prot, int flags,
HANDLE hFile = HANDLE_from_intptr(_get_osfhandle(fd));
if(hFile == INVALID_HANDLE_VALUE)
WARN_RETURN(ERR_INVALID_PARAM);
WARN_RETURN(ERR::INVALID_PARAM);
// MapViewOfFileEx will fail if the "suggested" base address is
// nonzero but cannot be honored, so wipe out <start> unless MAP_FIXED.
@ -703,7 +703,7 @@ static LibError mmap_file(void* start, size_t len, int prot, int flags,
const HANDLE hMap = CreateFileMapping(hFile, 0, flProtect, 0, 0, (LPCSTR)0);
// .. create failed; bail now to avoid overwriting the last error value.
if(!hMap)
WARN_RETURN(ERR_NO_MEM);
WARN_RETURN(ERR::NO_MEM);
const DWORD ofs_hi = u64_hi(ofs), ofs_lo = u64_lo(ofs);
void* p = MapViewOfFileEx(hMap, dwAccess, ofs_hi, ofs_lo, (SIZE_T)len, start);
// .. make sure we got the requested address if MAP_FIXED was passed.
@ -714,14 +714,14 @@ static LibError mmap_file(void* start, size_t len, int prot, int flags,
CloseHandle(hMap);
// .. map failed; bail now to avoid "restoring" the last error value.
if(!p)
WARN_RETURN(ERR_NO_MEM);
WARN_RETURN(ERR::NO_MEM);
// slap on correct (more restrictive) permissions.
(void)mprotect(p, len, prot);
WIN_RESTORE_LAST_ERROR;
*pp = p;
return INFO_OK;
return INFO::OK;
}

View File

@ -143,7 +143,7 @@ int pthread_key_create(pthread_key_t* key, void (*dtor)(void*))
}
// not enough slots; we have a valid key, but its dtor won't be called.
WARN_ERR(ERR_LIMIT);
WARN_ERR(ERR::LIMIT);
return -1;
have_slot:
@ -183,7 +183,7 @@ void* pthread_getspecific(pthread_key_t key)
SetLastError(last_err);
}
else
WARN_ERR(ERR_FAIL);
WARN_ERR(ERR::FAIL);
return data;
}
@ -382,7 +382,7 @@ static DWORD calc_timeout_length_ms(const struct timespec* abs_timeout,
// that's the Win32 INFINITE value.
if(length_ms >= 0xffffffff)
{
WARN_ERR(ERR_LIMIT);
WARN_ERR(ERR::LIMIT);
length_ms = 0xfffffffe;
}
return (DWORD)(length_ms & 0xffffffff);
@ -441,7 +441,7 @@ int sem_msgwait_np(sem_t* sem)
else
{
errno = EINVAL;
WARN_ERR(ERR_FAIL);
WARN_ERR(ERR::FAIL);
}
return -1;
}
@ -517,7 +517,7 @@ int pthread_create(pthread_t* thread_id, const void* UNUSED(attr), void* (*func)
const uintptr_t id = _beginthreadex(0, 0, thread_start, (void*)&func_and_arg, 0, 0);
if(!id)
{
WARN_ERR(ERR_FAIL);
WARN_ERR(ERR::FAIL);
return -1;
}
@ -552,7 +552,7 @@ int pthread_join(pthread_t thread, void** value_ptr)
DWORD ret = WaitForSingleObject(hThread, INFINITE);
if(ret != WAIT_OBJECT_0)
{
WARN_ERR(ERR_FAIL);
WARN_ERR(ERR::FAIL);
return -1;
}
@ -572,12 +572,12 @@ static LibError wpthread_init()
{
int err = sem_init(&sem_thread_create, 0, 0);
debug_assert(err == 0);
return INFO_OK;
return INFO::OK;
}
static LibError wpthread_shutdown()
{
int err = sem_destroy(&sem_thread_create);
debug_assert(err == 0);
return INFO_OK;
return INFO::OK;
}

View File

@ -97,7 +97,7 @@ static LibError calc_gamma_ramp(float gamma, u16* ramp)
{
for(u16 i = 0; i < 256; i++)
ramp[i] = (i << 8);
return INFO_OK;
return INFO::OK;
}
const double inv_gamma = 1.0 / gamma;
@ -110,7 +110,7 @@ static LibError calc_gamma_ramp(float gamma, u16* ramp)
ramp[i] = fp_to_u16(pow(frac, inv_gamma));
}
return INFO_OK;
return INFO::OK;
}
@ -142,7 +142,7 @@ int SDL_SetGamma(float r, float g, float b)
LibError err1 = calc_gamma_ramp(r, cur_ramp[0]);
LibError err2 = calc_gamma_ramp(g, cur_ramp[1]);
LibError err3 = calc_gamma_ramp(b, cur_ramp[2]);
if(err1 != INFO_OK || err2 != INFO_OK || err3 != INFO_OK)
if(err1 != INFO::OK || err2 != INFO::OK || err3 != INFO::OK)
return -1;
if(!SetDeviceGammaRamp(hDC, cur_ramp))
@ -1339,7 +1339,7 @@ static LibError wsdl_init()
enable_kbd_hook(true);
return INFO_OK;
return INFO::OK;
}
@ -1357,7 +1357,7 @@ static LibError wsdl_shutdown()
enable_kbd_hook(false);
return INFO_OK;
return INFO::OK;
}

View File

@ -26,10 +26,6 @@
#include "lib/types.h"
#include "SDL/SDL_keysym.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef u8 Uint8;
typedef u16 Uint16;
typedef u32 Uint32;
@ -304,9 +300,4 @@ extern Uint8 SDL_GetMouseState(int* x, int* y);
extern Uint8 SDL_GetAppState();
#ifdef __cplusplus
}
#endif
#endif // #ifndef WSDL_H__

View File

@ -86,19 +86,19 @@ static LibError add_if_oal_dll(const DirEnt* ent, PathPackage* pp, StringSet* dl
// skip non-files.
if(!DIRENT_IS_DIR(ent))
return INFO_OK;
return INFO::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 INFO_OK;
return INFO::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 INFO_OK;
return INFO::OK;
RETURN_ERR(path_package_append_file(pp, fn));
return dll_list_add(pp->path);
@ -123,13 +123,13 @@ static LibError add_oal_dlls_in_dir(const char* dir, StringSet* dlls)
for(;;) // instead of while to avoid warning
{
LibError err = dir_next_ent(&d, &ent);
if(err != INFO_OK)
if(err != INFO::OK)
break;
(void)add_if_oal_dll(&ent, &pp, dlls);
}
(void)dir_close(&d);
return INFO_OK;
return INFO::OK;
}
@ -169,7 +169,7 @@ LibError win_get_snd_info()
{
strcpy_s(snd_card, SND_CARD_LEN, "(none)");
strcpy_s(snd_drv_ver, SND_DRV_VER_LEN, "(none)");
return INFO_OK;
return INFO::OK;
}
// find all DLLs related to OpenAL, retrieve their versions,
@ -179,5 +179,5 @@ LibError 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 INFO_OK;
return INFO::OK;
}

View File

@ -45,7 +45,7 @@ WIN_REGISTER_FUNC(wsock_shutdown);
// These are included in the linux C libraries and in newer platform SDKs,
// so should only be needed in VC++6 or earlier.
const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; // ::
const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT; // ::1
const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT; // ::_1
static HMODULE hWs2_32Dll;
static int dll_refs;
@ -65,7 +65,7 @@ static LibError wsock_actual_init()
debug_warn("WSAStartup failed");
}
return INFO_OK;
return INFO::OK;
}
@ -74,7 +74,7 @@ static LibError wsock_actual_init()
static LibError wsock_init()
{
WDLL_LOAD_NOTIFY("ws2_32", wsock_actual_init);
return INFO_OK;
return INFO::OK;
}
static LibError wsock_shutdown()
@ -89,7 +89,7 @@ static LibError wsock_shutdown()
while(dll_refs-- > 0)
FreeLibrary(hWs2_32Dll);
return INFO_OK;
return INFO::OK;
}

View File

@ -115,7 +115,7 @@ struct ip_mreq
#define in6addr_loopback PS_in6addr_loopback
extern const struct in6_addr in6addr_any; /* :: */
extern const struct in6_addr in6addr_loopback; /* ::1 */
extern const struct in6_addr in6addr_loopback; /* ::_1 */
#define IN6ADDR_ANY_INIT { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }
#define IN6ADDR_LOOPBACK_INIT { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } }

View File

@ -356,17 +356,17 @@ LibError sys_clipboard_set(const wchar_t* text)
// MSDN: passing 0 requests the current task be granted ownership;
// there's no need to pass our window handle.
if(!OpenClipboard(new_owner))
WARN_RETURN(ERR_FAIL);
WARN_RETURN(ERR::FAIL);
EmptyClipboard();
LibError err = ERR_FAIL;
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;
err = ERR::NO_MEM;
goto fail;
}
@ -378,7 +378,7 @@ LibError sys_clipboard_set(const wchar_t* text)
GlobalUnlock(hMem);
if(SetClipboardData(CF_UNICODETEXT, hMem) != 0)
err = INFO_OK;
err = INFO::OK;
}
}
@ -432,7 +432,7 @@ wchar_t* sys_clipboard_get()
LibError sys_clipboard_free(wchar_t* copy)
{
free(copy);
return INFO_OK;
return INFO::OK;
}
@ -468,7 +468,7 @@ static HCURSOR HCURSOR_from_ptr(void* p)
// it is no longer needed and can be freed after this call returns.
// hotspot (hx,hy) is the offset from its upper-left corner to the
// position where mouse clicks are registered.
// cursor is only valid when INFO_OK is returned; in that case, it must be
// cursor is only valid when INFO::OK is returned; in that case, it must be
// sys_cursor_free-ed when no longer needed.
LibError sys_cursor_create(uint w, uint h, void* bgra_img,
uint hx, uint hy, void** cursor)
@ -498,10 +498,10 @@ LibError sys_cursor_create(uint w, uint h, void* bgra_img,
DeleteObject(hbmColour);
if(!hIcon) // not INVALID_HANDLE_VALUE
WARN_RETURN(ERR_FAIL);
WARN_RETURN(ERR::FAIL);
*cursor = ptr_from_HICON(hIcon);
return INFO_OK;
return INFO::OK;
}
LibError sys_cursor_create_empty(void **cursor)
@ -521,7 +521,7 @@ LibError sys_cursor_set(void* cursor)
(void)SetCursor(HCURSOR_from_ptr(cursor));
// return value (previous cursor) is useless.
return INFO_OK;
return INFO::OK;
}
@ -531,7 +531,7 @@ LibError sys_cursor_free(void* cursor)
{
// bail now to prevent potential confusion below; there's nothing to do.
if(!cursor)
return INFO_OK;
return INFO::OK;
// if the cursor being freed is active, restore the default arrow
// (just for safety).
@ -552,7 +552,7 @@ LibError sys_error_description_r(int user_err, char* buf, size_t max_chars)
DWORD err = (DWORD)user_err;
// not in our range (Win32 error numbers are positive)
if(user_err < 0)
return ERR_FAIL; // NOWARN
return ERR::FAIL; // NOWARN
// user doesn't know error code; get current error state
if(!user_err)
err = GetLastError();
@ -563,9 +563,9 @@ LibError sys_error_description_r(int user_err, char* buf, size_t max_chars)
DWORD chars_output = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, source, err,
lang_id, buf, (DWORD)max_chars, args);
if(!chars_output)
WARN_RETURN(ERR_FAIL);
WARN_RETURN(ERR::FAIL);
debug_assert(chars_output < max_chars);
return INFO_OK;
return INFO::OK;
}
@ -597,7 +597,7 @@ wchar_t* sys_get_module_filename(void* addr, wchar_t* path)
inline LibError sys_get_executable_name(char* n_path, size_t buf_size)
{
DWORD nbytes = GetModuleFileName(0, n_path, (DWORD)buf_size);
return nbytes? INFO_OK : ERR_FAIL;
return nbytes? INFO::OK : ERR::FAIL;
}

Some files were not shown because too many files have changed in this diff Show More