mirror of
https://github.com/c-sooyoung/fold_slice.git
synced 2026-09-17 21:39:08 +09:00
initial commit
This commit is contained in:
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
-----------------------------------------------------------------------
|
||||
Copyright: 2010-2015, iMinds-Vision Lab, University of Antwerp
|
||||
2014-2015, CWI, Amsterdam
|
||||
|
||||
Contact: astra@uantwerpen.be
|
||||
Website: http://sf.net/projects/astra-toolbox
|
||||
|
||||
This file is part of the ASTRA Toolbox.
|
||||
|
||||
|
||||
The ASTRA Toolbox 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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
The ASTRA Toolbox 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
$Id$
|
||||
*/
|
||||
|
||||
#ifndef _INC_ASTRA_GEOMETRYUTIL3D
|
||||
#define _INC_ASTRA_GEOMETRYUTIL3D
|
||||
|
||||
namespace astra {
|
||||
|
||||
struct SConeProjection {
|
||||
// the source
|
||||
double fSrcX, fSrcY, fSrcZ;
|
||||
|
||||
// the origin ("bottom left") of the (flat-panel) detector
|
||||
double fDetSX, fDetSY, fDetSZ;
|
||||
|
||||
// the U-edge of a detector pixel
|
||||
double fDetUX, fDetUY, fDetUZ;
|
||||
|
||||
// the V-edge of a detector pixel
|
||||
double fDetVX, fDetVY, fDetVZ;
|
||||
|
||||
|
||||
|
||||
|
||||
void translate(double dx, double dy, double dz) {
|
||||
fSrcX += dx;
|
||||
fSrcY += dy;
|
||||
fSrcZ += dz;
|
||||
fDetSX += dx;
|
||||
fDetSY += dy;
|
||||
fDetSZ += dz;
|
||||
|
||||
}
|
||||
void scale(double factor) {
|
||||
fSrcX *= factor;
|
||||
fSrcY *= factor;
|
||||
fSrcZ *= factor;
|
||||
fDetSX *= factor;
|
||||
fDetSY *= factor;
|
||||
fDetSZ *= factor;
|
||||
fDetUX *= factor;
|
||||
fDetUY *= factor;
|
||||
fDetUZ *= factor;
|
||||
fDetVX *= factor;
|
||||
fDetVY *= factor;
|
||||
fDetVZ *= factor;
|
||||
}
|
||||
};
|
||||
|
||||
struct SPar3DProjection {
|
||||
// the ray direction
|
||||
double fRayX, fRayY, fRayZ;
|
||||
|
||||
// the origin ("bottom left") of the (flat-panel) detector
|
||||
double fDetSX, fDetSY, fDetSZ;
|
||||
|
||||
// the U-edge of a detector pixel
|
||||
double fDetUX, fDetUY, fDetUZ;
|
||||
|
||||
// the V-edge of a detector pixel
|
||||
double fDetVX, fDetVY, fDetVZ;
|
||||
|
||||
|
||||
|
||||
|
||||
void translate(double dx, double dy, double dz) {
|
||||
fDetSX += dx;
|
||||
fDetSY += dy;
|
||||
fDetSZ += dz;
|
||||
}
|
||||
void scale(double factor) {
|
||||
fRayX *= factor;
|
||||
fRayY *= factor;
|
||||
fRayZ *= factor;
|
||||
fDetSX *= factor;
|
||||
fDetSY *= factor;
|
||||
fDetSZ *= factor;
|
||||
fDetUX *= factor;
|
||||
fDetUY *= factor;
|
||||
fDetUZ *= factor;
|
||||
fDetVX *= factor;
|
||||
fDetVY *= factor;
|
||||
fDetVZ *= factor;
|
||||
}
|
||||
};
|
||||
|
||||
void computeBP_UV_Coeffs(const SPar3DProjection& proj,
|
||||
double &fUX, double &fUY, double &fUZ, double &fUC,
|
||||
double &fVX, double &fVY, double &fVZ, double &fVC);
|
||||
|
||||
void computeBP_UV_Coeffs(const SConeProjection& proj,
|
||||
double &fUX, double &fUY, double &fUZ, double &fUC,
|
||||
double &fVX, double &fVY, double &fVZ, double &fVC,
|
||||
double &fDX, double &fDY, double &fDZ, double &fDC);
|
||||
|
||||
|
||||
SConeProjection* genConeProjections(unsigned int iProjAngles,
|
||||
unsigned int iProjU,
|
||||
unsigned int iProjV,
|
||||
double fOriginSourceDistance,
|
||||
double fOriginDetectorDistance,
|
||||
double fDetUSize,
|
||||
double fDetVSize,
|
||||
const float *pfAngles);
|
||||
|
||||
SPar3DProjection* genPar3DProjections(unsigned int iProjAngles,
|
||||
unsigned int iProjU,
|
||||
unsigned int iProjV,
|
||||
double fDetUSize,
|
||||
double fDetVSize,
|
||||
const float *pfAngles);
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,318 @@
|
||||
/*
|
||||
-----------------------------------------------------------------------
|
||||
Copyright: 2010-2015, iMinds-Vision Lab, University of Antwerp
|
||||
2014-2015, CWI, Amsterdam
|
||||
|
||||
Contact: astra@uantwerpen.be
|
||||
Website: http://sf.net/projects/astra-toolbox
|
||||
|
||||
This file is part of the ASTRA Toolbox.
|
||||
|
||||
|
||||
The ASTRA Toolbox 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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
The ASTRA Toolbox 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
$Id$
|
||||
*/
|
||||
|
||||
#ifndef _INC_ASTRA_GLOBALS
|
||||
#define _INC_ASTRA_GLOBALS
|
||||
|
||||
/*! \mainpage The ASTRA-toolbox
|
||||
*
|
||||
* <img src="../images/logo_big.png"/>
|
||||
*/
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
// disable warning: 'fopen' was declared deprecated
|
||||
#pragma warning (disable : 4996)
|
||||
// disable warning: C++ exception handler used, but unwind semantics are not enables
|
||||
#pragma warning (disable : 4530)
|
||||
// disable warning: no suitable definition provided for explicit template instantiation request
|
||||
#pragma warning (disable : 4661)
|
||||
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
// standard includes
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <math.h>
|
||||
//#include <boost/static_assert.hpp>
|
||||
//#include <boost/throw_exception.hpp>
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
// macro's
|
||||
|
||||
#define ASTRA_TOOLBOXVERSION_MAJOR 1
|
||||
#define ASTRA_TOOLBOXVERSION_MINOR 7
|
||||
#define ASTRA_TOOLBOXVERSION ((ASTRA_TOOLBOXVERSION_MAJOR)*100 + (ASTRA_TOOLBOXVERSION_MINOR))
|
||||
#define ASTRA_TOOLBOXVERSION_STRING "1.7.1"
|
||||
|
||||
|
||||
#define ASTRA_ASSERT(a) assert(a)
|
||||
|
||||
#define ASTRA_CONFIG_CHECK(value, type, msg) if (!(value)) { cout << "Configuration Error in " << type << ": " << msg << endl; return false; }
|
||||
|
||||
#define ASTRA_CONFIG_WARNING(type, msg) { cout << "Warning in " << type << ": " << msg << endl; }
|
||||
|
||||
|
||||
#define ASTRA_DELETE(a) if (a) { delete a; a = NULL; }
|
||||
#define ASTRA_DELETE_ARRAY(a) if (a) { delete[] a; a = NULL; }
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
#ifdef DLL_EXPORTS
|
||||
#define _AstraExport __declspec(dllexport)
|
||||
#define EXPIMP_TEMPLATE
|
||||
#else
|
||||
#define _AstraExport __declspec(dllimport)
|
||||
#define EXPIMP_TEMPLATE extern
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#define _AstraExport
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
// typedefs
|
||||
namespace astra {
|
||||
typedef float float32;
|
||||
typedef double float64;
|
||||
typedef unsigned short int uint16;
|
||||
typedef signed short int sint16;
|
||||
typedef unsigned char uchar8;
|
||||
typedef signed char schar8;
|
||||
|
||||
typedef int int32;
|
||||
typedef short int int16;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
// globals vars & functions
|
||||
//namespace astra {
|
||||
//#define ToolboxVersion 0.1f;
|
||||
|
||||
//float32 getVersion() { return ToolboxVersion; }
|
||||
|
||||
//_AstraExport bool cudaEnabled() {
|
||||
//#ifdef ASTRA_CUDA
|
||||
// return true;
|
||||
//#else
|
||||
// return false;
|
||||
//#endif
|
||||
//}
|
||||
//}
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
// errors
|
||||
namespace astra {
|
||||
|
||||
typedef enum {ASTRA_SUCCESS,
|
||||
ASTRA_ERROR_NOT_INITIALIZED,
|
||||
ASTRA_ERROR_INVALID_FILE,
|
||||
ASTRA_ERROR_OUT_OF_RANGE,
|
||||
ASTRA_ERROR_DIMENSION_MISMATCH,
|
||||
ASTRA_ERROR_EXTERNAL_LIBRARY,
|
||||
ASTRA_ERROR_ALLOCATION,
|
||||
ASTRA_ERROR_NOT_IMPLEMENTED} AstraError;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
// variables
|
||||
namespace astra {
|
||||
const float32 PI = 3.14159265358979323846264338328f;
|
||||
const float32 PI32 = 3.14159265358979323846264338328f;
|
||||
const float32 PIdiv2 = PI / 2;
|
||||
const float32 PIdiv4 = PI / 4;
|
||||
const float32 eps = 1e-7f;
|
||||
|
||||
extern _AstraExport bool running_in_matlab;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
// math
|
||||
namespace astra {
|
||||
|
||||
inline float32 cos_73s(float32 x)
|
||||
{
|
||||
/*
|
||||
const float32 c1 = 0.999999953464f;
|
||||
const float32 c2 = -0.4999999053455f;
|
||||
const float32 c3 = 0.0416635846769f;
|
||||
const float32 c4 = -0.0013853704264f;
|
||||
const float32 c5 = 0.000023233f;
|
||||
*/
|
||||
const float c1= (float)0.99940307;
|
||||
const float c2= (float)-0.49558072;
|
||||
const float c3= (float)0.03679168;
|
||||
|
||||
float32 x2;
|
||||
x2 = x * x;
|
||||
//return (c1 + x2*(c2 + x2*(c3 + x2*(c4 + c5*x2))));
|
||||
return (c1 + x2*(c2 + c3 * x2));
|
||||
}
|
||||
|
||||
inline float32 fast_cos(float32 x)
|
||||
{
|
||||
int quad;
|
||||
|
||||
//x = fmod(x, 2*PI); // Get rid of values > 2* pi
|
||||
if (x < 0) x = -x; // cos(-x) = cos(x)
|
||||
quad = int(x/PIdiv2); // Get quadrant # (0 to 3)
|
||||
switch (quad) {
|
||||
case 0: return cos_73s(x);
|
||||
case 1: return -cos_73s(PI-x);
|
||||
case 2: return -cos_73s(x-PI);
|
||||
case 3: return cos_73s(2*PI-x);
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
inline float32 fast_sin(float32 x){
|
||||
return fast_cos(PIdiv2-x);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
// structs
|
||||
namespace astra {
|
||||
/**
|
||||
* Struct for storing pixel weigths
|
||||
**/
|
||||
struct SPixelWeight
|
||||
{
|
||||
int m_iIndex;
|
||||
float32 m_fWeight;
|
||||
};
|
||||
|
||||
/**
|
||||
* Struct combining some properties of a detector in 1D detector row
|
||||
**/
|
||||
struct SDetector2D
|
||||
{
|
||||
int m_iIndex;
|
||||
int m_iAngleIndex;
|
||||
int m_iDetectorIndex;
|
||||
};
|
||||
|
||||
/**
|
||||
* Struct combining some properties of a detector in 2D detector array
|
||||
**/
|
||||
struct SDetector3D
|
||||
{
|
||||
int m_iIndex;
|
||||
int m_iAngleIndex;
|
||||
int m_iDetectorIndex;
|
||||
int m_iSliceIndex;
|
||||
};
|
||||
}
|
||||
//----------------------------------------------------------------------------------------
|
||||
// some toys
|
||||
|
||||
// safe reinterpret cast
|
||||
// template <class To, class From>
|
||||
// To safe_reinterpret_cast(From from)
|
||||
// {
|
||||
// BOOST_STATIC_ASSERT(sizeof(From) <= sizeof(To));
|
||||
// return reinterpret_cast<To>(from);
|
||||
// }
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
// functions for testing
|
||||
template<typename T>
|
||||
inline void writeArray(T*** arr, int dim1, int dim2, int dim3, const std::string& filename)
|
||||
{
|
||||
std::ofstream out(filename.c_str());
|
||||
int i1, i2, i3;
|
||||
for (i1 = 0; i1 < dim1; ++i1) {
|
||||
for (i2 = 0; i2 < dim2; ++i2) {
|
||||
for (i3 = 0; i3 < dim3; ++i3) {
|
||||
out << arr[i1][i2][i3] << " ";
|
||||
}
|
||||
out << std::endl;
|
||||
}
|
||||
out << std::endl;
|
||||
}
|
||||
out.close();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void writeArray(T** arr, int dim1, int dim2, const std::string& filename)
|
||||
{
|
||||
std::ofstream out(filename.c_str());
|
||||
for (int i1 = 0; i1 < dim1; i1++) {
|
||||
for (int i2 = 0; i2 < dim2; i2++) {
|
||||
out << arr[i1][i2] << " ";
|
||||
}
|
||||
out << std::endl;
|
||||
}
|
||||
out.close();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void writeArray(T* arr, int dim1, const std::string& filename)
|
||||
{
|
||||
std::ofstream out(filename.c_str());
|
||||
for (int i1 = 0; i1 < dim1; i1++) {
|
||||
out << arr[i1] << " ";
|
||||
}
|
||||
out.close();
|
||||
}
|
||||
namespace astra {
|
||||
_AstraExport inline int getVersion() { return ASTRA_TOOLBOXVERSION; }
|
||||
_AstraExport inline const char* getVersionString() { return ASTRA_TOOLBOXVERSION_STRING; }
|
||||
#ifdef ASTRA_CUDA
|
||||
_AstraExport inline bool cudaEnabled() { return true; }
|
||||
#else
|
||||
_AstraExport inline bool cudaEnabled() { return false; }
|
||||
#endif
|
||||
}
|
||||
//----------------------------------------------------------------------------------------
|
||||
// portability between MSVC and Linux/gcc
|
||||
|
||||
#ifndef _MSC_VER
|
||||
// #include "swrap.h"
|
||||
#define EXPIMP_TEMPLATE
|
||||
|
||||
#if !defined(FORCEINLINE) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
|
||||
#define FORCEINLINE inline __attribute__((__always_inline__))
|
||||
#else
|
||||
#define FORCEINLINE inline
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#define FORCEINLINE __forceinline
|
||||
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
// use pthreads on Linux and OSX
|
||||
#if defined(__linux__) || defined(__MACH__)
|
||||
#define USE_PTHREADS
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
-----------------------------------------------------------------------
|
||||
Copyright: 2010-2015, iMinds-Vision Lab, University of Antwerp
|
||||
2014-2015, CWI, Amsterdam
|
||||
|
||||
Contact: astra@uantwerpen.be
|
||||
Website: http://sf.net/projects/astra-toolbox
|
||||
|
||||
This file is part of the ASTRA Toolbox.
|
||||
|
||||
|
||||
The ASTRA Toolbox 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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
The ASTRA Toolbox 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
$Id$
|
||||
*/
|
||||
|
||||
#define CLOG_MAIN
|
||||
#include "clog.h"
|
||||
|
||||
#include "Logging.h"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
using namespace astra;
|
||||
|
||||
void CLogger::enableScreen()
|
||||
{
|
||||
m_bEnabledScreen = true;
|
||||
}
|
||||
|
||||
void CLogger::enableFile()
|
||||
{
|
||||
m_bEnabledFile = true;
|
||||
}
|
||||
|
||||
void CLogger::enable()
|
||||
{
|
||||
enableScreen();
|
||||
enableFile();
|
||||
}
|
||||
|
||||
void CLogger::disableScreen()
|
||||
{
|
||||
m_bEnabledScreen = false;
|
||||
}
|
||||
|
||||
void CLogger::disableFile()
|
||||
{
|
||||
m_bEnabledFile = false;
|
||||
}
|
||||
|
||||
void CLogger::disable()
|
||||
{
|
||||
disableScreen();
|
||||
disableFile();
|
||||
}
|
||||
|
||||
void CLogger::debug(const char *sfile, int sline, const char *fmt, ...)
|
||||
{
|
||||
_assureIsInitialized();
|
||||
va_list ap, apf;
|
||||
if(m_bEnabledScreen){
|
||||
va_start(ap, fmt);
|
||||
clog_debug(sfile,sline,0,fmt,ap);
|
||||
va_end(ap);
|
||||
}
|
||||
if(m_bEnabledFile && m_bFileProvided){
|
||||
va_start(apf, fmt);
|
||||
clog_debug(sfile,sline,1,fmt,apf);
|
||||
va_end(apf);
|
||||
}
|
||||
}
|
||||
|
||||
void CLogger::info(const char *sfile, int sline, const char *fmt, ...)
|
||||
{
|
||||
_assureIsInitialized();
|
||||
va_list ap, apf;
|
||||
if(m_bEnabledScreen){
|
||||
va_start(ap, fmt);
|
||||
clog_info(sfile,sline,0,fmt,ap);
|
||||
va_end(ap);
|
||||
}
|
||||
if(m_bEnabledFile && m_bFileProvided){
|
||||
va_start(apf, fmt);
|
||||
clog_info(sfile,sline,1,fmt,apf);
|
||||
va_end(apf);
|
||||
}
|
||||
}
|
||||
|
||||
void CLogger::warn(const char *sfile, int sline, const char *fmt, ...)
|
||||
{
|
||||
_assureIsInitialized();
|
||||
va_list ap, apf;
|
||||
if(m_bEnabledScreen){
|
||||
va_start(ap, fmt);
|
||||
clog_warn(sfile,sline,0,fmt,ap);
|
||||
va_end(ap);
|
||||
}
|
||||
if(m_bEnabledFile && m_bFileProvided){
|
||||
va_start(apf, fmt);
|
||||
clog_warn(sfile,sline,1,fmt,apf);
|
||||
va_end(apf);
|
||||
}
|
||||
}
|
||||
|
||||
void CLogger::error(const char *sfile, int sline, const char *fmt, ...)
|
||||
{
|
||||
_assureIsInitialized();
|
||||
va_list ap, apf;
|
||||
if(m_bEnabledScreen){
|
||||
va_start(ap, fmt);
|
||||
clog_error(sfile,sline,0,fmt,ap);
|
||||
va_end(ap);
|
||||
}
|
||||
if(m_bEnabledFile && m_bFileProvided){
|
||||
va_start(apf, fmt);
|
||||
clog_error(sfile,sline,1,fmt,apf);
|
||||
va_end(apf);
|
||||
}
|
||||
}
|
||||
|
||||
void CLogger::_setLevel(int id, log_level m_eLevel)
|
||||
{
|
||||
switch(m_eLevel){
|
||||
case LOG_DEBUG:
|
||||
clog_set_level(id,CLOG_DEBUG);
|
||||
break;
|
||||
case LOG_INFO:
|
||||
clog_set_level(id,CLOG_INFO);
|
||||
break;
|
||||
case LOG_WARN:
|
||||
clog_set_level(id,CLOG_WARN);
|
||||
break;
|
||||
case LOG_ERROR:
|
||||
clog_set_level(id,CLOG_ERROR);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CLogger::setOutputScreen(int fd, log_level m_eLevel)
|
||||
{
|
||||
_assureIsInitialized();
|
||||
if(fd==1||fd==2){
|
||||
clog_set_fd(0, fd);
|
||||
}else{
|
||||
error(__FILE__,__LINE__,"Invalid file descriptor");
|
||||
}
|
||||
_setLevel(0,m_eLevel);
|
||||
}
|
||||
|
||||
void CLogger::setOutputFile(const char *filename, log_level m_eLevel)
|
||||
{
|
||||
if(m_bFileProvided){
|
||||
clog_free(1);
|
||||
m_bFileProvided=false;
|
||||
}
|
||||
if(!clog_init_path(1,filename)){
|
||||
m_bFileProvided=true;
|
||||
_setLevel(1,m_eLevel);
|
||||
}
|
||||
}
|
||||
|
||||
void CLogger::_assureIsInitialized()
|
||||
{
|
||||
if(!m_bInitialized)
|
||||
{
|
||||
clog_init_fd(0, 2);
|
||||
clog_set_level(0, CLOG_INFO);
|
||||
clog_set_fmt(0, "%l: %m\n");
|
||||
m_bInitialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
void CLogger::setFormatFile(const char *fmt)
|
||||
{
|
||||
if(m_bFileProvided){
|
||||
clog_set_fmt(1,fmt);
|
||||
}else{
|
||||
error(__FILE__,__LINE__,"No log file specified");
|
||||
}
|
||||
}
|
||||
void CLogger::setFormatScreen(const char *fmt)
|
||||
{
|
||||
clog_set_fmt(0,fmt);
|
||||
}
|
||||
|
||||
CLogger::CLogger()
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
bool CLogger::setCallbackScreen(void (*cb)(const char *msg, size_t len)){
|
||||
_assureIsInitialized();
|
||||
return clog_set_cb(0,cb)==0;
|
||||
}
|
||||
|
||||
bool CLogger::m_bEnabledScreen = true;
|
||||
bool CLogger::m_bEnabledFile = true;
|
||||
bool CLogger::m_bFileProvided = false;
|
||||
bool CLogger::m_bInitialized = false;
|
||||
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
-----------------------------------------------------------------------
|
||||
Copyright: 2010-2015, iMinds-Vision Lab, University of Antwerp
|
||||
2014-2015, CWI, Amsterdam
|
||||
|
||||
Contact: astra@uantwerpen.be
|
||||
Website: http://sf.net/projects/astra-toolbox
|
||||
|
||||
This file is part of the ASTRA Toolbox.
|
||||
|
||||
|
||||
The ASTRA Toolbox 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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
The ASTRA Toolbox 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.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
$Id$
|
||||
*/
|
||||
|
||||
#ifndef _INC_ASTRA_LOGGING
|
||||
#define _INC_ASTRA_LOGGING
|
||||
|
||||
#include "Globals.h"
|
||||
|
||||
//#define ASTRA_DEBUG(...) astra::CLogger::debug(__FILE__,__LINE__, __VA_ARGS__)
|
||||
//#define ASTRA_INFO(...) astra::CLogger::info(__FILE__,__LINE__, __VA_ARGS__)
|
||||
//#define ASTRA_WARN(...) astra::CLogger::warn(__FILE__,__LINE__, __VA_ARGS__)
|
||||
//#define ASTRA_ERROR(...) astra::CLogger::error(__FILE__,__LINE__, __VA_ARGS__)
|
||||
|
||||
// FIXME !!!!!!
|
||||
#define ASTRA_DEBUG(...)
|
||||
#define ASTRA_INFO(...)
|
||||
#define ASTRA_WARN(...)
|
||||
#define ASTRA_ERROR(...)
|
||||
|
||||
namespace astra
|
||||
{
|
||||
|
||||
enum log_level {
|
||||
LOG_DEBUG,
|
||||
LOG_INFO,
|
||||
LOG_WARN,
|
||||
LOG_ERROR
|
||||
};
|
||||
|
||||
class _AstraExport CLogger
|
||||
{
|
||||
CLogger();
|
||||
~CLogger();
|
||||
static bool m_bEnabledFile;
|
||||
static bool m_bEnabledScreen;
|
||||
static bool m_bFileProvided;
|
||||
static bool m_bInitialized;
|
||||
static void _assureIsInitialized();
|
||||
static void _setLevel(int id, log_level m_eLevel);
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Writes a line to the log file (newline is added). Ignored if logging is turned off.
|
||||
*
|
||||
* @param sfile
|
||||
* The name of the source file making this log call (e.g. __FILE__).
|
||||
*
|
||||
* @param sline
|
||||
* The line number of the call in the source code (e.g. __LINE__).
|
||||
*
|
||||
* @param id
|
||||
* The id of the logger to write to.
|
||||
*
|
||||
* @param fmt
|
||||
* The format string for the message (printf formatting).
|
||||
*
|
||||
* @param ...
|
||||
* Any additional format arguments.
|
||||
*/
|
||||
static void debug(const char *sfile, int sline, const char *fmt, ...);
|
||||
static void info(const char *sfile, int sline, const char *fmt, ...);
|
||||
static void warn(const char *sfile, int sline, const char *fmt, ...);
|
||||
static void error(const char *sfile, int sline, const char *fmt, ...);
|
||||
|
||||
/**
|
||||
* Sets the file to log to, with logging level.
|
||||
*
|
||||
* @param filename
|
||||
* File to log to.
|
||||
*
|
||||
* @param m_eLevel
|
||||
* Logging level (LOG_DEBUG, LOG_WARN, LOG_INFO, LOG_ERROR).
|
||||
*
|
||||
*/
|
||||
static void setOutputFile(const char *filename, log_level m_eLevel);
|
||||
|
||||
/**
|
||||
* Sets the screen to log to, with logging level.
|
||||
*
|
||||
* @param screen_fd
|
||||
* Screen file descriptor (1 for stdout, 2 for stderr)
|
||||
*
|
||||
* @param m_eLevel
|
||||
* Logging level (LOG_DEBUG, LOG_WARN, LOG_INFO, LOG_ERROR).
|
||||
*
|
||||
*/
|
||||
static void setOutputScreen(int fd, log_level m_eLevel);
|
||||
|
||||
/**
|
||||
* Set the format string for log messages. Here are the substitutions you may
|
||||
* use:
|
||||
*
|
||||
* %f: Source file name generating the log call.
|
||||
* %n: Source line number where the log call was made.
|
||||
* %m: The message text sent to the logger (after printf formatting).
|
||||
* %d: The current date, formatted using the logger's date format.
|
||||
* %t: The current time, formatted using the logger's time format.
|
||||
* %l: The log level (one of "DEBUG", "INFO", "WARN", or "ERROR").
|
||||
* %%: A literal percent sign.
|
||||
*
|
||||
* The default format string is "%d %t %f(%n): %l: %m\n".
|
||||
*
|
||||
* @param fmt
|
||||
* The new format string, which must be less than 256 bytes.
|
||||
* You probably will want to end this with a newline (\n).
|
||||
*
|
||||
*/
|
||||
static void setFormatFile(const char *fmt);
|
||||
static void setFormatScreen(const char *fmt);
|
||||
|
||||
|
||||
/**
|
||||
* Enable logging.
|
||||
*
|
||||
*/
|
||||
static void enable();
|
||||
static void enableScreen();
|
||||
static void enableFile();
|
||||
|
||||
/**
|
||||
* Disable logging.
|
||||
*
|
||||
*/
|
||||
static void disable();
|
||||
static void disableScreen();
|
||||
static void disableFile();
|
||||
|
||||
/**
|
||||
* Set callback function for logging to screen.
|
||||
* @return whether callback was set succesfully.
|
||||
*
|
||||
*/
|
||||
static bool setCallbackScreen(void (*cb)(const char *msg, size_t len));
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* _INC_ASTRA_LOGGING */
|
||||
@@ -0,0 +1,693 @@
|
||||
/* clog: Extremely simple logger for C.
|
||||
*
|
||||
* Features:
|
||||
* - Implemented purely as a single header file.
|
||||
* - Create multiple loggers.
|
||||
* - Four log levels (debug, info, warn, error).
|
||||
* - Custom formats.
|
||||
* - Fast.
|
||||
*
|
||||
* Dependencies:
|
||||
* - Should conform to C89, C++98 (but requires vsnprintf, unfortunately).
|
||||
* - POSIX environment.
|
||||
*
|
||||
* USAGE:
|
||||
*
|
||||
* Include this header in any file that wishes to write to logger(s). In
|
||||
* exactly one file (per executable), define CLOG_MAIN first (e.g. in your
|
||||
* main .c file).
|
||||
*
|
||||
* #define CLOG_MAIN
|
||||
* #include "clog.h"
|
||||
*
|
||||
* This will define the actual objects that all the other units will use.
|
||||
*
|
||||
* Loggers are identified by integers (0 - 15). It's expected that you'll
|
||||
* create meaningful constants and then refer to the loggers as such.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* const int MY_LOGGER = 0;
|
||||
*
|
||||
* int main() {
|
||||
* int r;
|
||||
* r = clog_init_path(MY_LOGGER, "my_log.txt");
|
||||
* if (r != 0) {
|
||||
* fprintf(stderr, "Logger initialization failed.\n");
|
||||
* return 1;
|
||||
* }
|
||||
* clog_info(CLOG(MY_LOGGER), "Hello, world!");
|
||||
* clog_free(MY_LOGGER);
|
||||
* return 0;
|
||||
* }
|
||||
*
|
||||
* The CLOG macro used in the call to clog_info is a helper that passes the
|
||||
* __FILE__ and __LINE__ parameters for you, so you don't have to type them
|
||||
* every time. (It could be prettier with variadic macros, but that requires
|
||||
* C99 or C++11 to be standards compliant.)
|
||||
*
|
||||
* Errors encountered by clog will be printed to stderr. You can suppress
|
||||
* these by defining a macro called CLOG_SILENT before including clog.h.
|
||||
*
|
||||
* License: Do whatever you want. It would be nice if you contribute
|
||||
* improvements as pull requests here:
|
||||
*
|
||||
* https://github.com/mmueller/clog
|
||||
*
|
||||
* Copyright 2013 Mike Mueller <mike@subfocal.net>.
|
||||
*
|
||||
* As is; no warranty is provided; use at your own risk.
|
||||
*/
|
||||
|
||||
#ifndef __CLOG_H__
|
||||
#define __CLOG_H__
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#ifndef _MSC_VER
|
||||
#include <unistd.h>
|
||||
#else
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <io.h>
|
||||
#define open _open
|
||||
#define close _close
|
||||
#define write _write
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
/* Number of loggers that can be defined. */
|
||||
#define CLOG_MAX_LOGGERS 16
|
||||
|
||||
/* Format strings cannot be longer than this. */
|
||||
#define CLOG_FORMAT_LENGTH 256
|
||||
|
||||
/* Formatted times and dates should be less than this length. If they are not,
|
||||
* they will not appear in the log. */
|
||||
#define CLOG_DATETIME_LENGTH 256
|
||||
|
||||
/* Default format strings. */
|
||||
#define CLOG_DEFAULT_FORMAT "%d %t %f(%n): %l: %m\n"
|
||||
#define CLOG_DEFAULT_DATE_FORMAT "%Y-%m-%d"
|
||||
#define CLOG_DEFAULT_TIME_FORMAT "%H:%M:%S"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum clog_level {
|
||||
CLOG_DEBUG,
|
||||
CLOG_INFO,
|
||||
CLOG_WARN,
|
||||
CLOG_ERROR
|
||||
};
|
||||
|
||||
struct clog;
|
||||
|
||||
/**
|
||||
* Create a new logger writing to the given file path. The file will always
|
||||
* be opened in append mode.
|
||||
*
|
||||
* @param id
|
||||
* A constant integer between 0 and 15 that uniquely identifies this logger.
|
||||
*
|
||||
* @param path
|
||||
* Path to the file where log messages will be written.
|
||||
*
|
||||
* @return
|
||||
* Zero on success, non-zero on failure.
|
||||
*/
|
||||
int clog_init_path(int id, const char *const path);
|
||||
|
||||
/**
|
||||
* Create a new logger writing to a file descriptor.
|
||||
*
|
||||
* @param id
|
||||
* A constant integer between 0 and 15 that uniquely identifies this logger.
|
||||
*
|
||||
* @param fd
|
||||
* The file descriptor where log messages will be written.
|
||||
*
|
||||
* @return
|
||||
* Zero on success, non-zero on failure.
|
||||
*/
|
||||
int clog_init_fd(int id, int fd);
|
||||
|
||||
/**
|
||||
* Destroy (clean up) a logger. You should do this at the end of execution,
|
||||
* or when you are done using the logger.
|
||||
*
|
||||
* @param id
|
||||
* The id of the logger to destroy.
|
||||
*/
|
||||
void clog_free(int id);
|
||||
|
||||
#define CLOG(id) __FILE__, __LINE__, id
|
||||
|
||||
/**
|
||||
* Log functions (one per level). Call these to write messages to the log
|
||||
* file. The first three arguments can be replaced with a call to the CLOG
|
||||
* macro defined above, e.g.:
|
||||
*
|
||||
* clog_debug(CLOG(MY_LOGGER_ID), "This is a log message.");
|
||||
*
|
||||
* @param sfile
|
||||
* The name of the source file making this log call (e.g. __FILE__).
|
||||
*
|
||||
* @param sline
|
||||
* The line number of the call in the source code (e.g. __LINE__).
|
||||
*
|
||||
* @param id
|
||||
* The id of the logger to write to.
|
||||
*
|
||||
* @param fmt
|
||||
* The format string for the message (printf formatting).
|
||||
*
|
||||
* @param ...
|
||||
* Any additional format arguments.
|
||||
*/
|
||||
void clog_debug(const char *sfile, int sline, int id, const char *fmt, va_list ap);
|
||||
void clog_info(const char *sfile, int sline, int id, const char *fmt, va_list ap);
|
||||
void clog_warn(const char *sfile, int sline, int id, const char *fmt, va_list ap);
|
||||
void clog_error(const char *sfile, int sline, int id, const char *fmt, va_list ap);
|
||||
|
||||
/**
|
||||
* Set the minimum level of messages that should be written to the log.
|
||||
* Messages below this level will not be written. By default, loggers are
|
||||
* created with level == CLOG_DEBUG.
|
||||
*
|
||||
* @param id
|
||||
* The identifier of the logger.
|
||||
*
|
||||
* @param level
|
||||
* The new minimum log level.
|
||||
*
|
||||
* @return
|
||||
* Zero on success, non-zero on failure.
|
||||
*/
|
||||
int clog_set_level(int id, enum clog_level level);
|
||||
|
||||
/**
|
||||
* Set the format string used for times. See strftime(3) for how this string
|
||||
* should be defined. The default format string is CLOG_DEFAULT_TIME_FORMAT.
|
||||
*
|
||||
* @param fmt
|
||||
* The new format string, which must be less than CLOG_FORMAT_LENGTH bytes.
|
||||
*
|
||||
* @return
|
||||
* Zero on success, non-zero on failure.
|
||||
*/
|
||||
int clog_set_time_fmt(int id, const char *fmt);
|
||||
|
||||
/**
|
||||
* Set the format string used for dates. See strftime(3) for how this string
|
||||
* should be defined. The default format string is CLOG_DEFAULT_DATE_FORMAT.
|
||||
*
|
||||
* @param fmt
|
||||
* The new format string, which must be less than CLOG_FORMAT_LENGTH bytes.
|
||||
*
|
||||
* @return
|
||||
* Zero on success, non-zero on failure.
|
||||
*/
|
||||
int clog_set_date_fmt(int id, const char *fmt);
|
||||
|
||||
/**
|
||||
* Set the format string for log messages. Here are the substitutions you may
|
||||
* use:
|
||||
*
|
||||
* %f: Source file name generating the log call.
|
||||
* %n: Source line number where the log call was made.
|
||||
* %m: The message text sent to the logger (after printf formatting).
|
||||
* %d: The current date, formatted using the logger's date format.
|
||||
* %t: The current time, formatted using the logger's time format.
|
||||
* %l: The log level (one of "DEBUG", "INFO", "WARN", or "ERROR").
|
||||
* %%: A literal percent sign.
|
||||
*
|
||||
* The default format string is CLOG_DEFAULT_FORMAT.
|
||||
*
|
||||
* @param fmt
|
||||
* The new format string, which must be less than CLOG_FORMAT_LENGTH bytes.
|
||||
* You probably will want to end this with a newline (\n).
|
||||
*
|
||||
* @return
|
||||
* Zero on success, non-zero on failure.
|
||||
*/
|
||||
int clog_set_fmt(int id, const char *fmt);
|
||||
|
||||
/**
|
||||
* Set the callback function.
|
||||
*
|
||||
* @param cb
|
||||
* The new callback function.
|
||||
*
|
||||
* @return
|
||||
* Zero on success, non-zero on failure.
|
||||
*/
|
||||
int clog_set_cb(int id, void (*cb)(const char *msg, size_t len));
|
||||
|
||||
/**
|
||||
* Set the file descriptor.
|
||||
*
|
||||
* @param id
|
||||
* The identifier of the logger.
|
||||
*
|
||||
* @param fd
|
||||
* The new file descriptor.
|
||||
*
|
||||
* @return
|
||||
* Zero on success, non-zero on failure.
|
||||
*/
|
||||
int clog_set_fd(int id, int fd);
|
||||
|
||||
|
||||
/*
|
||||
* No need to read below this point.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The C logger structure.
|
||||
*/
|
||||
struct clog {
|
||||
|
||||
/* The current level of this logger. Messages below it will be dropped. */
|
||||
enum clog_level level;
|
||||
|
||||
/* The file being written. */
|
||||
int fd;
|
||||
|
||||
/* The format specifier. */
|
||||
char fmt[CLOG_FORMAT_LENGTH];
|
||||
|
||||
/* Date format */
|
||||
char date_fmt[CLOG_FORMAT_LENGTH];
|
||||
|
||||
/* Time format */
|
||||
char time_fmt[CLOG_FORMAT_LENGTH];
|
||||
|
||||
/* Tracks whether the fd needs to be closed eventually. */
|
||||
int opened;
|
||||
|
||||
/* Callback function for each log message. */
|
||||
void (*cb)(const char *msg, size_t len);
|
||||
};
|
||||
|
||||
void _clog_err(const char *fmt, ...);
|
||||
|
||||
#ifdef CLOG_MAIN
|
||||
struct clog *_clog_loggers[CLOG_MAX_LOGGERS] = { 0 };
|
||||
#else
|
||||
extern struct clog *_clog_loggers[CLOG_MAX_LOGGERS];
|
||||
#endif
|
||||
|
||||
#ifdef CLOG_MAIN
|
||||
|
||||
const char *const CLOG_LEVEL_NAMES[] = {
|
||||
"Debug",
|
||||
"Info",
|
||||
"Warning",
|
||||
"Error",
|
||||
};
|
||||
|
||||
int
|
||||
clog_init_path(int id, const char *const path)
|
||||
{
|
||||
int fd = open(path, O_CREAT | O_WRONLY | O_APPEND, 0666);
|
||||
if (fd == -1) {
|
||||
_clog_err("Unable to open %s: %s\n", path, strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
if (clog_init_fd(id, fd)) {
|
||||
close(fd);
|
||||
return 1;
|
||||
}
|
||||
_clog_loggers[id]->opened = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
clog_init_fd(int id, int fd)
|
||||
{
|
||||
struct clog *logger;
|
||||
|
||||
if (_clog_loggers[id] != NULL) {
|
||||
_clog_err("Logger %d already initialized.\n", id);
|
||||
return 1;
|
||||
}
|
||||
|
||||
logger = (struct clog *) malloc(sizeof(struct clog));
|
||||
if (logger == NULL) {
|
||||
_clog_err("Failed to allocate logger: %s\n", strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
logger->level = CLOG_DEBUG;
|
||||
logger->fd = fd;
|
||||
logger->opened = 0;
|
||||
strcpy(logger->fmt, CLOG_DEFAULT_FORMAT);
|
||||
strcpy(logger->date_fmt, CLOG_DEFAULT_DATE_FORMAT);
|
||||
strcpy(logger->time_fmt, CLOG_DEFAULT_TIME_FORMAT);
|
||||
logger->cb = NULL;
|
||||
|
||||
_clog_loggers[id] = logger;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
clog_free(int id)
|
||||
{
|
||||
if (_clog_loggers[id]) {
|
||||
if (_clog_loggers[id]->opened) {
|
||||
close(_clog_loggers[id]->fd);
|
||||
}
|
||||
free(_clog_loggers[id]);
|
||||
_clog_loggers[id]=NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
clog_set_level(int id, enum clog_level level)
|
||||
{
|
||||
if (_clog_loggers[id] == NULL) {
|
||||
return 1;
|
||||
}
|
||||
if ((unsigned) level > CLOG_ERROR) {
|
||||
return 1;
|
||||
}
|
||||
_clog_loggers[id]->level = level;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
clog_set_fd(int id, int fd)
|
||||
{
|
||||
if (_clog_loggers[id] == NULL) {
|
||||
return 1;
|
||||
}
|
||||
_clog_loggers[id]->fd = fd;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
clog_set_time_fmt(int id, const char *fmt)
|
||||
{
|
||||
struct clog *logger = _clog_loggers[id];
|
||||
if (logger == NULL) {
|
||||
_clog_err("clog_set_time_fmt: No such logger: %d\n", id);
|
||||
return 1;
|
||||
}
|
||||
if (strlen(fmt) >= CLOG_FORMAT_LENGTH) {
|
||||
_clog_err("clog_set_time_fmt: Format specifier too long.\n");
|
||||
return 1;
|
||||
}
|
||||
strcpy(logger->time_fmt, fmt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
clog_set_date_fmt(int id, const char *fmt)
|
||||
{
|
||||
struct clog *logger = _clog_loggers[id];
|
||||
if (logger == NULL) {
|
||||
_clog_err("clog_set_date_fmt: No such logger: %d\n", id);
|
||||
return 1;
|
||||
}
|
||||
if (strlen(fmt) >= CLOG_FORMAT_LENGTH) {
|
||||
_clog_err("clog_set_date_fmt: Format specifier too long.\n");
|
||||
return 1;
|
||||
}
|
||||
strcpy(logger->date_fmt, fmt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
clog_set_fmt(int id, const char *fmt)
|
||||
{
|
||||
struct clog *logger = _clog_loggers[id];
|
||||
if (logger == NULL) {
|
||||
_clog_err("clog_set_fmt: No such logger: %d\n", id);
|
||||
return 1;
|
||||
}
|
||||
if (strlen(fmt) >= CLOG_FORMAT_LENGTH) {
|
||||
_clog_err("clog_set_fmt: Format specifier too long.\n");
|
||||
return 1;
|
||||
}
|
||||
strcpy(logger->fmt, fmt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
clog_set_cb(int id, void (*cb)(const char *msg, size_t len))
|
||||
{
|
||||
struct clog *logger = _clog_loggers[id];
|
||||
if (logger == NULL) {
|
||||
_clog_err("clog_set_cb: No such logger: %d\n", id);
|
||||
return 1;
|
||||
}
|
||||
logger->cb = cb;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Internal functions */
|
||||
|
||||
size_t
|
||||
_clog_append_str(char **dst, char *orig_buf, const char *src, size_t cur_size)
|
||||
{
|
||||
size_t new_size = cur_size;
|
||||
|
||||
while (strlen(*dst) + strlen(src) >= new_size) {
|
||||
new_size *= 2;
|
||||
}
|
||||
if (new_size != cur_size) {
|
||||
if (*dst == orig_buf) {
|
||||
*dst = (char *) malloc(new_size);
|
||||
strcpy(*dst, orig_buf);
|
||||
} else {
|
||||
*dst = (char *) realloc(*dst, new_size);
|
||||
}
|
||||
}
|
||||
|
||||
strcat(*dst, src);
|
||||
return new_size;
|
||||
}
|
||||
|
||||
size_t
|
||||
_clog_append_int(char **dst, char *orig_buf, long int d, size_t cur_size)
|
||||
{
|
||||
char buf[40]; /* Enough for 128-bit decimal */
|
||||
if (snprintf(buf, 40, "%ld", d) >= 40) {
|
||||
return cur_size;
|
||||
}
|
||||
return _clog_append_str(dst, orig_buf, buf, cur_size);
|
||||
}
|
||||
|
||||
size_t
|
||||
_clog_append_time(char **dst, char *orig_buf, struct tm *lt,
|
||||
const char *fmt, size_t cur_size)
|
||||
{
|
||||
char buf[CLOG_DATETIME_LENGTH];
|
||||
size_t result = strftime(buf, CLOG_DATETIME_LENGTH, fmt, lt);
|
||||
|
||||
if (result > 0) {
|
||||
return _clog_append_str(dst, orig_buf, buf, cur_size);
|
||||
}
|
||||
|
||||
return cur_size;
|
||||
}
|
||||
|
||||
const char *
|
||||
_clog_basename(const char *path)
|
||||
{
|
||||
const char *slash = strrchr(path, '/');
|
||||
if (slash) {
|
||||
path = slash + 1;
|
||||
}
|
||||
#ifdef _WIN32
|
||||
slash = strrchr(path, '\\');
|
||||
if (slash) {
|
||||
path = slash + 1;
|
||||
}
|
||||
#endif
|
||||
return path;
|
||||
}
|
||||
|
||||
char *
|
||||
_clog_format(const struct clog *logger, char buf[], size_t buf_size,
|
||||
const char *sfile, int sline, const char *level,
|
||||
const char *message)
|
||||
{
|
||||
size_t cur_size = buf_size;
|
||||
char *result = buf;
|
||||
enum { NORMAL, SUBST } state = NORMAL;
|
||||
size_t fmtlen = strlen(logger->fmt);
|
||||
size_t i;
|
||||
time_t t = time(NULL);
|
||||
struct tm *lt = localtime(&t);
|
||||
|
||||
sfile = _clog_basename(sfile);
|
||||
result[0] = 0;
|
||||
for (i = 0; i < fmtlen; ++i) {
|
||||
if (state == NORMAL) {
|
||||
if (logger->fmt[i] == '%') {
|
||||
state = SUBST;
|
||||
} else {
|
||||
char str[2] = { 0 };
|
||||
str[0] = logger->fmt[i];
|
||||
cur_size = _clog_append_str(&result, buf, str, cur_size);
|
||||
}
|
||||
} else {
|
||||
switch (logger->fmt[i]) {
|
||||
case '%':
|
||||
cur_size = _clog_append_str(&result, buf, "%", cur_size);
|
||||
break;
|
||||
case 't':
|
||||
cur_size = _clog_append_time(&result, buf, lt,
|
||||
logger->time_fmt, cur_size);
|
||||
break;
|
||||
case 'd':
|
||||
cur_size = _clog_append_time(&result, buf, lt,
|
||||
logger->date_fmt, cur_size);
|
||||
break;
|
||||
case 'l':
|
||||
cur_size = _clog_append_str(&result, buf, level, cur_size);
|
||||
break;
|
||||
case 'n':
|
||||
cur_size = _clog_append_int(&result, buf, sline, cur_size);
|
||||
break;
|
||||
case 'f':
|
||||
cur_size = _clog_append_str(&result, buf, sfile, cur_size);
|
||||
break;
|
||||
case 'm':
|
||||
cur_size = _clog_append_str(&result, buf, message,
|
||||
cur_size);
|
||||
break;
|
||||
}
|
||||
state = NORMAL;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
_clog_log(const char *sfile, int sline, enum clog_level level,
|
||||
int id, const char *fmt, va_list ap)
|
||||
{
|
||||
/* For speed: Use a stack buffer until message exceeds 4096, then switch
|
||||
* to dynamically allocated. This should greatly reduce the number of
|
||||
* memory allocations (and subsequent fragmentation). */
|
||||
char buf[4096];
|
||||
size_t buf_size = 4096;
|
||||
char *dynbuf = buf;
|
||||
char *message;
|
||||
int result;
|
||||
struct clog *logger = _clog_loggers[id];
|
||||
|
||||
if (!logger) {
|
||||
_clog_err("No such logger: %d\n", id);
|
||||
return;
|
||||
}
|
||||
|
||||
if (level < logger->level) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Format the message text with the argument list. */
|
||||
result = vsnprintf(dynbuf, buf_size, fmt, ap);
|
||||
if ((size_t) result >= buf_size) {
|
||||
buf_size = result + 1;
|
||||
dynbuf = (char *) malloc(buf_size);
|
||||
result = vsnprintf(dynbuf, buf_size, fmt, ap);
|
||||
if ((size_t) result >= buf_size) {
|
||||
/* Formatting failed -- too large */
|
||||
_clog_err("Formatting failed (1).\n");
|
||||
free(dynbuf);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Format according to log format and write to log */
|
||||
{
|
||||
char message_buf[4096];
|
||||
message = _clog_format(logger, message_buf, 4096, sfile, sline,
|
||||
CLOG_LEVEL_NAMES[level], dynbuf);
|
||||
if (!message) {
|
||||
_clog_err("Formatting failed (2).\n");
|
||||
if (dynbuf != buf) {
|
||||
free(dynbuf);
|
||||
}
|
||||
return;
|
||||
}
|
||||
result = write(logger->fd, message, strlen(message));
|
||||
if (logger->cb) logger->cb(message,strlen(message));
|
||||
if (result == -1) {
|
||||
_clog_err("Unable to write to log file: %s\n", strerror(errno));
|
||||
}
|
||||
if (message != message_buf) {
|
||||
free(message);
|
||||
}
|
||||
if (dynbuf != buf) {
|
||||
free(dynbuf);
|
||||
}
|
||||
#ifndef _MSC_VER
|
||||
fsync(logger->fd);
|
||||
#else
|
||||
HANDLE h = (HANDLE) _get_osfhandle(logger->fd);
|
||||
if (h != INVALID_HANDLE_VALUE) {
|
||||
// This call will fail on a console fd, but that's ok.
|
||||
FlushFileBuffers(h);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
clog_debug(const char *sfile, int sline, int id, const char *fmt, va_list ap)
|
||||
{
|
||||
_clog_log(sfile, sline, CLOG_DEBUG, id, fmt, ap);
|
||||
}
|
||||
|
||||
void
|
||||
clog_info(const char *sfile, int sline, int id, const char *fmt, va_list ap)
|
||||
{
|
||||
_clog_log(sfile, sline, CLOG_INFO, id, fmt, ap);
|
||||
}
|
||||
|
||||
void
|
||||
clog_warn(const char *sfile, int sline, int id, const char *fmt, va_list ap)
|
||||
{
|
||||
_clog_log(sfile, sline, CLOG_WARN, id, fmt, ap);
|
||||
}
|
||||
|
||||
void
|
||||
clog_error(const char *sfile, int sline, int id, const char *fmt, va_list ap)
|
||||
{
|
||||
_clog_log(sfile, sline, CLOG_ERROR, id, fmt, ap);
|
||||
}
|
||||
|
||||
void
|
||||
_clog_err(const char *fmt, ...)
|
||||
{
|
||||
#ifdef CLOG_SILENT
|
||||
(void) fmt;
|
||||
#else
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* CLOG_MAIN */
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* __CLOG_H__ */
|
||||
Reference in New Issue
Block a user