mirror of
https://github.com/ZDoom/raze-gles.git
synced 2025-01-14 03:40:50 +00:00
43eb98fdec
1. The application must specify its proper name and technical name. Instead of eduke32_or_mapster32.crash.log, we now have eduke32.crash.log and mapster32.crash.log. 2. The exception handler will display a message box informing the user of a crash and requesting they send in the crash log. The box has three options: "Quit", the DLL's current behavior, "Continue", which passes the exception to the next handler, and "Ignore", which resumes execution immediately. These should allow the user to skip bogus exceptions picked up by ebacktrace, such as one I get with my laptop that causes EDuke32 no issues. git-svn-id: https://svn.eduke32.com/eduke32@4538 1a8010ca-5511-0410-912e-c29ae57300e0
702 lines
17 KiB
C
702 lines
17 KiB
C
/*
|
|
Copyright (c) 2010 ,
|
|
Cloud Wu . All rights reserved.
|
|
|
|
http://www.codingnow.com
|
|
|
|
Use, modification and distribution are subject to the "New BSD License"
|
|
as listed at <url: http://www.opensource.org/licenses/bsd-license.php >.
|
|
|
|
filename: backtrace.c
|
|
|
|
build command: gcc -O2 -shared -Wall -o backtrace.dll backtrace.c -lbfd -liberty -limagehlp
|
|
|
|
how to use: Call LoadLibraryA("backtrace.dll"); at beginning of your program .
|
|
|
|
*/
|
|
|
|
/* modified from original for EDuke32 */
|
|
|
|
// warnings cleaned up, ported to 64-bit, and heavily extended by Hendricks266
|
|
|
|
#include <windows.h>
|
|
#include <excpt.h>
|
|
#include <imagehlp.h>
|
|
|
|
// Tenuous: MinGW provides _IMAGEHLP_H while MinGW-w64 defines _IMAGEHLP_.
|
|
#ifdef _IMAGEHLP_H
|
|
# define EBACKTRACE_MINGW32
|
|
#endif
|
|
#ifdef _IMAGEHLP_
|
|
# define EBACKTRACE_MINGW_W64
|
|
#endif
|
|
#if defined(EBACKTRACE_MINGW32) && !defined(EBACKTRACE_MINGW_W64)
|
|
# include "_dbg_common.h"
|
|
#endif
|
|
|
|
#ifndef PACKAGE
|
|
# define PACKAGE EBACKTRACE1
|
|
#endif
|
|
#ifndef PACKAGE_VERSION
|
|
# define PACKAGE_VERSION 1
|
|
#endif
|
|
|
|
#if defined(_M_X64) || defined(__amd64__) || defined(__x86_64__) || defined(_WIN64)
|
|
# define EBACKTRACE64
|
|
#endif
|
|
|
|
#include <bfd.h>
|
|
#include <psapi.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
#include <stdbool.h>
|
|
|
|
#include <sys/stat.h>
|
|
#include <time.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
#ifndef DBG_PRINTEXCEPTION_C
|
|
# define DBG_PRINTEXCEPTION_C (0x40010006)
|
|
#endif
|
|
#ifndef MS_VC_EXCEPTION
|
|
# define MS_VC_EXCEPTION 1080890248
|
|
#endif
|
|
|
|
#if defined __GNUC__ || defined __clang__
|
|
# define ATTRIBUTE(attrlist) __attribute__(attrlist)
|
|
#else
|
|
# define ATTRIBUTE(attrlist)
|
|
#endif
|
|
|
|
#define BUFFER_MAX (16*1024)
|
|
|
|
struct bfd_ctx {
|
|
bfd * handle;
|
|
asymbol ** symbol;
|
|
};
|
|
|
|
struct bfd_set {
|
|
char * name;
|
|
struct bfd_ctx * bc;
|
|
struct bfd_set *next;
|
|
};
|
|
|
|
struct find_info {
|
|
asymbol **symbol;
|
|
bfd_vma counter;
|
|
const char *file;
|
|
const char *func;
|
|
unsigned line;
|
|
};
|
|
|
|
struct output_buffer {
|
|
char * buf;
|
|
size_t sz;
|
|
size_t ptr;
|
|
};
|
|
|
|
static void
|
|
output_init(struct output_buffer *ob, char * buf, size_t sz)
|
|
{
|
|
ob->buf = buf;
|
|
ob->sz = sz;
|
|
ob->ptr = 0;
|
|
ob->buf[0] = '\0';
|
|
}
|
|
|
|
static void
|
|
output_print(struct output_buffer *ob, const char * format, ...)
|
|
{
|
|
va_list ap;
|
|
|
|
if (ob->sz == ob->ptr)
|
|
return;
|
|
ob->buf[ob->ptr] = '\0';
|
|
va_start(ap,format);
|
|
vsnprintf(ob->buf + ob->ptr , ob->sz - ob->ptr , format, ap);
|
|
va_end(ap);
|
|
|
|
ob->ptr = strlen(ob->buf + ob->ptr) + ob->ptr;
|
|
}
|
|
|
|
static void
|
|
lookup_section(bfd *abfd, asection *sec, void *opaque_data)
|
|
{
|
|
struct find_info *data = opaque_data;
|
|
bfd_vma vma;
|
|
|
|
if (data->func)
|
|
return;
|
|
|
|
if (!(bfd_get_section_flags(abfd, sec) & SEC_ALLOC))
|
|
return;
|
|
|
|
vma = bfd_get_section_vma(abfd, sec);
|
|
if (data->counter < vma || vma + bfd_get_section_size(sec) <= data->counter)
|
|
return;
|
|
|
|
bfd_find_nearest_line(abfd, sec, data->symbol, data->counter - vma, &(data->file), &(data->func), &(data->line));
|
|
}
|
|
|
|
static void
|
|
find(struct bfd_ctx * b, DWORD offset, const char **file, const char **func, unsigned *line)
|
|
{
|
|
struct find_info data;
|
|
data.func = NULL;
|
|
data.symbol = b->symbol;
|
|
data.counter = offset;
|
|
data.file = NULL;
|
|
data.func = NULL;
|
|
data.line = 0;
|
|
|
|
bfd_map_over_sections(b->handle, &lookup_section, &data);
|
|
if (file) {
|
|
*file = data.file;
|
|
}
|
|
if (func) {
|
|
*func = data.func;
|
|
}
|
|
if (line) {
|
|
*line = data.line;
|
|
}
|
|
}
|
|
|
|
static int
|
|
init_bfd_ctx(struct bfd_ctx *bc, const char * procname, struct output_buffer *ob)
|
|
{
|
|
int r1, r2, r3;
|
|
bfd *b;
|
|
void *symbol_table;
|
|
unsigned dummy = 0;
|
|
bc->handle = NULL;
|
|
bc->symbol = NULL;
|
|
|
|
b = bfd_openr(procname, 0);
|
|
if (!b) {
|
|
output_print(ob,"Failed to open bfd from (%s)\n" , procname);
|
|
return 1;
|
|
}
|
|
|
|
r1 = bfd_check_format(b, bfd_object);
|
|
r2 = bfd_check_format_matches(b, bfd_object, NULL);
|
|
r3 = bfd_get_file_flags(b) & HAS_SYMS;
|
|
|
|
if (!(r1 && r2 && r3)) {
|
|
bfd_close(b);
|
|
if (!(r1 && r2))
|
|
output_print(ob,"Failed to init bfd from (%s): %d %d %d\n", procname, r1, r2, r3);
|
|
return 1;
|
|
}
|
|
|
|
if (bfd_read_minisymbols(b, FALSE, &symbol_table, &dummy) == 0) {
|
|
if (bfd_read_minisymbols(b, TRUE, &symbol_table, &dummy) < 0) {
|
|
free(symbol_table);
|
|
bfd_close(b);
|
|
output_print(ob,"Failed to read symbols from (%s)\n", procname);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
bc->handle = b;
|
|
bc->symbol = symbol_table;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
close_bfd_ctx(struct bfd_ctx *bc)
|
|
{
|
|
if (bc) {
|
|
if (bc->symbol) {
|
|
free(bc->symbol);
|
|
}
|
|
if (bc->handle) {
|
|
bfd_close(bc->handle);
|
|
}
|
|
}
|
|
}
|
|
|
|
static struct bfd_ctx *
|
|
get_bc(struct output_buffer *ob , struct bfd_set *set , const char *procname)
|
|
{
|
|
struct bfd_ctx bc;
|
|
while(set->name) {
|
|
if (strcmp(set->name , procname) == 0) {
|
|
return set->bc;
|
|
}
|
|
set = set->next;
|
|
}
|
|
if (init_bfd_ctx(&bc, procname , ob)) {
|
|
return NULL;
|
|
}
|
|
set->next = calloc(1, sizeof(*set));
|
|
set->bc = malloc(sizeof(struct bfd_ctx));
|
|
memcpy(set->bc, &bc, sizeof(bc));
|
|
set->name = strdup(procname);
|
|
|
|
return set->bc;
|
|
}
|
|
|
|
static void
|
|
release_set(struct bfd_set *set)
|
|
{
|
|
while(set) {
|
|
struct bfd_set * temp = set->next;
|
|
if (set->name)
|
|
free(set->name);
|
|
close_bfd_ctx(set->bc);
|
|
free(set);
|
|
set = temp;
|
|
}
|
|
}
|
|
|
|
static char procname[MAX_PATH];
|
|
|
|
#ifdef EBACKTRACE64
|
|
# define MachineType IMAGE_FILE_MACHINE_AMD64
|
|
# define MAYBE64(x) x ## 64
|
|
#else
|
|
# define MachineType IMAGE_FILE_MACHINE_I386
|
|
# define MAYBE64(x) x
|
|
#endif
|
|
|
|
static void
|
|
_backtrace(struct output_buffer *ob, struct bfd_set *set, int depth , LPCONTEXT context)
|
|
{
|
|
MAYBE64(STACKFRAME) frame;
|
|
HANDLE process, thread;
|
|
char symbol_buffer[sizeof(MAYBE64(IMAGEHLP_SYMBOL)) + 255];
|
|
char module_name_raw[MAX_PATH];
|
|
struct bfd_ctx *bc = NULL;
|
|
|
|
GetModuleFileNameA(NULL, procname, sizeof procname);
|
|
|
|
memset(&frame,0,sizeof(frame));
|
|
|
|
#ifdef EBACKTRACE64
|
|
frame.AddrPC.Offset = context->Rip;
|
|
frame.AddrStack.Offset = context->Rsp;
|
|
frame.AddrFrame.Offset = context->Rbp;
|
|
#else
|
|
frame.AddrPC.Offset = context->Eip;
|
|
frame.AddrStack.Offset = context->Esp;
|
|
frame.AddrFrame.Offset = context->Ebp;
|
|
#endif
|
|
|
|
frame.AddrPC.Mode = AddrModeFlat;
|
|
frame.AddrStack.Mode = AddrModeFlat;
|
|
frame.AddrFrame.Mode = AddrModeFlat;
|
|
|
|
process = GetCurrentProcess();
|
|
thread = GetCurrentThread();
|
|
|
|
while(MAYBE64(StackWalk)(MachineType,
|
|
process,
|
|
thread,
|
|
&frame,
|
|
context,
|
|
NULL,
|
|
MAYBE64(SymFunctionTableAccess),
|
|
MAYBE64(SymGetModuleBase), NULL)) {
|
|
MAYBE64(IMAGEHLP_SYMBOL) *symbol;
|
|
MAYBE64(DWORD) module_base;
|
|
const char * module_name = "[unknown module]";
|
|
|
|
const char * file = NULL;
|
|
const char * func = NULL;
|
|
unsigned line = 0;
|
|
|
|
--depth;
|
|
if (depth < 0)
|
|
break;
|
|
|
|
symbol = (MAYBE64(IMAGEHLP_SYMBOL) *)symbol_buffer;
|
|
symbol->SizeOfStruct = (sizeof *symbol) + 255;
|
|
symbol->MaxNameLength = 254;
|
|
|
|
module_base = MAYBE64(SymGetModuleBase)(process, frame.AddrPC.Offset);
|
|
|
|
if (module_base &&
|
|
GetModuleFileNameA((HINSTANCE)(intptr_t)module_base, module_name_raw, MAX_PATH)) {
|
|
module_name = module_name_raw;
|
|
bc = get_bc(ob, set, module_name);
|
|
}
|
|
|
|
if (bc) {
|
|
find(bc,frame.AddrPC.Offset,&file,&func,&line);
|
|
}
|
|
|
|
if (file == NULL) {
|
|
MAYBE64(DWORD) dummy = 0;
|
|
if (MAYBE64(SymGetSymFromAddr)(process, frame.AddrPC.Offset, &dummy, symbol)) {
|
|
file = symbol->Name;
|
|
}
|
|
else {
|
|
file = "[unknown file]";
|
|
}
|
|
}
|
|
|
|
output_print(ob,"0x%p : %s : %s", frame.AddrPC.Offset, module_name, file);
|
|
if (func != NULL)
|
|
output_print(ob, " (%d) : in function (%s)", line, func);
|
|
output_print(ob, "\n");
|
|
}
|
|
}
|
|
|
|
static LPTSTR FormatErrorMessage(DWORD dwMessageId)
|
|
{
|
|
LPTSTR lpBuffer = NULL;
|
|
|
|
// adapted from http://stackoverflow.com/a/455533
|
|
FormatMessage(
|
|
FORMAT_MESSAGE_FROM_SYSTEM
|
|
|FORMAT_MESSAGE_ALLOCATE_BUFFER
|
|
|FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
NULL,
|
|
dwMessageId,
|
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)
|
|
(LPTSTR)&lpBuffer,
|
|
0,
|
|
NULL);
|
|
|
|
return lpBuffer; // must be LocalFree()'d by caller
|
|
}
|
|
|
|
static LPTSTR FormatExceptionCodeMessage(DWORD dwMessageId)
|
|
{
|
|
LPTSTR lpBuffer = NULL;
|
|
|
|
FormatMessage(
|
|
FORMAT_MESSAGE_FROM_HMODULE
|
|
|FORMAT_MESSAGE_ALLOCATE_BUFFER
|
|
|FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
GetModuleHandleA("ntdll.dll"),
|
|
dwMessageId,
|
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)
|
|
(LPTSTR)&lpBuffer,
|
|
0,
|
|
NULL);
|
|
|
|
return lpBuffer; // must be LocalFree()'d by caller
|
|
}
|
|
|
|
|
|
// adapted from http://www.catch22.net/tuts/custom-messagebox
|
|
static HHOOK hMsgBoxHook;
|
|
|
|
LRESULT CALLBACK CBTProc(int nCode, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
if (nCode < 0)
|
|
return CallNextHookEx(hMsgBoxHook, nCode, wParam, lParam);
|
|
|
|
switch (nCode)
|
|
{
|
|
case HCBT_ACTIVATE:
|
|
{
|
|
// Get handle to the message box!
|
|
HWND hwnd = (HWND)wParam;
|
|
|
|
// Do customization!
|
|
SetWindowTextA(GetDlgItem(hwnd, IDYES), "Quit");
|
|
SetWindowTextA(GetDlgItem(hwnd, IDNO), "Continue");
|
|
SetWindowTextA(GetDlgItem(hwnd, IDCANCEL), "Ignore");
|
|
return 0;
|
|
}
|
|
break;
|
|
}
|
|
|
|
// Call the next hook, if there is one
|
|
return CallNextHookEx(hMsgBoxHook, nCode, wParam, lParam);
|
|
}
|
|
|
|
int ExceptionMessage(TCHAR *szText, TCHAR *szCaption)
|
|
{
|
|
int retval;
|
|
|
|
// Install a window hook, so we can intercept the message-box
|
|
// creation, and customize it
|
|
hMsgBoxHook = SetWindowsHookEx(
|
|
WH_CBT,
|
|
CBTProc,
|
|
NULL,
|
|
GetCurrentThreadId() // Only install for THIS thread!!!
|
|
);
|
|
|
|
// Display a standard message box
|
|
retval = MessageBoxA(NULL, szText, szCaption, MB_YESNOCANCEL|MB_ICONERROR|MB_TASKMODAL);
|
|
|
|
// remove the window hook
|
|
UnhookWindowsHookEx(hMsgBoxHook);
|
|
|
|
return retval;
|
|
}
|
|
|
|
static char crashlogfilename[MAX_PATH] = "crash.log";
|
|
static char propername[MAX_PATH] = "this application";
|
|
|
|
__declspec(dllexport) void SetTechnicalName(const char* input)
|
|
{
|
|
snprintf(crashlogfilename, MAX_PATH, "%s.crash.log", input);
|
|
}
|
|
__declspec(dllexport) void SetProperName(const char* input)
|
|
{
|
|
strncpy(propername, input, MAX_PATH);
|
|
}
|
|
|
|
static char * g_output = NULL;
|
|
static PVOID g_prev = NULL;
|
|
|
|
static LONG WINAPI
|
|
exception_filter(LPEXCEPTION_POINTERS info)
|
|
{
|
|
struct output_buffer ob;
|
|
int logfd, written, msgboxID;
|
|
PEXCEPTION_RECORD exception;
|
|
BOOL initialized = FALSE;
|
|
char *ExceptionPrinted;
|
|
|
|
for (exception = info->ExceptionRecord; exception != NULL; exception = exception->ExceptionRecord)
|
|
{
|
|
#if 0
|
|
if (exception->ExceptionFlags & EXCEPTION_NONCONTINUABLE)
|
|
continuable = FALSE;
|
|
#endif
|
|
|
|
switch (exception->ExceptionCode)
|
|
{
|
|
case EXCEPTION_BREAKPOINT:
|
|
case EXCEPTION_SINGLE_STEP:
|
|
case DBG_CONTROL_C:
|
|
case DBG_PRINTEXCEPTION_C:
|
|
case MS_VC_EXCEPTION:
|
|
break;
|
|
default:
|
|
{
|
|
LPTSTR ExceptionCodeMsg = FormatExceptionCodeMessage(exception->ExceptionCode);
|
|
// The message for this exception code is broken.
|
|
LPTSTR ExceptionText = exception->ExceptionCode == EXCEPTION_ACCESS_VIOLATION ? "Access violation." : ExceptionCodeMsg;
|
|
|
|
if (!initialized)
|
|
{
|
|
output_init(&ob, g_output, BUFFER_MAX);
|
|
initialized = TRUE;
|
|
}
|
|
|
|
output_print(&ob, "Caught exception 0x%08X at 0x%p: %s\n", exception->ExceptionCode, exception->ExceptionAddress, ExceptionText);
|
|
|
|
LocalFree(ExceptionCodeMsg);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!initialized)
|
|
return EXCEPTION_CONTINUE_SEARCH; // EXCEPTION_CONTINUE_EXECUTION
|
|
|
|
ExceptionPrinted = (char*)calloc(strlen(g_output) + 37 + 2*MAX_PATH, sizeof(char));
|
|
strcpy(ExceptionPrinted, g_output);
|
|
strcat(ExceptionPrinted, "\nPlease send ");
|
|
strcat(ExceptionPrinted, crashlogfilename);
|
|
strcat(ExceptionPrinted, " to the maintainers of ");
|
|
strcat(ExceptionPrinted, propername);
|
|
strcat(ExceptionPrinted, ".");
|
|
|
|
{
|
|
DWORD error = 0;
|
|
BOOL SymInitialized = SymInitialize(GetCurrentProcess(), NULL, TRUE);
|
|
|
|
if (!SymInitialized)
|
|
{
|
|
LPTSTR errorText;
|
|
|
|
error = GetLastError();
|
|
errorText = FormatErrorMessage(error);
|
|
output_print(&ob, "SymInitialize() failed with error %d: %s\n", error, errorText);
|
|
LocalFree(errorText);
|
|
}
|
|
|
|
if (SymInitialized || error == 87)
|
|
{
|
|
struct bfd_set *set = calloc(1,sizeof(*set));
|
|
bfd_init();
|
|
_backtrace(&ob , set , 128 , info->ContextRecord);
|
|
release_set(set);
|
|
|
|
SymCleanup(GetCurrentProcess());
|
|
}
|
|
}
|
|
|
|
logfd = open(crashlogfilename, O_APPEND | O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
|
|
|
|
if (logfd) {
|
|
time_t curtime;
|
|
struct tm *curltime;
|
|
const char *theasctime;
|
|
const char *finistr = "---------------\n";
|
|
|
|
while ((written = write(logfd, g_output, strlen(g_output)))) {
|
|
g_output += written;
|
|
}
|
|
|
|
curtime = time(NULL);
|
|
curltime = localtime(&curtime);
|
|
theasctime = curltime ? asctime(curltime) : NULL;
|
|
|
|
if (theasctime)
|
|
write(logfd, theasctime, strlen(theasctime));
|
|
write(logfd, finistr, strlen(finistr));
|
|
close(logfd);
|
|
}
|
|
|
|
//fputs(g_output, stderr);
|
|
|
|
msgboxID = ExceptionMessage(ExceptionPrinted, propername);
|
|
|
|
free(ExceptionPrinted);
|
|
|
|
switch (msgboxID)
|
|
{
|
|
case IDYES:
|
|
exit(0xBAC);
|
|
break;
|
|
case IDNO:
|
|
break;
|
|
case IDCANCEL:
|
|
return EXCEPTION_CONTINUE_EXECUTION;
|
|
break;
|
|
}
|
|
|
|
return EXCEPTION_CONTINUE_SEARCH;
|
|
}
|
|
|
|
static void
|
|
backtrace_register(void)
|
|
{
|
|
if (g_output == NULL) {
|
|
g_output = malloc(BUFFER_MAX);
|
|
g_prev = AddVectoredExceptionHandler(1, exception_filter);
|
|
}
|
|
}
|
|
|
|
static void
|
|
backtrace_unregister(void)
|
|
{
|
|
if (g_output) {
|
|
free(g_output);
|
|
RemoveVectoredExceptionHandler(g_prev);
|
|
g_prev = NULL;
|
|
g_output = NULL;
|
|
}
|
|
}
|
|
|
|
BOOL WINAPI
|
|
DllMain(HINSTANCE hinstDLL ATTRIBUTE((unused)), DWORD dwReason, LPVOID lpvReserved ATTRIBUTE((unused)))
|
|
{
|
|
switch (dwReason) {
|
|
case DLL_PROCESS_ATTACH:
|
|
backtrace_register();
|
|
break;
|
|
case DLL_PROCESS_DETACH:
|
|
backtrace_unregister();
|
|
break;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/* cut dependence on libintl... libbfd needs this */
|
|
char *libintl_dgettext (const char *domain_name ATTRIBUTE((unused)), const char *msgid ATTRIBUTE((unused)))
|
|
{
|
|
static char buf[1024] = "XXX placeholder XXX";
|
|
return buf;
|
|
}
|
|
|
|
int __printf__ ( const char * format, ... );
|
|
int libintl_fprintf ( FILE * stream, const char * format, ... );
|
|
int libintl_sprintf ( char * str, const char * format, ... );
|
|
int libintl_snprintf ( char *buffer, int buf_size, const char *format, ... );
|
|
int libintl_vprintf ( const char * format, va_list arg );
|
|
int libintl_vfprintf ( FILE * stream, const char * format, va_list arg );
|
|
int libintl_vsprintf ( char * str, const char * format, va_list arg );
|
|
|
|
int __printf__ ( const char * format, ... )
|
|
{
|
|
int value;
|
|
va_list arg;
|
|
va_start(arg, format);
|
|
value = vprintf ( format, arg );
|
|
va_end(arg);
|
|
return value;
|
|
}
|
|
|
|
int libintl_fprintf ( FILE * stream, const char * format, ... )
|
|
{
|
|
int value;
|
|
va_list arg;
|
|
va_start(arg, format);
|
|
value = vfprintf ( stream, format, arg );
|
|
va_end(arg);
|
|
return value;
|
|
}
|
|
int libintl_sprintf ( char * str, const char * format, ... )
|
|
{
|
|
int value;
|
|
va_list arg;
|
|
va_start(arg, format);
|
|
value = vsprintf ( str, format, arg );
|
|
va_end(arg);
|
|
return value;
|
|
}
|
|
int libintl_snprintf ( char *buffer, int buf_size, const char *format, ... )
|
|
{
|
|
int value;
|
|
va_list arg;
|
|
va_start(arg, format);
|
|
value = vsnprintf ( buffer, buf_size, format, arg );
|
|
va_end(arg);
|
|
return value;
|
|
}
|
|
int libintl_vprintf ( const char * format, va_list arg )
|
|
{
|
|
return vprintf ( format, arg );
|
|
}
|
|
int libintl_vfprintf ( FILE * stream, const char * format, va_list arg )
|
|
{
|
|
return vfprintf ( stream, format, arg );
|
|
}
|
|
int libintl_vsprintf ( char * str, const char * format, va_list arg )
|
|
{
|
|
return vsprintf ( str, format, arg );
|
|
}
|
|
|
|
/* cut dependence on zlib... libbfd needs this */
|
|
|
|
int compress (unsigned char *dest ATTRIBUTE((unused)), unsigned long destLen ATTRIBUTE((unused)), const unsigned char source ATTRIBUTE((unused)), unsigned long sourceLen ATTRIBUTE((unused)))
|
|
{
|
|
return 0;
|
|
}
|
|
unsigned long compressBound (unsigned long sourceLen)
|
|
{
|
|
return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + (sourceLen >> 25) + 13;
|
|
}
|
|
int inflateEnd(void *strm ATTRIBUTE((unused)))
|
|
{
|
|
return 0;
|
|
}
|
|
int inflateInit_(void *strm ATTRIBUTE((unused)), const char *version ATTRIBUTE((unused)), int stream_size ATTRIBUTE((unused)))
|
|
{
|
|
return 0;
|
|
}
|
|
int inflateReset(void *strm ATTRIBUTE((unused)))
|
|
{
|
|
return 0;
|
|
}
|
|
int inflate(void *strm ATTRIBUTE((unused)), int flush ATTRIBUTE((unused)))
|
|
{
|
|
return 0;
|
|
}
|