00001 /*---------------------------------------------------------------------------- 00002 Name: xmlBlaster/src/c/util/helper.c 00003 Project: xmlBlaster.org 00004 Copyright: xmlBlaster.org, see xmlBlaster-LICENSE file 00005 Comment: Contains helper functions for string and message manipulation 00006 Generic helper code, used by Queue implementation and xmlBlaster client code 00007 Don't add any queue specific or xmlBlaster client specific code! 00008 Compile: gcc -Wall -g -o helper helper.c -DHELPER_UTIL_MAIN -I.. 00009 Testsuite: xmlBlaster/testsuite/src/c/TestUtil.c 00010 Author: "Marcel Ruff" <xmlBlaster@marcelruff.info> 00011 -----------------------------------------------------------------------------*/ 00012 00013 #include <stdio.h> 00014 #include <stdlib.h> 00015 #include <stdarg.h> 00016 #include <string.h> 00017 #include <ctype.h> 00018 #include <assert.h> 00019 #include <time.h> 00020 #include "helper.h" 00021 00022 #ifdef _ENABLE_STACK_TRACE_ 00023 # include <execinfo.h> 00024 #endif 00025 00026 #ifdef _WINDOWS 00027 # if defined(WINCE) 00028 /* time between jan 1, 1601 and jan 1, 1970 in units of 100 nanoseconds */ 00029 # if !defined(PTW32_TIMESPEC_TO_FILETIME_OFFSET) 00030 # define PTW32_TIMESPEC_TO_FILETIME_OFFSET \ 00031 ( ((LONGLONG) 27111902 << 32) + (LONGLONG) 3577643008 ) 00032 # endif 00033 # else 00034 # include <sys/timeb.h> 00035 # endif 00036 # include <Winsock2.h> /* Sleep() */ 00037 # if XB_USE_PTHREADS 00038 # include <pthreads/pthread.h> /* Our pthreads.h: For logging output of thread ID, for Windows and WinCE downloaded from http://sources.redhat.com/pthreads-win32 */ 00039 # endif 00040 #else 00041 # include <unistd.h> /* sleep(), only used in main */ 00042 # include <errno.h> /* errno */ 00043 # include <sys/time.h> /* sleep with select(), gettimeofday() */ 00044 # include <sys/types.h> /* sleep with select() */ 00045 # if XB_USE_PTHREADS 00046 # include <pthread.h> /* The original pthreads.h from the OS */ 00047 # endif 00048 #endif 00049 00050 00051 #define MICRO_SECS_PER_SECOND 1000000 00052 #define NANO_SECS_PER_SECOND MICRO_SECS_PER_SECOND * 1000 00053 00054 static const char *LOG_TEXT[] = { "NOLOG", "ERROR", "WARN", "INFO", "CALL", "TIME", "TRACE", "DUMP", "PLAIN" }; 00055 static const int numLOG_TEXT = 9; /* sizeof(LOG_TEXT) returns 36 which is not what we want */ 00056 00057 #define ESC "\033[0m"; /* Reset color to original values */ 00058 #define BOLD "\033[1m" 00059 00060 #define RED_BLACK "\033[31;40m" 00061 #define GREEN_BLACK "\033[32;40m" 00062 #define YELLOW_BLACK "\033[33;40m" 00063 #define BLUE_BLACK "\033[34;40m" 00064 #define PINK_BLACK "\033[35;40m" 00065 #define LTGREEN_BLACK "\033[36;40m" 00066 #define WHITE_BLACK "\033[37;40m" 00067 00068 #define WHITE_RED "\033[37;41m" 00069 #define BLACK_RED "\033[30;41m" 00070 #define BLACK_GREEN "\033[40;42m" 00071 #define BLACK_PINK "\033[40;45m" 00072 #define BLACK_LTGREEN "\033[40;46m" 00073 00074 /* To support colored logging output in xterminals */ 00075 static const char *LOG_TEXT_ESCAPE[] = { 00076 "NOLOG", 00077 "\033[31;40mERROR\033[0m", 00078 "\033[33;40mWARN\033[0m", 00079 "\033[32;40mINFO\033[0m", 00080 "\033[34;40mCALL\033[0m", 00081 "\033[36;40mTIME\033[0m", 00082 "\033[37;40mTRACE\033[0m", 00083 "\033[35;40mDUMP\033[0m", 00084 "\033[37;40mPLAIN\033[0m" 00085 }; 00086 00087 static int vsnprintf0(char *s, size_t size, const char *format, va_list ap); 00088 00094 Dll_Export char *getStackTrace(int maxNumOfLines) 00095 { 00096 #ifdef _ENABLE_STACK_TRACE_ 00097 int i; 00098 void** arr = (void **)calloc(maxNumOfLines, sizeof(void *)); 00099 if (arr == 0) return (char *)0; 00100 { 00101 /* 00102 > +Currently, the function name and offset can only be obtained on systems 00103 > +that use the ELF binary format for programs and libraries. 00104 Perhaps a reference to the addr2line program can be added here. It 00105 can be used to retrieve symbols even if the -rdynamic flag wasn't 00106 passed to the linker, and it should work on non-ELF targets as well. 00107 o Under linux, gcc interprets it by setting the 00108 "-export-dynamic" option for ld, which has that effect, according 00109 to the linux ld manpage. 00110 00111 o Under IRIX it's ignored, and the program's happy as a clam. 00112 00113 o Under SunOS-4.1, gcc interprets it by setting the -dc -dp 00114 options for ld, which again forces the allocation of the symbol 00115 table in the code produced (see ld(1) on a Sun). 00116 */ 00117 int bt = backtrace(arr, maxNumOfLines); 00118 char** list = (char **)backtrace_symbols(arr, bt); /* malloc the return pointer, the entries don't need to be freed */ 00119 char *ret = strcpyAlloc(""); 00120 for (i=0; i<bt; i++) { 00121 if (list[i] != NULL) { 00122 strcatAlloc(&ret, list[i]); 00123 strcatAlloc(&ret, "\n"); 00124 } 00125 } 00126 free(list); 00127 free(arr); 00128 if (strlen(ret) < 1) { 00129 strcatAlloc(&ret, ""); /* Creation of stackTrace failed */ 00130 } 00131 return ret; 00132 } 00133 #else 00134 if (maxNumOfLines > 0) /* to make the compiler happy */ 00135 return strcpyAlloc(""); 00136 return strcpyAlloc(""); /* No stack trace provided in this system */ 00137 #endif 00138 } 00139 00140 #ifndef XMLBLASTER_SLEEP_FALLBACK 00141 # define XMLBLASTER_SLEEP_FALLBACK 0 /* Initialize to make icc happy */ 00142 #endif 00143 #ifndef XMLBLASTER_SLEEP_NANO 00144 # define XMLBLASTER_SLEEP_NANO 0 00145 #endif 00146 00150 Dll_Export void sleepMillis(long millisecs) 00151 { 00152 #ifdef _WINDOWS 00153 Sleep(millisecs); 00154 #elif XMLBLASTER_SLEEP_FALLBACK /* rounded to seconds */ 00155 if (millisecs < 1000) 00156 millisecs = 1000; 00157 sleep(millisecs/1000); 00158 #elif XMLBLASTER_SLEEP_NANO 00159 TODO: 00160 int nanosleep(const struct timespec *rqtp, struct timespec *rmtp); 00161 struct timespec 00162 { 00163 time_t tv_sec; /* seconds */ 00164 long tv_nsec; /* nanoseconds */ 00165 }; 00166 /* 00167 usleep() deprecated 00168 */ 00169 /* 00170 #include <time.h> 00171 void Sleep(clock_t wait) 00172 { 00173 clock_t goal; 00174 goal = wait * (CLOCKS_PER_SEC / 1000); 00175 while( goal >= clock()) 00176 ; 00177 } 00178 */ 00179 #else 00180 fd_set dummy; 00181 struct timeval toWait; 00182 int ret; 00183 00184 FD_ZERO(&dummy); 00185 toWait.tv_sec = millisecs / 1000; 00186 toWait.tv_usec = (millisecs % 1000) * 1000; 00187 00188 ret = select(0, &dummy, NULL, NULL, &toWait); 00189 if (ret == -1) { 00190 printf("[helper.c] ERROR: sleepMillis(%ld) returned errnor %d", millisecs, errno); 00191 } 00192 #endif 00193 } 00194 00199 Dll_Export int64_t getTimestamp() { 00200 struct timespec abstime; 00201 int64_t timestamp; 00202 static int64_t lastNanos=0; 00203 00204 getAbsoluteTime(0L, &abstime); 00205 00206 timestamp = (int64_t)abstime.tv_sec * NANO_SECS_PER_SECOND; 00207 timestamp += abstime.tv_nsec; 00208 if (timestamp <= lastNanos) { 00209 timestamp = lastNanos + 1; 00210 } 00211 lastNanos = timestamp; 00212 return timestamp; 00213 } 00214 00215 00216 #include <wchar.h> 00224 Dll_Export char **convertWcsArgv(wchar_t **argv_wcs, int argc) { 00225 int i; 00226 char **argv = (char **)malloc(argc*sizeof(char*)); 00227 for (i=0; i<argc; i++) { 00228 int sizeInBytes = 4*(int)wcslen(argv_wcs[i]); 00229 argv[i] = (char *)malloc(sizeInBytes*sizeof(char)); 00230 # if _MSC_VER >= 1400 && !defined(WINCE) 00231 { 00232 size_t pReturnValue; 00233 /*errno_t err = */ 00234 wcstombs_s(&pReturnValue, argv[i], sizeInBytes, argv_wcs[i], _TRUNCATE); 00235 } 00236 # else 00237 wcstombs(argv[i], argv_wcs[i], sizeInBytes); 00238 # endif 00239 /*printf("%s ", argv[i]);*/ 00240 } 00241 return argv; 00242 } 00243 00249 Dll_Export void freeArgv(char **argv, int argc) { 00250 int i; 00251 if (argv == 0) return; 00252 for (i=0; i<argc; i++) { 00253 free(argv[i]); 00254 } 00255 free(argv); 00256 } 00257 00266 Dll_Export bool getAbsoluteTime(long relativeTimeFromNow, struct timespec *abstime) 00267 { 00268 # if defined(WINCE) 00269 /* Copied from pthreads_win32: thank you! */ 00270 FILETIME ft; 00271 SYSTEMTIME st; 00272 GetSystemTime(&st); 00273 SystemTimeToFileTime(&st, &ft); 00274 /* 00275 * GetSystemTimeAsFileTime(&ft); would be faster, 00276 * but it does not exist on WinCE 00277 */ 00278 /* 00279 * ------------------------------------------------------------------- 00280 * converts FILETIME (as set by GetSystemTimeAsFileTime), where the time is 00281 * expressed in 100 nanoseconds from Jan 1, 1601, 00282 * into struct timespec 00283 * where the time is expressed in seconds and nanoseconds from Jan 1, 1970. 00284 * ------------------------------------------------------------------- 00285 */ 00286 abstime->tv_sec = 00287 (int) ((*(LONGLONG *) &ft - PTW32_TIMESPEC_TO_FILETIME_OFFSET) / 10000000); 00288 abstime->tv_nsec = 00289 (int) ((*(LONGLONG *) &ft - PTW32_TIMESPEC_TO_FILETIME_OFFSET - 00290 ((LONGLONG) abstime->tv_sec * (LONGLONG) 10000000)) * 100); 00291 00292 if (relativeTimeFromNow > 0) { 00293 abstime->tv_sec += relativeTimeFromNow / 1000; 00294 abstime->tv_nsec += (relativeTimeFromNow % 1000) * 1000 * 1000; 00295 } 00296 if (abstime->tv_nsec >= NANO_SECS_PER_SECOND) { 00297 abstime->tv_nsec -= NANO_SECS_PER_SECOND; 00298 abstime->tv_sec += 1; 00299 } 00300 return true; 00301 00302 # elif defined(_WINDOWS) 00303 struct _timeb tm; 00304 # if _MSC_VER >= 1400 /* _WINDOWS: 1200->VC++6.0, 1310->VC++7.1 (2003), 1400->VC++8.0 (2005) */ 00305 errno_t err = _ftime_s(&tm); 00306 if (err) return false; 00307 # else 00308 (void) _ftime(&tm); 00309 # endif 00310 00311 abstime->tv_sec = (long)tm.time; 00312 abstime->tv_nsec = tm.millitm * 1000 * 1000; /* TODO !!! How to get the more precise current time on Win? */ 00313 00314 if (relativeTimeFromNow > 0) { 00315 abstime->tv_sec += relativeTimeFromNow / 1000; 00316 abstime->tv_nsec += (relativeTimeFromNow % 1000) * 1000 * 1000; 00317 } 00318 if (abstime->tv_nsec >= NANO_SECS_PER_SECOND) { 00319 abstime->tv_nsec -= NANO_SECS_PER_SECOND; 00320 abstime->tv_sec += 1; 00321 } 00322 return true; 00323 # else /* LINUX, __sun */ 00324 struct timeval tv; 00325 00326 memset(abstime, 0, sizeof(struct timespec)); 00327 00328 gettimeofday(&tv, 0); 00329 abstime->tv_sec = tv.tv_sec; 00330 abstime->tv_nsec = tv.tv_usec * 1000; /* microseconds to nanoseconds */ 00331 00332 if (relativeTimeFromNow > 0) { 00333 abstime->tv_sec += relativeTimeFromNow / 1000; 00334 abstime->tv_nsec += (relativeTimeFromNow % 1000) * 1000 * 1000; 00335 } 00336 if (abstime->tv_nsec >= NANO_SECS_PER_SECOND) { 00337 abstime->tv_nsec -= NANO_SECS_PER_SECOND; 00338 abstime->tv_sec += 1; 00339 } 00340 return true; 00341 # endif 00342 # ifdef MORE_REALTIME 00343 clock_gettime(CLOCK_REALTIME, abstime); 00344 00345 if (relativeTimeFromNow > 0) { 00346 abstime->tv_sec += relativeTimeFromNow / 1000; 00347 abstime->tv_nsec += (relativeTimeFromNow % 1000) * 1000 * 1000; 00348 } 00349 if (abstime->tv_nsec >= NANO_SECS_PER_SECOND) { 00350 abstime->tv_nsec -= NANO_SECS_PER_SECOND; 00351 abstime->tv_sec += 1; 00352 } 00353 return true; 00354 # endif 00355 } 00356 00363 Dll_Export char *strcpyAlloc(const char *src) 00364 { 00365 char *dest; 00366 size_t len; 00367 if (src == 0) return (char *)0; 00368 len = strlen(src) + 1; 00369 dest = (char *)malloc(len*sizeof(char)); 00370 if (dest == 0) return 0; 00371 strncpy0(dest, src, len); 00372 return dest; 00373 } 00374 00379 Dll_Export char *strcatAlloc(char **dest, const char *src) 00380 { 00381 size_t len; 00382 assert(dest != 0); 00383 if (src == 0) return (char *)0; 00384 len = strlen(src)+strlen(*dest)+1; 00385 (*dest) = (char *)realloc(*dest, len*sizeof(char)); 00386 if ((*dest) == 0) return 0; 00387 strncat0((*dest), src, len); 00388 return (*dest); 00389 } 00390 00396 Dll_Export char *strcpyRealloc(char **dest, const char *src) 00397 { 00398 if (*dest != 0) 00399 free(*dest); 00400 *dest = strcpyAlloc(src); 00401 return *dest; 00402 } 00403 00410 Dll_Export char *strFromBlobAlloc(const char *blob, const size_t len) 00411 { 00412 char *dest; 00413 size_t i; 00414 if (blob == 0 || len < 1) { 00415 dest = (char *)malloc(1*sizeof(char)); 00416 if (dest == 0) return 0; 00417 *dest = 0; 00418 return dest; 00419 } 00420 00421 dest = (char *)malloc((len+1)*sizeof(char)); 00422 if (dest == 0) return 0; 00423 for (i=0; i<len; i++) { 00424 dest[i] = (char)blob[i]; 00425 } 00426 dest[len] = '\0'; 00427 return dest; 00428 } 00429 00430 00437 Dll_Export void xb_strerror(char *errnoStr, size_t sizeInBytes, int errnum) { 00438 snprintf0(errnoStr, sizeInBytes, "%d", errnum); /* default if string lookup fails */ 00439 # if defined(WINCE) 00440 # elif _MSC_VER >= 1400 00441 strerror_s(errnoStr, sizeInBytes, errnum); 00442 # elif defined(_LINUX) 00443 strerror_r(errnum, errnoStr, sizeInBytes-1); /* glibc > 2. returns a char*, but should return an int */ 00444 # else 00445 { 00446 char *p = strerror(errnum); 00447 strncpy0(errnoStr, p, sizeInBytes); 00448 } 00449 # endif 00450 } 00451 00452 00461 Dll_Export char *strncpy0(char * const to, const char * const from, const size_t maxLen) 00462 { 00463 # if defined(WINCE) 00464 char *ret=strncpy(to, from, maxLen-1); 00465 *(to+maxLen-1) = '\0'; 00466 return ret; 00467 # elif _MSC_VER >= 1400 00468 /* errno_t strncpy_s( 00469 char *strDest, 00470 size_t sizeInBytes, 00471 const char *strSource, 00472 size_t count 00473 ); */ 00474 errno_t ee = strncpy_s(to, maxLen, from, _TRUNCATE); /*maxLen);*/ 00475 return to; 00476 # else /* MAC OSX calls it strlcpy() */ 00477 char *ret=strncpy(to, from, maxLen-1); 00478 *(to+maxLen-1) = '\0'; 00479 return ret; 00480 # endif 00481 } 00482 00483 00491 Dll_Export char *strncat0(char * const to, const char * const from, const size_t max) 00492 { 00493 # if _MSC_VER >= 1400 && !defined(WINCE) 00494 /* buffersize of 'to' in bytes */ 00495 size_t bufferSizeInBytes = strlen(to) + max; 00496 errno_t ee = strncat_s(to, bufferSizeInBytes, from, _TRUNCATE); 00497 return to; 00498 # else /* MAC OSX calls it strlcat() */ 00499 int oldLen = strlen(to); 00500 char *ret=strncat(to, from, max-1); 00501 *(to+oldLen+max-1) = '\0'; 00502 return ret; 00503 # endif 00504 } 00505 00506 int vsnprintf0(char *s, size_t size, const char *format, va_list ap) { 00507 # if _MSC_VER >= 1400 && !defined(WINCE) 00508 errno_t err = vsnprintf_s(s, size, _TRUNCATE, format, ap); 00509 if ( err == STRUNCATE ) { 00510 printf("truncation occurred %s!\n", format); 00511 return 0; 00512 } 00513 return err; 00514 # elif defined(_WINDOWS) 00515 return _vsnprintf(s, size, format, ap); 00516 # else 00517 return vsnprintf(s, size, format, ap); 00518 # endif 00519 } 00520 00524 Dll_Export int snprintf0(char *buffer, size_t sizeOfBuffer, const char *format, ...) { 00525 int ret; 00526 va_list ap; 00527 va_start (ap, format); 00528 ret = vsnprintf0( 00529 buffer, 00530 sizeOfBuffer, 00531 format, 00532 ap); 00533 va_end (ap); 00534 return ret; 00535 } 00536 00540 Dll_Export void trim(char *s) 00541 { 00542 size_t first=0; 00543 size_t len; 00544 int i; 00545 00546 if (s == (char *)0) return; 00547 00548 len = strlen((char *) s); 00549 00550 { /* find beginning of text */ 00551 while (first<len) { 00552 if (!isspace((unsigned char)s[first])) 00553 break; 00554 first++; 00555 } 00556 } 00557 00558 if (first>=len) { 00559 *s = '\0'; 00560 return; 00561 } 00562 else 00563 memmove((char *) s, (char *) s+first, strlen(s+first)+1); /* including '\0' */ 00564 00565 for (i=(int)strlen((char *) s)-1; i >= 0; i--) 00566 if (!isspace((unsigned char)s[i])) { 00567 s[i+1] = '\0'; 00568 return; 00569 } 00570 if (i<0) *s = '\0'; 00571 } 00572 00576 Dll_Export void trimStart(char *s) 00577 { 00578 size_t first=0; 00579 size_t len; 00580 00581 if (s == (char *)0) return; 00582 00583 len = strlen((char *) s); 00584 00585 { /* find beginning of text */ 00586 while (first<len) { 00587 if (!isspace((unsigned char)s[first])) 00588 break; 00589 first++; 00590 } 00591 } 00592 00593 if (first>=len) { 00594 *s = '\0'; 00595 return; 00596 } 00597 else 00598 memmove((char *) s, (char *) s+first, strlen(s+first)+1); /* including '\0' */ 00599 } 00600 00604 Dll_Export void trimEnd(char *s) 00605 { 00606 int i; 00607 for (i=(int)strlen((char *) s)-1; i >= 0; i--) 00608 if (!isspace((unsigned char)s[i])) { 00609 s[i+1] = '\0'; 00610 return; 00611 } 00612 if (i<0) *s = '\0'; 00613 } 00614 00623 Dll_Export char *toReadableDump(char *data, size_t len) 00624 { 00625 char *readable; 00626 size_t i; 00627 if (data == 0) { 00628 return (char *)0; 00629 } 00630 readable = (char *)malloc((len+1) * sizeof(char)); 00631 if (readable == (char *)0) return (char *)0; 00632 for (i=0; i<len; i++) { 00633 if (data[i] == '\0') 00634 readable[i] = '*'; 00635 else 00636 readable[i] = data[i]; 00637 } 00638 readable[len] = '\0'; 00639 return readable; 00640 } 00641 00642 #if defined(XB_USE_PTHREADS) 00643 00648 long get_pthread_id(pthread_t t) 00649 { 00650 # ifdef _WINDOWS 00651 return (long)t.p; /* typedef ptw32_handle_t pthread_t; with struct {void*p; unsigned int x;} */ 00652 # else 00653 return (long)t; 00654 # endif 00655 } 00656 #endif 00657 00663 Dll_Export void getCurrentTimeStr(char *timeStr, int bufSize) { 00664 # if defined(WINCE) 00665 /*http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wcekernl/html/_wcesdk_win32_systemtime_str.asp*/ 00666 SYSTEMTIME st; 00667 GetSystemTime(&st); 00668 snprintf0(timeStr, bufSize, "%hd:%hd:%hd\n", st.wHour, st.wMinute, st.wSecond); 00669 /*wDay, wMilliseconds etc. */ 00670 # elif _MSC_VER >= 1400 00671 /*__time64_t timer; 00672 _time64(&timer);*/ 00673 time_t t1; /* unsigned long */ 00674 (void) time(&t1); /* in seconds since the Epoch. 1970 */ 00675 ctime_s(timeStr, bufSize-1, &t1); 00676 # elif defined(_WINDOWS) 00677 time_t t1; /* unsigned long */ 00678 (void) time(&t1); 00679 strncpy0(timeStr, ctime(&t1), bufSize); 00680 # elif defined(__sun) 00681 time_t t1; /* unsigned long */ 00682 (void) time(&t1); 00683 ctime_r(&t1, (char *)timeStr, bufSize-1); 00684 # else 00685 time_t t1; /* unsigned long */ 00686 (void) time(&t1); 00687 ctime_r(&t1, (char *)timeStr); 00688 # endif 00689 *(timeStr + strlen(timeStr) - 1) = '\0'; /* strip \n */ 00690 } 00691 00710 Dll_Export void xmlBlasterDefaultLogging(void *logUserP, XMLBLASTER_LOG_LEVEL currLevel, 00711 XMLBLASTER_LOG_LEVEL level, 00712 const char *location, const char *fmt, ...) 00713 { 00714 /* Guess, we need no more than 200 bytes. */ 00715 int n, size = 200; 00716 char *p = 0; 00717 va_list ap; 00718 char *stackTrace = 0; 00719 # ifdef _WINDOWS 00720 const char * const * logText = LOG_TEXT; 00721 # else 00722 const char * const * logText = LOG_TEXT_ESCAPE; 00723 # endif 00724 if (logUserP) {} /* To avoid "logUserP was never referenced" compiler warning */ 00725 00726 if (level > currLevel) { 00727 return; 00728 } 00729 if ((p = (char *)malloc (size)) == NULL) 00730 return; 00731 00732 if (level <= XMLBLASTER_LOG_ERROR) { 00733 stackTrace = getStackTrace(10); 00734 } 00735 00736 for (;;) { 00737 /* Try to print in the allocated space. */ 00738 va_start(ap, fmt); 00739 n = vsnprintf0(p, size, fmt, ap); 00740 va_end(ap); 00741 /* If that worked, print the string to console. */ 00742 if (n > -1 && n < size) { 00743 enum { SIZE=128 }; 00744 char timeStr[SIZE]; 00745 getCurrentTimeStr(timeStr, SIZE); 00746 # if XB_USE_PTHREADS 00747 printf("[%s %s %s thread0x%lx] %s %s\n", timeStr, logText[level], location, 00748 get_pthread_id(pthread_self()), p, 00749 (stackTrace != 0) ? stackTrace : ""); 00750 # else 00751 printf("[%s %s %s] %s %s\n", timeStr, logText[level], location, p, 00752 (stackTrace != 0) ? stackTrace : ""); 00753 # endif 00754 free(p); 00755 free(stackTrace); 00756 return; 00757 } 00758 /* Else try again with more space. */ 00759 if (n > -1) /* glibc 2.1 */ 00760 size = n+1; /* precisely what is needed */ 00761 else /* glibc 2.0 */ 00762 size *= 2; /* twice the old size */ 00763 if ((p = (char *)realloc (p, size)) == NULL) { 00764 free(stackTrace); 00765 return; 00766 } 00767 } 00768 } 00769 00776 Dll_Export XMLBLASTER_LOG_LEVEL parseLogLevel(const char *logLevelStr) 00777 { 00778 int i; 00779 int len = numLOG_TEXT; 00780 if (logLevelStr == 0 || *logLevelStr == '\0' ) { 00781 return XMLBLASTER_LOG_WARN; 00782 } 00783 for (i=0; i<len; i++) { 00784 # ifdef _WINDOWS 00785 if (!strcmp(LOG_TEXT[i], logLevelStr)) { 00786 # else 00787 if (!strcasecmp(LOG_TEXT[i], logLevelStr)) { 00788 # endif 00789 return (XMLBLASTER_LOG_LEVEL)i; 00790 } 00791 } 00792 if (strToInt(&i, logLevelStr) == 1) 00793 return (XMLBLASTER_LOG_LEVEL)i; 00794 return XMLBLASTER_LOG_WARN; 00795 } 00796 00800 Dll_Export const char *getLogLevelStr(XMLBLASTER_LOG_LEVEL logLevel) 00801 { 00802 return LOG_TEXT[logLevel]; 00803 } 00804 00811 Dll_Export _INLINE_FUNC bool doLog(XMLBLASTER_LOG_LEVEL currLevel, XMLBLASTER_LOG_LEVEL level) 00812 { 00813 return (currLevel <= level) ? true : false; 00814 } 00815 00822 Dll_Export void embedException(ExceptionStruct *exception, const char *newErrorCode, const char *newMessage, const ExceptionStruct *embed) 00823 { 00824 char embedStr[EXCEPTIONSTRUCT_MESSAGE_LEN]; 00825 char newErrorCodeTmp[EXCEPTIONSTRUCT_ERRORCODE_LEN]; 00826 char message[EXCEPTIONSTRUCT_MESSAGE_LEN]; 00827 00828 strncpy0(newErrorCodeTmp, newErrorCode, EXCEPTIONSTRUCT_ERRORCODE_LEN); /* Make temporary copy in case the memory overlaps */ 00829 if (*embed->errorCode != 0) { 00830 SNPRINTF(message, EXCEPTIONSTRUCT_MESSAGE_LEN, "%s {Root cause: %s}", newMessage, getExceptionStr(embedStr, EXCEPTIONSTRUCT_MESSAGE_LEN, embed)); 00831 } 00832 else { 00833 SNPRINTF(message, EXCEPTIONSTRUCT_MESSAGE_LEN, "%s", newMessage); 00834 } 00835 strncpy0(exception->message, message, EXCEPTIONSTRUCT_MESSAGE_LEN); 00836 strncpy0(exception->errorCode, newErrorCodeTmp, EXCEPTIONSTRUCT_ERRORCODE_LEN); 00837 } 00838 00843 Dll_Export void initializeExceptionStruct(ExceptionStruct *exception) 00844 { 00845 exception->remote = false; 00846 *exception->errorCode = (char)0; 00847 *exception->message = (char)0; 00848 } 00849 00861 Dll_Export const char *getExceptionStr(char *out, int outSize, const ExceptionStruct *exception) 00862 { 00863 SNPRINTF(out, outSize, "[%s] %s", exception->errorCode, exception->message); 00864 return out; 00865 } 00866 00874 Dll_Export const char* int64ToStr(char * const buf, int64_t val) 00875 { 00876 if (buf == 0) return 0; 00877 *buf = 0; 00878 /* SNPRINTF(buf, INT64_STRLEN_MAX, "%lld", val); The normal sprintf should be safe enough */ 00879 snprintf0(buf, INT64_STRLEN_MAX, PRINTF_PREFIX_INT64_T, val); /* Returns number of written chars */ 00880 return buf; 00881 } 00882 00891 Dll_Export bool strToInt64(int64_t *val, const char * const str) 00892 { 00893 if (str == 0 || val == 0) return false; 00894 /*str[INT64_STRLEN_MAX-1] = 0; sscanf should be safe enough to handle overflow */ 00895 /* %lld on UNIX, %I64d on Windows */ 00896 # if _MSC_VER >= 1400 && !defined(WINCE) 00897 return (sscanf_s(str, PRINTF_PREFIX_INT64_T, val) == 1) ? true : false; 00898 # else 00899 return (sscanf(str, PRINTF_PREFIX_INT64_T, val) == 1) ? true : false; 00900 # endif 00901 } 00902 00903 Dll_Export bool strToLong(long *val, const char * const str) 00904 { 00905 if (str == 0 || val == 0) return false; 00906 { 00907 int64_t tmp; 00908 bool ret = strToInt64(&tmp, str); 00909 if (ret == false) return false; 00910 *val = (long)tmp; 00911 return true; 00912 } 00913 } 00914 00915 Dll_Export bool strToInt(int *val, const char * const str) 00916 { 00917 if (str == 0 || val == 0) return false; 00918 { 00919 int64_t tmp; 00920 bool ret = strToInt64(&tmp, str); 00921 if (ret == false) return false; 00922 *val = (int)tmp; 00923 return true; 00924 } 00925 } 00926 00927 Dll_Export bool strToULong(unsigned long *val, const char * const str) 00928 { 00929 if (str == 0 || val == 0) return false; 00930 # if _MSC_VER >= 1400 && !defined(WINCE) 00931 return (sscanf_s(str, "%lu", val) == 1) ? true : false; 00932 # else 00933 return (sscanf(str, "%lu", val) == 1) ? true : false; 00934 # endif 00935 } 00936 00937 00945 Dll_Export BlobHolder *blobcpyAlloc(BlobHolder *blob, const char *data, size_t dataLen) 00946 { 00947 if (blob == 0) { 00948 blob = (BlobHolder *)calloc(1, sizeof(BlobHolder)); 00949 if (blob == 0) return blob; 00950 } 00951 blob->dataLen = dataLen; 00952 blob->data = (char *)malloc((dataLen+1)*sizeof(char)); 00953 if (blob->data == 0) { 00954 free(blob); 00955 return (BlobHolder *)0; 00956 } 00957 *(blob->data + dataLen) = 0; 00958 memcpy(blob->data, data, dataLen); 00959 return blob; 00960 } 00961 00967 Dll_Export BlobHolder *freeBlobHolderContent(BlobHolder *blob) 00968 { 00969 if (blob == 0) return 0; 00970 if (blob->data != 0) { 00971 free(blob->data); 00972 blob->data = 0; 00973 blob->dataLen = 0; 00974 } 00975 return blob; 00976 } 00977 00984 Dll_Export char *blobDump(BlobHolder *blob) 00985 { 00986 return toReadableDump(blob->data, blob->dataLen); 00987 } 00988 00989 Dll_Export void freeBlobDump(char *blobDump) 00990 { 00991 free(blobDump); 00992 } 00993 00994 # ifdef HELPER_UTIL_MAIN 00995 /* 00996 * gcc -g -Wall -DHELPER_UTIL_MAIN=1 -I../../ -o helper helper.c -I../ 00997 */ 00998 int main() 00999 { 01000 const long millisecs = 500; 01001 const int currLevel = 3; 01002 const char *location = __FILE__; 01003 const char *p = "OOOO"; 01004 int i = 3; 01005 xmlBlasterDefaultLogging(0, currLevel, XMLBLASTER_LOG_WARN, location, "%s i=%d\n", p, i); 01006 01007 printf("Sleeping now for %ld millis\n", millisecs); 01008 sleepMillis(millisecs); 01009 printf("Waiking up after %ld millis\n", millisecs); 01010 01011 { 01012 const char *ptr = " 28316"; 01013 char tr[20]; 01014 strncpy0(tr, ptr, 20); 01015 trim(tr); 01016 printf("Before '%s' after '%s'\n", ptr, tr); 01017 } 01018 { 01019 const char *ptr = " 28316 "; 01020 char tr[20]; 01021 strncpy0(tr, ptr, 20); 01022 trim(tr); 01023 printf("Before '%s' after '%s'\n", ptr, tr); 01024 } 01025 { 01026 ExceptionStruct ex; 01027 strncpy0(ex.errorCode, "Original.cause", EXCEPTIONSTRUCT_ERRORCODE_LEN); 01028 strncpy0(ex.message, "Original message", EXCEPTIONSTRUCT_MESSAGE_LEN); 01029 embedException(&ex, "new.cause", "new message", &ex); 01030 printf("errorCode=%s message=%s\n", ex.errorCode, ex.message); 01031 } 01032 return 0; 01033 } 01034 # endif