]> git.saurik.com Git - wxWidgets.git/blob - src/common/utilscmn.cpp
Added Property List classes to main library; added proplist sample; merged
[wxWidgets.git] / src / common / utilscmn.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: utilscmn.cpp
3 // Purpose: Miscellaneous utility functions and classes
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 29/01/98
7 // RCS-ID: $Id$
8 // Copyright: (c) 1998 Julian Smart
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation "utils.h"
14 #endif
15
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
18
19 #ifdef __BORLANDC__
20 #pragma hdrstop
21 #endif
22
23 #ifndef WX_PRECOMP
24 #include "wx/defs.h"
25 #include "wx/utils.h"
26 #include "wx/window.h"
27 #include "wx/menu.h"
28 #include "wx/frame.h"
29 #include "wx/msgdlg.h"
30 #include "wx/textdlg.h"
31 #endif
32
33 #if wxUSE_IOSTREAMH
34 #include <iostream.h>
35 #include <fstream.h>
36 #else
37 #include <iostream>
38 #include <fstream>
39 # ifdef _MSC_VER
40 using namespace std;
41 # endif
42 #endif
43
44 #include <ctype.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #if !defined(__WATCOMC__)
49 #if !(defined(_MSC_VER) && (_MSC_VER > 800))
50 #include <errno.h>
51 #endif
52 #endif
53 #include <time.h>
54 #ifndef __MWERKS__
55 #include <sys/types.h>
56 #include <sys/stat.h>
57 #endif
58
59 // Pattern matching code.
60 // Yes, this path is deliberate (for Borland compilation)
61 #ifdef wx_mac /* MATTHEW: [5] Mac doesn't like paths with "/" */
62 #include "glob.inc"
63 #else
64 #include "../common/glob.inc"
65 #endif
66
67 #ifdef __WXMSW__
68 #include "windows.h"
69 #endif
70
71 #define _MAXPATHLEN 500
72
73 extern char *wxBuffer;
74
75 #ifdef __VMS__
76 // we have no strI functions under VMS, therefore I have implemented
77 // an inefficient but portable version: convert copies of strings to lowercase
78 // and then use the normal comparison
79 static void myLowerString(char *s)
80 {
81 while(*s){
82 if(isalpha(*s)) *s = (char)tolower(*s);
83 s++;
84 }
85 }
86
87 int strcasecmp(const char *str_1, const char *str_2)
88 {
89 char *temp1 = new char[strlen(str_1)+1];
90 char *temp2 = new char[strlen(str_2)+1];
91 strcpy(temp1,str_1);
92 strcpy(temp2,str_2);
93 myLowerString(temp1);
94 myLowerString(temp2);
95
96 int result = strcmp(temp1,temp2);
97 delete[] temp1;
98 delete[] temp2;
99
100 return(result);
101 }
102
103 int strncasecmp(const char *str_1, const char *str_2, size_t maxchar)
104 {
105 char *temp1 = new char[strlen(str_1)+1];
106 char *temp2 = new char[strlen(str_2)+1];
107 strcpy(temp1,str_1);
108 strcpy(temp2,str_2);
109 myLowerString(temp1);
110 myLowerString(temp2);
111
112 int result = strncmp(temp1,temp2,maxchar);
113 delete[] temp1;
114 delete[] temp2;
115
116 return(result);
117 }
118 #endif
119
120 #ifdef __WINDOWS__
121
122 #ifndef __GNUWIN32__
123 #ifndef __MWERKS__
124 #define strcasecmp stricmp
125 #define strncasecmp strnicmp
126 #else
127 #define strcasecmp _stricmp
128 #define strncasecmp _strnicmp
129 #endif
130 #endif
131
132 #ifdef _MSC_VER
133 #pragma warning (disable : 4245)
134 #endif
135
136 #ifdef _MSC_VER
137 #pragma warning (default : 4245)
138 #endif
139
140 #else
141 // This declaration is missing in SunOS!
142 // (Yes, I know it is NOT ANSI-C but its in BSD libc)
143 #if defined(__xlC) || defined(__AIX__) || defined(__GNUG__)
144 extern "C"
145 {
146 int strcasecmp (const char *, const char *);
147 int strncasecmp (const char *, const char *, size_t);
148 }
149 #endif
150 #endif /* __WXMSW__ */
151
152
153 char *
154 copystring (const char *s)
155 {
156 if (s == NULL) s = "";
157 size_t len = strlen (s) + 1;
158
159 char *news = new char[len];
160 memcpy (news, s, len); // Should be the fastest
161
162 return news;
163 }
164
165 // Id generation
166 static long wxCurrentId = 100;
167
168 long
169 wxNewId (void)
170 {
171 return wxCurrentId++;
172 }
173
174 long
175 wxGetCurrentId(void) { return wxCurrentId; }
176
177 void
178 wxRegisterId (long id)
179 {
180 if (id >= wxCurrentId)
181 wxCurrentId = id + 1;
182 }
183
184 void
185 StringToFloat (char *s, float *number)
186 {
187 if (s && *s && number)
188 *number = (float) strtod (s, (char **) NULL);
189 }
190
191 void
192 StringToDouble (char *s, double *number)
193 {
194 if (s && *s && number)
195 *number = strtod (s, (char **) NULL);
196 }
197
198 char *
199 FloatToString (float number, const char *fmt)
200 {
201 static char buf[256];
202
203 // sprintf (buf, "%.2f", number);
204 sprintf (buf, fmt, number);
205 return buf;
206 }
207
208 char *
209 DoubleToString (double number, const char *fmt)
210 {
211 static char buf[256];
212
213 sprintf (buf, fmt, number);
214 return buf;
215 }
216
217 void
218 StringToInt (char *s, int *number)
219 {
220 if (s && *s && number)
221 *number = (int) strtol (s, (char **) NULL, 10);
222 }
223
224 void
225 StringToLong (char *s, long *number)
226 {
227 if (s && *s && number)
228 *number = strtol (s, (char **) NULL, 10);
229 }
230
231 char *
232 IntToString (int number)
233 {
234 static char buf[20];
235
236 sprintf (buf, "%d", number);
237 return buf;
238 }
239
240 char *
241 LongToString (long number)
242 {
243 static char buf[20];
244
245 sprintf (buf, "%ld", number);
246 return buf;
247 }
248
249 // Array used in DecToHex conversion routine.
250 static char hexArray[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B',
251 'C', 'D', 'E', 'F' };
252
253 // Convert 2-digit hex number to decimal
254 int wxHexToDec(const wxString& buf)
255 {
256 int firstDigit, secondDigit;
257
258 if (buf.GetChar(0) >= 'A')
259 firstDigit = buf.GetChar(0) - 'A' + 10;
260 else
261 firstDigit = buf.GetChar(0) - '0';
262
263 if (buf.GetChar(1) >= 'A')
264 secondDigit = buf.GetChar(1) - 'A' + 10;
265 else
266 secondDigit = buf.GetChar(1) - '0';
267
268 return firstDigit * 16 + secondDigit;
269 }
270
271 // Convert decimal integer to 2-character hex string
272 void wxDecToHex(int dec, char *buf)
273 {
274 int firstDigit = (int)(dec/16.0);
275 int secondDigit = (int)(dec - (firstDigit*16.0));
276 buf[0] = hexArray[firstDigit];
277 buf[1] = hexArray[secondDigit];
278 buf[2] = 0;
279 }
280
281 // Convert decimal integer to 2-character hex string
282 wxString wxDecToHex(int dec)
283 {
284 char buf[3];
285 wxDecToHex(dec, buf);
286 return wxString(buf);
287 }
288
289 // Match a string INDEPENDENT OF CASE
290 bool
291 StringMatch (char *str1, char *str2, bool subString, bool exact)
292 {
293 if (str1 == NULL || str2 == NULL)
294 return FALSE;
295 if (str1 == str2)
296 return TRUE;
297
298 if (subString)
299 {
300 int len1 = strlen (str1);
301 int len2 = strlen (str2);
302 int i;
303
304 // Search for str1 in str2
305 // Slow .... but acceptable for short strings
306 for (i = 0; i <= len2 - len1; i++)
307 {
308 if (strncasecmp (str1, str2 + i, len1) == 0)
309 return TRUE;
310 }
311 }
312 else if (exact)
313 {
314 if (strcasecmp (str1, str2) == 0)
315 return TRUE;
316 }
317 else
318 {
319 int len1 = strlen (str1);
320 int len2 = strlen (str2);
321
322 if (strncasecmp (str1, str2, wxMin (len1, len2)) == 0)
323 return TRUE;
324 }
325
326 return FALSE;
327 }
328
329 // Return the current date/time
330 // [volatile]
331 wxString wxNow( void )
332 {
333 time_t now = time((time_t *) NULL);
334 char *date = ctime(&now);
335 date[24] = '\0';
336 return wxString(date);
337 }
338
339 /* Get Full RFC822 style email address */
340 bool
341 wxGetEmailAddress (char *address, int maxSize)
342 {
343 char host[65];
344 char user[65];
345
346 if (wxGetHostName(host, 64) == FALSE)
347 return FALSE;
348 if (wxGetUserId(user, 64) == FALSE)
349 return FALSE;
350
351 char tmp[130];
352 strcpy(tmp, user);
353 strcat(tmp, "@");
354 strcat(tmp, host);
355
356 strncpy(address, tmp, maxSize - 1);
357 address[maxSize-1] = '\0';
358 return TRUE;
359 }
360
361 /*
362 * Strip out any menu codes
363 */
364
365 char *wxStripMenuCodes (char *in, char *out)
366 {
367 if (!in)
368 return (char *) NULL;
369
370 if (!out)
371 out = copystring(in);
372
373 char *tmpOut = out;
374
375 while (*in)
376 {
377 if (*in == '&')
378 {
379 // Check && -> &, &x -> x
380 if (*++in == '&')
381 *out++ = *in++;
382 }
383 else if (*in == '\t')
384 {
385 // Remove all stuff after \t in X mode, and let the stuff as is
386 // in Windows mode.
387 // Accelerators are handled in wx_item.cc for Motif, and are not
388 // YET supported in XView
389 break;
390 }
391 else
392 *out++ = *in++;
393 } // while
394
395 *out = '\0';
396
397 return tmpOut;
398 }
399
400 wxString wxStripMenuCodes(const wxString& str)
401 {
402 char *buf = new char[str.Length() + 1];
403 wxStripMenuCodes((char*) (const char*) str, buf);
404 wxString str1(buf);
405 delete[] buf;
406 return str1;
407 }
408
409 /*
410 * Window search functions
411 *
412 */
413
414 /*
415 * If parent is non-NULL, look through children for a label or title
416 * matching the specified string. If NULL, look through all top-level windows.
417 *
418 */
419
420 static wxWindow *wxFindWindowByLabel1 (const wxString& title, wxWindow * parent);
421
422 wxWindow *
423 wxFindWindowByLabel (const wxString& title, wxWindow * parent)
424 {
425 if (parent)
426 {
427 return wxFindWindowByLabel1 (title, parent);
428 }
429 else
430 {
431 for (wxNode * node = wxTopLevelWindows.First (); node; node = node->Next ())
432 {
433 wxWindow *win = (wxWindow *) node->Data ();
434 wxWindow *retwin = wxFindWindowByLabel1 (title, win);
435 if (retwin)
436 return retwin;
437 } // for()
438
439 }
440 return (wxWindow *) NULL;
441 }
442
443 // Recursive
444 static wxWindow *
445 wxFindWindowByLabel1 (const wxString& title, wxWindow * parent)
446 {
447 if (parent)
448 {
449 if (parent->GetLabel() == title)
450 return parent;
451 }
452
453 if (parent)
454 {
455 for (wxNode * node = parent->GetChildren().First (); node; node = node->Next ())
456 {
457 wxWindow *win = (wxWindow *) node->Data ();
458 wxWindow *retwin = wxFindWindowByLabel1 (title, win);
459 if (retwin)
460 return retwin;
461 } // for()
462
463 }
464
465 return (wxWindow *) NULL; // Not found
466
467 }
468
469 /*
470 * If parent is non-NULL, look through children for a name
471 * matching the specified string. If NULL, look through all top-level windows.
472 *
473 */
474
475 static wxWindow *wxFindWindowByName1 (const wxString& title, wxWindow * parent);
476
477 wxWindow *
478 wxFindWindowByName (const wxString& title, wxWindow * parent)
479 {
480 if (parent)
481 {
482 return wxFindWindowByName1 (title, parent);
483 }
484 else
485 {
486 for (wxNode * node = wxTopLevelWindows.First (); node; node = node->Next ())
487 {
488 wxWindow *win = (wxWindow *) node->Data ();
489 wxWindow *retwin = wxFindWindowByName1 (title, win);
490 if (retwin)
491 return retwin;
492 } // for()
493
494 }
495 // Failed? Try by label instead.
496 return wxFindWindowByLabel(title, parent);
497 }
498
499 // Recursive
500 static wxWindow *
501 wxFindWindowByName1 (const wxString& title, wxWindow * parent)
502 {
503 if (parent)
504 {
505 if ( parent->GetName() == title )
506 return parent;
507 }
508
509 if (parent)
510 {
511 for (wxNode * node = parent->GetChildren().First (); node; node = node->Next ())
512 {
513 wxWindow *win = (wxWindow *) node->Data ();
514 wxWindow *retwin = wxFindWindowByName1 (title, win);
515 if (retwin)
516 return retwin;
517 } // for()
518
519 }
520
521 return (wxWindow *) NULL; // Not found
522
523 }
524
525 // Returns menu item id or -1 if none.
526 int
527 wxFindMenuItemId (wxFrame * frame, const wxString& menuString, const wxString& itemString)
528 {
529 wxMenuBar *menuBar = frame->GetMenuBar ();
530 if (!menuBar)
531 return -1;
532 return menuBar->FindMenuItem (menuString, itemString);
533 }
534
535 /*
536 * wxDebugStreamBuf
537 */
538 #if !defined(_WINDLL)
539
540 wxDebugStreamBuf::wxDebugStreamBuf(void)
541 {
542 // <iostream> usage doesn't need this, and i have no idea how to simulate it.
543 #if wxUSE_IOSTREAMH
544 if (allocate())
545 setp(base(),ebuf());
546 #endif
547 }
548
549 int wxDebugStreamBuf::overflow(int WXUNUSED(i))
550 {
551 int len = pptr() - pbase();
552 char *txt = new char[len+1];
553 strncpy(txt, pbase(), len);
554 txt[len] = '\0';
555 #ifdef __WXMSW__
556 OutputDebugString((LPCSTR)txt);
557 #else
558 fprintf(stderr, txt);
559 #endif
560 setp(pbase(), epptr());
561 delete[] txt;
562 return EOF;
563 }
564
565 int wxDebugStreamBuf::sync(void)
566 {
567 int len = pptr() - pbase();
568 char *txt = new char[len+1];
569 strncpy(txt, pbase(), len);
570 txt[len] = '\0';
571 #ifdef __WXMSW__
572 OutputDebugString((LPCSTR)txt);
573 #else
574 fprintf(stderr, txt);
575 #endif
576 setp(pbase(), epptr());
577 delete[] txt;
578 return 0;
579 }
580
581 #endif
582
583 /*
584 On Fri, 21 Jul 1995, Paul Craven wrote:
585
586 > Is there a way to find the path of running program's executable? I can get
587 > my home directory, and the current directory, but I don't know how to get the
588 > executable directory.
589 >
590
591 The code below (warty as it is), does what you want on most Unix,
592 DOS, and Mac platforms (it's from the ALS Prolog main).
593
594 || Ken Bowen Applied Logic Systems, Inc. PO Box 180,
595 ||==== Voice: +1 (617)965-9191 Newton Centre,
596 || FAX: +1 (617)965-1636 MA 02159 USA
597 Email: ken@als.com WWW: http://www.als.com
598 ------------------------------------------------------------------------
599 */
600
601 // This code is commented out but it may be integrated with wxWin at
602 // a later date, after testing. Thanks Ken!
603 #if 0
604
605 /*--------------------------------------------------------------------*
606 | whereami is given a filename f in the form: whereami(argv[0])
607 | It returns the directory in which the executable file (containing
608 | this code [main.c] ) may be found. A dot will be returned to indicate
609 | the current directory.
610 *--------------------------------------------------------------------*/
611
612 static void
613 whereami(name)
614 char *name;
615 {
616 register char *cutoff = NULL; /* stifle -Wall */
617 register char *s;
618 register char *t;
619 int cc;
620 char ebuf[4096];
621
622 /*
623 * See if the file is accessible either through the current directory
624 * or through an absolute path.
625 */
626
627 if (access(name, R_OK) == 0) {
628
629 /*-------------------------------------------------------------*
630 * The file was accessible without any other work. But the current
631 * working directory might change on us, so if it was accessible
632 * through the cwd, then we should get it for later accesses.
633 *-------------------------------------------------------------*/
634
635 t = imagedir;
636 if (!absolute_pathname(name)) {
637 #if defined(DOS) || defined(__WIN32__)
638 int drive;
639 char *newrbuf;
640
641 newrbuf = imagedir;
642 #ifndef __DJGPP__
643 if (*(name + 1) == ':') {
644 if (*name >= 'a' && *name <= 'z')
645 drive = (int) (*name - 'a' + 1);
646 else
647 drive = (int) (*name - 'A' + 1);
648 *newrbuf++ = *name;
649 *newrbuf++ = *(name + 1);
650 *newrbuf++ = DIR_SEPARATOR;
651 }
652 else {
653 drive = 0;
654 *newrbuf++ = DIR_SEPARATOR;
655 }
656 if (getcwd(newrbuf, drive) == 0) { /* } */
657 #else
658 if (getcwd(newrbuf, 1024) == 0) { /* } */
659 #endif
660 #else /* DOS */
661 #ifdef HAVE_GETWD
662 if (getwd(imagedir) == 0) { /* } */
663 #else /* !HAVE_GETWD */
664 if (getcwd(imagedir, 1024) == 0) {
665 #endif /* !HAVE_GETWD */
666 #endif /* DOS */
667 fatal_error(FE_GETCWD, 0);
668 }
669 for (; *t; t++) /* Set t to end of buffer */
670 ;
671 if (*(t - 1) == DIR_SEPARATOR) /* leave slash if already
672 * last char
673 */
674 cutoff = t - 1;
675 else {
676 cutoff = t; /* otherwise put one in */
677 *t++ = DIR_SEPARATOR;
678 }
679 }
680 #if (!defined(__MAC__) && !defined(__DJGPP__) && !defined(__GO32__) && !defined(__WIN32__))
681 else
682 (*t++ = DIR_SEPARATOR);
683 #endif
684
685 /*-------------------------------------------------------------*
686 * Copy the rest of the string and set the cutoff if it was not
687 * already set. If the first character of name is a slash, cutoff
688 * is not presently set but will be on the first iteration of the
689 * loop below.
690 *-------------------------------------------------------------*/
691
692 for ((*name == DIR_SEPARATOR ? (s = name+1) : (s = name));;) {
693 if (*s == DIR_SEPARATOR)
694 cutoff = t;
695 if (!(*t++ = *s++))
696 break;
697 }
698
699 }
700 else {
701
702 /*-------------------------------------------------------------*
703 * Get the path list from the environment. If the path list is
704 * inaccessible for any reason, leave with fatal error.
705 *-------------------------------------------------------------*/
706
707 #ifdef __MAC__
708 if ((s = getenv("Commands")) == (char *) 0)
709 #else
710 if ((s = getenv("PATH")) == (char *) 0)
711 #endif
712 fatal_error(FE_PATH, 0);
713
714 /*
715 * Copy path list into ebuf and set the source pointer to the
716 * beginning of this buffer.
717 */
718
719 strcpy(ebuf, s);
720 s = ebuf;
721
722 for (;;) {
723 t = imagedir;
724 while (*s && *s != PATH_SEPARATOR)
725 *t++ = *s++;
726 if (t > imagedir && *(t - 1) == DIR_SEPARATOR)
727 ; /* do nothing -- slash already is in place */
728 else
729 *t++ = DIR_SEPARATOR; /* put in the slash */
730 cutoff = t - 1; /* set cutoff */
731 strcpy(t, name);
732 if (access(imagedir, R_OK) == 0)
733 break;
734
735 if (*s)
736 s++; /* advance source pointer */
737 else
738 fatal_error(FE_INFND, 0);
739 }
740
741 }
742
743 /*-------------------------------------------------------------*
744 | At this point the full pathname should exist in imagedir and
745 | cutoff should be set to the final slash. We must now determine
746 | whether the file name is a symbolic link or not and chase it down
747 | if it is. Note that we reuse ebuf for getting the link.
748 *-------------------------------------------------------------*/
749
750 #ifdef HAVE_SYMLINK
751 while ((cc = readlink(imagedir, ebuf, 512)) != -1) {
752 ebuf[cc] = 0;
753 s = ebuf;
754 if (*s == DIR_SEPARATOR) {
755 t = imagedir;
756 }
757 else {
758 t = cutoff + 1;
759 }
760 for (;;) {
761 if (*s == DIR_SEPARATOR)
762 cutoff = t; /* mark the last slash seen */
763 if (!(*t++ = *s++)) /* copy the character */
764 break;
765 }
766 }
767
768 #endif /* HAVE_SYMLINK */
769
770 strcpy(imagename, cutoff + 1); /* keep the image name */
771 *(cutoff + 1) = 0; /* chop off the filename part */
772 }
773
774 #endif
775
776 /*
777 * N.B. these convenience functions must be separate from msgdlgg.cpp, textdlgg.cpp
778 * since otherwise the generic code may be pulled in unnecessarily.
779 */
780
781 int wxMessageBox(const wxString& message, const wxString& caption, long style,
782 wxWindow *parent, int WXUNUSED(x), int WXUNUSED(y) )
783 {
784 wxMessageDialog dialog(parent, message, caption, style);
785
786 int ans = dialog.ShowModal();
787 switch ( ans )
788 {
789 case wxID_OK:
790 return wxOK;
791 break;
792 case wxID_YES:
793 return wxYES;
794 break;
795 case wxID_NO:
796 return wxNO;
797 break;
798 default:
799 case wxID_CANCEL:
800 return wxCANCEL;
801 break;
802 }
803 return ans;
804 }
805
806 wxString wxGetTextFromUser(const wxString& message, const wxString& caption,
807 const wxString& defaultValue, wxWindow *parent,
808 int x, int y, bool WXUNUSED(centre) )
809 {
810 wxTextEntryDialog dialog(parent, message, caption, defaultValue, wxOK|wxCANCEL, wxPoint(x, y));
811 if (dialog.ShowModal() == wxID_OK)
812 return dialog.GetValue();
813 else
814 return wxString("");
815 }
816
817 #ifdef __MWERKS__
818 char *strdup(const char *s)
819 {
820 return strcpy( (char*) malloc( strlen( s ) + 1 ) , s ) ;
821 }
822
823 int isascii( int c )
824 {
825 return ( c >= 0 && c < 128 ) ;
826 }
827 #endif