comparison dwcompat.c @ 1594:6baf177f335c

Rename compat.c/h dwcompat.c/h and configure option to --with-dwcompat. There are several other projects that include compat.c and compat.h... To avoid conflicts make sure the header and source files match the library.
author bsmith@81767d24-ef19-dc11-ae90-00e081727c95
date Thu, 23 Feb 2012 12:44:15 +0000
parents compat.c@007ed833ac79
children 71e0a3ad07f7
comparison
equal deleted inserted replaced
1593:19af25f71e1f 1594:6baf177f335c
1 /* $Id$ */
2
3 #include "dwcompat.h"
4 #include "dw.h"
5 #if defined(__OS2__) || defined(__WIN32__)
6 #include <share.h>
7 #endif
8
9 #if defined(__UNIX__) || defined(__MAC__)
10 #if defined(__FreeBSD__) || defined(__MAC__)
11 #include <sys/param.h>
12 #include <sys/ucred.h>
13 #include <sys/mount.h>
14 #elif defined(__sun__)
15 #include <sys/mnttab.h>
16 #include <sys/param.h>
17 #include <sys/mount.h>
18 #include <sys/statvfs.h>
19 #else
20 #include <mntent.h>
21 #include <sys/vfs.h>
22 #endif
23 #endif
24 #include <time.h>
25 #include <errno.h>
26
27 #if defined(__UNIX__) || defined(__MAC__)
28 void msleep(long period)
29 {
30 #ifdef __sun__
31 /* usleep() isn't threadsafe on Solaris */
32 struct timespec req;
33
34 req.tv_sec = 0;
35 if(period >= 1000)
36 {
37 req.tv_sec = (int)(period / 1000);
38 period -= (req.tv_sec * 1000);
39 }
40 req.tv_nsec = period * 10000000;
41
42 nanosleep(&req, NULL);
43 #else
44 usleep((int)(period * 1000));
45 #endif
46 }
47 #endif
48
49 int API makedir(char *path)
50 {
51 #if defined(__IBMC__) || defined(__WATCOMC__) || (defined(__WIN32__) && !defined(__CYGWIN32__))
52 return mkdir(path);
53 #else
54 return mkdir(path,S_IRWXU);
55 #endif
56 }
57
58 char * API vargs(char *buf, int len, char *format, ...)
59 {
60 va_list args;
61
62 va_start(args, format);
63 #ifdef HAVE_VSNPRINTF
64 vsnprintf(buf, len, format, args);
65 #else
66 len = len;
67 vsprintf(buf, format, args);
68 #endif
69 va_end(args);
70
71 return buf;
72 }
73
74 long double API drivefree(int drive)
75 {
76 #if defined(__EMX__) || defined(__OS2__)
77 ULONG aulFSInfoBuf[40] = {0};
78 APIRET rc = NO_ERROR;
79
80 DosError(FERR_DISABLEHARDERR);
81 rc = DosQueryFSInfo(drive,
82 FSIL_ALLOC,
83 (PVOID)aulFSInfoBuf,
84 sizeof(aulFSInfoBuf));
85
86 DosError(FERR_ENABLEHARDERR);
87 if (rc != NO_ERROR)
88 return 0;
89
90 return (long double)((double)aulFSInfoBuf[3] * (double)aulFSInfoBuf[1] * (double)aulFSInfoBuf[4]);
91 #elif defined(__WIN32__) || defined(WINNT)
92 char buffer[10] = "C:\\";
93 DWORD spc, bps, fc, tc;
94
95 buffer[0] = drive + 'A' - 1;
96
97 if(GetDiskFreeSpace(buffer, &spc, &bps, &fc, &tc) == 0)
98 return 0;
99
100 return (long double)((double)spc*(double)bps*(double)fc);
101 #elif defined(__FreeBSD__) || defined(__MAC__)
102 struct statfs *fsp;
103 int entries, index = 1;
104
105 entries = getmntinfo (&fsp, MNT_NOWAIT);
106
107 for (; entries-- > 0; fsp++)
108 {
109 if(index == drive)
110 return (long double)((double)fsp->f_bsize * (double)fsp->f_bavail);
111 index++;
112 }
113 return 0;
114 #elif defined(__sun__)
115 FILE *fp = fopen("/etc/mnttab", "r");
116 struct mnttab mnt;
117 struct statvfs sfs;
118 int index = 1;
119
120 if(fp)
121 {
122 while((getmntent(fp, &mnt) == 0))
123 {
124 if(index == drive)
125 {
126 long double size = 0;
127
128 if(mnt.mnt_mountp)
129 {
130 if(!statvfs(mnt.mnt_mountp, &sfs))
131 {
132 size = (long double)((double)sfs.f_bsize * (double)sfs.f_bavail);
133 }
134 }
135 fclose(fp);
136 return size;
137 }
138 index++;
139 }
140 fclose(fp);
141 }
142 return 0;
143 #else
144 FILE *fp = setmntent(MOUNTED, "r");
145 struct mntent mnt;
146 struct statfs sfs;
147 char buffer[1024];
148 int index = 1;
149
150 if(fp)
151 {
152 while(getmntent_r(fp, &mnt, buffer, sizeof(buffer)))
153 {
154 if(index == drive)
155 {
156 long double size = 0;
157
158 if(mnt.mnt_dir)
159 {
160 if(!statfs(mnt.mnt_dir, &sfs))
161 {
162 size = (long double)((double)sfs.f_bsize * (double)sfs.f_bavail);
163 }
164 }
165 endmntent(fp);
166 return size;
167 }
168 index++;
169 }
170 endmntent(fp);
171 }
172 return 0;
173 #endif
174 }
175
176 long double API drivesize(int drive)
177 {
178 #if defined(__EMX__) || defined(__OS2__)
179 ULONG aulFSInfoBuf[40] = {0};
180 APIRET rc = NO_ERROR;
181
182 DosError(FERR_DISABLEHARDERR);
183 rc = DosQueryFSInfo(drive,
184 FSIL_ALLOC,
185 (PVOID)aulFSInfoBuf,
186 sizeof(aulFSInfoBuf));
187
188 DosError(FERR_ENABLEHARDERR);
189 if (rc != NO_ERROR)
190 return 0;
191
192 return (long double)((double)aulFSInfoBuf[2] * (double)aulFSInfoBuf[1] * (double)aulFSInfoBuf[4]);
193 #elif defined(__WIN32__) || defined(WINNT)
194 char buffer[10] = "C:\\";
195 DWORD spc, bps, fc, tc;
196
197 buffer[0] = drive + 'A' - 1;
198
199 if(GetDiskFreeSpace(buffer, &spc, &bps, &fc, &tc) == 0)
200 return 0;
201
202 return (long double)((double)spc*(double)bps*(double)tc);
203 #elif defined(__FreeBSD__) || defined(__MAC__)
204 struct statfs *fsp;
205 int entries, index = 1;
206
207 entries = getmntinfo (&fsp, MNT_NOWAIT);
208
209 for (; entries-- > 0; fsp++)
210 {
211 if(index == drive)
212 return (long double)((double)fsp->f_bsize * (double)fsp->f_blocks);
213 index++;
214 }
215 return 0;
216 #elif defined(__sun__)
217 FILE *fp = fopen("/etc/mnttab", "r");
218 struct mnttab mnt;
219 struct statvfs sfs;
220 int index = 1;
221
222 if(fp)
223 {
224 while(getmntent(fp, &mnt) == 0)
225 {
226 if(index == drive)
227 {
228 long double size = 0;
229
230 if(mnt.mnt_mountp)
231 {
232 if(!statvfs(mnt.mnt_mountp, &sfs))
233 {
234 size = (long double)((double)sfs.f_bsize * (double)sfs.f_blocks);
235 }
236 }
237 fclose(fp);
238 return size;
239 }
240 index++;
241 }
242 fclose(fp);
243 }
244 return 0;
245 #else
246 FILE *fp = setmntent(MOUNTED, "r");
247 struct mntent mnt;
248 char buffer[1024];
249 struct statfs sfs;
250 int index = 1;
251
252 if(fp)
253 {
254 while(getmntent_r(fp, &mnt, buffer, sizeof(buffer)))
255 {
256 if(index == drive)
257 {
258 long double size = 0;
259
260 if(mnt.mnt_dir)
261 {
262 if(!statfs(mnt.mnt_dir, &sfs))
263 {
264 size = (long double)((double)sfs.f_bsize * (double)sfs.f_blocks);
265 }
266 }
267 endmntent(fp);
268 return size;
269 }
270 index++;
271 }
272 endmntent(fp);
273 }
274 return 0;
275 #endif
276 }
277
278 int API isdrive(int drive)
279 {
280 #if defined(__EMX__) || defined(__OS2__)
281 APIRET rc = NO_ERROR;
282 FSINFO volinfo;
283
284 DosError(FERR_DISABLEHARDERR);
285 rc = DosQueryFSInfo(drive,
286 FSIL_VOLSER,
287 (PVOID)&volinfo,
288 sizeof(FSINFO));
289
290 DosError(FERR_ENABLEHARDERR);
291 if (rc == NO_ERROR)
292 return 1;
293
294 #elif defined(__WIN32__) || defined(WINNT)
295 char buffer[10] = "C:\\", volname[100];
296 DWORD spc, bps, fc;
297
298 buffer[0] = drive + 'A' - 1;
299
300 if(GetVolumeInformation(buffer, volname, 100, &spc, &bps, &fc, NULL, 0) != 0)
301 return 1;
302 #elif defined(__FreeBSD__) || defined(__MAC__)
303 struct statfs *fsp;
304 int entries, index = 1;
305
306 entries = getmntinfo (&fsp, MNT_NOWAIT);
307
308 for (; entries-- > 0; fsp++)
309 {
310 if(index == drive && fsp->f_blocks)
311 return 1;
312 index++;
313 }
314 return 0;
315 #elif defined(__sun__)
316 FILE *fp = fopen("/etc/mnttab", "r");
317 struct mnttab mnt;
318 struct statvfs sfs;
319 int index = 1;
320
321 if(fp)
322 {
323 while(getmntent(fp, &mnt) == 0)
324 {
325 if(index == drive)
326 {
327 fclose(fp);
328 if(mnt.mnt_mountp)
329 {
330 if(!statvfs(mnt.mnt_mountp, &sfs) && sfs.f_blocks)
331 return 1;
332 }
333 return 0;
334 }
335 index++;
336 }
337 fclose(fp);
338 }
339 #else
340 FILE *fp = setmntent(MOUNTED, "r");
341 struct mntent mnt;
342 char buffer[1024];
343 struct statfs sfs;
344 int index = 1;
345
346 if(fp)
347 {
348 while(getmntent_r(fp, &mnt, buffer, sizeof(buffer)))
349 {
350 if(index == drive)
351 {
352 endmntent(fp);
353 if(mnt.mnt_dir)
354 {
355 if(!statfs(mnt.mnt_dir, &sfs) && sfs.f_blocks)
356 {
357 return 1;
358 }
359 }
360 return 0;
361 }
362 index++;
363 }
364 endmntent(fp);
365 }
366 #endif
367 return 0;
368 }
369
370 void API getfsname(int drive, char *buf, int len)
371 {
372 #if defined(__UNIX__) || defined(__MAC__)
373 #if defined(__FreeBSD__) || defined(__MAC__)
374 struct statfs *fsp;
375 int entries, index = 1;
376
377 strncpy(buf, "Unknown", len);
378
379 entries = getmntinfo (&fsp, MNT_NOWAIT);
380
381 for (; entries-- > 0; fsp++)
382 {
383 if(index == drive)
384 strncpy(buf, fsp->f_mntonname, len);
385 index++;
386 }
387 #elif defined(__sun__)
388 FILE *fp = fopen("/etc/mnttab", "r");
389 struct mnttab mnt;
390 int index = 1;
391
392 strncpy(buf, "Unknown", len);
393
394 if(fp)
395 {
396 while(getmntent(fp, &mnt) == 0)
397 {
398 if(index == drive && mnt.mnt_mountp)
399 strncpy(buf, mnt.mnt_mountp, len);
400 index++;
401 }
402 fclose(fp);
403 }
404 #else
405 FILE *fp = setmntent(MOUNTED, "r");
406 struct mntent mnt;
407 char buffer[1024];
408 int index = 1;
409
410 strncpy(buf, "Unknown", len);
411
412 if(fp)
413 {
414 while(getmntent_r(fp, &mnt, buffer, sizeof(buffer)))
415 {
416 if(index == drive && mnt.mnt_dir)
417 strncpy(buf, mnt.mnt_dir, len);
418 index++;
419 }
420 endmntent(fp);
421 }
422 #endif
423 #elif defined(__OS2__)
424 /* No snprintf() on OS/2 ??? */
425 len = len;
426 sprintf(buf, "Drive %c", (char)drive + 'A' - 1);
427 #else
428 _snprintf(buf, len, "Drive %c", (char)drive + 'A' - 1);
429 #endif
430 }
431
432 void API setfileinfo(char *filename, char *url, char *logfile)
433 {
434 time_t ltime;
435 struct tm *tm;
436 char buffer[200], timebuf[200];
437 #ifdef __OS2__
438 const unsigned fea2listsize = 6000;
439 char *pData;
440 EAOP2 eaop2;
441 PFEA2 pFEA2;
442 #else
443 FILE *urlfile;
444 #endif
445
446 ltime = time(NULL);
447
448 tm = localtime(&ltime);
449
450 strftime(timebuf, 200, "%c", tm);
451
452 sprintf(buffer, "%s %s", url, timebuf);
453
454 #ifdef __OS2__
455 logfile = logfile;
456 eaop2.fpGEA2List = 0;
457 eaop2.fpFEA2List = (PFEA2LIST)malloc(fea2listsize);
458 pFEA2 = &eaop2.fpFEA2List->list[0];
459
460 pFEA2->fEA = 0;
461 /* .COMMENTS is 9 characters long */
462 pFEA2->cbName = 9;
463
464 /* space for the type and length field. */
465 pFEA2->cbValue = strlen(buffer)+2*sizeof(USHORT);
466
467 strcpy(pFEA2->szName, ".COMMENTS");
468 pData = pFEA2->szName+pFEA2->cbName+1;
469 /* data begins at first byte after the name */
470
471 *(USHORT*)pData = EAT_ASCII; /* type */
472 *((USHORT*)pData+1) = strlen(buffer); /* length */
473 strcpy(pData+2*sizeof(USHORT), buffer);/* content */
474
475 pFEA2->oNextEntryOffset = 0;
476
477 eaop2.fpFEA2List->cbList = ((PCHAR)pData+2*sizeof(USHORT)+
478 pFEA2->cbValue)-((PCHAR)eaop2.fpFEA2List);
479
480 DosSetPathInfo((PSZ)filename,
481 FIL_QUERYEASIZE,
482 &eaop2,
483 sizeof(eaop2),
484 0);
485
486 free((void *)eaop2.fpFEA2List);
487 #else
488
489 if((urlfile = fopen(logfile, "a"))!=NULL)
490 {
491 fprintf(urlfile, "%s\n", buffer);
492 fclose(urlfile);
493 }
494 #endif
495 }
496
497 #if defined(__OS2__) || defined(__WIN32__)
498 typedef struct _fsinfo {
499 FILE *fp;
500 int fd;
501 } FSInfo;
502
503 FSInfo *FSIRoot = NULL;
504
505 #define FSI_MAX 100
506 #endif
507
508 /* Sharable fopen() and fclose() calls. */
509 FILE * API fsopen(char *path, char *modes)
510 {
511 #if (defined(__OS2__) && !defined(__WATCOMC__)) || defined(__WIN32__)
512 int z;
513
514 if(!FSIRoot)
515 FSIRoot = calloc(sizeof(struct _fsinfo), FSI_MAX);
516
517 for(z=0;z<FSI_MAX;z++)
518 {
519 if(FSIRoot[z].fd < 1)
520 {
521 int s, sopenmode = 0, wrmode = 0;
522
523 /* Check the flags passed */
524 for(s=0;s<3;s++)
525 {
526 if(modes[s] == 'b')
527 sopenmode |= O_BINARY;
528 if(modes[s] == 'r')
529 wrmode |= O_RDONLY;
530 if(modes[s] == 'w')
531 wrmode |= O_WRONLY;
532 if(modes[s] == 'a')
533 sopenmode |= O_APPEND;
534 if(modes[s] == 't')
535 sopenmode |= O_TEXT;
536 }
537
538 /* Check the read/write request */
539 if((wrmode & O_RDONLY) && (wrmode & O_WRONLY))
540 sopenmode |= O_RDWR;
541 else
542 sopenmode |= wrmode;
543 FSIRoot[z].fd = _sopen(path, sopenmode, SH_DENYNO, S_IREAD|S_IWRITE);
544 if(FSIRoot[z].fd > 0)
545 {
546 FSIRoot[z].fp = fdopen(FSIRoot[z].fd, modes);
547
548 return FSIRoot[z].fp;
549 }
550 }
551 }
552 return NULL;
553 #else
554 return fopen(path, modes);
555 #endif
556 }
557
558 int API fsclose(FILE *fp)
559 {
560 #if defined(__OS2__) || defined(__WIN32__)
561 if(FSIRoot)
562 {
563
564 int z;
565 for(z=0;z<FSI_MAX;z++)
566 {
567 if(fp == FSIRoot[z].fp)
568 {
569 int ret = fclose(fp);
570 close(FSIRoot[z].fd);
571 FSIRoot[z].fd = 0;
572 FSIRoot[z].fp = NULL;
573 return ret;
574 }
575 }
576 }
577 #endif
578 return fclose(fp);
579 }
580
581 char * API fsgets(char *str, int size, FILE *stream)
582 {
583 return fgets(str, size, stream);
584 }
585
586 int API fsseek(FILE *stream, long offset, int whence)
587 {
588 return fseek(stream, offset, whence);
589 }
590
591 void API nice_strformat(char *dest, long double val, int dec)
592 {
593 char formatbuf[10];
594 char format = 0;
595 double printval;
596
597 /* 1024 ^ 3 = Gigabytes */
598 if(val >= 1073741824L)
599 {
600 printval = val/(1073741824L);
601 format = 'G';
602 }
603 /* 1024 ^ 2 = Megabytes */
604 else if(val >= 1048576)
605 {
606 printval = val/(1048576);
607 format = 'M';
608 }
609 /* 1024 = Kilobytes */
610 else if(val > 1024)
611 {
612 printval = val/1024;
613 format = 'K';
614 }
615 else
616 printval = val;
617
618 /* Generate the format string */
619 sprintf(formatbuf, "%%.%df%c", dec, format);
620 /* Create the pretty value */
621 sprintf(dest, formatbuf, printval);
622 }
623
624 /* Update the current working directory based on the
625 * path of the executable being executed.
626 */
627 void API initdir(int argc, char *argv[])
628 {
629 if(argc > 0)
630 {
631 char *tmpdir = strdup(argv[0]);
632 int z, len = (int)strlen(argv[0]);
633
634 for(z=len;z > -1;z--)
635 {
636 if(tmpdir[z] == '/')
637 {
638 tmpdir[z+1] = 0;
639 setpath(tmpdir);
640 free(tmpdir);
641 return;
642 }
643 }
644 free(tmpdir);
645 }
646 }
647
648 /*
649 * Sets the current directory (and drive) information.
650 * Parameters:
651 * path: A buffer containing the new path.
652 * Returns:
653 * -1 on error.
654 */
655 int API setpath(char *path)
656 {
657 #if defined(__OS2__) || defined(__WIN32__)
658 if(strlen(path) > 2)
659 {
660 if(path[1] == ':')
661 {
662 char drive = toupper(path[0]);
663 _chdrive((drive - 'A')+1);
664 }
665 }
666 #endif
667 return chdir(path);
668 }
669
670 static int locale_number = -1, locale_count = 0;
671 static char **locale_text = NULL;
672
673 void _compat_free_locale(void)
674 {
675 if(locale_text)
676 {
677 int z;
678
679 for(z=0;z<locale_count;z++)
680 {
681 if(locale_text[z])
682 free(locale_text[z]);
683 }
684 free(locale_text);
685 locale_text = NULL;
686 }
687 }
688
689 int _stripcrlf(char *buf)
690 {
691 int z, len = (int)strlen(buf);
692
693 for(z=0;z<len;z++)
694 {
695 if(buf[z] == '\r' || buf[z] == '\n')
696 {
697 buf[z] = 0;
698 return 1;
699 }
700 }
701 return 1;
702 }
703
704 #ifdef __WIN32__
705 #define LOCALE_CHARACTERS 62
706 static char locale_table[LOCALE_CHARACTERS * 2] = {
707 0xc0, 0xb7, 0xc1, 0xb5, 0xc2, 0xb6, 0xc3, 0xc7, 0xc4, 0x8e, 0xc5, 0x8f,
708 0xc6, 0x92, 0xc7, 0x80, 0xc8, 0xd4, 0xc9, 0x90, 0xcb, 0xd3, 0xcc, 0xde,
709 0xcd, 0xd6, 0xce, 0xd7, 0xcf, 0xd8, 0xd0, 0xd1, 0xd1, 0xa5, 0xd2, 0xe3,
710 0xd3, 0xe0, 0xd4, 0xe2, 0xd5, 0xe5, 0xd6, 0x99, 0xd8, 0x9d, 0xd9, 0xeb,
711 0xda, 0xe9, 0xdb, 0xea, 0xdc, 0x9a, 0xde, 0xed, 0xde, 0xe8, 0xdf, 0xe1,
712 0xe0, 0x85, 0xe1, 0xa0, 0xe2, 0x83, 0xe3, 0xc6, 0xe4, 0x84, 0xe5, 0x86,
713 0xe6, 0x91, 0xe7, 0x87, 0xe8, 0x8a, 0xe9, 0x82, 0xea, 0x88, 0xeb, 0x89,
714 0xec, 0x8d, 0xed, 0xa1, 0xee, 0x8c, 0xef, 0x8b, 0xf0, 0xd0, 0xf1, 0xa4,
715 0xf2, 0x95, 0xf3, 0xa3, 0xf4, 0x93, 0xf5, 0xe4, 0xf6, 0x94, 0xf7, 0xf6,
716 0xf8, 0x9b, 0xf9, 0x97, 0xfa, 0xa3, 0xfb, 0x96, 0xfc, 0x81, 0xfd, 0xec,
717 0xfe, 0xe7, 0xff, 0x9e
718
719 };
720
721 char locale_convert(int codepage, char c)
722 {
723 int z;
724
725 for(z=0;z<LOCALE_CHARACTERS;z++)
726 {
727 if(locale_table[(z*2)+1] == c)
728 return locale_table[z*2];
729 }
730 return c;
731 }
732 #endif
733
734 /* Initialize the locale engine
735 * Returns: TRUE on success, FALSE on failure.
736 */
737 int API locale_init(char *filename, int my_locale)
738 {
739 FILE *fp = fopen(filename, FOPEN_READ_TEXT);
740 static char text[1025];
741 int count = 0;
742
743 _compat_free_locale();
744
745 if(fp)
746 {
747 if(fgets(text, 1024, fp) && strncasecmp(text, "MESSAGES=", 9) == 0 && (count = atoi(&text[9])) > 0)
748 {
749 int current = -1;
750
751 locale_text = calloc(count, sizeof(char *));
752
753 while(!feof(fp))
754 {
755 if(fgets(text, 1024, fp) && _stripcrlf(text) &&
756 strncasecmp(text, "LOCALE=", 7) == 0)
757 {
758 if(current > -1)
759 {
760 fclose(fp);
761 locale_count = count;
762 locale_number = my_locale;
763 return 1;
764 }
765 if(atoi(&text[7]) == my_locale)
766 current = 0;
767 }
768 else if(current > -1 && current < count)
769 {
770 /* Use defaults on blank lines */
771 if(text[0])
772 {
773 int x = 0, z, len = (int)strlen(text);
774
775 locale_text[current] = calloc(1, len + 1);
776
777 for(z=0;z<len;z++)
778 {
779 if(text[z] == '\\' && (text[z+1] == 'r' || text[z+1] == 'n'
780 || text[z+1] == '\"' || text[z+1] == '\''))
781 {
782 switch(text[z+1])
783 {
784 case 'r':
785 locale_text[current][x] = '\r';
786 break;
787 case 'n':
788 locale_text[current][x] = '\n';
789 break;
790 case '\"':
791 locale_text[current][x] = '\"';
792 break;
793 case '\'':
794 locale_text[current][x] = '\'';
795 break;
796 }
797 x++;
798 z++;
799 }
800 else
801 {
802 #ifdef __WIN32__
803 locale_text[current][x] = locale_convert(1252, text[z]);
804 #else
805 locale_text[current][x] = text[z];
806 #endif
807 x++;
808 }
809 }
810 }
811 current++;
812 }
813 }
814 }
815 fclose(fp);
816 }
817 if(locale_text && count)
818 {
819 locale_count = count;
820 locale_number = my_locale;
821 return 1;
822 }
823 return 0;
824 }
825
826 /* Retrieve a localized string if available */
827 char * API locale_string(char *default_text, int message)
828 {
829 if(locale_number > -1 && message < locale_count && message > -1 && locale_text[message])
830 return locale_text[message];
831 return default_text;
832 }
833