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