1
0
forked from 0ad/0ad

-move app-specific stuff out of lib/ and into "hooks". see new lib/app_hooks* (note X macro goodness)

-move tex_codec stuff out of tex.cpp and into tex_codec.cpp
-tex_codec: use linked list of codecs instead of array (simplifies code
and removes limit)
-ogl_tex: add override mechanism for s3tc/automipmapgen extension detect
-tired of keeping of debug_warn text in sync with function name; now use
__func__ everywhere (and emulate that with __FUNCTION__ on MSC)
-add ONCE_NOT (opposite of ONCE)
-fix 3!! stupid bugs in ia32_control87, its caller and the header that
were canceling each other out. float exceptions now enabled except for
"inexact result" (too common). (update: nicolai had already fixed 2 of
these)

This was SVN commit r2964.
This commit is contained in:
janwas 2005-10-19 03:06:54 +00:00
parent 2ef8a7b630
commit b17fbf003d
37 changed files with 619 additions and 395 deletions

View File

@ -135,7 +135,7 @@ int da_free(DynArray* da)
if(da->prot & DA_NOT_OUR_MEM)
{
debug_warn("da_free: da is marked DA_NOT_OUR_MEM, must not be altered");
debug_warn(__func__": da is marked DA_NOT_OUR_MEM, must not be altered");
return -1;
}
@ -156,7 +156,7 @@ int da_set_size(DynArray* da, size_t new_size)
if(da->prot & DA_NOT_OUR_MEM)
{
debug_warn("da_set_size: da is marked DA_NOT_OUR_MEM, must not be altered");
debug_warn(__func__": da is marked DA_NOT_OUR_MEM, must not be altered");
return -1;
}
@ -191,7 +191,7 @@ int da_set_prot(DynArray* da, int prot)
// mmap-ed, which it probably wasn't here.
if(da->prot & DA_NOT_OUR_MEM)
{
debug_warn("da_set_prot: da is marked DA_NOT_OUR_MEM, must not be altered");
debug_warn(__func__": da is marked DA_NOT_OUR_MEM, must not be altered");
return -1;
}
@ -336,7 +336,7 @@ void pool_free(Pool* p, void* el)
if(pool_contains(p, el))
freelist_push(&p->freelist, el);
else
debug_warn("pool_free: invalid pointer (not in pool)");
debug_warn(__func__": invalid pointer (not in pool)");
}

163
source/lib/app_hooks.cpp Normal file
View File

@ -0,0 +1,163 @@
// Hooks to allow application-specific behavior
// Copyright (c) 2005 Jan Wassenberg
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// 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. See the GNU
// General Public License for more details.
//
// Contact info:
// Jan.Wassenberg@stud.uni-karlsruhe.de
// http://www.stud.uni-karlsruhe.de/~urkt/
#include "precompiled.h"
#include <string.h>
#include <stdio.h>
#include "detect.h"
#include "res/graphics/ogl_tex.h"
#include "res/file/file.h"
#include "app_hooks.h"
//-----------------------------------------------------------------------------
// default implementations
//-----------------------------------------------------------------------------
static void override_gl_upload_caps()
{
if(gfx_card[0] == '\0')
debug_warn("get_gfx_info must be called before ogl_tex_upload");
if(!strcmp(gfx_card, "S3 SuperSavage/IXC 1014"))
{
if(strstr(gfx_drv_ver, "ssicdnt.dll (2.60.115)"))
ogl_tex_override(OGL_TEX_S3TC, OGL_TEX_DISABLE);
}
}
// convert contents of file <in_filename> from char to wchar_t and
// append to <out> file.
static void cat_atow(FILE* out, const char* in_filename)
{
FILE* in = fopen(in_filename, "rb");
if(!in)
{
fwprintf(out, L"(unavailable)");
return;
}
const size_t buf_size = 1024;
char buf[buf_size+1]; // include space for trailing '\0'
while(!feof(in))
{
size_t bytes_read = fread(buf, 1, buf_size, in);
if(!bytes_read)
break;
buf[bytes_read] = 0; // 0-terminate
fwprintf(out, L"%hs", buf);
}
fclose(in);
}
static void bundle_logs(FILE* f)
{
// for user convenience, bundle all logs into this file:
char N_path[PATH_MAX];
fwprintf(f, L"System info:\n\n");
(void)file_make_full_native_path("../logs/system_info.txt", N_path);
cat_atow(f, N_path);
fwprintf(f, L"\n\n====================================\n\n");
fwprintf(f, L"Main log:\n\n");
(void)file_make_full_native_path("../logs/mainlog.html", N_path);
cat_atow(f, N_path);
fwprintf(f, L"\n\n====================================\n\n");
}
// TODO: leaks memory returned by wcsdup
static const wchar_t* translate(const wchar_t* text)
{
#if HAVE_I18N
// make sure i18n system is (already|still) initialized.
if(g_CurrentLocale)
{
// be prepared for this to fail, because translation potentially
// involves script code and the JS context might be corrupted.
#if OS_WIN
__try
#endif
{
const wchar_t* text2 = wcsdup(I18n::translate(text).c_str());
// only overwrite if wcsdup succeeded, i.e. not out of memory.
if(text2)
text = text2;
}
#if OS_WIN
__except(EXCEPTION_EXECUTE_HANDLER)
#endif
{
}
}
#endif
return text;
}
static void log(const wchar_t* text)
{
wprintf(text);
}
//-----------------------------------------------------------------------------
// contains the current set of hooks. starts with the stub values and
// may be changed via set_app_hooks.
//
// rationale: we don't ever need to switch "hook sets", so one global struct
// is fine. by always having one defined, we also avoid having to check
// if anything was registered yet.
static AppHooks ah =
{
#define FUNC(ret, name, params, param_names, call_prefix) name,
#include "app_hooks.h"
#undef FUNC
// int dummy; used to terminate list, since last entry ended with ','.
0
};
// register the specified hook function pointers. any of them that
// are non-zero override the previous function pointer value
// (these default to the stub hooks which are functional but basic).
void set_app_hooks(AppHooks* ah_)
{
debug_assert(ah_);
ONCE_NOT(debug_warn(__func__": app hooks already set"));
// override members in <ah> if they are non-zero in <ah_>
// (otherwise, we stick with the defaults set above)
#define FUNC(ret, name, params, param_names, call_prefix) if(ah_->name) ah.name = ah_->name;
#include "app_hooks.h"
#undef FUNC
}
// trampolines used by lib code; they call the hooks or fall back to the
// default implementation if not set.
#define FUNC(ret, name, params, param_names, call_prefix) inline ret ah_##name params { call_prefix ah.name param_names; }
#include "app_hooks.h"
#undef FUNC

128
source/lib/app_hooks.h Normal file
View File

