|
|
1.1 ! root 1: /* genwrap.c */ ! 2: ! 3: /* General cross-platform development wrappers */ ! 4: ! 5: /* $Id: genwrap.c,v 1.72 2006/08/26 18:45:48 rswindell Exp $ */ ! 6: ! 7: /**************************************************************************** ! 8: * @format.tab-size 4 (Plain Text/Source Code File Header) * ! 9: * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) * ! 10: * * ! 11: * Copyright 2006 Rob Swindell - http://www.synchro.net/copyright.html * ! 12: * * ! 13: * This library is free software; you can redistribute it and/or * ! 14: * modify it under the terms of the GNU Lesser General Public License * ! 15: * as published by the Free Software Foundation; either version 2 * ! 16: * of the License, or (at your option) any later version. * ! 17: * See the GNU Lesser General Public License for more details: lgpl.txt or * ! 18: * http://www.fsf.org/copyleft/lesser.html * ! 19: * * ! 20: * Anonymous FTP access to the most recent released source is available at * ! 21: * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net * ! 22: * * ! 23: * Anonymous CVS access to the development source and modification history * ! 24: * is available at cvs.synchro.net:/cvsroot/sbbs, example: * ! 25: * cvs -d :pserver:[email protected]:/cvsroot/sbbs login * ! 26: * (just hit return, no password is necessary) * ! 27: * cvs -d :pserver:[email protected]:/cvsroot/sbbs checkout src * ! 28: * * ! 29: * For Synchronet coding style and modification guidelines, see * ! 30: * http://www.synchro.net/source.html * ! 31: * * ! 32: * You are encouraged to submit any modifications (preferably in Unix diff * ! 33: * format) via e-mail to [email protected] * ! 34: * * ! 35: * Note: If this box doesn't appear square, then you need to fix your tabs. * ! 36: ****************************************************************************/ ! 37: ! 38: #include <string.h> /* strlen() */ ! 39: #include <stdarg.h> /* vsnprintf() */ ! 40: #include <stdlib.h> /* RAND_MAX */ ! 41: #include <fcntl.h> /* O_NOCTTY */ ! 42: #include <time.h> /* clock() */ ! 43: #include <errno.h> /* errno */ ! 44: #include <ctype.h> /* toupper/tolower */ ! 45: ! 46: #if defined(__unix__) ! 47: #include <sys/ioctl.h> /* ioctl() */ ! 48: #include <sys/utsname.h> /* uname() */ ! 49: #endif /* __unix__ */ ! 50: ! 51: #include "genwrap.h" /* Verify prototypes */ ! 52: #include "xpendian.h" /* BYTE_SWAP */ ! 53: ! 54: /****************************************************************************/ ! 55: /* Used to replace snprintf() guarantees to terminate. */ ! 56: /****************************************************************************/ ! 57: int DLLCALL safe_snprintf(char *dst, size_t size, const char *fmt, ...) ! 58: { ! 59: va_list argptr; ! 60: int numchars; ! 61: ! 62: va_start(argptr,fmt); ! 63: numchars= vsnprintf(dst,size,fmt,argptr); ! 64: va_end(argptr); ! 65: dst[size-1]=0; ! 66: #ifdef _MSC_VER ! 67: if(numchars==-1) ! 68: numchars=strlen(dst); ! 69: #endif ! 70: if(numchars>=(int)size && numchars>0) ! 71: numchars=size-1; ! 72: return(numchars); ! 73: } ! 74: ! 75: /****************************************************************************/ ! 76: /* Return last character of string */ ! 77: /****************************************************************************/ ! 78: char* DLLCALL lastchar(const char* str) ! 79: { ! 80: size_t len; ! 81: ! 82: len = strlen(str); ! 83: ! 84: if(len) ! 85: return((char*)&str[len-1]); ! 86: ! 87: return((char*)str); ! 88: } ! 89: ! 90: /****************************************************************************/ ! 91: /* Return character value of C-escaped (\) character */ ! 92: /****************************************************************************/ ! 93: char DLLCALL c_unescape_char(char ch) ! 94: { ! 95: switch(ch) { ! 96: case 'e': return(ESC); /* non-standard */ ! 97: case 'a': return('\a'); ! 98: case 'b': return('\b'); ! 99: case 'f': return('\f'); ! 100: case 'n': return('\n'); ! 101: case 'r': return('\r'); ! 102: case 't': return('\t'); ! 103: case 'v': return('\v'); ! 104: } ! 105: return(ch); ! 106: } ! 107: ! 108: /****************************************************************************/ ! 109: /* Return character value of C-escaped (\) character sequence */ ! 110: /* (supports \Xhh and \0ooo escape sequences) */ ! 111: /* This code currently has problems with sequences like: "\x01blue" */ ! 112: /****************************************************************************/ ! 113: char DLLCALL c_unescape_char_ptr(const char* str, char** endptr) ! 114: { ! 115: char ch; ! 116: ! 117: if(toupper(*str)=='X') ! 118: ch=(char)strtol(++str,endptr,16); ! 119: else if(isdigit(*str)) ! 120: ch=(char)strtol(++str,endptr,8); ! 121: else { ! 122: ch=c_unescape_char(*(str++)); ! 123: if(endptr!=NULL) ! 124: *endptr=(char*)str; ! 125: } ! 126: ! 127: return(ch); ! 128: } ! 129: ! 130: /****************************************************************************/ ! 131: /* Unescape a C string, in place */ ! 132: /****************************************************************************/ ! 133: char* DLLCALL c_unescape_str(char* str) ! 134: { ! 135: char ch; ! 136: char* buf; ! 137: char* src; ! 138: char* dst; ! 139: ! 140: if(str==NULL || (buf=strdup(str))==NULL) ! 141: return(NULL); ! 142: ! 143: src=buf; ! 144: dst=str; ! 145: while((ch=*(src++))!=0) { ! 146: if(ch=='\\') /* escape */ ! 147: ch=c_unescape_char_ptr(src,&src); ! 148: *(dst++)=ch; ! 149: } ! 150: *dst=0; ! 151: free(buf); ! 152: return(str); ! 153: } ! 154: ! 155: char* DLLCALL c_escape_char(char ch) ! 156: { ! 157: switch(ch) { ! 158: case 0: return("\\x00"); ! 159: case 1: return("\\x01"); ! 160: case ESC: return("\\e"); /* non-standard */ ! 161: case '\a': return("\\a"); ! 162: case '\b': return("\\b"); ! 163: case '\f': return("\\f"); ! 164: case '\n': return("\\n"); ! 165: case '\r': return("\\r"); ! 166: case '\t': return("\\t"); ! 167: case '\v': return("\\v"); ! 168: case '\\': return("\\\\"); ! 169: case '\"': return("\\\""); ! 170: case '\'': return("\\'"); ! 171: } ! 172: return(NULL); ! 173: } ! 174: ! 175: char* DLLCALL c_escape_str(const char* src, char* dst, size_t maxlen, BOOL ctrl_only) ! 176: { ! 177: const char* s; ! 178: char* d; ! 179: char* e; ! 180: ! 181: for(s=src,d=dst;*s && (size_t)(d-dst)<maxlen;s++,d++) { ! 182: if((!ctrl_only || (uchar)*s < ' ') && (e=c_escape_char(*s))!=NULL) { ! 183: *d=0; ! 184: strncat(dst,e,maxlen-(d-dst)); ! 185: d++; ! 186: } else *d=*s; ! 187: } ! 188: *d=0; ! 189: ! 190: return(dst); ! 191: } ! 192: ! 193: /****************************************************************************/ ! 194: /* Convert ASCIIZ string to upper case */ ! 195: /****************************************************************************/ ! 196: #if defined(__unix__) ! 197: char* DLLCALL strupr(char* str) ! 198: { ! 199: char* p=str; ! 200: ! 201: while(*p) { ! 202: *p=toupper(*p); ! 203: p++; ! 204: } ! 205: return(str); ! 206: } ! 207: /****************************************************************************/ ! 208: /* Convert ASCIIZ string to lower case */ ! 209: /****************************************************************************/ ! 210: char* DLLCALL strlwr(char* str) ! 211: { ! 212: char* p=str; ! 213: ! 214: while(*p) { ! 215: *p=tolower(*p); ! 216: p++; ! 217: } ! 218: return(str); ! 219: } ! 220: /****************************************************************************/ ! 221: /* Reverse characters of a string (provided by amcleod) */ ! 222: /****************************************************************************/ ! 223: char* strrev(char* str) ! 224: { ! 225: char t, *i=str, *j=str+strlen(str); ! 226: ! 227: while (i<j) { ! 228: t=*i; *(i++)=*(--j); *j=t; ! 229: } ! 230: return str; ! 231: } ! 232: #endif ! 233: ! 234: #if !defined(__unix__) ! 235: ! 236: /****************************************************************************/ ! 237: /* Implementations of the recursive (thread-safe) version of strtok */ ! 238: /* Thanks to Apache Portable Runtime (APR) */ ! 239: /****************************************************************************/ ! 240: char* DLLCALL strtok_r(char *str, const char *delim, char **last) ! 241: { ! 242: char* token; ! 243: ! 244: if (str==NULL) /* subsequent call */ ! 245: str = *last; /* start where we left off */ ! 246: ! 247: /* skip characters in delimiter (will terminate at '\0') */ ! 248: while(*str && strchr(delim, *str)) ! 249: ++str; ! 250: ! 251: if(!*str) { /* no more tokens */ ! 252: *last = str; ! 253: return NULL; ! 254: } ! 255: ! 256: token = str; ! 257: ! 258: /* skip valid token characters to terminate token and ! 259: * prepare for the next call (will terminate at '\0) ! 260: */ ! 261: *last = token + 1; ! 262: while(**last && !strchr(delim, **last)) ! 263: ++*last; ! 264: ! 265: if (**last) { ! 266: **last = '\0'; ! 267: ++*last; ! 268: } ! 269: ! 270: return token; ! 271: } ! 272: ! 273: #endif ! 274: ! 275: /****************************************************************************/ ! 276: /* Initialize (seed) the random number generator */ ! 277: /****************************************************************************/ ! 278: unsigned DLLCALL xp_randomize(void) ! 279: { ! 280: unsigned seed=~0; ! 281: ! 282: #if defined(HAS_DEV_URANDOM) && defined(URANDOM_DEV) ! 283: int rf; ! 284: ! 285: if((rf=open(URANDOM_DEV, O_RDONLY))!=-1) { ! 286: read(rf, &seed, sizeof(seed)); ! 287: close(rf); ! 288: } ! 289: else { ! 290: #endif ! 291: unsigned curtime = (unsigned)time(NULL); ! 292: unsigned process_id = (unsigned)GetCurrentProcessId(); ! 293: ! 294: seed = curtime ^ BYTE_SWAP_INT(process_id); ! 295: ! 296: #if defined(_WIN32) || defined(GetCurrentThreadId) ! 297: seed ^= (unsigned)GetCurrentThreadId(); ! 298: #endif ! 299: ! 300: #if defined(HAS_DEV_URANDOM) && defined(URANDOM_DEV) ! 301: } ! 302: #endif ! 303: ! 304: #ifdef HAS_RANDOM_FUNC ! 305: srandom(seed); ! 306: return(seed); ! 307: #else ! 308: srand(seed); ! 309: return(seed); ! 310: #endif ! 311: } ! 312: ! 313: /****************************************************************************/ ! 314: /* Return random number between 0 and n-1 */ ! 315: /****************************************************************************/ ! 316: int DLLCALL xp_random(int n) ! 317: { ! 318: #ifdef HAS_RANDOM_FUNC ! 319: if(n<2) ! 320: return(0); ! 321: return(random()%n); ! 322: #else ! 323: float f=0; ! 324: ! 325: if(n<2) ! 326: return(0); ! 327: f=(float)rand()/(float)RAND_MAX; ! 328: ! 329: return((int)(n*f)); ! 330: #endif ! 331: } ! 332: ! 333: /****************************************************************************/ ! 334: /* Return ASCII string representation of ulong */ ! 335: /* There may be a native GNU C Library function to this... */ ! 336: /****************************************************************************/ ! 337: #if !defined(_MSC_VER) && !defined(__BORLANDC__) && !defined(__WATCOMC__) ! 338: char* DLLCALL ultoa(ulong val, char* str, int radix) ! 339: { ! 340: switch(radix) { ! 341: case 8: ! 342: sprintf(str,"%lo",val); ! 343: break; ! 344: case 10: ! 345: sprintf(str,"%lu",val); ! 346: break; ! 347: case 16: ! 348: sprintf(str,"%lx",val); ! 349: break; ! 350: default: ! 351: sprintf(str,"bad radix: %d",radix); ! 352: break; ! 353: } ! 354: return(str); ! 355: } ! 356: #endif ! 357: ! 358: /****************************************************************************/ ! 359: /* Write the version details of the current operating system into str */ ! 360: /****************************************************************************/ ! 361: char* DLLCALL os_version(char *str) ! 362: { ! 363: #if defined(__OS2__) && defined(__BORLANDC__) ! 364: ! 365: sprintf(str,"OS/2 %u.%u (%u.%u)",_osmajor/10,_osminor/10,_osmajor,_osminor); ! 366: ! 367: #elif defined(_WIN32) ! 368: ! 369: /* Windows Version */ ! 370: char* winflavor=""; ! 371: OSVERSIONINFO winver; ! 372: ! 373: winver.dwOSVersionInfoSize=sizeof(winver); ! 374: GetVersionEx(&winver); ! 375: ! 376: switch(winver.dwPlatformId) { ! 377: case VER_PLATFORM_WIN32_NT: ! 378: winflavor="NT "; ! 379: break; ! 380: case VER_PLATFORM_WIN32s: ! 381: winflavor="Win32s "; ! 382: break; ! 383: case VER_PLATFORM_WIN32_WINDOWS: ! 384: winver.dwBuildNumber&=0xffff; ! 385: break; ! 386: } ! 387: ! 388: sprintf(str,"Windows %sVersion %u.%u (Build %u) %s" ! 389: ,winflavor ! 390: ,winver.dwMajorVersion, winver.dwMinorVersion ! 391: ,winver.dwBuildNumber,winver.szCSDVersion); ! 392: ! 393: #elif defined(__unix__) ! 394: ! 395: struct utsname unixver; ! 396: ! 397: if(uname(&unixver)<0) ! 398: sprintf(str,"Unix (uname errno: %d)",errno); ! 399: else ! 400: sprintf(str,"%s %s %s" ! 401: ,unixver.sysname /* e.g. "Linux" */ ! 402: ,unixver.release /* e.g. "2.2.14-5.0" */ ! 403: ,unixver.machine /* e.g. "i586" */ ! 404: ); ! 405: ! 406: #else /* DOS */ ! 407: ! 408: sprintf(str,"DOS %u.%02u",_osmajor,_osminor); ! 409: ! 410: #endif ! 411: ! 412: return(str); ! 413: } ! 414: ! 415: char* DLLCALL os_cmdshell(void) ! 416: { ! 417: char* shell=getenv(OS_CMD_SHELL_ENV_VAR); ! 418: ! 419: #if !defined(__unix__) ! 420: if(shell==NULL) ! 421: #ifdef _PATH_BSHELL ! 422: shell=_PATH_BSHELL; ! 423: #else ! 424: shell="/bin/sh"; ! 425: #endif ! 426: #endif ! 427: ! 428: return(shell); ! 429: } ! 430: ! 431: #if !defined(__unix__) ! 432: ! 433: /****************************************************************************/ ! 434: /* Win32 implementations of the recursive (thread-safe) versions of std C */ ! 435: /* time functions (gmtime, localtime, ctime, and asctime) used in Unix. */ ! 436: /* The native Win32 versions of these functions are already thread-safe. */ ! 437: /****************************************************************************/ ! 438: ! 439: struct tm* DLLCALL gmtime_r(const time_t* t, struct tm* tm) ! 440: { ! 441: struct tm* tmp = gmtime(t); ! 442: ! 443: if(tmp==NULL) ! 444: return(NULL); ! 445: ! 446: *tm = *tmp; ! 447: return(tm); ! 448: } ! 449: ! 450: struct tm* DLLCALL localtime_r(const time_t* t, struct tm* tm) ! 451: { ! 452: struct tm* tmp = localtime(t); ! 453: ! 454: if(tmp==NULL) ! 455: return(NULL); ! 456: ! 457: *tm = *tmp; ! 458: return(tm); ! 459: } ! 460: ! 461: char* DLLCALL ctime_r(const time_t *t, char *buf) ! 462: { ! 463: char* p = ctime(t); ! 464: ! 465: if(p==NULL) ! 466: return(NULL); ! 467: ! 468: strcpy(buf,p); ! 469: return(buf); ! 470: } ! 471: ! 472: char* DLLCALL asctime_r(const struct tm *tm, char *buf) ! 473: { ! 474: char* p = asctime(tm); ! 475: ! 476: if(p==NULL) ! 477: return(NULL); ! 478: ! 479: strcpy(buf,p); ! 480: return(buf); ! 481: } ! 482: ! 483: #endif /* !defined(__unix__) */ ! 484: ! 485: /****************************************************************/ ! 486: /* Microsoft (DOS/Win32) real-time system clock implementation. */ ! 487: /****************************************************************/ ! 488: #ifdef __unix__ ! 489: clock_t DLLCALL msclock(void) ! 490: { ! 491: long long int usecs; ! 492: struct timeval tv; ! 493: if(gettimeofday(&tv,NULL)==1) ! 494: return(-1); ! 495: usecs=tv.tv_sec*1000000+tv.tv_usec; ! 496: return((clock_t)(usecs/(1000000/MSCLOCKS_PER_SEC))); ! 497: } ! 498: #endif ! 499: ! 500: /****************************************************************************/ ! 501: /* Truncates all white-space chars off end of 'str' (needed by STRERRROR) */ ! 502: /****************************************************************************/ ! 503: char* DLLCALL truncsp(char* str) ! 504: { ! 505: size_t i,len; ! 506: ! 507: i=len=strlen(str); ! 508: while(i && (str[i-1]==' ' || str[i-1]=='\t' || str[i-1]=='\r' || str[i-1]=='\n')) ! 509: i--; ! 510: if(i!=len) ! 511: str[i]=0; /* truncate */ ! 512: ! 513: return(str); ! 514: } ! 515: ! 516: /****************************************************************************/ ! 517: /* Truncates all white-space chars off end of \n-terminated lines in 'str' */ ! 518: /****************************************************************************/ ! 519: char* DLLCALL truncsp_lines(char* dst) ! 520: { ! 521: char* sp; ! 522: char* dp; ! 523: char* src; ! 524: ! 525: if((src=strdup(dst))==NULL) ! 526: return(dst); ! 527: ! 528: for(sp=src, dp=dst; *sp!=0; sp++) { ! 529: if(*sp=='\n') ! 530: while(dp!=dst ! 531: && (*(dp-1)==' ' || *(dp-1)=='\t' || *(dp-1)=='\r') && *(dp-1)!='\n') ! 532: dp--; ! 533: *(dp++)=*sp; ! 534: } ! 535: *dp=0; ! 536: ! 537: free(src); ! 538: return(dst); ! 539: } ! 540: ! 541: /****************************************************************************/ ! 542: /* Truncates carriage-return and line-feed chars off end of 'str' */ ! 543: /****************************************************************************/ ! 544: char* DLLCALL truncnl(char* str) ! 545: { ! 546: size_t i,len; ! 547: ! 548: i=len=strlen(str); ! 549: while(i && (str[i-1]=='\r' || str[i-1]=='\n')) ! 550: i--; ! 551: if(i!=len) ! 552: str[i]=0; /* truncate */ ! 553: ! 554: return(str); ! 555: } ! 556: ! 557: /****************************************************************************/ ! 558: /* Return errno from the proper C Library implementation */ ! 559: /* (single/multi-threaded) */ ! 560: /****************************************************************************/ ! 561: int DLLCALL get_errno(void) ! 562: { ! 563: return(errno); ! 564: } ! 565: ! 566: /****************************************************************************/ ! 567: /* Returns the current value of the systems best timer (in SECONDS) */ ! 568: /* Any value < 0 indicates an error */ ! 569: /****************************************************************************/ ! 570: long double DLLCALL xp_timer(void) ! 571: { ! 572: long double ret; ! 573: #if defined(__unix__) ! 574: struct timeval tv; ! 575: if(gettimeofday(&tv,NULL)==1) ! 576: return(-1); ! 577: ret=tv.tv_usec; ! 578: ret /= 1000000; ! 579: ret += tv.tv_sec; ! 580: #elif defined(_WIN32) ! 581: LARGE_INTEGER freq; ! 582: LARGE_INTEGER tick; ! 583: if(QueryPerformanceFrequency(&freq) && QueryPerformanceCounter(&tick)) { ! 584: #if 0 ! 585: ret=((long double)tick.HighPart*4294967296)+((long double)tick.LowPart); ! 586: ret /= ((long double)freq.HighPart*4294967296)+((long double)freq.LowPart); ! 587: #else ! 588: /* In MSVC, a long double does NOT have 19 decimals of precision */ ! 589: ret=(((long double)(tick.QuadPart%freq.QuadPart))/freq.QuadPart); ! 590: ret+=tick.QuadPart/freq.QuadPart; ! 591: #endif ! 592: } ! 593: else { ! 594: ret=GetTickCount(); ! 595: ret /= 1000; ! 596: } ! 597: #else ! 598: ret=time(NULL); /* Weak implementation */ ! 599: #endif ! 600: return(ret); ! 601: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.