|
|
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.