@ -0,0 +1,128 @@
// Hooks to allow application-specific behavior
// Copyright (c) 2005 Jan Wassenberg
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// 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. See the GNU
// General Public License for more details.
//
// Contact info:
// Jan.Wassenberg@stud.uni-karlsruhe.de
// http://www.stud.uni-karlsruhe.de/~urkt/
/*
Background
----------
This codebase is shared between several projects, each with differing needs.
Some of them have e.g. complicated i18n/translation facilities and require
all text output to go through it; others strive to minimize size and
therefore do not want to include that.
Since commenting things out isn't an option with shared source and
conditional compilation is ugly, we bridge the differences via "hooks".
These are functions whose behavior is expected to differ between projects;
they are defined by the app, registered here and called from lib code via
our trampolines.
Introduction
------------
This module provides a clean interface for other code to call hooks
and allows the app to register them. It also defines default stub
implementations.
Usage
-----
In the simplest case, the stubs are already acceptable. Otherwise,
you need to implement a new version of some hooks, fill an
AppHooks struct with pointers to those functions (zero the rest),
and call set_app_hooks.
*/
// X macros that define the individual hooks. All function pointers,
// struct contents, trampoline functions etc. are automatically
// generated from them to ease maintenance.
// When adding a new hook, you need only update this and write a
// default (stub) implementation.
//
// params:
// - ret: return value type
// - name: function name identifier
// - params: parameter declarations, used when declaring the function;
// enclosed in parentheses.
// - param_names: names of parameters, used when calling the function;
// enclosed in parentheses.
// - call_prefix: precedes the call to this function.
// must be (without quotes) '(void)' if ret is void, else 'return'.
// this is to allow generating trampoline functions with or without
// a return value.
#ifdef FUNC
// override default decision on using OpenGL extensions relating to
// texture upload. this should call ogl_tex_override to disable/force
// their use if the current card/driver combo respectively crashes or
// supports it even though the extension isn't advertised.
//
// default implementation works but is hardwired in code and therefore
// not expandable.
FUNC(void, override_gl_upload_caps, (void), (), (void))
// gather all app-related logs/information and write it into <f>.
// used when writing a crashlog so that all relevant info is in one file.
//
// default implementation gathers 0ad data but is fail-safe.
FUNC(void, bundle_logs, (FILE* f), (f), (void))
// return localized version of <text> if i18n functionality is available.
//
// default implementation just returns the pointer unchanged.
FUNC(const wchar_t*, translate, (const wchar_t* text), (text), return)
// write <text> to the app's log.
//
// default implementation uses stdout.
FUNC(void, log, (const wchar_t* text), (text), (void))
#endif // #ifdef FUNC
//-----------------------------------------------------------------------------
// normal header part
#ifndef APP_HOOKS_H__
#define APP_HOOKS_H__
// holds a function pointer for each hook. passed to set_app_hooks.
struct AppHooks
{
#define FUNC(ret, name, params, param_names, call_prefix) ret(*name) params;
#include "app_hooks.h"
#undef FUNC
// used to safely terminate initializer list
int dummy;
};
// register the specified hook function pointers. any of them that
// are non-zero override the previous function pointer value
// (these default to the stub hooks which are functional but basic).
extern void set_app_hooks(AppHooks* ah);
// trampolines used by lib code to call the hooks. they encapsulate
// the details of how exactly to do this.
#define FUNC(ret, name, params, param_names, call_prefix) extern ret ah_##name params;
#include "app_hooks.h"
#undef FUNC
#endif // #ifndef APP_HOOKS_H__

View File

@ -28,8 +28,7 @@
// so that our allocations don't cause infinite recursion.
#include "nommgr.h"
#include "self_test.h"
// file_make_full_native_path is needed when bundling game data files.
#include "lib/res/file/file.h"
#include "app_hooks.h"
// needed when writing crashlog
static const size_t LOG_CHARS = 16384;
@ -60,7 +59,7 @@ void debug_wprintf_mem(const wchar_t* fmt, ...)
va_end(args);
if(len < 0)
{
debug_warn("debug_wprintf_mem: vswprintf failed");
debug_warn(__func__": vswprintf failed");
return;
}
debug_log_pos += len+2;
@ -68,59 +67,22 @@ void debug_wprintf_mem(const wchar_t* fmt, ...)
}
// convert contents of file <in_filename> from char to wchar_t and
// append to <out> file. used by debug_write_crashlog.
static void cat_atow(FILE* out, const char* in_filename)
{
FILE* in = fopen(in_filename, "rb");
if(!in)
{
fwprintf(out, L"(unavailable)");
return;
}
const size_t buf_size = 1024;
char buf[buf_size+1]; // include space for trailing '\0'
while(!feof(in))
{
size_t bytes_read = fread(buf, 1, buf_size, in);
if(!bytes_read)
break;
buf[bytes_read] = 0; // 0-terminate
fwprintf(out, L"%hs", buf);
}
fclose(in);
}
int debug_write_crashlog(const wchar_t* text)
{
const wchar_t divider[] = L"\n\n====================================\n\n";
#define WRITE_DIVIDER fwprintf(f, divider);
FILE* f = fopen("crashlog.txt", "w");
if(!f)
{
DISPLAY_ERROR(L"debug_write_crashlog: unable to open file");
return -1;
}
fputwc(0xfeff, f); // BOM
fwprintf(f, L"%ls\n", text);
WRITE_DIVIDER
fwprintf(f, L"\n\n====================================\n\n");
// for user convenience, bundle all logs into this file:
char N_path[PATH_MAX];
fwprintf(f, L"System info:\n\n");
(void)file_make_full_native_path("../logs/system_info.txt", N_path);
cat_atow(f, N_path);
WRITE_DIVIDER
fwprintf(f, L"Main log:\n\n");
(void)file_make_full_native_path("../logs/mainlog.html", N_path);
cat_atow(f, N_path);
WRITE_DIVIDER
// allow user to bundle whatever information they want
ah_bundle_logs(f);
fwprintf(f, L"Last known activity:\n\n %ls\n", debug_log);

View File

@ -149,8 +149,8 @@ static void get_cpu_info()
void cpu_init()
{
#if CPU_IA32
// must come before any uses of ia32.asm, e.g. by get_cpu_info
ia32_init();
#endif
// no longer set 24 bit (float) precision by default: for
// very long game uptimes (> 1 day; e.g. dedicated server),
@ -159,19 +159,19 @@ void cpu_init()
// we can temporarily change precision there.
//_control87(_PC_24, _MCW_PC);
// disable all floating-point exceptions except zero-divide
// Note that most exceptions are triggered by the JS engine.
// to help catch bugs, enable as many floating-point exceptions as
// possible. that means only zero-divide, because the JS engine is
// triggering the rest.
_control87(_MCW_PM|_MCW_IM|_MCW_UM|_MCW_OM|_MCW_DM, _MCW_EM);
// If possible, hook up capability-sensitive assembler routines
ia32_hook_capabilities();
#endif
// detects CPU clock frequency and capabilities, which are prerequisites
// for using the TSC as a timer (desirable due to its high resolution).
// do this before lengthy init so we can time those accurately.
get_cpu_info();
#if CPU_IA32
// If possible, hook up capability-sensitive assembler routines
ia32_hook_capabilities();
#endif
}

View File

@ -36,14 +36,15 @@ static int handler_stack_top = 0;
int in_add_handler(EventHandler handler)
{
if(handler_stack_top >= MAX_HANDLERS || !handler)
debug_assert(handler);
if(handler_stack_top >= MAX_HANDLERS)
{
debug_warn("in_add_handler");
debug_warn(__func__": increase MAX_HANDLERS");
return -1;
}
handler_stack[handler_stack_top++] = handler;
return 0;
}
@ -62,7 +63,7 @@ void dispatch_event(const SDL_Event* event)
continue;
// .. invalid return value
else
debug_warn("dispatch_event: invalid handler return value");
debug_warn(__func__": invalid handler return value");
}
}

View File

@ -60,6 +60,7 @@ scope
#include "lib/types.h"
#include "sysdep/sysdep.h"
#include "sysdep/cpu.h" // CAS
#if defined(__cplusplus)
@ -78,6 +79,8 @@ scope
// squelch the warning (unfortunately non-portable).
#define STMT(STMT_code__) do { STMT_code__; } while(false)
// execute the code passed as a parameter only the first time this is
// reached.
// may be called at any time (in particular before main), but is not
// thread-safe. if that's important, use pthread_once() instead.
#define ONCE(ONCE_code__)\
@ -90,6 +93,20 @@ STMT(\
}\
)
// execute the code passed as a parameter except the first time this is
// reached.
// may be called at any time (in particular before main), but is not
// thread-safe.
#define ONCE_NOT(ONCE_code__)\
STMT(\
static bool ONCE_done__ = false;\
if(!ONCE_done__)\
ONCE_done__ = true;\
else\
ONCE_code__;\
)
// be careful here. the given expression (e.g. variable or
// function return value) may be a Handle (=i64), so it needs to be

View File

