|
|
1.1 root 1: /* genwrap.c */
2:
3: /* General cross-platform development wrappers */
4:
5: /* $Id: genwrap.c,v 1.47 2004/10/27 22:00:28 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 2004 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: /* KIOCSOUND */
50: #if defined(__FreeBSD__)
51: #include <sys/kbio.h>
52: #elif defined(__linux__)
53: #include <sys/kd.h>
54: #elif defined(__solaris__)
55: #include <sys/kbio.h>
56: #include <sys/kbd.h>
57: #endif
58: #if defined(__OpenBSD__) || defined(__NetBSD__)
59: #include <machine/spkr.h>
60: #elif defined(__FreeBSD__)
61: #include <machine/speaker.h>
62: #endif
63: #endif /* __unix__ */
64:
65: #include "genwrap.h" /* Verify prototypes */
66:
67: /****************************************************************************/
68: /* Used to replace snprintf() guarantees to terminate. */
69: /****************************************************************************/
70: int DLLCALL safe_snprintf(char *dst, size_t size, const char *fmt, ...)
71: {
72: va_list argptr;
73: int numchars;
74:
75: va_start(argptr,fmt);
76: numchars= vsnprintf(dst,size,fmt,argptr);
77: va_end(argptr);
78: dst[size-1]=0;
79: #ifdef _MSC_VER
80: if(numchars==-1)
81: numchars=strlen(dst);
82: #endif
83: if(numchars>=(int)size && numchars>0)
84: numchars=size-1;
85: return(numchars);
86: }
87:
88: /****************************************************************************/
89: /* Return last character of string */
90: /****************************************************************************/
91: char* DLLCALL lastchar(const char* str)
92: {
93: size_t len;
94:
95: len = strlen(str);
96:
97: if(len)
98: return((char*)&str[len-1]);
99:
100: return((char*)str);
101: }
102:
103: /****************************************************************************/
104: /* Return character value of C-escaped (\) character */
105: /****************************************************************************/
106: char DLLCALL unescape_char(char ch)
107: {
108: switch(ch) {
109: case '\\': return('\\');
110: case '\'': return('\'');
111: case '"': return('"');
112: case '?': return('?');
113: case 'a': return('\a');
114: case 'b': return('\b');
115: case 'f': return('\f');
116: case 'n': return('\n');
117: case 'r': return('\r');
118: case 't': return('\t');
119: case 'v': return('\v');
120: }
121: return(ch);
122: }
123:
124: /****************************************************************************/
125: /* Return character value of C-escaped (\) character sequence */
126: /* (supports \Xhh and \0ooo escape sequences) */
127: /* This code currently has problems with sequences like: "\x01blue" */
128: /****************************************************************************/
129: char DLLCALL unescape_char_ptr(const char* str, char** endptr)
130: {
131: char ch;
132:
133: if(toupper(*str)=='X')
134: ch=(char)strtol(++str,endptr,16);
135: else if(isdigit(*str))
136: ch=(char)strtol(++str,endptr,8);
137: else {
138: ch=unescape_char(*(str++));
139: if(endptr!=NULL)
140: *endptr=(char*)str;
141: }
142:
143: return(ch);
144: }
145:
146: /****************************************************************************/
147: /* Unescape a C string, in place */
148: /****************************************************************************/
149: char* DLLCALL unescape_cstr(char* str)
150: {
151: char ch;
152: char* buf;
153: char* src;
154: char* dst;
155:
156: if(str==NULL || (buf=strdup(str))==NULL)
157: return(NULL);
158:
159: src=buf;
160: dst=str;
161: while((ch=*(src++))!=0) {
162: if(ch=='\\') /* escape */
163: ch=unescape_char_ptr(src,&src);
164: *(dst++)=ch;
165: }
166: *dst=0;
167: free(buf);
168: return(str);
169: }
170:
171: /****************************************************************************/
172: /* Convert ASCIIZ string to upper case */
173: /****************************************************************************/
174: #if defined(__unix__)
175: char* DLLCALL strupr(char* str)
176: {
177: char* p=str;
178:
179: while(*p) {
180: *p=toupper(*p);
181: p++;
182: }
183: return(str);
184: }
185: /****************************************************************************/
186: /* Convert ASCIIZ string to lower case */
187: /****************************************************************************/
188: char* DLLCALL strlwr(char* str)
189: {
190: char* p=str;
191:
192: while(*p) {
193: *p=tolower(*p);
194: p++;
195: }
196: return(str);
197: }
198: /****************************************************************************/
199: /* Reverse characters of a string (provided by amcleod) */
200: /****************************************************************************/
201: char* strrev(char* str)
202: {
203: char t, *i=str, *j=str+strlen(str);
204:
205: while (i<j) {
206: t=*i; *(i++)=*(--j); *j=t;
207: }
208: return str;
209: }
210:
211: /****************************************************************************/
212: /* Generate a tone at specified frequency for specified milliseconds */
213: /* Thanks to Casey Martin for this code */
214: /****************************************************************************/
215: void DLLCALL unix_beep(int freq, int dur)
216: {
217: static int console_fd=-1;
218:
219: #if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__)
220: int speaker_fd=-1;
221: tone_t tone;
222:
223: speaker_fd = open("/dev/speaker", O_WRONLY|O_APPEND);
224: if(speaker_fd != -1) {
225: tone.frequency=freq;
226: tone.duration=dur;
227: ioctl(speaker_fd,SPKRTONE,&tone);
228: close(speaker_fd);
229: return;
230: }
231: #endif
232:
233: #if !defined(__GNU__) && !defined(__QNX__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__APPLE__)
234: if(console_fd == -1)
235: console_fd = open("/dev/console", O_NOCTTY);
236:
237: if(console_fd != -1) {
238: #if defined(__solaris__)
239: ioctl(console_fd, KIOCCMD, KBD_CMD_BELL);
240: #else
241: if(freq != 0) /* Don't divide by zero */
242: ioctl(console_fd, KIOCSOUND, (int) (1193180 / freq));
243: #endif /* solaris */
244: SLEEP(dur);
245: #if defined(__solaris__)
246: ioctl(console_fd, KIOCCMD, KBD_CMD_NOBELL); /* turn off tone */
247: #else
248: ioctl(console_fd, KIOCSOUND, 0); /* turn off tone */
249: #endif /* solaris */
250: }
251: #endif
252: }
253: #endif
254:
255: /****************************************************************************/
256: /* Return random number between 0 and n-1 */
257: /****************************************************************************/
258: int DLLCALL xp_random(int n)
259: {
260: float f;
261: static BOOL initialized;
262:
263: if(!initialized) {
264: srand(time(NULL)); /* seed random number generator */
265: rand(); /* throw away first result */
266: initialized=TRUE;
267: }
268: if(n<2)
269: return(0);
270: f=(float)rand()/(float)RAND_MAX;
271:
272: return((int)(n*f));
273: }
274:
275: /****************************************************************************/
276: /* Return ASCII string representation of ulong */
277: /* There may be a native GNU C Library function to this... */
278: /****************************************************************************/
279: #if !defined(_MSC_VER) && !defined(__BORLANDC__) && !defined(__WATCOMC__)
280: char* DLLCALL ultoa(ulong val, char* str, int radix)
281: {
282: switch(radix) {
283: case 8:
284: sprintf(str,"%lo",val);
285: break;
286: case 10:
287: sprintf(str,"%lu",val);
288: break;
289: case 16:
290: sprintf(str,"%lx",val);
291: break;
292: default:
293: sprintf(str,"bad radix: %d",radix);
294: break;
295: }
296: return(str);
297: }
298: #endif
299:
300: /****************************************************************************/
301: /* Write the version details of the current operating system into str */
302: /****************************************************************************/
303: char* DLLCALL os_version(char *str)
304: {
305: #if defined(__OS2__) && defined(__BORLANDC__)
306:
307: sprintf(str,"OS/2 %u.%u (%u.%u)",_osmajor/10,_osminor/10,_osmajor,_osminor);
308:
309: #elif defined(_WIN32)
310:
311: /* Windows Version */
312: char* winflavor="";
313: OSVERSIONINFO winver;
314:
315: winver.dwOSVersionInfoSize=sizeof(winver);
316: GetVersionEx(&winver);
317:
318: switch(winver.dwPlatformId) {
319: case VER_PLATFORM_WIN32_NT:
320: winflavor="NT ";
321: break;
322: case VER_PLATFORM_WIN32s:
323: winflavor="Win32s ";
324: break;
325: case VER_PLATFORM_WIN32_WINDOWS:
326: winver.dwBuildNumber&=0xffff;
327: break;
328: }
329:
330: sprintf(str,"Windows %sVersion %u.%u (Build %u) %s"
331: ,winflavor
332: ,winver.dwMajorVersion, winver.dwMinorVersion
333: ,winver.dwBuildNumber,winver.szCSDVersion);
334:
335: #elif defined(__unix__)
336:
337: struct utsname unixver;
338:
339: if(uname(&unixver)<0)
340: sprintf(str,"Unix (uname errno: %d)",errno);
341: else
342: sprintf(str,"%s %s %s"
343: ,unixver.sysname /* e.g. "Linux" */
344: ,unixver.release /* e.g. "2.2.14-5.0" */
345: ,unixver.machine /* e.g. "i586" */
346: );
347:
348: #else /* DOS */
349:
350: sprintf(str,"DOS %u.%02u",_osmajor,_osminor);
351:
352: #endif
353:
354: return(str);
355: }
356:
357: #if !defined(__unix__)
358:
359: /****************************************************************************/
360: /* Win32 implementations of the recursive (thread-safe) versions of std C */
361: /* time functions (gmtime, localtime, ctime, and asctime) used in Unix. */
362: /* The native Win32 versions of these functions are already thread-safe. */
363: /****************************************************************************/
364:
365: struct tm* DLLCALL gmtime_r(const time_t* t, struct tm* tm)
366: {
367: struct tm* tmp = gmtime(t);
368:
369: if(tmp==NULL)
370: return(NULL);
371:
372: *tm = *tmp;
373: return(tm);
374: }
375:
376: struct tm* DLLCALL localtime_r(const time_t* t, struct tm* tm)
377: {
378: struct tm* tmp = localtime(t);
379:
380: if(tmp==NULL)
381: return(NULL);
382:
383: *tm = *tmp;
384: return(tm);
385: }
386:
387: char* DLLCALL ctime_r(const time_t *t, char *buf)
388: {
389: char* p = ctime(t);
390:
391: if(p==NULL)
392: return(NULL);
393:
394: strcpy(buf,p);
395: return(buf);
396: }
397:
398: char* DLLCALL asctime_r(const struct tm *tm, char *buf)
399: {
400: char* p = asctime(tm);
401:
402: if(p==NULL)
403: return(NULL);
404:
405: strcpy(buf,p);
406: return(buf);
407: }
408:
409: #endif /* !defined(__unix__) */
410:
411: /********************************************/
412: /* Hi-res real-time clock implementation. */
413: /********************************************/
414: #ifdef __unix__
415: clock_t DLLCALL msclock(void)
416: {
417: long long int usecs;
418: struct timeval tv;
419: if(gettimeofday(&tv,NULL)==1)
420: return(-1);
421: usecs=tv.tv_sec*1000000+tv.tv_usec;
422: return((clock_t)(usecs/(1000000/MSCLOCKS_PER_SEC)));
423: }
424: #endif
425:
426: /****************************************************************************/
427: /* Truncates all white-space chars off end of 'str' (needed by STRERRROR) */
428: /****************************************************************************/
429: char* DLLCALL truncsp(char* str)
430: {
431: size_t i,len;
432:
433: i=len=strlen(str);
434: while(i && (str[i-1]==' ' || str[i-1]=='\t' || str[i-1]=='\r' || str[i-1]=='\n'))
435: i--;
436: if(i!=len)
437: str[i]=0; /* truncate */
438:
439: return(str);
440: }
441:
442: /****************************************************************************/
443: /* Truncates all white-space chars off end of \n-terminated lines in 'str' */
444: /****************************************************************************/
445: char* DLLCALL truncsp_lines(char* dst)
446: {
447: char* sp;
448: char* dp;
449: char* src;
450:
451: if((src=strdup(dst))==NULL)
452: return(dst);
453:
454: for(sp=src, dp=dst; *sp!=0; sp++) {
455: if(*sp=='\n')
456: while(dp!=dst
457: && (*(dp-1)==' ' || *(dp-1)=='\t' || *(dp-1)=='\r') && *(dp-1)!='\n')
458: dp--;
459: *(dp++)=*sp;
460: }
461: *dp=0;
462:
463: free(src);
464: return(dst);
465: }
466:
467: /****************************************************************************/
468: /* Truncates carriage-return and line-feed chars off end of 'str' */
469: /****************************************************************************/
470: char* DLLCALL truncnl(char* str)
471: {
472: size_t i,len;
473:
474: i=len=strlen(str);
475: while(i && (str[i-1]=='\r' || str[i-1]=='\n'))
476: i--;
477: if(i!=len)
478: str[i]=0; /* truncate */
479:
480: return(str);
481: }
482:
483: /****************************************************************************/
484: /* Return errno from the proper C Library implementation */
485: /* (single/multi-threaded) */
486: /****************************************************************************/
487: int DLLCALL get_errno(void)
488: {
489: return(errno);
490: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.