I have to use libxml in my c++ code, for some reason and my program is parsing xml files with sax method.Is there any way to handle errors or exceptions in parsing?thanks in advance.
You can write your own error handler like this :
static void my_error(void *user_data, const char *msg, ...) {
va_list args;
va_start(args, msg);
g_logv("XML", G_LOG_LEVEL_CRITICAL, msg, args);
va_end(args);
}
static void my_fatalError(void *user_data, const char *msg, ...) {
va_list args;
va_start(args, msg);
g_logv("XML", G_LOG_LEVEL_ERROR, msg, args);
va_end(args);
}
(example from here)
And register them using xmlSetGenericErrorFunc and xmlSetStructuredErrorFunc.
Example of registration without context :
xmlSetGenericErrorFunc(NULL, my_fatalError);
Related
I wrote a very simple test code to test vsnprintf, but in xcode and visual studio environment, the results are very different. The test code is as follows:
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string.h>
#include <cstdarg>
void p(const char* fmt, ...)
{
static const int DefaultLength = 256;
char defaultBuf[DefaultLength] = { 0 };
va_list args;
va_start(args, fmt);
vsprintf(defaultBuf, fmt, args);
printf("%s\n", defaultBuf);
memset(defaultBuf, 0, sizeof(defaultBuf));
vsnprintf(defaultBuf, DefaultLength, fmt, args);
printf("%s\n", defaultBuf);
va_end(args);
}
int main(int argc, const char* argv[])
{
// if you uncomment this line(std::cout ...), it will crash at vsnprintf in xcode
std::cout << "Tests...!\n";
p("Create:%s(%d)", "I'm A String", 0x16);
return 0;
}
this is the output in visual studio :
Tests...!
Create:I'm A String(22)
Create:I'm A String(22)
This is normal and doesn't seem to be a problem. But the same code, I created a macos command line project, pasted this code in, something strange happened, when the code is executed to vsnprintf, it will start EXC_BAD_ACCESS directly.
What's more outrageous is that if I comment out the std::cout in the main function, it will not crash, but the output is wrong. So the question is, what is the reason for this difference, shouldn't these functions all be functions of the C standard library, and their behavior should be constrained by the standard library? Or is my usage wrong?
the output when i delete std::cout:
Create:I'm A String(22)
Create:\310\366\357\277\367(3112398)
Program ended with exit code: 0
If only one is right, is xcode right or visual studio is right, in the end I used is the latest xcode 14, visual studio 2022。
You must reinitialize the va_list between calls to vsprintf. Failure to do so is undefined behavior.
See https://en.cppreference.com/w/c/variadic/va_list :
If a va_list instance is created, passed to another function, and used via va_arg in that function, then any subsequent use in the calling function should be preceded by a call to va_end.
void p(const char* fmt, ...)
{
static const int DefaultLength = 256;
char defaultBuf[DefaultLength] = { 0 };
va_list args;
va_start(args, fmt);
vsprintf(defaultBuf, fmt, args);
va_end(args);
printf("%s\n", defaultBuf);
memset(defaultBuf, 0, sizeof(defaultBuf));
va_start(args, fmt);
vsnprintf(defaultBuf, DefaultLength, fmt, args);
va_end(args);
printf("%s\n", defaultBuf);
}
void p(const char* fmt, ...)
{
static const int DefaultLength = 256;
char defaultBuf[DefaultLength] = { 0 };
va_list args;
va_start(args, fmt);
va_list args_r;
va_copy(args_r, args);
vsprintf(defaultBuf, fmt, args);
printf("%s\n", defaultBuf);
memset(defaultBuf, 0, sizeof(defaultBuf));
vsnprintf(defaultBuf, DefaultLength, fmt, args_r);
printf("%s\n", defaultBuf);
va_end(args_r);
va_end(args);
}
I am porting Einstein#Home (Radio Pulsar Edition) to Solaris and am stuck on erp_execinfo_plus.c that reports the error below.
builder#bertha:~/brp/src$ g++ -g -I/export/home/builder/brp/install/include/libxml2 -I/export/home/builder/brp/install/include/boinc -I/usr/gnu/include -I/export/home/builder/brp/install/include -DHAVE_INLINE -DBOINCIFIED -DUSE_CPU_RESAMP -DUSE_FFTW_FFT -DNDEBUG -DLOGLEVEL=info -ggdb3 -rdynamic -O3 -Wall -fprofile-use -c /export/home/builder/brp/src/erp_extract.c
/export/home/builder/brp/src/erp_extract.c:8:12: error: expected initializer before 'VPARAMS'
void fatal VPARAMS ((const char *format, ...)) {
^~~~~~~
/export/home/builder/brp/src/erp_extract.c:16:16: error: expected initializer before 'VPARAMS'
void non_fatal VPARAMS ((const char *format, ...)) {
^~~~~~~
I have tried numerous iterations to correct the issue by moving code blocks around, redefining them as a struct and overloading. I have even used gcc and the gcc/g++ preprocessor outputs to find the error to no avail.
gcc:
/export/home/builder/brp/src/erp_extract.c:16:16: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'VPARAMS'
NOTES:
The erp_extract.c file is the minimum source code to reproduce the error.
The #include is the default binutils sysdef.h
erp_extract.c
#include "sysdep.h"
static FILE *ostream; /* output stream */
void fatal(const char *, ...) ATTRIBUTE_PRINTF_1 ATTRIBUTE_NORETURN;
void non_fatal(const char *, ...) ATTRIBUTE_PRINTF_1;
void report(const char *, va_list) ATTRIBUTE_PRINTF(1,0);
void fatal VPARAMS ((const char *format, ...)) {
VA_OPEN (args, format);
VA_FIXEDARG (args, const char *, format);
report(format, args);
VA_CLOSE (args);
}
void non_fatal VPARAMS ((const char *format, ...)) {
VA_OPEN (args, format);
VA_FIXEDARG (args, const char *, format);
report(format, args);
VA_CLOSE (args);
}
void report(const char * format, va_list args)
{
vfprintf(ostream, format, args);
putc ('\n', ostream);
}
The following code produces warning about wrong format specifier in all major compilers
std::wstring ws = L"some example string";
char buff[100];
sprintf(buff, "%s", ws.c_str());
The warning disappears if we use it in 'variadic' context (variadic template or va_list).
std::wstring ws = L"some example string";
void foo_va_list(const char* fmt, ...)
{
va_list argv;
va_start( argv, fmt );
char buff[1000];
vsprintf(buff, fmt, argv);
va_end(argv);
}
template<typename ... T>
void foo_variadic_template(const char* fmt, T && ... args)
{
char buff[100];
sprintf(buff, fmt, args...);
}
int main()
{
//this two should produce a warning but don't
foo_va_list("foo_va_list %s", ws.c_str());
foo_variadic_template("foo_variadic_template %s", ws.c_str());
char buff[100];
//this one produces warning as expected
sprintf(buff, "sprintf %s", ws.c_str());
}
The question is how to enable this warning in this context?
some compilers have an extension for the [s]printf functions and can "understand" the given format string and check the used format specifier against the used arguments.
Obviously these checks can not work if you hide this relation in your own implementation.
I'm trying to suppress -Wformat-nonliteral warnings. I have used attribute((format(printf with success elsewhere but the following example eludes me.
exceptions.hpp
class Exceptions {
...
static void fthrow(Thread* thread, const char* file, int line, Symbol* name,
const char* format, ...);
};
exceptions.cpp
__attribute__((format(printf, 5, 6)))
void Exceptions::fthrow(Thread* thread, const char* file, int line, Symbol* h_name, const char* format, ...) {
const int max_msg_size = 1024;
va_list ap;
va_start(ap, format);
char msg[max_msg_size];
vsnprintf(msg, max_msg_size, format, ap);
msg[max_msg_size-1] = '\0';
va_end(ap);
_throw_msg(thread, file, line, h_name, msg);
}
result
exceptions.cpp:229:16: error: format argument not a string type
__attribute__((format(printf, 5, 6)))
^ ~
exceptions.cpp:235:32: error: format string is not a string literal [-Werror,-Wformat-nonliteral]
vsnprintf(msg, max_msg_size, format, ap);
^~~~~~
Since it is a static, the exact index should be used, but I've tried 4, 5 and 6, 7 (if out by one) with similar fail.
The attribute should be set on the declaration of the function, not the definition.
class Exceptions {
...
static void fthrow(Thread* thread, const char* file, int line, Symbol* name,
const char* format, ...) __attribute__((format(printf, 5, 6)));
};
I've a log system written in C++ with this type of functions to write on it:
void processMessages();
void DEBUG_MSG(const std::string& appender,const char* msg, ...);
void INFO_MSG(const std::string& appender,const char* msg, ...);
void WARNING_MSG(const std::string& appender, const char* msg, ...);
void ERROR_MSG(const std::string& appender, const char* msg, ...);
void FATAL_MSG(const std::string& appender, const char* msg, ...);
I want to disable via macros in C++.
I've read this thread: Disable functions using MACROS but
#ifdef GLOG_SILENCE
#define processMessages (void)sizeof
#define DEBUG_MSG (void)sizeof
#define INFO_MSG (void)sizeof
#define WARNING_MSG (void)sizeof
#define ERROR_MSG (void)sizeof
#define FATAL_MSG (void)sizeof
#else //GLOG_SILENCE
void processMessages();
void DEBUG_MSG(const std::string& appender,const char* msg, ...);
void INFO_MSG(const std::string& appender,const char* msg, ...);
void WARNING_MSG(const std::string& appender, const char* msg, ...);
void ERROR_MSG(const std::string& appender, const char* msg, ...);
void FATAL_MSG(const std::string& appender, const char* msg, ...);
#endif //GLOG_SILENCE
doesn't work properly. I keep getting errors like:
In file included from ../src/test_core.cpp:2:
../src/test_Log.h: In member function ‘virtual void LogTestFixtureTest_defining_SILENCE_macro_avoids_write_and_processing_activity_from_log_Test::TestBody()’:
../src/test_Log.h:63: error: expected unqualified-id before ‘(’ token
../src/test_Log.h:63: error: expected primary-expression before ‘void’
../src/test_Log.h:63: error: expected ‘;’ before ‘sizeof’
../src/test_Log.h:64: error: expected unqualified-id before ‘(’ token
../src/test_Log.h:64: error: expected primary-expression before ‘void’
../src/test_Log.h:64: error: expected ‘;’ before ‘sizeof’
I suspect that the problem is related with the fact that Log is a class, but I don't know how to do it.
Some help?
Indeed, if these are member functions, then the "silent" versions will expand to nonsense:
log.(void)sizeof(stuff);
You could define a member function that does nothing, and macros that swallow their arguments:
void nothing() {}
#define processMessages(...) nothing()
then using the "silent" versions will give valid code that should compile away to nothing:
log.nothing();
The disadvantages of this are (a) you're relying on the compiler to inline the empty function, and not generate a function call; (b) the arguments' syntax is not checked when compiling in silent mode.
If your compiler support variadic macros you can simply define macros with empty replacements:
#ifdef GLOG_SILENCE
#define processMessages(_1, _2, ...)
#define DEBUG_MSG(_1, _2, ...)
#define INFO_MSG(_1, _2, ...)
#define WARNING_MSG(_1, _2, ...)
#define ERROR_MSG(_1, _2, ...)
#define FATAL_MSG(_1, _2, ...)
#else //GLOG_SILENCE
void processMessages();
void DEBUG_MSG(const std::string& appender,const char* msg, ...);
void INFO_MSG(const std::string& appender,const char* msg, ...);
void WARNING_MSG(const std::string& appender, const char* msg, ...);
void ERROR_MSG(const std::string& appender, const char* msg, ...);
void FATAL_MSG(const std::string& appender, const char* msg, ...);
#endif //GLOG_SILENCE
However, this will only work if the functions are NOT members of a class or a namespace, but true global functions.
I would like to suggest you to work in a different way. Just declare the interface ILogger after that implement it in the different loggers, like
class ILogger{
public:
virtual void DEBUG_MSG(const std::string& appender,const char* msg, ...);
virtual void INFO_MSG(const std::string& appender,const char* msg, ...);
virtual void WARNING_MSG(const std::string& appender, const char* msg, ...);
virtual void ERROR_MSG(const std::string& appender, const char* msg, ...);
virtual void FATAL_MSG(const std::string& appender, const char* msg, ...);
virtual ~ILogger(){}
};
For the file logger
class FileLogger : public ILogger{
public:
void DEBUG_MSG(const std::string& appender,const char* msg, ...){....}
void INFO_MSG(const std::string& appender,const char* msg, ...){....}
void WARNING_MSG(const std::string& appender, const char* msg, ...){....}
void ERROR_MSG(const std::string& appender, const char* msg, ...){....}
void FATAL_MSG(const std::string& appender, const char* msg, ...){....}
virtual ~EmptyLogger(){}
};
and the empty logger like:
for the empty logger
class EmptyLogger : public ILogger{
public:
void DEBUG_MSG(const std::string& appender,const char* msg, ...){do nothing here}
void INFO_MSG(const std::string& appender,const char* msg, ...){do nothing here}
void WARNING_MSG(const std::string& appender, const char* msg, ...){do nothing here}
void ERROR_MSG(const std::string& appender, const char* msg, ...){do nothing here}
void FATAL_MSG(const std::string& appender, const char* msg, ...){do nothing here}
virtual ~FileLogger(){}
};
after that in the place where you create the logger could be a factory make a macros in order to generate a different type of logger.
class LoggerFactory{
public:
static ILogger* getLogger(/*loggertype as argument*/){
#ifdef GLOG_SILENCE
/* create a normal logger*/
#else
return new EmptyLogger();
#endif
}
};