@ -174,7 +174,7 @@ bool oglHaveVersion(const char* desired_version)
int desired_major, desired_minor;
if(sscanf(desired_version, "%d.%d", &desired_major, &desired_minor) != 2)
{
debug_warn("oglHaveVersion: invalid version string");
debug_warn(__func__": invalid version string");
return false;
}
@ -182,7 +182,7 @@ bool oglHaveVersion(const char* desired_version)
const char* version = (const char*)glGetString(GL_VERSION);
if(!version || sscanf(version, "%d.%d", &major, &minor) != 2)
{
debug_warn("oglHaveVersion: GL_VERSION invalid");
debug_warn(__func__": GL_VERSION invalid");
return false;
}
@ -288,7 +288,7 @@ void oglCheck()
}
if(error_enountered)
debug_warn("oglCheck reports error(s)");
debug_warn(__func__": OpenGL error(s) occurred");
}
#endif
@ -319,7 +319,7 @@ void oglSquelchError(GLenum err_to_ignore)
}
if(error_enountered)
debug_warn("oglSquelchError reports other error(s)");
debug_warn(__func__": OpenGL error(s) occurred");
}
@ -360,7 +360,7 @@ void oglInit()
// time-critical) than centralizing the 'OpenGL is ready' check.
exts = (const char*)glGetString(GL_EXTENSIONS);
if(!exts)
debug_warn("oglInit called before OpenGL is ready for use");
debug_warn(__func__": called before OpenGL is ready for use");
have_12 = oglHaveVersion("1.2");
have_13 = oglHaveVersion("1.3");
have_14 = oglHaveVersion("1.4");

View File

@ -288,10 +288,10 @@ int file_set_root_dir(const char* argv0, const char* rel_path)
}
fail:
debug_warn("file_set_root_dir failed");
debug_warn(__func__" failed");
if(msg)
{
debug_printf("file_set_root_dir: %s\n", msg);
debug_printf(__func__": %s\n", msg);
return -1;
}
@ -781,7 +781,7 @@ int file_io_issue(File* f, off_t ofs, size_t size, void* p, FileIo* io)
const off_t bytes_left = f->size - ofs;
if(bytes_left < 0)
{
debug_warn("file_io_issue: EOF");
debug_warn(__func__": EOF");
return ERR_EOF;
}
if((off_t)size > bytes_left)
@ -832,7 +832,7 @@ int file_io_has_completed(FileIo* io)
if(ret == 0)
return 1;
debug_warn("file_io_has_completed: unexpected aio_error return");
debug_warn(__func__": unexpected aio_error return");
return -1;
}
@ -840,7 +840,7 @@ int file_io_has_completed(FileIo* io)
int file_io_wait(FileIo* io, void*& p, size_t& size)
{
#if CONFIG_PARANOIA
debug_printf("file_io_wait: hio=%p\n", io);
debug_printf(__func__": hio=%p\n", io);
#endif
// zero output params in case something (e.g. H_DEREF) fails.
@ -857,7 +857,7 @@ debug_printf("file_io_wait: hio=%p\n", io);
// query number of bytes transferred (-1 if the transfer failed)
const ssize_t bytes_transferred = aio_return(cb);
#if CONFIG_PARANOIA
debug_printf("file_io_wait: bytes_transferred=%d aio_nbytes=%d\n",
debug_printf(__func__": bytes_transferred=%d aio_nbytes=%d\n",
bytes_transferred, cb->aio_nbytes);
#endif
// (size was clipped to EOF in file_io => this is an actual IO error)
@ -1004,7 +1004,7 @@ static void* block_find(u64 block_id)
static void block_add(u64 block_id, void* block)
{
if(block_find(block_id))
debug_warn("block_add: already in cache");
debug_warn(__func__": already in cache");
else
block_cache[block_id] = block;
}
@ -1115,7 +1115,7 @@ debug_printf("file_io fd=%d size=%d ofs=%d\n", f->fd, data_size, data_ofs);
// (not reading OR using lowio OR no callback)
if(temp && (is_write || no_aio || !cb))
{
debug_warn("file_io: invalid parameter");
debug_warn(__func__": invalid parameter");
return ERR_INVALID_PARAM;
}
@ -1334,7 +1334,7 @@ int file_map(File* f, void*& p, size_t& size)
// prevent overflow; if we have this many refs, should find out why.
if(f->map_refs >= MAX_MAP_REFS)
{
debug_warn("file_map: too many references to mapping");
debug_warn(__func__": too many references to mapping");
return -1;
}
f->map_refs++;
@ -1374,7 +1374,7 @@ int file_unmap(File* f)
// file is not currently mapped
if(f->map_refs == 0)
{
debug_warn("file_unmap: not currently mapped");
debug_warn(__func__": not currently mapped");
return -1;
}

View File

@ -196,7 +196,7 @@ int vfs_dir_next_ent(const Handle hd, DirEnt* ent, const char* filter)
vd->filter_latched = 1;
}
if(vd->filter != filter)
debug_warn("vfs_dir_next_ent: filter has changed for this directory. are you scanning it twice?");
debug_warn(__func__": filter has changed for this directory. are you scanning it twice?");
#endif
bool want_dir = true;
@ -269,7 +269,7 @@ static void file_listing_add(const char* v_fn)
// we've already shut down - complain.
if(file_listing_enabled == -1)
{
debug_warn("file_listing_add: called after file_listing_shutdown atexit");
debug_warn(__func__": called after file_listing_shutdown atexit");
return;
}
@ -296,7 +296,7 @@ void vfs_enable_file_listing(bool want_enabled)
// already shut down - don't allow enabling
if(file_listing_enabled == -1 && want_enabled)
{
debug_warn("vfs_enable_file_listing: enabling after shutdown");
debug_warn(__func__": enabling after shutdown");
return;
}
@ -567,7 +567,7 @@ debug_printf("vfs_load v_fn=%s\n", v_fn);
goto ret;
}
else
debug_warn("vfs_load: invalid MEM attached to vfile (0 pointer)");
debug_warn(__func__": invalid MEM attached to vfile (0 pointer)");
// happens if someone frees the pointer. not an error!
}
/*

View File

@ -543,7 +543,7 @@ static int remount(const Mount& m)
case MT_FILE:
return mount_dir_tree(td, m);
default:
debug_warn("remount: invalid type");
debug_warn(__func__": invalid type");
return ERR_CORRUPTED;
}
}
@ -578,7 +578,7 @@ int vfs_mount(const char* V_mount_point, const char* P_real_path, int flags, uin
#ifndef NDEBUG
const size_t len = strlen(V_mount_point);
if(len && V_mount_point[len-1] != '/')
debug_warn("vfs_mount: path doesn't end in '/'");
debug_warn(__func__": path doesn't end in '/'");
#endif
// make sure it's not already mounted, i.e. in mounts.
@ -591,7 +591,7 @@ int vfs_mount(const char* V_mount_point, const char* P_real_path, int flags, uin
{
if(file_is_subpath(P_real_path, it->P_name.c_str()))
{
debug_warn("vfs_mount: already mounted");
debug_warn(__func__": already mounted");
return -1;
}
}
@ -601,7 +601,7 @@ int vfs_mount(const char* V_mount_point, const char* P_real_path, int flags, uin
// "./" and "/." are caught by CHECK_PATH.
if(!strcmp(P_real_path, "."))
{
debug_warn("vfs_mount: mounting . not allowed");
debug_warn(__func__": mounting . not allowed");
return -1;
}
@ -874,7 +874,7 @@ int x_realpath(const Mount* m, const char* V_exact_path, char* P_real_path)
P_parent_path = m->P_name.c_str();
break;
default:
debug_warn("x_realpath: invalid type");
debug_warn(__func__": invalid type");
return -1;
}
@ -895,7 +895,7 @@ int x_open(const Mount* m, const char* V_exact_path, int flags, TFile* tf, XFile
case MT_ARCHIVE:
if(flags & FILE_WRITE)
{
debug_warn("requesting write access to file in archive");
debug_warn(__func__": requesting write access to file in archive");
return -1;
}
RETURN_ERR(zip_open(m->archive, V_exact_path, flags, &xf->u.zf));
@ -905,7 +905,7 @@ int x_open(const Mount* m, const char* V_exact_path, int flags, TFile* tf, XFile
RETURN_ERR(file_open(P_path, flags, &xf->u.f));
break;
default:
debug_warn("VFile_reload: invalid type");
debug_warn(__func__": invalid type");
return ERR_CORRUPTED;
}
@ -933,7 +933,7 @@ int x_close(XFile* xf)
(void)file_close(&xf->u.f);
break;
default:
debug_warn("x_close: invalid type");
debug_warn(__func__": invalid type");
break;
}
@ -1022,7 +1022,7 @@ int x_io(XFile* xf, off_t ofs, size_t size, void* buf, FileIOCB cb, uintptr_t ct
return file_io(&xf->u.f, ofs, size, buf, cb, ctx);
default:
debug_warn("vfs_io: invalid file type");
debug_warn(__func__": invalid file type");
return ERR_CORRUPTED;
}
}
@ -1037,7 +1037,7 @@ int x_map(XFile* xf, void*& p, size_t& size)
case MT_FILE:
return file_map(&xf->u.f, p, size);
default:
debug_warn("vfs_map: invalid type");
debug_warn(__func__": invalid file type");
return ERR_CORRUPTED;
}
}
@ -1052,7 +1052,7 @@ int x_unmap(XFile* xf)
case MT_FILE:
return file_unmap(&xf->u.f);
default:
debug_warn("vfs_unmap: invalid type");
debug_warn(__func__": invalid file type");
return ERR_CORRUPTED;
}
}
@ -1068,7 +1068,7 @@ int x_io_issue(XFile* xf, off_t ofs, size_t size, void* buf, XIo* xio)
case MT_FILE:
return file_io_issue(&xf->u.f, ofs, size, buf, &xio->u.fio);
default:
debug_warn("vfs_io_issue: invalid file type");
debug_warn(__func__": invalid file type");
return ERR_CORRUPTED;
}
}
@ -1083,7 +1083,7 @@ int x_io_has_completed(XIo* xio)
case MT_FILE:
return file_io_has_completed(&xio->u.fio);
default:
debug_warn("vfs_io_has_completed: invalid type");
debug_warn(__func__": invalid file type");
return ERR_CORRUPTED;
}
}
@ -1098,7 +1098,7 @@ int x_io_wait(XIo* xio, void*& p, size_t& size)
case MT_FILE:
return file_io_wait(&xio->u.fio, p, size);
default:
debug_warn("vfs_io_wait: invalid type");
debug_warn(__func__": invalid file type");
return ERR_CORRUPTED;
}
}
@ -1113,7 +1113,7 @@ int x_io_discard(XIo* xio)
case MT_FILE:
return file_io_discard(&xio->u.fio);
default:
debug_warn("VIo_dtor: invalid type");
debug_warn(__func__": invalid file type");
return ERR_CORRUPTED;
}
}
@ -1128,7 +1128,7 @@ int x_io_validate(const XIo* xio)
case MT_FILE:
return file_io_validate(&xio->u.fio);
default:
return -103; // invalid type
return -100; // invalid type
}
UNREACHABLE;
}

View File

@ -81,8 +81,8 @@ int path_validate(const uint line, const char* path)
// failed somewhere - err is the error code,
// or -1 if not set specifically above.
fail:
debug_printf("path_validate at line %d failed: %s (error code %d)\n", line, msg, err);
debug_warn("path_validate failed");
debug_printf(__func__" at line %d failed: %s (error code %d)\n", line, msg, err);
debug_warn(__func__" failed");
return err;
ok:

View File

@ -106,7 +106,7 @@ TNode* node_alloc(size_t size)
// would overflow a bucket
if(size > BUCKET_SIZE-sizeof(u8*))
{
debug_warn("node_alloc: size doesn't fit in a bucket");
debug_warn(__func__": size doesn't fit in a bucket");
return 0;
}
@ -458,7 +458,7 @@ int TDir::add(const char* name, TNodeType new_type, TNode** pnode)
if(!children.add(name, node))
{
debug_warn("failed to expand table");
debug_warn(__func__": failed to expand table");
// node will be freed by node_free_all
return 0;
}
@ -816,7 +816,7 @@ int tree_dir_next_ent(TreeDirIterator* d_, DirEnt* ent)
ent->mtime = node->u.file.mtime;
break;
default:
debug_warn("invalid TNode type");
debug_warn(__func__": invalid TNode type");
}
return 0; // success

View File

@ -139,7 +139,7 @@ static const u8* z_find_id(const u8* file, size_t size, const u8* start, const c
{
#ifndef NDEBUG
if(p != start)
debug_warn("z_find_id: archive damaged, but still found next record.");
debug_warn(__func__": archive damaged, but still found next record.");
#endif
return p;
}
@ -150,7 +150,7 @@ static const u8* z_find_id(const u8* file, size_t size, const u8* start, const c
}
// passed EOF, didn't find it.
debug_warn("z_find_id: archive corrupted, next record not found.");
debug_warn(__func__": archive corrupted, next record not found.");
return 0;
}
@ -203,7 +203,7 @@ static time_t convert_dos_date(u16 fatdate, u16 fattime)
time_t ret = mktime(&t);
if(ret == (time_t)-1)
debug_warn("convert_dos_date: mktime failed");
debug_warn(__func__": mktime failed");
return ret;
}
@ -764,7 +764,7 @@ int inf_set_dest(uintptr_t _ctx, void* out, size_t out_size)
if(zs->next_out || zs->avail_out)
{
debug_warn("zip_set_dest: ctx already in use!");
debug_warn(__func__": ctx already in use!");
return -1;
}
zs->next_out = (Byte*)out;
@ -804,7 +804,7 @@ double t0 = get_time();
if(in)
{
if(ctx->in_buf)
debug_warn("inf_inflate: previous input buffer not empty");
debug_warn(__func__": previous input buffer not empty");
zs->avail_in = (uInt)in_size;
zs->next_in = (Byte*)in;
@ -1231,7 +1231,7 @@ int zip_map(ZFile* zf, void*& p, size_t& size)
// compression algorithm is unspecified - disallow it.
if(zfile_compressed(zf))
{
debug_warn("zip_map: file is compressed");
debug_warn(__func__": file is compressed");
return -1;
}

View File

@ -118,7 +118,7 @@ static GLint choose_fmt(uint bpp, uint flags)
case 5:
return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
default:
debug_warn("choose_fmt: invalid DXT value");
debug_warn(__func__": invalid DXT value");
return 0;
}
}
@ -138,7 +138,7 @@ static GLint choose_fmt(uint bpp, uint flags)
debug_assert(alpha);
return bgr? GL_BGRA : GL_RGBA;
default:
debug_warn("choose_fmt: invalid bpp");
debug_warn(__func__": invalid bpp");
return 0;
}
@ -227,7 +227,7 @@ static GLint choose_int_fmt(GLenum fmt, uint q_flags)
return half_bpp? GL_RGBA4 : GL_RGBA8;
default:
debug_warn("choose_int_fmt doesn't cover the given fmt! please add it.");
debug_warn(__func__": given fmt isn't covered! please add it.");
// fall back to a reasonable default
return half_bpp? GL_RGB4 : GL_RGB8;
}
@ -615,7 +615,7 @@ void ogl_tex_override(OglTexOverrides what, OglTexAllow allow)
have_auto_mipmap_gen = enable;
break;
default:
debug_warn("ogl_tex_override: invalid <what>");
debug_warn(__func__": invalid <what>");
break;
}
}
@ -640,15 +640,6 @@ static void detect_gl_upload_caps()
}
//apphook - call back into override if app thinks anything should be disabled
// disable features if we're on a card/driver combo on which they
// are known to break.
if(gfx_card[0] == '\0')
debug_warn("ogl_tex requires get_gfx_info be called before ogl_tex_upload");
if(!strcmp(gfx_card, "S3 SuperSavage/IXC 1014"))
{
if(strstr(gfx_drv_ver, "ssicdnt.dll (2.60.115)"))
have_s3tc = false;
}
// warn if more-or-less essential features are missing
if(!have_s3tc)
@ -871,7 +862,7 @@ int ogl_tex_get_format(Handle ht, uint* flags, GLenum* fmt)
if(fmt)
{
if(!ot->is_currently_uploaded)
debug_warn("ogl_tex_get_format: hasn't been defined yet!");
debug_warn(__func__": hasn't been defined yet!");
*fmt = ot->fmt;
}
return 0;

View File

@ -249,6 +249,8 @@ enum OglTexAllow
OGL_TEX_ENABLE
};
// override the default decision and force/disallow use of the
// given feature. should be called from ah_override_gl_upload_caps.
extern void ogl_tex_override(OglTexOverrides what, OglTexAllow allow);
// upload the texture to OpenGL.

View File

@ -331,7 +331,7 @@ static void flip_to_global_orientation(Tex* t)
// dst_orientation (if the latter is 0, then the global_orientation).
// (we ask for src_flags instead of src_orientation so callers don't
// have to mask off TEX_ORIENTATION)
static bool orientations_match(uint src_flags, uint dst_orientation)
bool tex_orientations_match(uint src_flags, uint dst_orientation)
{
const uint src_orientation = src_flags & TEX_ORIENTATION;
if(dst_orientation == 0)
@ -344,51 +344,6 @@ static bool orientations_match(uint src_flags, uint dst_orientation)
// util
//-----------------------------------------------------------------------------
// allocate an array of row pointers that point into the given texture data.
// <file_orientation> indicates whether the file format is top-down or
// bottom-up; the row array is inverted if necessary to match global
// orienatation. (this is more efficient than "transforming" later)
//
// used by PNG and JPG codecs; caller must free() rows when done.
//
// note: we don't allocate the data param ourselves because this function is
// needed for encoding, too (where data is already present).
int tex_util_alloc_rows(const u8* data, size_t h, size_t pitch,
uint src_flags, uint dst_orientation, RowArray& rows)
{
const bool flip = !orientations_match(src_flags, dst_orientation);
rows = (RowArray)malloc(h * sizeof(RowPtr));
if(!rows)
return ERR_NO_MEM;
// determine start position and direction
RowPtr pos = flip? data+pitch*(h-1) : data;
const ssize_t add = flip? -(ssize_t)pitch : (ssize_t)pitch;
const RowPtr end = flip? data-pitch : data+pitch*h;
for(size_t i = 0; i < h; i++)
{
rows[i] = pos;
pos += add;
}
debug_assert(pos == end);
return 0;
}
int tex_util_write(Tex* t, uint transforms, const void* hdr, size_t hdr_size, DynArray* da)
{
RETURN_ERR(tex_transform(t, transforms));
void* img_data = tex_get_data(t); const size_t img_size = tex_img_size(t);
RETURN_ERR(da_append(da, hdr, hdr_size));
RETURN_ERR(da_append(da, img_data, img_size));
return 0;
}
void tex_util_foreach_mipmap(uint w, uint h, uint bpp, const u8* restrict data,
int levels_to_skip, uint data_padding, MipmapCB cb, void* restrict ctx)
{
@ -433,109 +388,6 @@ void tex_util_foreach_mipmap(uint w, uint h, uint bpp, const u8* restrict data,
}
//-----------------------------------------------------------------------------
// support routines for codecs
//-----------------------------------------------------------------------------
// should be a tight bound because we iterate this many times (for convenience)
static const uint MAX_CODECS = 8;
static const TexCodecVTbl* codecs[MAX_CODECS];
// add this vtbl to the codec list. called at NLSO init time by the
// TEX_CODEC_REGISTER in each codec file. note that call order and therefore
// order in the list is undefined, but since each codec only steps up if it
// can handle the given format, this is not a problem.
int tex_codec_register(const TexCodecVTbl* c)
{
debug_assert(c != 0 && "tex_codec_register(0) - why?");
for(uint i = 0; i < MAX_CODECS; i++)
{
// slot available
if(codecs[i] == 0)
{
codecs[i] = c;
return 0; // success
}
}
// didn't find a free slot.
debug_warn("tex_codec_register: increase MAX_CODECS");
return 0; // failure, but caller ignores return value
}
// find codec that recognizes the desired output file extension
int tex_codec_for_filename(const char* fn, const TexCodecVTbl** c)
{
const char* ext = strrchr(fn, '.');
if(!ext)
return ERR_UNKNOWN_FORMAT;
ext++; // skip '.'
for(uint i = 0; i < MAX_CODECS; i++)
{
*c = codecs[i];
// skip if 0 (e.g. if MAX_CODECS != num codecs)
if(!*c)
continue;
// we found it
if((*c)->is_ext(ext))
return 0;
}
return ERR_UNKNOWN_FORMAT;
}
// find codec that recognizes the header's magic field
int tex_codec_for_header(const u8* file, size_t file_size, const TexCodecVTbl** c)
{
// we guarantee at least 4 bytes for is_hdr to look at
if(file_size < 4)
return ERR_TEX_HEADER_NOT_COMPLETE;
for(uint i = 0; i < MAX_CODECS; i++)
{
*c = codecs[i];
// skip if 0 (e.g. if MAX_CODECS != num codecs)
if(!*c)
continue;
// we found it
if((*c)->is_hdr(file))
return 0;
}
return ERR_UNKNOWN_FORMAT;
}
static int tex_codec_transform(Tex* t, uint transforms)
{
int ret = TEX_CODEC_CANNOT_HANDLE;
// find codec that understands the data, and transform
for(int i = 0; i < MAX_CODECS; i++)
{
// MAX_CODECS isn't a tight bound and we have hit a 0 entry
if(!codecs[i])
continue;
int err = codecs[i]->transform(t, transforms);
if(err == 0)
return 0;
else if(err == TEX_CODEC_CANNOT_HANDLE)
continue;
else
{
ret = err;
debug_warn("tex_codec_transform: codec indicates error");
}
}
return ret;
}
//-----------------------------------------------------------------------------
// API
//-----------------------------------------------------------------------------
@ -587,7 +439,7 @@ int tex_load(const char* fn, Tex* t)
if(ret < 0)
{
(void)tex_free(t);
debug_warn("tex_load failed");
debug_warn(__func__" failed");
}
// do not free hm! it either still holds the image data (i.e. texture
@ -772,8 +624,8 @@ int tex_write(Tex* t, const char* fn)
err = c->encode(t, &da);
if(err < 0)
{
debug_printf("tex_write (%s): %d", c->name, err);
debug_warn("tex_writefailed");
debug_printf(__func__" (%s): %d", c->name, err);
debug_warn(__func__"failed");
goto fail;
}

View File

@ -261,6 +261,12 @@ extern int tex_write(Tex* t, const char* fn);
// internal use only:
extern int tex_validate(const Tex* t);
// indicate if the orientation specified by <src_flags> matches
// dst_orientation (if the latter is 0, then the global_orientation).
// (we ask for src_flags instead of src_orientation so callers don't
// have to mask off TEX_ORIENTATION)
extern bool tex_orientations_match(uint src_flags, uint dst_orientation);
typedef void(*MipmapCB)(uint level, uint level_w, uint level_h,
const u8* level_data, size_t level_data_size, void* ctx);

View File

@ -129,7 +129,7 @@ static int bmp_encode(Tex* restrict t, DynArray* restrict da)
(u32)img_size, // biSizeImage
0, 0, 0, 0 // unused (bi?PelsPerMeter, biClr*)
};
return tex_util_write(t, transforms, &hdr, hdr_size, da);
return tex_codec_write(t, transforms, &hdr, hdr_size, da);
}
TEX_CODEC_REGISTER(bmp);

View File

@ -0,0 +1,133 @@
#include "precompiled.h"
#include <string.h>
#include <stdlib.h>
#include "tex_codec.h"
#include "tex.h"
static const TexCodecVTbl* codecs;
// add this vtbl to the codec list. called at NLSO init time by the
// TEX_CODEC_REGISTER in each codec file. note that call order and therefore
// order in the list is undefined, but since each codec only steps up if it
// can handle the given format, this is not a problem.
int tex_codec_register(TexCodecVTbl* c)
{
debug_assert(c);
// insert at front of list.
c->next = codecs;
codecs = c;
return 0; // (assigned to dummy variable)
}
// find codec that recognizes the desired output file extension
int tex_codec_for_filename(const char* fn, const TexCodecVTbl** c)
{
const char* ext = strrchr(fn, '.');
if(!ext)
return ERR_UNKNOWN_FORMAT;
ext++; // skip '.'
for(*c = codecs; *c; *c = (*c)->next)
{
// we found it
if((*c)->is_ext(ext))
return 0;
}
return ERR_UNKNOWN_FORMAT;
}
// find codec that recognizes the header's magic field
int tex_codec_for_header(const u8* file, size_t file_size, const TexCodecVTbl** c)
{
// we guarantee at least 4 bytes for is_hdr to look at
if(file_size < 4)
return ERR_TEX_HEADER_NOT_COMPLETE;
for(*c = codecs; *c; *c = (*c)->next)
{
// we found it
if((*c)->is_hdr(file))
return 0;
}
return ERR_UNKNOWN_FORMAT;
}
int tex_codec_transform(Tex* t, uint transforms)
{
int ret = TEX_CODEC_CANNOT_HANDLE;
// find codec that understands the data, and transform
for(const TexCodecVTbl* c = codecs; c; c = c->next)
{
int err = c->transform(t, transforms);
// success
if(err == 0)
return 0;
// something went wrong
else if(err != TEX_CODEC_CANNOT_HANDLE)
{
ret = err;
debug_warn(__func__": codec indicates error");
}
}
return ret;
}
//-----------------------------------------------------------------------------
// helper functions used by codecs
//-----------------------------------------------------------------------------
// allocate an array of row pointers that point into the given texture data.
// <file_orientation> indicates whether the file format is top-down or
// bottom-up; the row array is inverted if necessary to match global
// orienatation. (this is more efficient than "transforming" later)
//
// used by PNG and JPG codecs; caller must free() rows when done.
//
// note: we don't allocate the data param ourselves because this function is
// needed for encoding, too (where data is already present).
int tex_codec_alloc_rows(const u8* data, size_t h, size_t pitch,
uint src_flags, uint dst_orientation, RowArray& rows)
{
const bool flip = !tex_orientations_match(src_flags, dst_orientation);
rows = (RowArray)malloc(h * sizeof(RowPtr));
if(!rows)
return ERR_NO_MEM;
// determine start position and direction
RowPtr pos = flip? data+pitch*(h-1) : data;
const ssize_t add = flip? -(ssize_t)pitch : (ssize_t)pitch;
const RowPtr end = flip? data-pitch : data+pitch*h;
for(size_t i = 0; i < h; i++)
{
rows[i] = pos;
pos += add;
}
debug_assert(pos == end);
return 0;
}
int tex_codec_write(Tex* t, uint transforms, const void* hdr, size_t hdr_size, DynArray* da)
{
RETURN_ERR(tex_transform(t, transforms));
void* img_data = tex_get_data(t); const size_t img_size = tex_img_size(t);
RETURN_ERR(da_append(da, hdr, hdr_size));
RETURN_ERR(da_append(da, img_data, img_size));
return 0;
}

View File

@ -37,11 +37,15 @@ struct TexCodecVTbl
size_t (*hdr_size)(const u8* file);
const char* name;
// intrusive linked-list of codecs: more convenient than fixed-size
// static storage.
const TexCodecVTbl* next;
};
#define TEX_CODEC_REGISTER(name)\
static const TexCodecVTbl vtbl = { name##_decode, name##_encode, name##_transform, name##_is_hdr, name##_is_ext, name##_hdr_size, #name};\
static TexCodecVTbl vtbl = { name##_decode, name##_encode, name##_transform, name##_is_hdr, name##_is_ext, name##_hdr_size, #name};\
static int dummy = tex_codec_register(&vtbl);
@ -53,7 +57,7 @@ const int TEX_CODEC_CANNOT_HANDLE = 1;
// TEX_CODEC_REGISTER in each codec file. note that call order and therefore
// order in the list is undefined, but since each codec only steps up if it
// can handle the given format, this is not a problem.
extern int tex_codec_register(const TexCodecVTbl* c);
extern int tex_codec_register(TexCodecVTbl* c);
// find codec that recognizes the desired output file extension
@ -62,6 +66,7 @@ extern int tex_codec_for_filename(const char* fn, const TexCodecVTbl** c);
// find codec that recognizes the header's magic field
extern int tex_codec_for_header(const u8* file, size_t file_size, const TexCodecVTbl** c);
extern int tex_codec_transform(Tex* t, uint transforms);
// allocate an array of row pointers that point into the given texture data.
@ -75,9 +80,9 @@ extern int tex_codec_for_header(const u8* file, size_t file_size, const TexCodec
// needed for encoding, too (where data is already present).
typedef const u8* RowPtr;
typedef RowPtr* RowArray;
extern int tex_util_alloc_rows(const u8* data, size_t h, size_t pitch,
extern int tex_codec_alloc_rows(const u8* data, size_t h, size_t pitch,
uint src_flags, uint dst_orientation, RowArray& rows);
extern int tex_util_write(Tex* t, uint transforms, const void* hdr, size_t hdr_size, DynArray* da);
extern int tex_codec_write(Tex* t, uint transforms, const void* hdr, size_t hdr_size, DynArray* da);
#endif // #ifndef TEX_CODEC_H__

View File

@ -459,7 +459,7 @@ static int jpg_decode_impl(DynArray* da,
return ERR_NO_MEM;
// read rows
RETURN_ERR(tex_util_alloc_rows(img, h, pitch, TEX_TOP_DOWN, 0, rows));
RETURN_ERR(tex_codec_alloc_rows(img, h, pitch, TEX_TOP_DOWN, 0, rows));
// could use cinfo->output_scanline to keep track of progress,
// but we need to count lines_left anyway (paranoia).
JSAMPARRAY row = (JSAMPARRAY)rows;
@ -520,7 +520,7 @@ static int jpg_encode_impl(Tex* t,
const size_t pitch = t->w * t->bpp / 8;
u8* data = tex_get_data(t);
RETURN_ERR(tex_util_alloc_rows(data, t->h, pitch, t->flags, TEX_TOP_DOWN, rows));
RETURN_ERR(tex_codec_alloc_rows(data, t->h, pitch, t->flags, TEX_TOP_DOWN, rows));
// could use cinfo->output_scanline to keep track of progress,

View File

@ -105,7 +105,7 @@ static int png_decode_impl(DynArray* da,
if(!img)
return ERR_NO_MEM;
RETURN_ERR(tex_util_alloc_rows(img, h, pitch, TEX_TOP_DOWN, 0, rows));
RETURN_ERR(tex_codec_alloc_rows(img, h, pitch, TEX_TOP_DOWN, 0, rows));
png_read_image(png_ptr, (png_bytepp)rows);
png_read_end(png_ptr, info_ptr);
@ -158,7 +158,7 @@ static int png_encode_impl(Tex* t,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
u8* data = tex_get_data(t);
RETURN_ERR(tex_util_alloc_rows(data, h, pitch, t->flags, TEX_TOP_DOWN, rows));
RETURN_ERR(tex_codec_alloc_rows(data, h, pitch, t->flags, TEX_TOP_DOWN, rows));
// PNG is native RGB.
const int png_transforms = (t->flags & TEX_BGR)? PNG_TRANSFORM_BGR : PNG_TRANSFORM_IDENTITY;

View File

@ -146,7 +146,7 @@ static int tga_encode(Tex* restrict t, DynArray* restrict da)
img_desc
};
const size_t hdr_size = sizeof(hdr);
return tex_util_write(t, transforms, &hdr, hdr_size, da);
return tex_codec_write(t, transforms, &hdr, hdr_size, da);
}
TEX_CODEC_REGISTER(tga);

View File

@ -286,7 +286,7 @@ static int alloc_idx(i32& idx, HDATA*& hd)
// add another
if(last_in_use >= hdata_cap)
{
debug_warn("alloc_idx: too many open handles (increase IDX_BITS)");
debug_warn(__func__": too many open handles (increase IDX_BITS)");
return ERR_LIMIT;
}
idx = last_in_use+1; // just incrementing idx would start it at 1
@ -296,7 +296,7 @@ static int alloc_idx(i32& idx, HDATA*& hd)
// can't fail for any other reason - idx is checked above.
{ // VC6 goto fix
bool is_unused = !hd->tag;
debug_assert(is_unused && "alloc_idx: invalid last_in_use");
debug_assert(is_unused && __func__": invalid last_in_use");
}
have_idx:;
@ -491,17 +491,17 @@ static int type_validate(H_Type type)
if(!type)
{
debug_warn("h_alloc: type is 0");
debug_warn(__func__": type is 0");
goto fail;
}
if(type->user_size > HDATA_USER_SIZE)
{
debug_warn("h_alloc: type's user data is too large for HDATA");
debug_warn(__func__": type's user data is too large for HDATA");
goto fail;
}
if(type->name == 0)
{
debug_warn("h_alloc: type's name field is 0");
debug_warn(__func__": type's name field is 0");
goto fail;
}
@ -539,7 +539,7 @@ static Handle reuse_existing_handle(uintptr_t key, H_Type type, uint flags)
HDATA* hd = h_data_tag_type(h, type);
if(hd->refs == REF_MAX)
{
debug_warn("reuse_existing: too many references to a handle - increase REF_BITS");
debug_warn(__func__": too many references to a handle - increase REF_BITS");
return ERR_LIMIT;
}
@ -761,7 +761,7 @@ void* h_user_data(const Handle h, const H_Type type)
if(!hd->refs)
{
// note: resetting the tag is not enough (user might pass in its value)
debug_warn("h_user_data: no references to resource (it's cached, but someone is accessing it directly)");
debug_warn(__func__": no references to resource (it's cached, but someone is accessing it directly)");
return 0;
}
@ -777,7 +777,7 @@ const char* h_filename(const Handle h)
HDATA* hd = h_data_tag(h);
if(!hd)
{
debug_warn("h_filename failed");
debug_warn(__func__" failed");
return 0;
}
return hd->fn;
@ -789,7 +789,9 @@ int h_reload(const char* fn)
{
if(!fn)
{
debug_warn("h_reload: fn = 0");
debug_warn(__func__": fn = 0");
// must not continue - some resources not backed by files have
// key = 0 and reloading those would be disastrous.
return ERR_INVALID_PARAM;
}
@ -871,13 +873,13 @@ void h_add_ref(Handle h)
HDATA* hd = h_data_tag(h);
if(!hd)
{
debug_warn("h_add_ref: invalid handle");
debug_warn(__func__": invalid handle");
return;
}
// if there are no refs, how did the caller manage to keep a Handle?!
if(!hd->refs)
debug_warn("h_add_ref: no refs open - resource is cached");
debug_warn(__func__": no refs open - resource is cached");
hd->refs++;
}
@ -894,13 +896,13 @@ int h_get_refcnt(Handle h)
HDATA* hd = h_data_tag(h);
if(!hd)
{
debug_warn("h_get_refcnt: invalid handle");
debug_warn(__func__": invalid handle");
return ERR_INVALID_PARAM;
}
// if there are no refs, how did the caller manage to keep a Handle?!
if(!hd->refs)
debug_warn("h_get_refcnt: no refs open - resource is cached");
debug_warn(__func__": no refs open - resource is cached");
return hd->refs;
}
@ -916,7 +918,7 @@ void h_mgr_shutdown()
// each HDATA entry has already been allocated.
if(!hd)
{
debug_warn("h_mgr_shutdown: h_data_from_idx failed - why?!");
debug_warn(__func__": h_data_from_idx failed - why?!");
continue;
}

View File

@ -106,7 +106,7 @@ static void remove_alloc(void* raw_p)
{
size_t num_removed = ptr_to_h.erase(raw_p);
if(num_removed != 1)
debug_warn("remove_alloc: not in map");
debug_warn(__func__": not in map");
}
@ -118,7 +118,7 @@ static void set_alloc(void* raw_p, Handle hm)
It it = ptr_to_h.find(raw_p);
if(it != ptr_to_h.end())
{
debug_warn("set_alloc: already in map");
debug_warn(__func__": already in map");
return;
}
#endif
@ -360,7 +360,7 @@ void* mem_alloc(size_t size, const size_t align, uint flags, Handle* phm)
Handle hm = mem_wrap(p, size, flags, raw_p, raw_size, dtor, ctx);
if(!hm) // failed to allocate a handle
{
debug_warn("mem_alloc: mem_wrap failed");
debug_warn(__func__": mem_wrap failed");
dtor(p, size, ctx);
return 0;
}

View File

@ -291,7 +291,7 @@ int snd_set_master_gain(float gain)
{
if(gain < 0)
{
debug_warn("snd_set_master_gain: gain < 0");
debug_warn(__func__": gain < 0");
return ERR_INVALID_PARAM;
}
@ -373,7 +373,7 @@ static void al_buf_free(ALuint al_buf)
static void al_buf_shutdown()
{
if(al_bufs_outstanding != 0)
debug_warn("al_buf_shutdown: not all buffers freed!");
debug_warn(__func__": not all buffers freed!");
}
@ -655,9 +655,9 @@ static void* io_buf_alloc()
if(!buf)
{
if(!io_bufs)
debug_warn("io_buf_alloc: not enough memory to allocate buffer pool");
debug_warn(__func__": not enough memory to allocate buffer pool");
else
debug_warn("io_buf_alloc: max #streams exceeded");
debug_warn(__func__": max #streams exceeded");
// can't happen (tm) because stream_open enforces MAX_STREAMS.
return 0;
}
@ -766,7 +766,7 @@ static int stream_open(Stream* s, const char* fn)
{
if(active_streams >= MAX_STREAMS)
{
debug_warn("stream_open: MAX_STREAMS exceeded - why?");
debug_warn(__func__": MAX_STREAMS exceeded - why?");
return -1;
// fail, because we wouldn't have enough IO buffers for all
}
@ -1418,7 +1418,7 @@ static void list_remove(VSrc* vs)
return;
}
debug_warn("list_remove: VSrc not found");
debug_warn(__func__": VSrc not found");
}
@ -1832,7 +1832,7 @@ int snd_disable(bool disabled)
if(snd_disabled)
{
if(al_initialized)
debug_warn("snd_disable: already initialized => disable is pointless");
debug_warn(__func__": already initialized => disable is pointless");
return 0;
}
else

View File

@ -346,18 +346,18 @@ sym(ia32_control87):
push eax
fnstcw [esp]
pop eax ; old_cw
mov ecx, [esp+4] ; new_cw
mov ecx, [esp+4] ; new_val
mov edx, [esp+8] ; mask
and ecx, edx ; new_cw & mask
and ecx, edx ; new_val & mask
not edx ; ~mask
and eax, edx ; old_cw & ~mask
or eax, ecx ; (old_cw & ~mask) | (new_cw & mask)
push eax
or eax, ecx ; (old_cw & ~mask) | (new_val & mask)
push eax ; = new_cw
fldcw [esp]
pop eax
xor eax, eax ; return value
ret
;-------------------------------------------------------------------------------
; init
;-------------------------------------------------------------------------------

View File

@ -39,15 +39,16 @@ extern double _ceil(double);
extern u64 rdtsc(void);
#ifndef _MCW_PC
# define _MCW_PC 0x0300 // Precision Control
#endif
#ifndef _PC_24
# define _PC_24 0x0000 // 24 bits
#endif
#ifndef _MCW_EM
# define _MCW_EM 0x003f // Exception Mask
#endif
// these may have been defined by system headers; we redefine them to
// the real IA-32 values for use with ia32_control87.
#undef _MCW_PC
#define _MCW_PC 0x0300 // Precision Control
#undef _PC_24
#define _PC_24 0x0000 // 24 bits
#undef _MCW_EM
#define _MCW_EM 0x003f // Exception Mask
#undef _MCW_PM
#define _MCW_PM BIT(5)
#ifndef _MCW_IM
# define _MCW_IM 0x0001 // Invalid Operation Mask
#endif
@ -72,7 +73,6 @@ extern void ia32_debug_break(void);
extern void ia32_memcpy(void* dst, const void* src, size_t nbytes);
// CPU caps (128 bits)
// do not change the order!
enum CpuCap

View File

@ -46,7 +46,7 @@ extern void* alloca(size_t size);
# define finite __finite
#endif
// restrict
// C99 restrict
// .. for some reason, g++-3.3 claims to support C99 (according to
// __STDC_VERSION__) but doesn't have the restrict keyword.
// use the extension __restrict__ instead.
@ -59,6 +59,16 @@ extern void* alloca(size_t size);
# define restrict
#endif
// C99 __func__
// .. already available; need do nothing
#if HAVE_C99
// .. VC supports something similar
#elif MSC_VERSION
# define __func__ __FUNCTION__
// .. unsupported; remove it from code
#else
# define __func__
#endif
//

View File

@ -181,7 +181,7 @@ static int aio_h_set(const int fd, const HANDLE h)
fail:
unlock();
debug_warn("aio_h_set failed");
debug_warn(__func__" failed");
return -1;
}
@ -225,7 +225,7 @@ WIN_RESTORE_LAST_ERROR;
return 0;
fail:
debug_warn("aio_reopen failed");
debug_warn(__func__" failed");
return -1;
}
@ -250,7 +250,7 @@ int aio_close(int fd)
return 0;
fail:
debug_warn("aio_close failed");
debug_warn(__func__" failed");
return -1;
}
@ -382,7 +382,7 @@ static int aio_rw(struct aiocb* cb)
// fail if aiocb is already in use (forbidden by SUSv3)
if(req_find(cb))
{
debug_warn("aio_rw: aiocb is already in use");
debug_warn(__func__": aiocb is already in use");
goto fail;
}
@ -398,14 +398,14 @@ static int aio_rw(struct aiocb* cb)
r = req_alloc(cb);
if(!r)
{
debug_warn("aio_rw: cannot allocate a Req (too many concurrent IOs)");
debug_warn(__func__": cannot allocate a Req (too many concurrent IOs)");
goto fail;
}
HANDLE h = aio_h_get(fd);
if(h == INVALID_HANDLE_VALUE)
{
debug_warn("aio_rw: associated handle is invalid");
debug_warn(__func__": associated handle is invalid");
ret = -EINVAL;
goto fail;
}
@ -531,7 +531,7 @@ int aio_error(const struct aiocb* cb)
// must not pass 0 to req_find - we'd look for a free cb!
if(!cb)
{
debug_warn("aio_error: invalid cb");
debug_warn(__func__": invalid cb");
return -1;
}
@ -557,14 +557,14 @@ ssize_t aio_return(struct aiocb* cb)
// must not pass 0 to req_find - we'd look for a free cb!
if(!cb)
{
debug_warn("aio_return: invalid cb");
debug_warn(__func__": invalid cb");
return -1;
}
Req* r = req_find(cb);
if(!r)
{
debug_warn("aio_return: cb not found (already called aio_return?)");
debug_warn(__func__": cb not found (already called aio_return?)");
return -1;
}
@ -574,7 +574,7 @@ ssize_t aio_return(struct aiocb* cb)
DWORD bytes_transferred;
if(!GetOverlappedResult(r->hFile, &r->ovl, &bytes_transferred, wait))
{
debug_warn("aio_return: GetOverlappedResult failed");
debug_warn(__func__": GetOverlappedResult failed");
return -1;
}

View File

@ -26,11 +26,7 @@
#include "sysdep/cpu.h"
#include "wdbg.h"
#include "byte_order.h" // FOURCC
// optional: enables translation of the "unhandled exception" dialog.
#if HAVE_I18N
#include "ps/i18n.h"
#endif
#include "app_hooks.h"
#pragma data_seg(WIN_CALLBACK_PRE_MAIN(b))
@ -61,44 +57,6 @@ static bool is_locked()
}
// return localized version of <text>, if i18n functionality is available.
// this is used to translate the "unhandled exception" dialog strings.
// WARNING: leaks memory returned by wcsdup, but that's ok since the
// program will terminate soon after. fixing this is hard and senseless.
static const wchar_t* translate(const wchar_t* text)
{
#if HAVE_I18N
// make sure i18n system is (already|still) initialized.
if(g_CurrentLocale)
{
// be prepared for this to fail, because translation potentially
// involves script code and the JS context might be corrupted.
__try
{
const wchar_t* text2 = wcsdup(I18n::translate(text).c_str());
// only overwrite if wcsdup succeeded, i.e. not out of memory.
if(text2)
text = text2;
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
}
}
#endif
return text;
}
// convenience wrapper using translate.
static void translate_and_display_msg(const wchar_t* caption, const wchar_t* text)
{
wdisplay_msg(translate(caption), translate(text));
}
//////////////////////////////////////////////////////////////////////////////
@ -412,7 +370,7 @@ have_reg:
case DBG_BREAK_DATA_WRITE:
rw = 3; break;
default:
debug_warn("brk_enable_in_ctx: invalid type");
debug_warn(__func__": invalid type");
}
// .. length (determine from addr's alignment).
// note: IA-32 requires len=0 for code breakpoints.
@ -641,13 +599,13 @@ static const wchar_t* get_SEH_exception_description(const EXCEPTION_RECORD* er)
{
const wchar_t* op = (ei[0])? L"writing" : L"reading";
const wchar_t* fmt = L"Access violation %s 0x%08X";
swprintf(description_buf, ARRAY_SIZE(description_buf), translate(fmt), translate(op), ei[1]);
swprintf(description_buf, ARRAY_SIZE(description_buf), ah_translate(fmt), ah_translate(op), ei[1]);
return description_buf;
}
// rationale: we don't use FormatMessage because it is unclear whether
// NTDLL's symbol table will always include English-language strings
// (we don't want crashlogs in foreign gobbledygook).
// (we don't want to receive crashlogs in foreign gobbledygook).
// it also adds unwanted formatting (e.g. {EXCEPTION} and trailing .).
switch(code)

View File

@ -562,7 +562,7 @@ static void out(const wchar_t* fmt, ...)
// make sure out_chars_left remains nonnegative
if((size_t)len > out_chars_left)
{
debug_warn("out: apparently wrote more than out_chars_left");
debug_warn(__func__": apparently wrote more than out_chars_left");
len = (int)out_chars_left;
}
out_chars_left -= len;

View File

@ -203,7 +203,7 @@ static int dll_list_add(const char* name)
// make sure we're allowed to be called.
if(!dll_list_pos)
{
debug_warn("dll_list_add: called before dll_list_init or after failure");
debug_warn(__func__": called before dll_list_init or after failure");
return -1;
}
@ -247,7 +247,7 @@ static int dll_list_add(const char* name)
// didn't fit; complain
sprintf(dll_list_pos, "..."); // (room was reserved above)
dll_list_pos = 0; // poison pill, prevent further calls
debug_warn("dll_list_add: not enough room");
debug_warn(__func__": not enough room");
return ERR_BUF_SIZE;
}

View File

@ -218,7 +218,7 @@ int dir_add_watch(const char* dir, intptr_t* _reqnum)
// need it before binding dir to IOCP because it is our "key".
if(last_reqnum == INT_MAX)
{
debug_warn("dir_add_watch: request numbers are no longer unique");
debug_warn(__func__": request numbers are no longer unique");
CloseHandle(hDir);
goto fail;
}
@ -280,7 +280,7 @@ int dir_cancel_watch(const intptr_t reqnum)
Watch* w = find_watch(reqnum);
if(!w)
{
debug_warn("dir_cancel_watch: watches[reqnum] invalid");
debug_warn(__func__": watches[reqnum] invalid");
return -1;
}

View File

@ -793,12 +793,6 @@ static
#endif
void win_pre_main_init()
{
// enable FPU exceptions
#if CPU_IA32
const int bits = _EM_INVALID|_EM_DENORMAL|_EM_ZERODIVIDE|_EM_OVERFLOW|_EM_UNDERFLOW|_EM_INEXACT;
_control87(bits, _MCW_EM);
#endif
// enable memory tracking and leak detection;
// no effect if !HAVE_VC_DEBUG_ALLOC.
#if CONFIG_PARANOIA

View File

@ -278,7 +278,7 @@ static int choose_impl()
return 0;
}
debug_warn("hrt_choose_impl: no safe timer found!");
debug_warn(__func__": no safe timer found!");
hrt_impl = HRT_NONE;
hrt_nominal_freq = -1.0;
return -1;
@ -320,7 +320,7 @@ static i64 ticks_lk()
case HRT_NUM_IMPLS:
default:
debug_warn("ticks_lk: invalid impl");
debug_warn(__func__": invalid impl");
//-fallthrough
case HRT_NONE:
@ -460,7 +460,7 @@ static int hrt_override_impl(HRTOverride ovr, HRTImpl impl)
if((ovr != HRT_DISABLE && ovr != HRT_FORCE && ovr != HRT_DEFAULT) ||
(impl != HRT_TSC && impl != HRT_QPC && impl != HRT_GTC && impl != HRT_NONE))
{
debug_warn("hrt_override: invalid ovr or impl param");
debug_warn(__func__": invalid ovr or impl param");
return -1;
}