]> git.saurik.com Git - wxWidgets.git/blob - samples/console/console.cpp
Fixed sample so that if the DATETIME test is enabled, then <math.h> is #included...
[wxWidgets.git] / samples / console / console.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: samples/console/console.cpp
3 // Purpose: a sample console (as opposed to GUI) progam using wxWindows
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 04.10.99
7 // RCS-ID: $Id$
8 // Copyright: (c) 1999 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #include <stdio.h>
21
22 #include <wx/string.h>
23 #include <wx/file.h>
24 #include <wx/app.h>
25
26 // without this pragma, the stupid compiler precompiles #defines below so that
27 // changing them doesn't "take place" later!
28 #ifdef __VISUALC__
29 #pragma hdrstop
30 #endif
31
32 // ----------------------------------------------------------------------------
33 // conditional compilation
34 // ----------------------------------------------------------------------------
35
36 // what to test (in alphabetic order)?
37
38 //#define TEST_ARRAYS
39 //#define TEST_CMDLINE
40 #define TEST_DATETIME
41 //#define TEST_DIR
42 //#define TEST_DLLLOADER
43 //#define TEST_ENVIRON
44 //#define TEST_EXECUTE
45 //#define TEST_FILE
46 //#define TEST_FILECONF
47 //#define TEST_FILENAME
48 //#define TEST_FTP
49 //#define TEST_HASH
50 //#define TEST_INFO_FUNCTIONS
51 //#define TEST_LIST
52 //#define TEST_LOG
53 //#define TEST_LONGLONG
54 //#define TEST_MIME
55 //#define TEST_PATHLIST
56 //#define TEST_REGISTRY
57 //#define TEST_SOCKETS
58 //#define TEST_STREAMS
59 //#define TEST_STRINGS
60 //#define TEST_THREADS
61 //#define TEST_TIMER
62 //#define TEST_VCARD -- don't enable this (VZ)
63 //#define TEST_WCHAR
64 #define TEST_ZIP
65 //#define TEST_ZLIB
66
67
68 #ifdef TEST_DATETIME
69 #include <math.h>
70 #endif
71
72
73 // ----------------------------------------------------------------------------
74 // test class for container objects
75 // ----------------------------------------------------------------------------
76
77 #if defined(TEST_ARRAYS) || defined(TEST_LIST)
78
79 class Bar // Foo is already taken in the hash test
80 {
81 public:
82 Bar(const wxString& name) : m_name(name) { ms_bars++; }
83 ~Bar() { ms_bars--; }
84
85 static size_t GetNumber() { return ms_bars; }
86
87 const char *GetName() const { return m_name; }
88
89 private:
90 wxString m_name;
91
92 static size_t ms_bars;
93 };
94
95 size_t Bar::ms_bars = 0;
96
97 #endif // defined(TEST_ARRAYS) || defined(TEST_LIST)
98
99 // ============================================================================
100 // implementation
101 // ============================================================================
102
103 // ----------------------------------------------------------------------------
104 // helper functions
105 // ----------------------------------------------------------------------------
106
107 #if defined(TEST_STRINGS) || defined(TEST_SOCKETS)
108
109 // replace TABs with \t and CRs with \n
110 static wxString MakePrintable(const wxChar *s)
111 {
112 wxString str(s);
113 (void)str.Replace(_T("\t"), _T("\\t"));
114 (void)str.Replace(_T("\n"), _T("\\n"));
115 (void)str.Replace(_T("\r"), _T("\\r"));
116
117 return str;
118 }
119
120 #endif // MakePrintable() is used
121
122 // ----------------------------------------------------------------------------
123 // wxCmdLineParser
124 // ----------------------------------------------------------------------------
125
126 #ifdef TEST_CMDLINE
127
128 #include <wx/cmdline.h>
129 #include <wx/datetime.h>
130
131 static void ShowCmdLine(const wxCmdLineParser& parser)
132 {
133 wxString s = "Input files: ";
134
135 size_t count = parser.GetParamCount();
136 for ( size_t param = 0; param < count; param++ )
137 {
138 s << parser.GetParam(param) << ' ';
139 }
140
141 s << '\n'
142 << "Verbose:\t" << (parser.Found("v") ? "yes" : "no") << '\n'
143 << "Quiet:\t" << (parser.Found("q") ? "yes" : "no") << '\n';
144
145 wxString strVal;
146 long lVal;
147 wxDateTime dt;
148 if ( parser.Found("o", &strVal) )
149 s << "Output file:\t" << strVal << '\n';
150 if ( parser.Found("i", &strVal) )
151 s << "Input dir:\t" << strVal << '\n';
152 if ( parser.Found("s", &lVal) )
153 s << "Size:\t" << lVal << '\n';
154 if ( parser.Found("d", &dt) )
155 s << "Date:\t" << dt.FormatISODate() << '\n';
156 if ( parser.Found("project_name", &strVal) )
157 s << "Project:\t" << strVal << '\n';
158
159 wxLogMessage(s);
160 }
161
162 #endif // TEST_CMDLINE
163
164 // ----------------------------------------------------------------------------
165 // wxDir
166 // ----------------------------------------------------------------------------
167
168 #ifdef TEST_DIR
169
170 #include <wx/dir.h>
171
172 static void TestDirEnumHelper(wxDir& dir,
173 int flags = wxDIR_DEFAULT,
174 const wxString& filespec = wxEmptyString)
175 {
176 wxString filename;
177
178 if ( !dir.IsOpened() )
179 return;
180
181 bool cont = dir.GetFirst(&filename, filespec, flags);
182 while ( cont )
183 {
184 printf("\t%s\n", filename.c_str());
185
186 cont = dir.GetNext(&filename);
187 }
188
189 puts("");
190 }
191
192 static void TestDirEnum()
193 {
194 wxDir dir(wxGetCwd());
195
196 puts("Enumerating everything in current directory:");
197 TestDirEnumHelper(dir);
198
199 puts("Enumerating really everything in current directory:");
200 TestDirEnumHelper(dir, wxDIR_DEFAULT | wxDIR_DOTDOT);
201
202 puts("Enumerating object files in current directory:");
203 TestDirEnumHelper(dir, wxDIR_DEFAULT, "*.o");
204
205 puts("Enumerating directories in current directory:");
206 TestDirEnumHelper(dir, wxDIR_DIRS);
207
208 puts("Enumerating files in current directory:");
209 TestDirEnumHelper(dir, wxDIR_FILES);
210
211 puts("Enumerating files including hidden in current directory:");
212 TestDirEnumHelper(dir, wxDIR_FILES | wxDIR_HIDDEN);
213
214 #ifdef __UNIX__
215 dir.Open("/");
216 #elif defined(__WXMSW__)
217 dir.Open("c:\\");
218 #else
219 #error "don't know where the root directory is"
220 #endif
221
222 puts("Enumerating everything in root directory:");
223 TestDirEnumHelper(dir, wxDIR_DEFAULT);
224
225 puts("Enumerating directories in root directory:");
226 TestDirEnumHelper(dir, wxDIR_DIRS);
227
228 puts("Enumerating files in root directory:");
229 TestDirEnumHelper(dir, wxDIR_FILES);
230
231 puts("Enumerating files including hidden in root directory:");
232 TestDirEnumHelper(dir, wxDIR_FILES | wxDIR_HIDDEN);
233
234 puts("Enumerating files in non existing directory:");
235 wxDir dirNo("nosuchdir");
236 TestDirEnumHelper(dirNo);
237 }
238
239 #endif // TEST_DIR
240
241 // ----------------------------------------------------------------------------
242 // wxDllLoader
243 // ----------------------------------------------------------------------------
244
245 #ifdef TEST_DLLLOADER
246
247 #include <wx/dynlib.h>
248
249 static void TestDllLoad()
250 {
251 #if defined(__WXMSW__)
252 static const wxChar *LIB_NAME = _T("kernel32.dll");
253 static const wxChar *FUNC_NAME = _T("lstrlenA");
254 #elif defined(__UNIX__)
255 // weird: using just libc.so does *not* work!
256 static const wxChar *LIB_NAME = _T("/lib/libc-2.0.7.so");
257 static const wxChar *FUNC_NAME = _T("strlen");
258 #else
259 #error "don't know how to test wxDllLoader on this platform"
260 #endif
261
262 puts("*** testing wxDllLoader ***\n");
263
264 wxDllType dllHandle = wxDllLoader::LoadLibrary(LIB_NAME);
265 if ( !dllHandle )
266 {
267 wxPrintf(_T("ERROR: failed to load '%s'.\n"), LIB_NAME);
268 }
269 else
270 {
271 typedef int (*strlenType)(char *);
272 strlenType pfnStrlen = (strlenType)wxDllLoader::GetSymbol(dllHandle, FUNC_NAME);
273 if ( !pfnStrlen )
274 {
275 wxPrintf(_T("ERROR: function '%s' wasn't found in '%s'.\n"),
276 FUNC_NAME, LIB_NAME);
277 }
278 else
279 {
280 if ( pfnStrlen("foo") != 3 )
281 {
282 wxPrintf(_T("ERROR: loaded function is not strlen()!\n"));
283 }
284 else
285 {
286 puts("... ok");
287 }
288 }
289
290 wxDllLoader::UnloadLibrary(dllHandle);
291 }
292 }
293
294 #endif // TEST_DLLLOADER
295
296 // ----------------------------------------------------------------------------
297 // wxGet/SetEnv
298 // ----------------------------------------------------------------------------
299
300 #ifdef TEST_ENVIRON
301
302 #include <wx/utils.h>
303
304 static wxString MyGetEnv(const wxString& var)
305 {
306 wxString val;
307 if ( !wxGetEnv(var, &val) )
308 val = _T("<empty>");
309 else
310 val = wxString(_T('\'')) + val + _T('\'');
311
312 return val;
313 }
314
315 static void TestEnvironment()
316 {
317 const wxChar *var = _T("wxTestVar");
318
319 puts("*** testing environment access functions ***");
320
321 printf("Initially getenv(%s) = %s\n", var, MyGetEnv(var).c_str());
322 wxSetEnv(var, _T("value for wxTestVar"));
323 printf("After wxSetEnv: getenv(%s) = %s\n", var, MyGetEnv(var).c_str());
324 wxSetEnv(var, _T("another value"));
325 printf("After 2nd wxSetEnv: getenv(%s) = %s\n", var, MyGetEnv(var).c_str());
326 wxUnsetEnv(var);
327 printf("After wxUnsetEnv: getenv(%s) = %s\n", var, MyGetEnv(var).c_str());
328 printf("PATH = %s\n", MyGetEnv(_T("PATH")));
329 }
330
331 #endif // TEST_ENVIRON
332
333 // ----------------------------------------------------------------------------
334 // wxExecute
335 // ----------------------------------------------------------------------------
336
337 #ifdef TEST_EXECUTE
338
339 #include <wx/utils.h>
340
341 static void TestExecute()
342 {
343 puts("*** testing wxExecute ***");
344
345 #ifdef __UNIX__
346 #define COMMAND "cat -n ../../Makefile" // "echo hi"
347 #define SHELL_COMMAND "echo hi from shell"
348 #define REDIRECT_COMMAND COMMAND // "date"
349 #elif defined(__WXMSW__)
350 #define COMMAND "command.com -c 'echo hi'"
351 #define SHELL_COMMAND "echo hi"
352 #define REDIRECT_COMMAND COMMAND
353 #else
354 #error "no command to exec"
355 #endif // OS
356
357 printf("Testing wxShell: ");
358 fflush(stdout);
359 if ( wxShell(SHELL_COMMAND) )
360 puts("Ok.");
361 else
362 puts("ERROR.");
363
364 printf("Testing wxExecute: ");
365 fflush(stdout);
366 if ( wxExecute(COMMAND, TRUE /* sync */) == 0 )
367 puts("Ok.");
368 else
369 puts("ERROR.");
370
371 #if 0 // no, it doesn't work (yet?)
372 printf("Testing async wxExecute: ");
373 fflush(stdout);
374 if ( wxExecute(COMMAND) != 0 )
375 puts("Ok (command launched).");
376 else
377 puts("ERROR.");
378 #endif // 0
379
380 printf("Testing wxExecute with redirection:\n");
381 wxArrayString output;
382 if ( wxExecute(REDIRECT_COMMAND, output) != 0 )
383 {
384 puts("ERROR.");
385 }
386 else
387 {
388 size_t count = output.GetCount();
389 for ( size_t n = 0; n < count; n++ )
390 {
391 printf("\t%s\n", output[n].c_str());
392 }
393
394 puts("Ok.");
395 }
396 }
397
398 #endif // TEST_EXECUTE
399
400 // ----------------------------------------------------------------------------
401 // file
402 // ----------------------------------------------------------------------------
403
404 #ifdef TEST_FILE
405
406 #include <wx/file.h>
407 #include <wx/ffile.h>
408 #include <wx/textfile.h>
409
410 static void TestFileRead()
411 {
412 puts("*** wxFile read test ***");
413
414 wxFile file(_T("testdata.fc"));
415 if ( file.IsOpened() )
416 {
417 printf("File length: %lu\n", file.Length());
418
419 puts("File dump:\n----------");
420
421 static const off_t len = 1024;
422 char buf[len];
423 for ( ;; )
424 {
425 off_t nRead = file.Read(buf, len);
426 if ( nRead == wxInvalidOffset )
427 {
428 printf("Failed to read the file.");
429 break;
430 }
431
432 fwrite(buf, nRead, 1, stdout);
433
434 if ( nRead < len )
435 break;
436 }
437
438 puts("----------");
439 }
440 else
441 {
442 printf("ERROR: can't open test file.\n");
443 }
444
445 puts("");
446 }
447
448 static void TestTextFileRead()
449 {
450 puts("*** wxTextFile read test ***");
451
452 wxTextFile file(_T("testdata.fc"));
453 if ( file.Open() )
454 {
455 printf("Number of lines: %u\n", file.GetLineCount());
456 printf("Last line: '%s'\n", file.GetLastLine().c_str());
457
458 wxString s;
459
460 puts("\nDumping the entire file:");
461 for ( s = file.GetFirstLine(); !file.Eof(); s = file.GetNextLine() )
462 {
463 printf("%6u: %s\n", file.GetCurrentLine() + 1, s.c_str());
464 }
465 printf("%6u: %s\n", file.GetCurrentLine() + 1, s.c_str());
466
467 puts("\nAnd now backwards:");
468 for ( s = file.GetLastLine();
469 file.GetCurrentLine() != 0;
470 s = file.GetPrevLine() )
471 {
472 printf("%6u: %s\n", file.GetCurrentLine() + 1, s.c_str());
473 }
474 printf("%6u: %s\n", file.GetCurrentLine() + 1, s.c_str());
475 }
476 else
477 {
478 printf("ERROR: can't open '%s'\n", file.GetName());
479 }
480
481 puts("");
482 }
483
484 static void TestFileCopy()
485 {
486 puts("*** Testing wxCopyFile ***");
487
488 static const wxChar *filename1 = _T("testdata.fc");
489 static const wxChar *filename2 = _T("test2");
490 if ( !wxCopyFile(filename1, filename2) )
491 {
492 puts("ERROR: failed to copy file");
493 }
494 else
495 {
496 wxFFile f1(filename1, "rb"),
497 f2(filename2, "rb");
498
499 if ( !f1.IsOpened() || !f2.IsOpened() )
500 {
501 puts("ERROR: failed to open file(s)");
502 }
503 else
504 {
505 wxString s1, s2;
506 if ( !f1.ReadAll(&s1) || !f2.ReadAll(&s2) )
507 {
508 puts("ERROR: failed to read file(s)");
509 }
510 else
511 {
512 if ( (s1.length() != s2.length()) ||
513 (memcmp(s1.c_str(), s2.c_str(), s1.length()) != 0) )
514 {
515 puts("ERROR: copy error!");
516 }
517 else
518 {
519 puts("File was copied ok.");
520 }
521 }
522 }
523 }
524
525 if ( !wxRemoveFile(filename2) )
526 {
527 puts("ERROR: failed to remove the file");
528 }
529
530 puts("");
531 }
532
533 #endif // TEST_FILE
534
535 // ----------------------------------------------------------------------------
536 // wxFileConfig
537 // ----------------------------------------------------------------------------
538
539 #ifdef TEST_FILECONF
540
541 #include <wx/confbase.h>
542 #include <wx/fileconf.h>
543
544 static const struct FileConfTestData
545 {
546 const wxChar *name; // value name
547 const wxChar *value; // the value from the file
548 } fcTestData[] =
549 {
550 { _T("value1"), _T("one") },
551 { _T("value2"), _T("two") },
552 { _T("novalue"), _T("default") },
553 };
554
555 static void TestFileConfRead()
556 {
557 puts("*** testing wxFileConfig loading/reading ***");
558
559 wxFileConfig fileconf(_T("test"), wxEmptyString,
560 _T("testdata.fc"), wxEmptyString,
561 wxCONFIG_USE_RELATIVE_PATH);
562
563 // test simple reading
564 puts("\nReading config file:");
565 wxString defValue(_T("default")), value;
566 for ( size_t n = 0; n < WXSIZEOF(fcTestData); n++ )
567 {
568 const FileConfTestData& data = fcTestData[n];
569 value = fileconf.Read(data.name, defValue);
570 printf("\t%s = %s ", data.name, value.c_str());
571 if ( value == data.value )
572 {
573 puts("(ok)");
574 }
575 else
576 {
577 printf("(ERROR: should be %s)\n", data.value);
578 }
579 }
580
581 // test enumerating the entries
582 puts("\nEnumerating all root entries:");
583 long dummy;
584 wxString name;
585 bool cont = fileconf.GetFirstEntry(name, dummy);
586 while ( cont )
587 {
588 printf("\t%s = %s\n",
589 name.c_str(),
590 fileconf.Read(name.c_str(), _T("ERROR")).c_str());
591
592 cont = fileconf.GetNextEntry(name, dummy);
593 }
594 }
595
596 #endif // TEST_FILECONF
597
598 // ----------------------------------------------------------------------------
599 // wxFileName
600 // ----------------------------------------------------------------------------
601
602 #ifdef TEST_FILENAME
603
604 #include <wx/filename.h>
605
606 static struct FileNameInfo
607 {
608 const wxChar *fullname;
609 const wxChar *path;
610 const wxChar *name;
611 const wxChar *ext;
612 } filenames[] =
613 {
614 { _T("/usr/bin/ls"), _T("/usr/bin"), _T("ls"), _T("") },
615 { _T("/usr/bin/"), _T("/usr/bin"), _T(""), _T("") },
616 { _T("~/.zshrc"), _T("~"), _T(".zshrc"), _T("") },
617 { _T("../../foo"), _T("../.."), _T("foo"), _T("") },
618 { _T("foo.bar"), _T(""), _T("foo"), _T("bar") },
619 { _T("~/foo.bar"), _T("~"), _T("foo"), _T("bar") },
620 { _T("Mahogany-0.60/foo.bar"), _T("Mahogany-0.60"), _T("foo"), _T("bar") },
621 { _T("/tmp/wxwin.tar.bz"), _T("/tmp"), _T("wxwin.tar"), _T("bz") },
622 };
623
624 static void TestFileNameConstruction()
625 {
626 puts("*** testing wxFileName construction ***");
627
628 for ( size_t n = 0; n < WXSIZEOF(filenames); n++ )
629 {
630 wxFileName fn(filenames[n].fullname, wxPATH_UNIX);
631
632 printf("Filename: '%s'\t", fn.GetFullPath().c_str());
633 if ( !fn.Normalize(wxPATH_NORM_ALL, _T(""), wxPATH_UNIX) )
634 {
635 puts("ERROR (couldn't be normalized)");
636 }
637 else
638 {
639 printf("normalized: '%s'\n", fn.GetFullPath().c_str());
640 }
641 }
642
643 puts("");
644 }
645
646 static void TestFileNameSplit()
647 {
648 puts("*** testing wxFileName splitting ***");
649
650 for ( size_t n = 0; n < WXSIZEOF(filenames); n++ )
651 {
652 const FileNameInfo &fni = filenames[n];
653 wxString path, name, ext;
654 wxFileName::SplitPath(fni.fullname, &path, &name, &ext);
655
656 printf("%s -> path = '%s', name = '%s', ext = '%s'",
657 fni.fullname, path.c_str(), name.c_str(), ext.c_str());
658 if ( path != fni.path )
659 printf(" (ERROR: path = '%s')", fni.path);
660 if ( name != fni.name )
661 printf(" (ERROR: name = '%s')", fni.name);
662 if ( ext != fni.ext )
663 printf(" (ERROR: ext = '%s')", fni.ext);
664 puts("");
665 }
666
667 puts("");
668 }
669
670 static void TestFileNameComparison()
671 {
672 // TODO!
673 }
674
675 static void TestFileNameOperations()
676 {
677 // TODO!
678 }
679
680 static void TestFileNameCwd()
681 {
682 // TODO!
683 }
684
685 #endif // TEST_FILENAME
686
687 // ----------------------------------------------------------------------------
688 // wxHashTable
689 // ----------------------------------------------------------------------------
690
691 #ifdef TEST_HASH
692
693 #include <wx/hash.h>
694
695 struct Foo
696 {
697 Foo(int n_) { n = n_; count++; }
698 ~Foo() { count--; }
699
700 int n;
701
702 static size_t count;
703 };
704
705 size_t Foo::count = 0;
706
707 WX_DECLARE_LIST(Foo, wxListFoos);
708 WX_DECLARE_HASH(Foo, wxListFoos, wxHashFoos);
709
710 #include <wx/listimpl.cpp>
711
712 WX_DEFINE_LIST(wxListFoos);
713
714 static void TestHash()
715 {
716 puts("*** Testing wxHashTable ***\n");
717
718 {
719 wxHashFoos hash;
720 hash.DeleteContents(TRUE);
721
722 printf("Hash created: %u foos in hash, %u foos totally\n",
723 hash.GetCount(), Foo::count);
724
725 static const int hashTestData[] =
726 {
727 0, 1, 17, -2, 2, 4, -4, 345, 3, 3, 2, 1,
728 };
729
730 size_t n;
731 for ( n = 0; n < WXSIZEOF(hashTestData); n++ )
732 {
733 hash.Put(hashTestData[n], n, new Foo(n));
734 }
735
736 printf("Hash filled: %u foos in hash, %u foos totally\n",
737 hash.GetCount(), Foo::count);
738
739 puts("Hash access test:");
740 for ( n = 0; n < WXSIZEOF(hashTestData); n++ )
741 {
742 printf("\tGetting element with key %d, value %d: ",
743 hashTestData[n], n);
744 Foo *foo = hash.Get(hashTestData[n], n);
745 if ( !foo )
746 {
747 printf("ERROR, not found.\n");
748 }
749 else
750 {
751 printf("%d (%s)\n", foo->n,
752 (size_t)foo->n == n ? "ok" : "ERROR");
753 }
754 }
755
756 printf("\nTrying to get an element not in hash: ");
757
758 if ( hash.Get(1234) || hash.Get(1, 0) )
759 {
760 puts("ERROR: found!");
761 }
762 else
763 {
764 puts("ok (not found)");
765 }
766 }
767
768 printf("Hash destroyed: %u foos left\n", Foo::count);
769 }
770
771 #endif // TEST_HASH
772
773 // ----------------------------------------------------------------------------
774 // wxList
775 // ----------------------------------------------------------------------------
776
777 #ifdef TEST_LIST
778
779 #include <wx/list.h>
780
781 WX_DECLARE_LIST(Bar, wxListBars);
782 #include <wx/listimpl.cpp>
783 WX_DEFINE_LIST(wxListBars);
784
785 static void TestListCtor()
786 {
787 puts("*** Testing wxList construction ***\n");
788
789 {
790 wxListBars list1;
791 list1.Append(new Bar(_T("first")));
792 list1.Append(new Bar(_T("second")));
793
794 printf("After 1st list creation: %u objects in the list, %u objects total.\n",
795 list1.GetCount(), Bar::GetNumber());
796
797 wxListBars list2;
798 list2 = list1;
799
800 printf("After 2nd list creation: %u and %u objects in the lists, %u objects total.\n",
801 list1.GetCount(), list2.GetCount(), Bar::GetNumber());
802
803 list1.DeleteContents(TRUE);
804 }
805
806 printf("After list destruction: %u objects left.\n", Bar::GetNumber());
807 }
808
809 #endif // TEST_LIST
810
811 // ----------------------------------------------------------------------------
812 // MIME types
813 // ----------------------------------------------------------------------------
814
815 #ifdef TEST_MIME
816
817 #include <wx/mimetype.h>
818
819 static void TestMimeEnum()
820 {
821 wxPuts(_T("*** Testing wxMimeTypesManager::EnumAllFileTypes() ***\n"));
822
823 wxArrayString mimetypes;
824
825 size_t count = wxTheMimeTypesManager->EnumAllFileTypes(mimetypes);
826
827 printf("*** All %u known filetypes: ***\n", count);
828
829 wxArrayString exts;
830 wxString desc;
831
832 for ( size_t n = 0; n < count; n++ )
833 {
834 wxFileType *filetype =
835 wxTheMimeTypesManager->GetFileTypeFromMimeType(mimetypes[n]);
836 if ( !filetype )
837 {
838 printf("nothing known about the filetype '%s'!\n",
839 mimetypes[n].c_str());
840 continue;
841 }
842
843 filetype->GetDescription(&desc);
844 filetype->GetExtensions(exts);
845
846 filetype->GetIcon(NULL);
847
848 wxString extsAll;
849 for ( size_t e = 0; e < exts.GetCount(); e++ )
850 {
851 if ( e > 0 )
852 extsAll << _T(", ");
853 extsAll += exts[e];
854 }
855
856 printf("\t%s: %s (%s)\n",
857 mimetypes[n].c_str(), desc.c_str(), extsAll.c_str());
858 }
859
860 puts("");
861 }
862
863 static void TestMimeOverride()
864 {
865 wxPuts(_T("*** Testing wxMimeTypesManager additional files loading ***\n"));
866
867 static const wxChar *mailcap = _T("/tmp/mailcap");
868 static const wxChar *mimetypes = _T("/tmp/mime.types");
869
870 if ( wxFile::Exists(mailcap) )
871 wxPrintf(_T("Loading mailcap from '%s': %s\n"),
872 mailcap,
873 wxTheMimeTypesManager->ReadMailcap(mailcap) ? _T("ok") : _T("ERROR"));
874 else
875 wxPrintf(_T("WARN: mailcap file '%s' doesn't exist, not loaded.\n"),
876 mailcap);
877
878 if ( wxFile::Exists(mimetypes) )
879 wxPrintf(_T("Loading mime.types from '%s': %s\n"),
880 mimetypes,
881 wxTheMimeTypesManager->ReadMimeTypes(mimetypes) ? _T("ok") : _T("ERROR"));
882 else
883 wxPrintf(_T("WARN: mime.types file '%s' doesn't exist, not loaded.\n"),
884 mimetypes);
885
886 puts("");
887 }
888
889 static void TestMimeFilename()
890 {
891 wxPuts(_T("*** Testing MIME type from filename query ***\n"));
892
893 static const wxChar *filenames[] =
894 {
895 _T("readme.txt"),
896 _T("document.pdf"),
897 _T("image.gif"),
898 };
899
900 for ( size_t n = 0; n < WXSIZEOF(filenames); n++ )
901 {
902 const wxString fname = filenames[n];
903 wxString ext = fname.AfterLast(_T('.'));
904 wxFileType *ft = wxTheMimeTypesManager->GetFileTypeFromExtension(ext);
905 if ( !ft )
906 {
907 wxPrintf(_T("WARNING: extension '%s' is unknown.\n"), ext.c_str());
908 }
909 else
910 {
911 wxString desc;
912 if ( !ft->GetDescription(&desc) )
913 desc = _T("<no description>");
914
915 wxString cmd;
916 if ( !ft->GetOpenCommand(&cmd,
917 wxFileType::MessageParameters(fname, _T(""))) )
918 cmd = _T("<no command available>");
919
920 wxPrintf(_T("To open %s (%s) do '%s'.\n"),
921 fname.c_str(), desc.c_str(), cmd.c_str());
922
923 delete ft;
924 }
925 }
926
927 puts("");
928 }
929
930 static void TestMimeAssociate()
931 {
932 wxPuts(_T("*** Testing creation of filetype association ***\n"));
933
934 wxFileTypeInfo ftInfo(
935 _T("application/x-xyz"),
936 _T("xyzview '%s'"), // open cmd
937 _T(""), // print cmd
938 _T("XYZ File") // description
939 _T(".xyz"), // extensions
940 NULL // end of extensions
941 );
942 ftInfo.SetShortDesc(_T("XYZFile")); // used under Win32 only
943
944 wxFileType *ft = wxTheMimeTypesManager->Associate(ftInfo);
945 if ( !ft )
946 {
947 wxPuts(_T("ERROR: failed to create association!"));
948 }
949 else
950 {
951 // TODO: read it back
952 delete ft;
953 }
954
955 puts("");
956 }
957
958 #endif // TEST_MIME
959
960 // ----------------------------------------------------------------------------
961 // misc information functions
962 // ----------------------------------------------------------------------------
963
964 #ifdef TEST_INFO_FUNCTIONS
965
966 #include <wx/utils.h>
967
968 static void TestOsInfo()
969 {
970 puts("*** Testing OS info functions ***\n");
971
972 int major, minor;
973 wxGetOsVersion(&major, &minor);
974 printf("Running under: %s, version %d.%d\n",
975 wxGetOsDescription().c_str(), major, minor);
976
977 printf("%ld free bytes of memory left.\n", wxGetFreeMemory());
978
979 printf("Host name is %s (%s).\n",
980 wxGetHostName().c_str(), wxGetFullHostName().c_str());
981
982 puts("");
983 }
984
985 static void TestUserInfo()
986 {
987 puts("*** Testing user info functions ***\n");
988
989 printf("User id is:\t%s\n", wxGetUserId().c_str());
990 printf("User name is:\t%s\n", wxGetUserName().c_str());
991 printf("Home dir is:\t%s\n", wxGetHomeDir().c_str());
992 printf("Email address:\t%s\n", wxGetEmailAddress().c_str());
993
994 puts("");
995 }
996
997 #endif // TEST_INFO_FUNCTIONS
998
999 // ----------------------------------------------------------------------------
1000 // long long
1001 // ----------------------------------------------------------------------------
1002
1003 #ifdef TEST_LONGLONG
1004
1005 #include <wx/longlong.h>
1006 #include <wx/timer.h>
1007
1008 // make a 64 bit number from 4 16 bit ones
1009 #define MAKE_LL(x1, x2, x3, x4) wxLongLong((x1 << 16) | x2, (x3 << 16) | x3)
1010
1011 // get a random 64 bit number
1012 #define RAND_LL() MAKE_LL(rand(), rand(), rand(), rand())
1013
1014 #if wxUSE_LONGLONG_WX
1015 inline bool operator==(const wxLongLongWx& a, const wxLongLongNative& b)
1016 { return a.GetHi() == b.GetHi() && a.GetLo() == b.GetLo(); }
1017 inline bool operator==(const wxLongLongNative& a, const wxLongLongWx& b)
1018 { return a.GetHi() == b.GetHi() && a.GetLo() == b.GetLo(); }
1019 #endif // wxUSE_LONGLONG_WX
1020
1021 static void TestSpeed()
1022 {
1023 static const long max = 100000000;
1024 long n;
1025
1026 {
1027 wxStopWatch sw;
1028
1029 long l = 0;
1030 for ( n = 0; n < max; n++ )
1031 {
1032 l += n;
1033 }
1034
1035 printf("Summing longs took %ld milliseconds.\n", sw.Time());
1036 }
1037
1038 #if wxUSE_LONGLONG_NATIVE
1039 {
1040 wxStopWatch sw;
1041
1042 wxLongLong_t l = 0;
1043 for ( n = 0; n < max; n++ )
1044 {
1045 l += n;
1046 }
1047
1048 printf("Summing wxLongLong_t took %ld milliseconds.\n", sw.Time());
1049 }
1050 #endif // wxUSE_LONGLONG_NATIVE
1051
1052 {
1053 wxStopWatch sw;
1054
1055 wxLongLong l;
1056 for ( n = 0; n < max; n++ )
1057 {
1058 l += n;
1059 }
1060
1061 printf("Summing wxLongLongs took %ld milliseconds.\n", sw.Time());
1062 }
1063 }
1064
1065 static void TestLongLongConversion()
1066 {
1067 puts("*** Testing wxLongLong conversions ***\n");
1068
1069 wxLongLong a;
1070 size_t nTested = 0;
1071 for ( size_t n = 0; n < 100000; n++ )
1072 {
1073 a = RAND_LL();
1074
1075 #if wxUSE_LONGLONG_NATIVE
1076 wxLongLongNative b(a.GetHi(), a.GetLo());
1077
1078 wxASSERT_MSG( a == b, "conversions failure" );
1079 #else
1080 puts("Can't do it without native long long type, test skipped.");
1081
1082 return;
1083 #endif // wxUSE_LONGLONG_NATIVE
1084
1085 if ( !(nTested % 1000) )
1086 {
1087 putchar('.');
1088 fflush(stdout);
1089 }
1090
1091 nTested++;
1092 }
1093
1094 puts(" done!");
1095 }
1096
1097 static void TestMultiplication()
1098 {
1099 puts("*** Testing wxLongLong multiplication ***\n");
1100
1101 wxLongLong a, b;
1102 size_t nTested = 0;
1103 for ( size_t n = 0; n < 100000; n++ )
1104 {
1105 a = RAND_LL();
1106 b = RAND_LL();
1107
1108 #if wxUSE_LONGLONG_NATIVE
1109 wxLongLongNative aa(a.GetHi(), a.GetLo());
1110 wxLongLongNative bb(b.GetHi(), b.GetLo());
1111
1112 wxASSERT_MSG( a*b == aa*bb, "multiplication failure" );
1113 #else // !wxUSE_LONGLONG_NATIVE
1114 puts("Can't do it without native long long type, test skipped.");
1115
1116 return;
1117 #endif // wxUSE_LONGLONG_NATIVE
1118
1119 if ( !(nTested % 1000) )
1120 {
1121 putchar('.');
1122 fflush(stdout);
1123 }
1124
1125 nTested++;
1126 }
1127
1128 puts(" done!");
1129 }
1130
1131 static void TestDivision()
1132 {
1133 puts("*** Testing wxLongLong division ***\n");
1134
1135 wxLongLong q, r;
1136 size_t nTested = 0;
1137 for ( size_t n = 0; n < 100000; n++ )
1138 {
1139 // get a random wxLongLong (shifting by 12 the MSB ensures that the
1140 // multiplication will not overflow)
1141 wxLongLong ll = MAKE_LL((rand() >> 12), rand(), rand(), rand());
1142
1143 // get a random long (not wxLongLong for now) to divide it with
1144 long l = rand();
1145 q = ll / l;
1146 r = ll % l;
1147
1148 #if wxUSE_LONGLONG_NATIVE
1149 wxLongLongNative m(ll.GetHi(), ll.GetLo());
1150
1151 wxLongLongNative p = m / l, s = m % l;
1152 wxASSERT_MSG( q == p && r == s, "division failure" );
1153 #else // !wxUSE_LONGLONG_NATIVE
1154 // verify the result
1155 wxASSERT_MSG( ll == q*l + r, "division failure" );
1156 #endif // wxUSE_LONGLONG_NATIVE
1157
1158 if ( !(nTested % 1000) )
1159 {
1160 putchar('.');
1161 fflush(stdout);
1162 }
1163
1164 nTested++;
1165 }
1166
1167 puts(" done!");
1168 }
1169
1170 static void TestAddition()
1171 {
1172 puts("*** Testing wxLongLong addition ***\n");
1173
1174 wxLongLong a, b, c;
1175 size_t nTested = 0;
1176 for ( size_t n = 0; n < 100000; n++ )
1177 {
1178 a = RAND_LL();
1179 b = RAND_LL();
1180 c = a + b;
1181
1182 #if wxUSE_LONGLONG_NATIVE
1183 wxASSERT_MSG( c == wxLongLongNative(a.GetHi(), a.GetLo()) +
1184 wxLongLongNative(b.GetHi(), b.GetLo()),
1185 "addition failure" );
1186 #else // !wxUSE_LONGLONG_NATIVE
1187 wxASSERT_MSG( c - b == a, "addition failure" );
1188 #endif // wxUSE_LONGLONG_NATIVE
1189
1190 if ( !(nTested % 1000) )
1191 {
1192 putchar('.');
1193 fflush(stdout);
1194 }
1195
1196 nTested++;
1197 }
1198
1199 puts(" done!");
1200 }
1201
1202 static void TestBitOperations()
1203 {
1204 puts("*** Testing wxLongLong bit operation ***\n");
1205
1206 wxLongLong ll;
1207 size_t nTested = 0;
1208 for ( size_t n = 0; n < 100000; n++ )
1209 {
1210 ll = RAND_LL();
1211
1212 #if wxUSE_LONGLONG_NATIVE
1213 for ( size_t n = 0; n < 33; n++ )
1214 {
1215 }
1216 #else // !wxUSE_LONGLONG_NATIVE
1217 puts("Can't do it without native long long type, test skipped.");
1218
1219 return;
1220 #endif // wxUSE_LONGLONG_NATIVE
1221
1222 if ( !(nTested % 1000) )
1223 {
1224 putchar('.');
1225 fflush(stdout);
1226 }
1227
1228 nTested++;
1229 }
1230
1231 puts(" done!");
1232 }
1233
1234 static void TestLongLongComparison()
1235 {
1236 puts("*** Testing wxLongLong comparison ***\n");
1237
1238 static const long testLongs[] =
1239 {
1240 0,
1241 1,
1242 -1,
1243 LONG_MAX,
1244 LONG_MIN,
1245 0x1234,
1246 -0x1234
1247 };
1248
1249 static const long ls[2] =
1250 {
1251 0x1234,
1252 -0x1234,
1253 };
1254
1255 wxLongLongWx lls[2];
1256 lls[0] = ls[0];
1257 lls[1] = ls[1];
1258
1259 for ( size_t n = 0; n < WXSIZEOF(testLongs); n++ )
1260 {
1261 bool res;
1262
1263 for ( size_t m = 0; m < WXSIZEOF(lls); m++ )
1264 {
1265 res = lls[m] > testLongs[n];
1266 printf("0x%lx > 0x%lx is %s (%s)\n",
1267 ls[m], testLongs[n], res ? "true" : "false",
1268 res == (ls[m] > testLongs[n]) ? "ok" : "ERROR");
1269
1270 res = lls[m] < testLongs[n];
1271 printf("0x%lx < 0x%lx is %s (%s)\n",
1272 ls[m], testLongs[n], res ? "true" : "false",
1273 res == (ls[m] < testLongs[n]) ? "ok" : "ERROR");
1274
1275 res = lls[m] == testLongs[n];
1276 printf("0x%lx == 0x%lx is %s (%s)\n",
1277 ls[m], testLongs[n], res ? "true" : "false",
1278 res == (ls[m] == testLongs[n]) ? "ok" : "ERROR");
1279 }
1280 }
1281 }
1282
1283 #undef MAKE_LL
1284 #undef RAND_LL
1285
1286 #endif // TEST_LONGLONG
1287
1288 // ----------------------------------------------------------------------------
1289 // path list
1290 // ----------------------------------------------------------------------------
1291
1292 #ifdef TEST_PATHLIST
1293
1294 static void TestPathList()
1295 {
1296 puts("*** Testing wxPathList ***\n");
1297
1298 wxPathList pathlist;
1299 pathlist.AddEnvList("PATH");
1300 wxString path = pathlist.FindValidPath("ls");
1301 if ( path.empty() )
1302 {
1303 printf("ERROR: command not found in the path.\n");
1304 }
1305 else
1306 {
1307 printf("Command found in the path as '%s'.\n", path.c_str());
1308 }
1309 }
1310
1311 #endif // TEST_PATHLIST
1312
1313 // ----------------------------------------------------------------------------
1314 // registry
1315 // ----------------------------------------------------------------------------
1316
1317 // this is for MSW only
1318 #ifndef __WXMSW__
1319 #undef TEST_REGISTRY
1320 #endif
1321
1322 #ifdef TEST_REGISTRY
1323
1324 #include <wx/msw/registry.h>
1325
1326 // I chose this one because I liked its name, but it probably only exists under
1327 // NT
1328 static const wxChar *TESTKEY =
1329 _T("HKEY_LOCAL_MACHINE\\SYSTEM\\ControlSet001\\Control\\CrashControl");
1330
1331 static void TestRegistryRead()
1332 {
1333 puts("*** testing registry reading ***");
1334
1335 wxRegKey key(TESTKEY);
1336 printf("The test key name is '%s'.\n", key.GetName().c_str());
1337 if ( !key.Open() )
1338 {
1339 puts("ERROR: test key can't be opened, aborting test.");
1340
1341 return;
1342 }
1343
1344 size_t nSubKeys, nValues;
1345 if ( key.GetKeyInfo(&nSubKeys, NULL, &nValues, NULL) )
1346 {
1347 printf("It has %u subkeys and %u values.\n", nSubKeys, nValues);
1348 }
1349
1350 printf("Enumerating values:\n");
1351
1352 long dummy;
1353 wxString value;
1354 bool cont = key.GetFirstValue(value, dummy);
1355 while ( cont )
1356 {
1357 printf("Value '%s': type ", value.c_str());
1358 switch ( key.GetValueType(value) )
1359 {
1360 case wxRegKey::Type_None: printf("ERROR (none)"); break;
1361 case wxRegKey::Type_String: printf("SZ"); break;
1362 case wxRegKey::Type_Expand_String: printf("EXPAND_SZ"); break;
1363 case wxRegKey::Type_Binary: printf("BINARY"); break;
1364 case wxRegKey::Type_Dword: printf("DWORD"); break;
1365 case wxRegKey::Type_Multi_String: printf("MULTI_SZ"); break;
1366 default: printf("other (unknown)"); break;
1367 }
1368
1369 printf(", value = ");
1370 if ( key.IsNumericValue(value) )
1371 {
1372 long val;
1373 key.QueryValue(value, &val);
1374 printf("%ld", val);
1375 }
1376 else // string
1377 {
1378 wxString val;
1379 key.QueryValue(value, val);
1380 printf("'%s'", val.c_str());
1381
1382 key.QueryRawValue(value, val);
1383 printf(" (raw value '%s')", val.c_str());
1384 }
1385
1386 putchar('\n');
1387
1388 cont = key.GetNextValue(value, dummy);
1389 }
1390 }
1391
1392 static void TestRegistryAssociation()
1393 {
1394 /*
1395 The second call to deleteself genertaes an error message, with a
1396 messagebox saying .flo is crucial to system operation, while the .ddf
1397 call also fails, but with no error message
1398 */
1399
1400 wxRegKey key;
1401
1402 key.SetName("HKEY_CLASSES_ROOT\\.ddf" );
1403 key.Create();
1404 key = "ddxf_auto_file" ;
1405 key.SetName("HKEY_CLASSES_ROOT\\.flo" );
1406 key.Create();
1407 key = "ddxf_auto_file" ;
1408 key.SetName("HKEY_CLASSES_ROOT\\ddxf_auto_file\\DefaultIcon");
1409 key.Create();
1410 key = "program,0" ;
1411 key.SetName("HKEY_CLASSES_ROOT\\ddxf_auto_file\\shell\\open\\command");
1412 key.Create();
1413 key = "program \"%1\"" ;
1414
1415 key.SetName("HKEY_CLASSES_ROOT\\.ddf" );
1416 key.DeleteSelf();
1417 key.SetName("HKEY_CLASSES_ROOT\\.flo" );
1418 key.DeleteSelf();
1419 key.SetName("HKEY_CLASSES_ROOT\\ddxf_auto_file\\DefaultIcon");
1420 key.DeleteSelf();
1421 key.SetName("HKEY_CLASSES_ROOT\\ddxf_auto_file\\shell\\open\\command");
1422 key.DeleteSelf();
1423 }
1424
1425 #endif // TEST_REGISTRY
1426
1427 // ----------------------------------------------------------------------------
1428 // sockets
1429 // ----------------------------------------------------------------------------
1430
1431 #ifdef TEST_SOCKETS
1432
1433 #include <wx/socket.h>
1434 #include <wx/protocol/protocol.h>
1435 #include <wx/protocol/http.h>
1436
1437 static void TestSocketServer()
1438 {
1439 puts("*** Testing wxSocketServer ***\n");
1440
1441 static const int PORT = 3000;
1442
1443 wxIPV4address addr;
1444 addr.Service(PORT);
1445
1446 wxSocketServer *server = new wxSocketServer(addr);
1447 if ( !server->Ok() )
1448 {
1449 puts("ERROR: failed to bind");
1450
1451 return;
1452 }
1453
1454 for ( ;; )
1455 {
1456 printf("Server: waiting for connection on port %d...\n", PORT);
1457
1458 wxSocketBase *socket = server->Accept();
1459 if ( !socket )
1460 {
1461 puts("ERROR: wxSocketServer::Accept() failed.");
1462 break;
1463 }
1464
1465 puts("Server: got a client.");
1466
1467 server->SetTimeout(60); // 1 min
1468
1469 while ( socket->IsConnected() )
1470 {
1471 wxString s;
1472 char ch = '\0';
1473 for ( ;; )
1474 {
1475 if ( socket->Read(&ch, sizeof(ch)).Error() )
1476 {
1477 // don't log error if the client just close the connection
1478 if ( socket->IsConnected() )
1479 {
1480 puts("ERROR: in wxSocket::Read.");
1481 }
1482
1483 break;
1484 }
1485
1486 if ( ch == '\r' )
1487 continue;
1488
1489 if ( ch == '\n' )
1490 break;
1491
1492 s += ch;
1493 }
1494
1495 if ( ch != '\n' )
1496 {
1497 break;
1498 }
1499
1500 printf("Server: got '%s'.\n", s.c_str());
1501 if ( s == _T("bye") )
1502 {
1503 delete socket;
1504
1505 break;
1506 }
1507
1508 socket->Write(s.MakeUpper().c_str(), s.length());
1509 socket->Write("\r\n", 2);
1510 printf("Server: wrote '%s'.\n", s.c_str());
1511 }
1512
1513 puts("Server: lost a client.");
1514
1515 socket->Destroy();
1516 }
1517
1518 // same as "delete server" but is consistent with GUI programs
1519 server->Destroy();
1520 }
1521
1522 static void TestSocketClient()
1523 {
1524 puts("*** Testing wxSocketClient ***\n");
1525
1526 static const char *hostname = "www.wxwindows.org";
1527
1528 wxIPV4address addr;
1529 addr.Hostname(hostname);
1530 addr.Service(80);
1531
1532 printf("--- Attempting to connect to %s:80...\n", hostname);
1533
1534 wxSocketClient client;
1535 if ( !client.Connect(addr) )
1536 {
1537 printf("ERROR: failed to connect to %s\n", hostname);
1538 }
1539 else
1540 {
1541 printf("--- Connected to %s:%u...\n",
1542 addr.Hostname().c_str(), addr.Service());
1543
1544 char buf[8192];
1545
1546 // could use simply "GET" here I suppose
1547 wxString cmdGet =
1548 wxString::Format("GET http://%s/\r\n", hostname);
1549 client.Write(cmdGet, cmdGet.length());
1550 printf("--- Sent command '%s' to the server\n",
1551 MakePrintable(cmdGet).c_str());
1552 client.Read(buf, WXSIZEOF(buf));
1553 printf("--- Server replied:\n%s", buf);
1554 }
1555 }
1556
1557 #endif // TEST_SOCKETS
1558
1559 // ----------------------------------------------------------------------------
1560 // FTP
1561 // ----------------------------------------------------------------------------
1562
1563 #ifdef TEST_FTP
1564
1565 #include <wx/protocol/ftp.h>
1566
1567 static wxFTP ftp;
1568
1569 #define FTP_ANONYMOUS
1570
1571 #ifdef FTP_ANONYMOUS
1572 static const char *directory = "/pub";
1573 static const char *filename = "welcome.msg";
1574 #else
1575 static const char *directory = "/etc";
1576 static const char *filename = "issue";
1577 #endif
1578
1579 static bool TestFtpConnect()
1580 {
1581 puts("*** Testing FTP connect ***");
1582
1583 #ifdef FTP_ANONYMOUS
1584 static const char *hostname = "ftp.wxwindows.org";
1585
1586 printf("--- Attempting to connect to %s:21 anonymously...\n", hostname);
1587 #else // !FTP_ANONYMOUS
1588 static const char *hostname = "localhost";
1589
1590 char user[256];
1591 fgets(user, WXSIZEOF(user), stdin);
1592 user[strlen(user) - 1] = '\0'; // chop off '\n'
1593 ftp.SetUser(user);
1594
1595 char password[256];
1596 printf("Password for %s: ", password);
1597 fgets(password, WXSIZEOF(password), stdin);
1598 password[strlen(password) - 1] = '\0'; // chop off '\n'
1599 ftp.SetPassword(password);
1600
1601 printf("--- Attempting to connect to %s:21 as %s...\n", hostname, user);
1602 #endif // FTP_ANONYMOUS/!FTP_ANONYMOUS
1603
1604 if ( !ftp.Connect(hostname) )
1605 {
1606 printf("ERROR: failed to connect to %s\n", hostname);
1607
1608 return FALSE;
1609 }
1610 else
1611 {
1612 printf("--- Connected to %s, current directory is '%s'\n",
1613 hostname, ftp.Pwd().c_str());
1614 }
1615
1616 return TRUE;
1617 }
1618
1619 // test (fixed?) wxFTP bug with wu-ftpd >= 2.6.0?
1620 static void TestFtpWuFtpd()
1621 {
1622 wxFTP ftp;
1623 static const char *hostname = "ftp.eudora.com";
1624 if ( !ftp.Connect(hostname) )
1625 {
1626 printf("ERROR: failed to connect to %s\n", hostname);
1627 }
1628 else
1629 {
1630 static const char *filename = "eudora/pubs/draft-gellens-submit-09.txt";
1631 wxInputStream *in = ftp.GetInputStream(filename);
1632 if ( !in )
1633 {
1634 printf("ERROR: couldn't get input stream for %s\n", filename);
1635 }
1636 else
1637 {
1638 size_t size = in->StreamSize();
1639 printf("Reading file %s (%u bytes)...", filename, size);
1640
1641 char *data = new char[size];
1642 if ( !in->Read(data, size) )
1643 {
1644 puts("ERROR: read error");
1645 }
1646 else
1647 {
1648 printf("Successfully retrieved the file.\n");
1649 }
1650
1651 delete [] data;
1652 delete in;
1653 }
1654 }
1655 }
1656
1657 static void TestFtpList()
1658 {
1659 puts("*** Testing wxFTP file listing ***\n");
1660
1661 // test CWD
1662 if ( !ftp.ChDir(directory) )
1663 {
1664 printf("ERROR: failed to cd to %s\n", directory);
1665 }
1666
1667 printf("Current directory is '%s'\n", ftp.Pwd().c_str());
1668
1669 // test NLIST and LIST
1670 wxArrayString files;
1671 if ( !ftp.GetFilesList(files) )
1672 {
1673 puts("ERROR: failed to get NLIST of files");
1674 }
1675 else
1676 {
1677 printf("Brief list of files under '%s':\n", ftp.Pwd().c_str());
1678 size_t count = files.GetCount();
1679 for ( size_t n = 0; n < count; n++ )
1680 {
1681 printf("\t%s\n", files[n].c_str());
1682 }
1683 puts("End of the file list");
1684 }
1685
1686 if ( !ftp.GetDirList(files) )
1687 {
1688 puts("ERROR: failed to get LIST of files");
1689 }
1690 else
1691 {
1692 printf("Detailed list of files under '%s':\n", ftp.Pwd().c_str());
1693 size_t count = files.GetCount();
1694 for ( size_t n = 0; n < count; n++ )
1695 {
1696 printf("\t%s\n", files[n].c_str());
1697 }
1698 puts("End of the file list");
1699 }
1700
1701 if ( !ftp.ChDir(_T("..")) )
1702 {
1703 puts("ERROR: failed to cd to ..");
1704 }
1705
1706 printf("Current directory is '%s'\n", ftp.Pwd().c_str());
1707 }
1708
1709 static void TestFtpDownload()
1710 {
1711 puts("*** Testing wxFTP download ***\n");
1712
1713 // test RETR
1714 wxInputStream *in = ftp.GetInputStream(filename);
1715 if ( !in )
1716 {
1717 printf("ERROR: couldn't get input stream for %s\n", filename);
1718 }
1719 else
1720 {
1721 size_t size = in->StreamSize();
1722 printf("Reading file %s (%u bytes)...", filename, size);
1723 fflush(stdout);
1724
1725 char *data = new char[size];
1726 if ( !in->Read(data, size) )
1727 {
1728 puts("ERROR: read error");
1729 }
1730 else
1731 {
1732 printf("\nContents of %s:\n%s\n", filename, data);
1733 }
1734
1735 delete [] data;
1736 delete in;
1737 }
1738 }
1739
1740 static void TestFtpFileSize()
1741 {
1742 puts("*** Testing FTP SIZE command ***");
1743
1744 if ( !ftp.ChDir(directory) )
1745 {
1746 printf("ERROR: failed to cd to %s\n", directory);
1747 }
1748
1749 printf("Current directory is '%s'\n", ftp.Pwd().c_str());
1750
1751 if ( ftp.FileExists(filename) )
1752 {
1753 int size = ftp.GetFileSize(filename);
1754 if ( size == -1 )
1755 printf("ERROR: couldn't get size of '%s'\n", filename);
1756 else
1757 printf("Size of '%s' is %d bytes.\n", filename, size);
1758 }
1759 else
1760 {
1761 printf("ERROR: '%s' doesn't exist\n", filename);
1762 }
1763 }
1764
1765 static void TestFtpMisc()
1766 {
1767 puts("*** Testing miscellaneous wxFTP functions ***");
1768
1769 if ( ftp.SendCommand("STAT") != '2' )
1770 {
1771 puts("ERROR: STAT failed");
1772 }
1773 else
1774 {
1775 printf("STAT returned:\n\n%s\n", ftp.GetLastResult().c_str());
1776 }
1777
1778 if ( ftp.SendCommand("HELP SITE") != '2' )
1779 {
1780 puts("ERROR: HELP SITE failed");
1781 }
1782 else
1783 {
1784 printf("The list of site-specific commands:\n\n%s\n",
1785 ftp.GetLastResult().c_str());
1786 }
1787 }
1788
1789 static void TestFtpInteractive()
1790 {
1791 puts("\n*** Interactive wxFTP test ***");
1792
1793 char buf[128];
1794
1795 for ( ;; )
1796 {
1797 printf("Enter FTP command: ");
1798 if ( !fgets(buf, WXSIZEOF(buf), stdin) )
1799 break;
1800
1801 // kill the last '\n'
1802 buf[strlen(buf) - 1] = 0;
1803
1804 // special handling of LIST and NLST as they require data connection
1805 wxString start(buf, 4);
1806 start.MakeUpper();
1807 if ( start == "LIST" || start == "NLST" )
1808 {
1809 wxString wildcard;
1810 if ( strlen(buf) > 4 )
1811 wildcard = buf + 5;
1812
1813 wxArrayString files;
1814 if ( !ftp.GetList(files, wildcard, start == "LIST") )
1815 {
1816 printf("ERROR: failed to get %s of files\n", start.c_str());
1817 }
1818 else
1819 {
1820 printf("--- %s of '%s' under '%s':\n",
1821 start.c_str(), wildcard.c_str(), ftp.Pwd().c_str());
1822 size_t count = files.GetCount();
1823 for ( size_t n = 0; n < count; n++ )
1824 {
1825 printf("\t%s\n", files[n].c_str());
1826 }
1827 puts("--- End of the file list");
1828 }
1829 }
1830 else // !list
1831 {
1832 char ch = ftp.SendCommand(buf);
1833 printf("Command %s", ch ? "succeeded" : "failed");
1834 if ( ch )
1835 {
1836 printf(" (return code %c)", ch);
1837 }
1838
1839 printf(", server reply:\n%s\n\n", ftp.GetLastResult().c_str());
1840 }
1841 }
1842
1843 puts("\n*** done ***");
1844 }
1845
1846 static void TestFtpUpload()
1847 {
1848 puts("*** Testing wxFTP uploading ***\n");
1849
1850 // upload a file
1851 static const char *file1 = "test1";
1852 static const char *file2 = "test2";
1853 wxOutputStream *out = ftp.GetOutputStream(file1);
1854 if ( out )
1855 {
1856 printf("--- Uploading to %s ---\n", file1);
1857 out->Write("First hello", 11);
1858 delete out;
1859 }
1860
1861 // send a command to check the remote file
1862 if ( ftp.SendCommand(wxString("STAT ") + file1) != '2' )
1863 {
1864 printf("ERROR: STAT %s failed\n", file1);
1865 }
1866 else
1867 {
1868 printf("STAT %s returned:\n\n%s\n",
1869 file1, ftp.GetLastResult().c_str());
1870 }
1871
1872 out = ftp.GetOutputStream(file2);
1873 if ( out )
1874 {
1875 printf("--- Uploading to %s ---\n", file1);
1876 out->Write("Second hello", 12);
1877 delete out;
1878 }
1879 }
1880
1881 #endif // TEST_FTP
1882
1883 // ----------------------------------------------------------------------------
1884 // streams
1885 // ----------------------------------------------------------------------------
1886
1887 #ifdef TEST_STREAMS
1888
1889 #include <wx/wfstream.h>
1890 #include <wx/mstream.h>
1891
1892 static void TestFileStream()
1893 {
1894 puts("*** Testing wxFileInputStream ***");
1895
1896 static const wxChar *filename = _T("testdata.fs");
1897 {
1898 wxFileOutputStream fsOut(filename);
1899 fsOut.Write("foo", 3);
1900 }
1901
1902 wxFileInputStream fsIn(filename);
1903 printf("File stream size: %u\n", fsIn.GetSize());
1904 while ( !fsIn.Eof() )
1905 {
1906 putchar(fsIn.GetC());
1907 }
1908
1909 if ( !wxRemoveFile(filename) )
1910 {
1911 printf("ERROR: failed to remove the file '%s'.\n", filename);
1912 }
1913
1914 puts("\n*** wxFileInputStream test done ***");
1915 }
1916
1917 static void TestMemoryStream()
1918 {
1919 puts("*** Testing wxMemoryInputStream ***");
1920
1921 wxChar buf[1024];
1922 wxStrncpy(buf, _T("Hello, stream!"), WXSIZEOF(buf));
1923
1924 wxMemoryInputStream memInpStream(buf, wxStrlen(buf));
1925 printf(_T("Memory stream size: %u\n"), memInpStream.GetSize());
1926 while ( !memInpStream.Eof() )
1927 {
1928 putchar(memInpStream.GetC());
1929 }
1930
1931 puts("\n*** wxMemoryInputStream test done ***");
1932 }
1933
1934 #endif // TEST_STREAMS
1935
1936 // ----------------------------------------------------------------------------
1937 // timers
1938 // ----------------------------------------------------------------------------
1939
1940 #ifdef TEST_TIMER
1941
1942 #include <wx/timer.h>
1943 #include <wx/utils.h>
1944
1945 static void TestStopWatch()
1946 {
1947 puts("*** Testing wxStopWatch ***\n");
1948
1949 wxStopWatch sw;
1950 printf("Sleeping 3 seconds...");
1951 wxSleep(3);
1952 printf("\telapsed time: %ldms\n", sw.Time());
1953
1954 sw.Pause();
1955 printf("Sleeping 2 more seconds...");
1956 wxSleep(2);
1957 printf("\telapsed time: %ldms\n", sw.Time());
1958
1959 sw.Resume();
1960 printf("And 3 more seconds...");
1961 wxSleep(3);
1962 printf("\telapsed time: %ldms\n", sw.Time());
1963
1964 wxStopWatch sw2;
1965 puts("\nChecking for 'backwards clock' bug...");
1966 for ( size_t n = 0; n < 70; n++ )
1967 {
1968 sw2.Start();
1969
1970 for ( size_t m = 0; m < 100000; m++ )
1971 {
1972 if ( sw.Time() < 0 || sw2.Time() < 0 )
1973 {
1974 puts("\ntime is negative - ERROR!");
1975 }
1976 }
1977
1978 putchar('.');
1979 }
1980
1981 puts(", ok.");
1982 }
1983
1984 #endif // TEST_TIMER
1985
1986 // ----------------------------------------------------------------------------
1987 // vCard support
1988 // ----------------------------------------------------------------------------
1989
1990 #ifdef TEST_VCARD
1991
1992 #include <wx/vcard.h>
1993
1994 static void DumpVObject(size_t level, const wxVCardObject& vcard)
1995 {
1996 void *cookie;
1997 wxVCardObject *vcObj = vcard.GetFirstProp(&cookie);
1998 while ( vcObj )
1999 {
2000 printf("%s%s",
2001 wxString(_T('\t'), level).c_str(),
2002 vcObj->GetName().c_str());
2003
2004 wxString value;
2005 switch ( vcObj->GetType() )
2006 {
2007 case wxVCardObject::String:
2008 case wxVCardObject::UString:
2009 {
2010 wxString val;
2011 vcObj->GetValue(&val);
2012 value << _T('"') << val << _T('"');
2013 }
2014 break;
2015
2016 case wxVCardObject::Int:
2017 {
2018 unsigned int i;
2019 vcObj->GetValue(&i);
2020 value.Printf(_T("%u"), i);
2021 }
2022 break;
2023
2024 case wxVCardObject::Long:
2025 {
2026 unsigned long l;
2027 vcObj->GetValue(&l);
2028 value.Printf(_T("%lu"), l);
2029 }
2030 break;
2031
2032 case wxVCardObject::None:
2033 break;
2034
2035 case wxVCardObject::Object:
2036 value = _T("<node>");
2037 break;
2038
2039 default:
2040 value = _T("<unknown value type>");
2041 }
2042
2043 if ( !!value )
2044 printf(" = %s", value.c_str());
2045 putchar('\n');
2046
2047 DumpVObject(level + 1, *vcObj);
2048
2049 delete vcObj;
2050 vcObj = vcard.GetNextProp(&cookie);
2051 }
2052 }
2053
2054 static void DumpVCardAddresses(const wxVCard& vcard)
2055 {
2056 puts("\nShowing all addresses from vCard:\n");
2057
2058 size_t nAdr = 0;
2059 void *cookie;
2060 wxVCardAddress *addr = vcard.GetFirstAddress(&cookie);
2061 while ( addr )
2062 {
2063 wxString flagsStr;
2064 int flags = addr->GetFlags();
2065 if ( flags & wxVCardAddress::Domestic )
2066 {
2067 flagsStr << _T("domestic ");
2068 }
2069 if ( flags & wxVCardAddress::Intl )
2070 {
2071 flagsStr << _T("international ");
2072 }
2073 if ( flags & wxVCardAddress::Postal )
2074 {
2075 flagsStr << _T("postal ");
2076 }
2077 if ( flags & wxVCardAddress::Parcel )
2078 {
2079 flagsStr << _T("parcel ");
2080 }
2081 if ( flags & wxVCardAddress::Home )
2082 {
2083 flagsStr << _T("home ");
2084 }
2085 if ( flags & wxVCardAddress::Work )
2086 {
2087 flagsStr << _T("work ");
2088 }
2089
2090 printf("Address %u:\n"
2091 "\tflags = %s\n"
2092 "\tvalue = %s;%s;%s;%s;%s;%s;%s\n",
2093 ++nAdr,
2094 flagsStr.c_str(),
2095 addr->GetPostOffice().c_str(),
2096 addr->GetExtAddress().c_str(),
2097 addr->GetStreet().c_str(),
2098 addr->GetLocality().c_str(),
2099 addr->GetRegion().c_str(),
2100 addr->GetPostalCode().c_str(),
2101 addr->GetCountry().c_str()
2102 );
2103
2104 delete addr;
2105 addr = vcard.GetNextAddress(&cookie);
2106 }
2107 }
2108
2109 static void DumpVCardPhoneNumbers(const wxVCard& vcard)
2110 {
2111 puts("\nShowing all phone numbers from vCard:\n");
2112
2113 size_t nPhone = 0;
2114 void *cookie;
2115 wxVCardPhoneNumber *phone = vcard.GetFirstPhoneNumber(&cookie);
2116 while ( phone )
2117 {
2118 wxString flagsStr;
2119 int flags = phone->GetFlags();
2120 if ( flags & wxVCardPhoneNumber::Voice )
2121 {
2122 flagsStr << _T("voice ");
2123 }
2124 if ( flags & wxVCardPhoneNumber::Fax )
2125 {
2126 flagsStr << _T("fax ");
2127 }
2128 if ( flags & wxVCardPhoneNumber::Cellular )
2129 {
2130 flagsStr << _T("cellular ");
2131 }
2132 if ( flags & wxVCardPhoneNumber::Modem )
2133 {
2134 flagsStr << _T("modem ");
2135 }
2136 if ( flags & wxVCardPhoneNumber::Home )
2137 {
2138 flagsStr << _T("home ");
2139 }
2140 if ( flags & wxVCardPhoneNumber::Work )
2141 {
2142 flagsStr << _T("work ");
2143 }
2144
2145 printf("Phone number %u:\n"
2146 "\tflags = %s\n"
2147 "\tvalue = %s\n",
2148 ++nPhone,
2149 flagsStr.c_str(),
2150 phone->GetNumber().c_str()
2151 );
2152
2153 delete phone;
2154 phone = vcard.GetNextPhoneNumber(&cookie);
2155 }
2156 }
2157
2158 static void TestVCardRead()
2159 {
2160 puts("*** Testing wxVCard reading ***\n");
2161
2162 wxVCard vcard(_T("vcard.vcf"));
2163 if ( !vcard.IsOk() )
2164 {
2165 puts("ERROR: couldn't load vCard.");
2166 }
2167 else
2168 {
2169 // read individual vCard properties
2170 wxVCardObject *vcObj = vcard.GetProperty("FN");
2171 wxString value;
2172 if ( vcObj )
2173 {
2174 vcObj->GetValue(&value);
2175 delete vcObj;
2176 }
2177 else
2178 {
2179 value = _T("<none>");
2180 }
2181
2182 printf("Full name retrieved directly: %s\n", value.c_str());
2183
2184
2185 if ( !vcard.GetFullName(&value) )
2186 {
2187 value = _T("<none>");
2188 }
2189
2190 printf("Full name from wxVCard API: %s\n", value.c_str());
2191
2192 // now show how to deal with multiply occuring properties
2193 DumpVCardAddresses(vcard);
2194 DumpVCardPhoneNumbers(vcard);
2195
2196 // and finally show all
2197 puts("\nNow dumping the entire vCard:\n"
2198 "-----------------------------\n");
2199
2200 DumpVObject(0, vcard);
2201 }
2202 }
2203
2204 static void TestVCardWrite()
2205 {
2206 puts("*** Testing wxVCard writing ***\n");
2207
2208 wxVCard vcard;
2209 if ( !vcard.IsOk() )
2210 {
2211 puts("ERROR: couldn't create vCard.");
2212 }
2213 else
2214 {
2215 // set some fields
2216 vcard.SetName("Zeitlin", "Vadim");
2217 vcard.SetFullName("Vadim Zeitlin");
2218 vcard.SetOrganization("wxWindows", "R&D");
2219
2220 // just dump the vCard back
2221 puts("Entire vCard follows:\n");
2222 puts(vcard.Write());
2223 }
2224 }
2225
2226 #endif // TEST_VCARD
2227
2228 // ----------------------------------------------------------------------------
2229 // wide char (Unicode) support
2230 // ----------------------------------------------------------------------------
2231
2232 #ifdef TEST_WCHAR
2233
2234 #include <wx/strconv.h>
2235 #include <wx/fontenc.h>
2236 #include <wx/encconv.h>
2237 #include <wx/buffer.h>
2238
2239 static void TestUtf8()
2240 {
2241 puts("*** Testing UTF8 support ***\n");
2242
2243 static const char textInUtf8[] =
2244 {
2245 208, 157, 208, 181, 209, 129, 208, 186, 208, 176, 208, 183, 208, 176,
2246 208, 189, 208, 189, 208, 190, 32, 208, 191, 208, 190, 209, 128, 208,
2247 176, 208, 180, 208, 190, 208, 178, 208, 176, 208, 187, 32, 208, 188,
2248 208, 181, 208, 189, 209, 143, 32, 209, 129, 208, 178, 208, 190, 208,
2249 181, 208, 185, 32, 208, 186, 209, 128, 209, 131, 209, 130, 208, 181,
2250 208, 185, 209, 136, 208, 181, 208, 185, 32, 208, 189, 208, 190, 208,
2251 178, 208, 190, 209, 129, 209, 130, 209, 140, 209, 142, 0
2252 };
2253
2254 char buf[1024];
2255 wchar_t wbuf[1024];
2256 if ( wxConvUTF8.MB2WC(wbuf, textInUtf8, WXSIZEOF(textInUtf8)) <= 0 )
2257 {
2258 puts("ERROR: UTF-8 decoding failed.");
2259 }
2260 else
2261 {
2262 // using wxEncodingConverter
2263 #if 0
2264 wxEncodingConverter ec;
2265 ec.Init(wxFONTENCODING_UNICODE, wxFONTENCODING_KOI8);
2266 ec.Convert(wbuf, buf);
2267 #else // using wxCSConv
2268 wxCSConv conv(_T("koi8-r"));
2269 if ( conv.WC2MB(buf, wbuf, 0 /* not needed wcslen(wbuf) */) <= 0 )
2270 {
2271 puts("ERROR: conversion to KOI8-R failed.");
2272 }
2273 else
2274 #endif
2275
2276 printf("The resulting string (in koi8-r): %s\n", buf);
2277 }
2278 }
2279
2280 #endif // TEST_WCHAR
2281
2282 // ----------------------------------------------------------------------------
2283 // ZIP stream
2284 // ----------------------------------------------------------------------------
2285
2286 #ifdef TEST_ZIP
2287
2288 #include "wx/filesys.h"
2289 #include "wx/fs_zip.h"
2290 #include "wx/zipstrm.h"
2291
2292 static const wxChar *TESTFILE_ZIP = _T("testdata.zip");
2293
2294 static void TestZipStreamRead()
2295 {
2296 puts("*** Testing ZIP reading ***\n");
2297
2298 static const wxChar *filename = _T("foo");
2299 wxZipInputStream istr(TESTFILE_ZIP, filename);
2300 printf("Archive size: %u\n", istr.GetSize());
2301
2302 printf("Dumping the file '%s':\n", filename);
2303 while ( !istr.Eof() )
2304 {
2305 putchar(istr.GetC());
2306 fflush(stdout);
2307 }
2308
2309 puts("\n----- done ------");
2310 }
2311
2312 static void DumpZipDirectory(wxFileSystem& fs,
2313 const wxString& dir,
2314 const wxString& indent)
2315 {
2316 wxString prefix = wxString::Format(_T("%s#zip:%s"),
2317 TESTFILE_ZIP, dir.c_str());
2318 wxString wildcard = prefix + _T("/*");
2319
2320 wxString dirname = fs.FindFirst(wildcard, wxDIR);
2321 while ( !dirname.empty() )
2322 {
2323 if ( !dirname.StartsWith(prefix + _T('/'), &dirname) )
2324 {
2325 wxPrintf(_T("ERROR: unexpected wxFileSystem::FindNext result\n"));
2326
2327 break;
2328 }
2329
2330 wxPrintf(_T("%s%s\n"), indent.c_str(), dirname.c_str());
2331
2332 DumpZipDirectory(fs, dirname,
2333 indent + wxString(_T(' '), 4));
2334
2335 dirname = fs.FindNext();
2336 }
2337
2338 wxString filename = fs.FindFirst(wildcard, wxFILE);
2339 while ( !filename.empty() )
2340 {
2341 if ( !filename.StartsWith(prefix, &filename) )
2342 {
2343 wxPrintf(_T("ERROR: unexpected wxFileSystem::FindNext result\n"));
2344
2345 break;
2346 }
2347
2348 wxPrintf(_T("%s%s\n"), indent.c_str(), filename.c_str());
2349
2350 filename = fs.FindNext();
2351 }
2352 }
2353
2354 static void TestZipFileSystem()
2355 {
2356 puts("*** Testing ZIP file system ***\n");
2357
2358 wxFileSystem::AddHandler(new wxZipFSHandler);
2359 wxFileSystem fs;
2360 wxPrintf(_T("Dumping all files in the archive %s:\n"), TESTFILE_ZIP);
2361
2362 DumpZipDirectory(fs, _T(""), wxString(_T(' '), 4));
2363 }
2364
2365 #endif // TEST_ZIP
2366
2367 // ----------------------------------------------------------------------------
2368 // ZLIB stream
2369 // ----------------------------------------------------------------------------
2370
2371 #ifdef TEST_ZLIB
2372
2373 #include <wx/zstream.h>
2374 #include <wx/wfstream.h>
2375
2376 static const wxChar *FILENAME_GZ = _T("test.gz");
2377 static const char *TEST_DATA = "hello and hello again";
2378
2379 static void TestZlibStreamWrite()
2380 {
2381 puts("*** Testing Zlib stream reading ***\n");
2382
2383 wxFileOutputStream fileOutStream(FILENAME_GZ);
2384 wxZlibOutputStream ostr(fileOutStream, 0);
2385 printf("Compressing the test string... ");
2386 ostr.Write(TEST_DATA, sizeof(TEST_DATA));
2387 if ( !ostr )
2388 {
2389 puts("(ERROR: failed)");
2390 }
2391 else
2392 {
2393 puts("(ok)");
2394 }
2395
2396 puts("\n----- done ------");
2397 }
2398
2399 static void TestZlibStreamRead()
2400 {
2401 puts("*** Testing Zlib stream reading ***\n");
2402
2403 wxFileInputStream fileInStream(FILENAME_GZ);
2404 wxZlibInputStream istr(fileInStream);
2405 printf("Archive size: %u\n", istr.GetSize());
2406
2407 puts("Dumping the file:");
2408 while ( !istr.Eof() )
2409 {
2410 putchar(istr.GetC());
2411 fflush(stdout);
2412 }
2413
2414 puts("\n----- done ------");
2415 }
2416
2417 #endif // TEST_ZLIB
2418
2419 // ----------------------------------------------------------------------------
2420 // date time
2421 // ----------------------------------------------------------------------------
2422
2423 #ifdef TEST_DATETIME
2424
2425 #include <wx/date.h>
2426
2427 #include <wx/datetime.h>
2428
2429 // the test data
2430 struct Date
2431 {
2432 wxDateTime::wxDateTime_t day;
2433 wxDateTime::Month month;
2434 int year;
2435 wxDateTime::wxDateTime_t hour, min, sec;
2436 double jdn;
2437 wxDateTime::WeekDay wday;
2438 time_t gmticks, ticks;
2439
2440 void Init(const wxDateTime::Tm& tm)
2441 {
2442 day = tm.mday;
2443 month = tm.mon;
2444 year = tm.year;
2445 hour = tm.hour;
2446 min = tm.min;
2447 sec = tm.sec;
2448 jdn = 0.0;
2449 gmticks = ticks = -1;
2450 }
2451
2452 wxDateTime DT() const
2453 { return wxDateTime(day, month, year, hour, min, sec); }
2454
2455 bool SameDay(const wxDateTime::Tm& tm) const
2456 {
2457 return day == tm.mday && month == tm.mon && year == tm.year;
2458 }
2459
2460 wxString Format() const
2461 {
2462 wxString s;
2463 s.Printf("%02d:%02d:%02d %10s %02d, %4d%s",
2464 hour, min, sec,
2465 wxDateTime::GetMonthName(month).c_str(),
2466 day,
2467 abs(wxDateTime::ConvertYearToBC(year)),
2468 year > 0 ? "AD" : "BC");
2469 return s;
2470 }
2471
2472 wxString FormatDate() const
2473 {
2474 wxString s;
2475 s.Printf("%02d-%s-%4d%s",
2476 day,
2477 wxDateTime::GetMonthName(month, wxDateTime::Name_Abbr).c_str(),
2478 abs(wxDateTime::ConvertYearToBC(year)),
2479 year > 0 ? "AD" : "BC");
2480 return s;
2481 }
2482 };
2483
2484 static const Date testDates[] =
2485 {
2486 { 1, wxDateTime::Jan, 1970, 00, 00, 00, 2440587.5, wxDateTime::Thu, 0, -3600 },
2487 { 21, wxDateTime::Jan, 2222, 00, 00, 00, 2532648.5, wxDateTime::Mon, -1, -1 },
2488 { 29, wxDateTime::May, 1976, 12, 00, 00, 2442928.0, wxDateTime::Sat, 202219200, 202212000 },
2489 { 29, wxDateTime::Feb, 1976, 00, 00, 00, 2442837.5, wxDateTime::Sun, 194400000, 194396400 },
2490 { 1, wxDateTime::Jan, 1900, 12, 00, 00, 2415021.0, wxDateTime::Mon, -1, -1 },
2491 { 1, wxDateTime::Jan, 1900, 00, 00, 00, 2415020.5, wxDateTime::Mon, -1, -1 },
2492 { 15, wxDateTime::Oct, 1582, 00, 00, 00, 2299160.5, wxDateTime::Fri, -1, -1 },
2493 { 4, wxDateTime::Oct, 1582, 00, 00, 00, 2299149.5, wxDateTime::Mon, -1, -1 },
2494 { 1, wxDateTime::Mar, 1, 00, 00, 00, 1721484.5, wxDateTime::Thu, -1, -1 },
2495 { 1, wxDateTime::Jan, 1, 00, 00, 00, 1721425.5, wxDateTime::Mon, -1, -1 },
2496 { 31, wxDateTime::Dec, 0, 00, 00, 00, 1721424.5, wxDateTime::Sun, -1, -1 },
2497 { 1, wxDateTime::Jan, 0, 00, 00, 00, 1721059.5, wxDateTime::Sat, -1, -1 },
2498 { 12, wxDateTime::Aug, -1234, 00, 00, 00, 1270573.5, wxDateTime::Fri, -1, -1 },
2499 { 12, wxDateTime::Aug, -4000, 00, 00, 00, 260313.5, wxDateTime::Sat, -1, -1 },
2500 { 24, wxDateTime::Nov, -4713, 00, 00, 00, -0.5, wxDateTime::Mon, -1, -1 },
2501 };
2502
2503 // this test miscellaneous static wxDateTime functions
2504 static void TestTimeStatic()
2505 {
2506 puts("\n*** wxDateTime static methods test ***");
2507
2508 // some info about the current date
2509 int year = wxDateTime::GetCurrentYear();
2510 printf("Current year %d is %sa leap one and has %d days.\n",
2511 year,
2512 wxDateTime::IsLeapYear(year) ? "" : "not ",
2513 wxDateTime::GetNumberOfDays(year));
2514
2515 wxDateTime::Month month = wxDateTime::GetCurrentMonth();
2516 printf("Current month is '%s' ('%s') and it has %d days\n",
2517 wxDateTime::GetMonthName(month, wxDateTime::Name_Abbr).c_str(),
2518 wxDateTime::GetMonthName(month).c_str(),
2519 wxDateTime::GetNumberOfDays(month));
2520
2521 // leap year logic
2522 static const size_t nYears = 5;
2523 static const size_t years[2][nYears] =
2524 {
2525 // first line: the years to test
2526 { 1990, 1976, 2000, 2030, 1984, },
2527
2528 // second line: TRUE if leap, FALSE otherwise
2529 { FALSE, TRUE, TRUE, FALSE, TRUE }
2530 };
2531
2532 for ( size_t n = 0; n < nYears; n++ )
2533 {
2534 int year = years[0][n];
2535 bool should = years[1][n] != 0,
2536 is = wxDateTime::IsLeapYear(year);
2537
2538 printf("Year %d is %sa leap year (%s)\n",
2539 year,
2540 is ? "" : "not ",
2541 should == is ? "ok" : "ERROR");
2542
2543 wxASSERT( should == wxDateTime::IsLeapYear(year) );
2544 }
2545 }
2546
2547 // test constructing wxDateTime objects
2548 static void TestTimeSet()
2549 {
2550 puts("\n*** wxDateTime construction test ***");
2551
2552 for ( size_t n = 0; n < WXSIZEOF(testDates); n++ )
2553 {
2554 const Date& d1 = testDates[n];
2555 wxDateTime dt = d1.DT();
2556
2557 Date d2;
2558 d2.Init(dt.GetTm());
2559
2560 wxString s1 = d1.Format(),
2561 s2 = d2.Format();
2562
2563 printf("Date: %s == %s (%s)\n",
2564 s1.c_str(), s2.c_str(),
2565 s1 == s2 ? "ok" : "ERROR");
2566 }
2567 }
2568
2569 // test time zones stuff
2570 static void TestTimeZones()
2571 {
2572 puts("\n*** wxDateTime timezone test ***");
2573
2574 wxDateTime now = wxDateTime::Now();
2575
2576 printf("Current GMT time:\t%s\n", now.Format("%c", wxDateTime::GMT0).c_str());
2577 printf("Unix epoch (GMT):\t%s\n", wxDateTime((time_t)0).Format("%c", wxDateTime::GMT0).c_str());
2578 printf("Unix epoch (EST):\t%s\n", wxDateTime((time_t)0).Format("%c", wxDateTime::EST).c_str());
2579 printf("Current time in Paris:\t%s\n", now.Format("%c", wxDateTime::CET).c_str());
2580 printf(" Moscow:\t%s\n", now.Format("%c", wxDateTime::MSK).c_str());
2581 printf(" New York:\t%s\n", now.Format("%c", wxDateTime::EST).c_str());
2582
2583 wxDateTime::Tm tm = now.GetTm();
2584 if ( wxDateTime(tm) != now )
2585 {
2586 printf("ERROR: got %s instead of %s\n",
2587 wxDateTime(tm).Format().c_str(), now.Format().c_str());
2588 }
2589 }
2590
2591 // test some minimal support for the dates outside the standard range
2592 static void TestTimeRange()
2593 {
2594 puts("\n*** wxDateTime out-of-standard-range dates test ***");
2595
2596 static const char *fmt = "%d-%b-%Y %H:%M:%S";
2597
2598 printf("Unix epoch:\t%s\n",
2599 wxDateTime(2440587.5).Format(fmt).c_str());
2600 printf("Feb 29, 0: \t%s\n",
2601 wxDateTime(29, wxDateTime::Feb, 0).Format(fmt).c_str());
2602 printf("JDN 0: \t%s\n",
2603 wxDateTime(0.0).Format(fmt).c_str());
2604 printf("Jan 1, 1AD:\t%s\n",
2605 wxDateTime(1, wxDateTime::Jan, 1).Format(fmt).c_str());
2606 printf("May 29, 2099:\t%s\n",
2607 wxDateTime(29, wxDateTime::May, 2099).Format(fmt).c_str());
2608 }
2609
2610 static void TestTimeTicks()
2611 {
2612 puts("\n*** wxDateTime ticks test ***");
2613
2614 for ( size_t n = 0; n < WXSIZEOF(testDates); n++ )
2615 {
2616 const Date& d = testDates[n];
2617 if ( d.ticks == -1 )
2618 continue;
2619
2620 wxDateTime dt = d.DT();
2621 long ticks = (dt.GetValue() / 1000).ToLong();
2622 printf("Ticks of %s:\t% 10ld", d.Format().c_str(), ticks);
2623 if ( ticks == d.ticks )
2624 {
2625 puts(" (ok)");
2626 }
2627 else
2628 {
2629 printf(" (ERROR: should be %ld, delta = %ld)\n",
2630 d.ticks, ticks - d.ticks);
2631 }
2632
2633 dt = d.DT().ToTimezone(wxDateTime::GMT0);
2634 ticks = (dt.GetValue() / 1000).ToLong();
2635 printf("GMtks of %s:\t% 10ld", d.Format().c_str(), ticks);
2636 if ( ticks == d.gmticks )
2637 {
2638 puts(" (ok)");
2639 }
2640 else
2641 {
2642 printf(" (ERROR: should be %ld, delta = %ld)\n",
2643 d.gmticks, ticks - d.gmticks);
2644 }
2645 }
2646
2647 puts("");
2648 }
2649
2650 // test conversions to JDN &c
2651 static void TestTimeJDN()
2652 {
2653 puts("\n*** wxDateTime to JDN test ***");
2654
2655 for ( size_t n = 0; n < WXSIZEOF(testDates); n++ )
2656 {
2657 const Date& d = testDates[n];
2658 wxDateTime dt(d.day, d.month, d.year, d.hour, d.min, d.sec);
2659 double jdn = dt.GetJulianDayNumber();
2660
2661 printf("JDN of %s is:\t% 15.6f", d.Format().c_str(), jdn);
2662 if ( jdn == d.jdn )
2663 {
2664 puts(" (ok)");
2665 }
2666 else
2667 {
2668 printf(" (ERROR: should be %f, delta = %f)\n",
2669 d.jdn, jdn - d.jdn);
2670 }
2671 }
2672 }
2673
2674 // test week days computation
2675 static void TestTimeWDays()
2676 {
2677 puts("\n*** wxDateTime weekday test ***");
2678
2679 // test GetWeekDay()
2680 size_t n;
2681 for ( n = 0; n < WXSIZEOF(testDates); n++ )
2682 {
2683 const Date& d = testDates[n];
2684 wxDateTime dt(d.day, d.month, d.year, d.hour, d.min, d.sec);
2685
2686 wxDateTime::WeekDay wday = dt.GetWeekDay();
2687 printf("%s is: %s",
2688 d.Format().c_str(),
2689 wxDateTime::GetWeekDayName(wday).c_str());
2690 if ( wday == d.wday )
2691 {
2692 puts(" (ok)");
2693 }
2694 else
2695 {
2696 printf(" (ERROR: should be %s)\n",
2697 wxDateTime::GetWeekDayName(d.wday).c_str());
2698 }
2699 }
2700
2701 puts("");
2702
2703 // test SetToWeekDay()
2704 struct WeekDateTestData
2705 {
2706 Date date; // the real date (precomputed)
2707 int nWeek; // its week index in the month
2708 wxDateTime::WeekDay wday; // the weekday
2709 wxDateTime::Month month; // the month
2710 int year; // and the year
2711
2712 wxString Format() const
2713 {
2714 wxString s, which;
2715 switch ( nWeek < -1 ? -nWeek : nWeek )
2716 {
2717 case 1: which = "first"; break;
2718 case 2: which = "second"; break;
2719 case 3: which = "third"; break;
2720 case 4: which = "fourth"; break;
2721 case 5: which = "fifth"; break;
2722
2723 case -1: which = "last"; break;
2724 }
2725
2726 if ( nWeek < -1 )
2727 {
2728 which += " from end";
2729 }
2730
2731 s.Printf("The %s %s of %s in %d",
2732 which.c_str(),
2733 wxDateTime::GetWeekDayName(wday).c_str(),
2734 wxDateTime::GetMonthName(month).c_str(),
2735 year);
2736
2737 return s;
2738 }
2739 };
2740
2741 // the array data was generated by the following python program
2742 /*
2743 from DateTime import *
2744 from whrandom import *
2745 from string import *
2746
2747 monthNames = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ]
2748 wdayNames = [ 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun' ]
2749
2750 week = DateTimeDelta(7)
2751
2752 for n in range(20):
2753 year = randint(1900, 2100)
2754 month = randint(1, 12)
2755 day = randint(1, 28)
2756 dt = DateTime(year, month, day)
2757 wday = dt.day_of_week
2758
2759 countFromEnd = choice([-1, 1])
2760 weekNum = 0;
2761
2762 while dt.month is month:
2763 dt = dt - countFromEnd * week
2764 weekNum = weekNum + countFromEnd
2765
2766 data = { 'day': rjust(`day`, 2), 'month': monthNames[month - 1], 'year': year, 'weekNum': rjust(`weekNum`, 2), 'wday': wdayNames[wday] }
2767
2768 print "{ { %(day)s, wxDateTime::%(month)s, %(year)d }, %(weekNum)d, "\
2769 "wxDateTime::%(wday)s, wxDateTime::%(month)s, %(year)d }," % data
2770 */
2771
2772 static const WeekDateTestData weekDatesTestData[] =
2773 {
2774 { { 20, wxDateTime::Mar, 2045 }, 3, wxDateTime::Mon, wxDateTime::Mar, 2045 },
2775 { { 5, wxDateTime::Jun, 1985 }, -4, wxDateTime::Wed, wxDateTime::Jun, 1985 },
2776 { { 12, wxDateTime::Nov, 1961 }, -3, wxDateTime::Sun, wxDateTime::Nov, 1961 },
2777 { { 27, wxDateTime::Feb, 2093 }, -1, wxDateTime::Fri, wxDateTime::Feb, 2093 },
2778 { { 4, wxDateTime::Jul, 2070 }, -4, wxDateTime::Fri, wxDateTime::Jul, 2070 },
2779 { { 2, wxDateTime::Apr, 1906 }, -5, wxDateTime::Mon, wxDateTime::Apr, 1906 },
2780 { { 19, wxDateTime::Jul, 2023 }, -2, wxDateTime::Wed, wxDateTime::Jul, 2023 },
2781 { { 5, wxDateTime::May, 1958 }, -4, wxDateTime::Mon, wxDateTime::May, 1958 },
2782 { { 11, wxDateTime::Aug, 1900 }, 2, wxDateTime::Sat, wxDateTime::Aug, 1900 },
2783 { { 14, wxDateTime::Feb, 1945 }, 2, wxDateTime::Wed, wxDateTime::Feb, 1945 },
2784 { { 25, wxDateTime::Jul, 1967 }, -1, wxDateTime::Tue, wxDateTime::Jul, 1967 },
2785 { { 9, wxDateTime::May, 1916 }, -4, wxDateTime::Tue, wxDateTime::May, 1916 },
2786 { { 20, wxDateTime::Jun, 1927 }, 3, wxDateTime::Mon, wxDateTime::Jun, 1927 },
2787 { { 2, wxDateTime::Aug, 2000 }, 1, wxDateTime::Wed, wxDateTime::Aug, 2000 },
2788 { { 20, wxDateTime::Apr, 2044 }, 3, wxDateTime::Wed, wxDateTime::Apr, 2044 },
2789 { { 20, wxDateTime::Feb, 1932 }, -2, wxDateTime::Sat, wxDateTime::Feb, 1932 },
2790 { { 25, wxDateTime::Jul, 2069 }, 4, wxDateTime::Thu, wxDateTime::Jul, 2069 },
2791 { { 3, wxDateTime::Apr, 1925 }, 1, wxDateTime::Fri, wxDateTime::Apr, 1925 },
2792 { { 21, wxDateTime::Mar, 2093 }, 3, wxDateTime::Sat, wxDateTime::Mar, 2093 },
2793 { { 3, wxDateTime::Dec, 2074 }, -5, wxDateTime::Mon, wxDateTime::Dec, 2074 },
2794 };
2795
2796 static const char *fmt = "%d-%b-%Y";
2797
2798 wxDateTime dt;
2799 for ( n = 0; n < WXSIZEOF(weekDatesTestData); n++ )
2800 {
2801 const WeekDateTestData& wd = weekDatesTestData[n];
2802
2803 dt.SetToWeekDay(wd.wday, wd.nWeek, wd.month, wd.year);
2804
2805 printf("%s is %s", wd.Format().c_str(), dt.Format(fmt).c_str());
2806
2807 const Date& d = wd.date;
2808 if ( d.SameDay(dt.GetTm()) )
2809 {
2810 puts(" (ok)");
2811 }
2812 else
2813 {
2814 dt.Set(d.day, d.month, d.year);
2815
2816 printf(" (ERROR: should be %s)\n", dt.Format(fmt).c_str());
2817 }
2818 }
2819 }
2820
2821 // test the computation of (ISO) week numbers
2822 static void TestTimeWNumber()
2823 {
2824 puts("\n*** wxDateTime week number test ***");
2825
2826 struct WeekNumberTestData
2827 {
2828 Date date; // the date
2829 wxDateTime::wxDateTime_t week; // the week number in the year
2830 wxDateTime::wxDateTime_t wmon; // the week number in the month
2831 wxDateTime::wxDateTime_t wmon2; // same but week starts with Sun
2832 wxDateTime::wxDateTime_t dnum; // day number in the year
2833 };
2834
2835 // data generated with the following python script:
2836 /*
2837 from DateTime import *
2838 from whrandom import *
2839 from string import *
2840
2841 monthNames = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ]
2842 wdayNames = [ 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun' ]
2843
2844 def GetMonthWeek(dt):
2845 weekNumMonth = dt.iso_week[1] - DateTime(dt.year, dt.month, 1).iso_week[1] + 1
2846 if weekNumMonth < 0:
2847 weekNumMonth = weekNumMonth + 53
2848 return weekNumMonth
2849
2850 def GetLastSundayBefore(dt):
2851 if dt.iso_week[2] == 7:
2852 return dt
2853 else:
2854 return dt - DateTimeDelta(dt.iso_week[2])
2855
2856 for n in range(20):
2857 year = randint(1900, 2100)
2858 month = randint(1, 12)
2859 day = randint(1, 28)
2860 dt = DateTime(year, month, day)
2861 dayNum = dt.day_of_year
2862 weekNum = dt.iso_week[1]
2863 weekNumMonth = GetMonthWeek(dt)
2864
2865 weekNumMonth2 = 0
2866 dtSunday = GetLastSundayBefore(dt)
2867
2868 while dtSunday >= GetLastSundayBefore(DateTime(dt.year, dt.month, 1)):
2869 weekNumMonth2 = weekNumMonth2 + 1
2870 dtSunday = dtSunday - DateTimeDelta(7)
2871
2872 data = { 'day': rjust(`day`, 2), \
2873 'month': monthNames[month - 1], \
2874 'year': year, \
2875 'weekNum': rjust(`weekNum`, 2), \
2876 'weekNumMonth': weekNumMonth, \
2877 'weekNumMonth2': weekNumMonth2, \
2878 'dayNum': rjust(`dayNum`, 3) }
2879
2880 print " { { %(day)s, "\
2881 "wxDateTime::%(month)s, "\
2882 "%(year)d }, "\
2883 "%(weekNum)s, "\
2884 "%(weekNumMonth)s, "\
2885 "%(weekNumMonth2)s, "\
2886 "%(dayNum)s }," % data
2887
2888 */
2889 static const WeekNumberTestData weekNumberTestDates[] =
2890 {
2891 { { 27, wxDateTime::Dec, 1966 }, 52, 5, 5, 361 },
2892 { { 22, wxDateTime::Jul, 1926 }, 29, 4, 4, 203 },
2893 { { 22, wxDateTime::Oct, 2076 }, 43, 4, 4, 296 },
2894 { { 1, wxDateTime::Jul, 1967 }, 26, 1, 1, 182 },
2895 { { 8, wxDateTime::Nov, 2004 }, 46, 2, 2, 313 },
2896 { { 21, wxDateTime::Mar, 1920 }, 12, 3, 4, 81 },
2897 { { 7, wxDateTime::Jan, 1965 }, 1, 2, 2, 7 },
2898 { { 19, wxDateTime::Oct, 1999 }, 42, 4, 4, 292 },
2899 { { 13, wxDateTime::Aug, 1955 }, 32, 2, 2, 225 },
2900 { { 18, wxDateTime::Jul, 2087 }, 29, 3, 3, 199 },
2901 { { 2, wxDateTime::Sep, 2028 }, 35, 1, 1, 246 },
2902 { { 28, wxDateTime::Jul, 1945 }, 30, 5, 4, 209 },
2903 { { 15, wxDateTime::Jun, 1901 }, 24, 3, 3, 166 },
2904 { { 10, wxDateTime::Oct, 1939 }, 41, 3, 2, 283 },
2905 { { 3, wxDateTime::Dec, 1965 }, 48, 1, 1, 337 },
2906 { { 23, wxDateTime::Feb, 1940 }, 8, 4, 4, 54 },
2907 { { 2, wxDateTime::Jan, 1987 }, 1, 1, 1, 2 },
2908 { { 11, wxDateTime::Aug, 2079 }, 32, 2, 2, 223 },
2909 { { 2, wxDateTime::Feb, 2063 }, 5, 1, 1, 33 },
2910 { { 16, wxDateTime::Oct, 1942 }, 42, 3, 3, 289 },
2911 };
2912
2913 for ( size_t n = 0; n < WXSIZEOF(weekNumberTestDates); n++ )
2914 {
2915 const WeekNumberTestData& wn = weekNumberTestDates[n];
2916 const Date& d = wn.date;
2917
2918 wxDateTime dt = d.DT();
2919
2920 wxDateTime::wxDateTime_t
2921 week = dt.GetWeekOfYear(wxDateTime::Monday_First),
2922 wmon = dt.GetWeekOfMonth(wxDateTime::Monday_First),
2923 wmon2 = dt.GetWeekOfMonth(wxDateTime::Sunday_First),
2924 dnum = dt.GetDayOfYear();
2925
2926 printf("%s: the day number is %d",
2927 d.FormatDate().c_str(), dnum);
2928 if ( dnum == wn.dnum )
2929 {
2930 printf(" (ok)");
2931 }
2932 else
2933 {
2934 printf(" (ERROR: should be %d)", wn.dnum);
2935 }
2936
2937 printf(", week in month is %d", wmon);
2938 if ( wmon == wn.wmon )
2939 {
2940 printf(" (ok)");
2941 }
2942 else
2943 {
2944 printf(" (ERROR: should be %d)", wn.wmon);
2945 }
2946
2947 printf(" or %d", wmon2);
2948 if ( wmon2 == wn.wmon2 )
2949 {
2950 printf(" (ok)");
2951 }
2952 else
2953 {
2954 printf(" (ERROR: should be %d)", wn.wmon2);
2955 }
2956
2957 printf(", week in year is %d", week);
2958 if ( week == wn.week )
2959 {
2960 puts(" (ok)");
2961 }
2962 else
2963 {
2964 printf(" (ERROR: should be %d)\n", wn.week);
2965 }
2966 }
2967 }
2968
2969 // test DST calculations
2970 static void TestTimeDST()
2971 {
2972 puts("\n*** wxDateTime DST test ***");
2973
2974 printf("DST is%s in effect now.\n\n",
2975 wxDateTime::Now().IsDST() ? "" : " not");
2976
2977 // taken from http://www.energy.ca.gov/daylightsaving.html
2978 static const Date datesDST[2][2004 - 1900 + 1] =
2979 {
2980 {
2981 { 1, wxDateTime::Apr, 1990 },
2982 { 7, wxDateTime::Apr, 1991 },
2983 { 5, wxDateTime::Apr, 1992 },
2984 { 4, wxDateTime::Apr, 1993 },
2985 { 3, wxDateTime::Apr, 1994 },
2986 { 2, wxDateTime::Apr, 1995 },
2987 { 7, wxDateTime::Apr, 1996 },
2988 { 6, wxDateTime::Apr, 1997 },
2989 { 5, wxDateTime::Apr, 1998 },
2990 { 4, wxDateTime::Apr, 1999 },
2991 { 2, wxDateTime::Apr, 2000 },
2992 { 1, wxDateTime::Apr, 2001 },
2993 { 7, wxDateTime::Apr, 2002 },
2994 { 6, wxDateTime::Apr, 2003 },
2995 { 4, wxDateTime::Apr, 2004 },
2996 },
2997 {
2998 { 28, wxDateTime::Oct, 1990 },
2999 { 27, wxDateTime::Oct, 1991 },
3000 { 25, wxDateTime::Oct, 1992 },
3001 { 31, wxDateTime::Oct, 1993 },
3002 { 30, wxDateTime::Oct, 1994 },
3003 { 29, wxDateTime::Oct, 1995 },
3004 { 27, wxDateTime::Oct, 1996 },
3005 { 26, wxDateTime::Oct, 1997 },
3006 { 25, wxDateTime::Oct, 1998 },
3007 { 31, wxDateTime::Oct, 1999 },
3008 { 29, wxDateTime::Oct, 2000 },
3009 { 28, wxDateTime::Oct, 2001 },
3010 { 27, wxDateTime::Oct, 2002 },
3011 { 26, wxDateTime::Oct, 2003 },
3012 { 31, wxDateTime::Oct, 2004 },
3013 }
3014 };
3015
3016 int year;
3017 for ( year = 1990; year < 2005; year++ )
3018 {
3019 wxDateTime dtBegin = wxDateTime::GetBeginDST(year, wxDateTime::USA),
3020 dtEnd = wxDateTime::GetEndDST(year, wxDateTime::USA);
3021
3022 printf("DST period in the US for year %d: from %s to %s",
3023 year, dtBegin.Format().c_str(), dtEnd.Format().c_str());
3024
3025 size_t n = year - 1990;
3026 const Date& dBegin = datesDST[0][n];
3027 const Date& dEnd = datesDST[1][n];
3028
3029 if ( dBegin.SameDay(dtBegin.GetTm()) && dEnd.SameDay(dtEnd.GetTm()) )
3030 {
3031 puts(" (ok)");
3032 }
3033 else
3034 {
3035 printf(" (ERROR: should be %s %d to %s %d)\n",
3036 wxDateTime::GetMonthName(dBegin.month).c_str(), dBegin.day,
3037 wxDateTime::GetMonthName(dEnd.month).c_str(), dEnd.day);
3038 }
3039 }
3040
3041 puts("");
3042
3043 for ( year = 1990; year < 2005; year++ )
3044 {
3045 printf("DST period in Europe for year %d: from %s to %s\n",
3046 year,
3047 wxDateTime::GetBeginDST(year, wxDateTime::Country_EEC).Format().c_str(),
3048 wxDateTime::GetEndDST(year, wxDateTime::Country_EEC).Format().c_str());
3049 }
3050 }
3051
3052 // test wxDateTime -> text conversion
3053 static void TestTimeFormat()
3054 {
3055 puts("\n*** wxDateTime formatting test ***");
3056
3057 // some information may be lost during conversion, so store what kind
3058 // of info should we recover after a round trip
3059 enum CompareKind
3060 {
3061 CompareNone, // don't try comparing
3062 CompareBoth, // dates and times should be identical
3063 CompareDate, // dates only
3064 CompareTime // time only
3065 };
3066
3067 static const struct
3068 {
3069 CompareKind compareKind;
3070 const char *format;
3071 } formatTestFormats[] =
3072 {
3073 { CompareBoth, "---> %c" },
3074 { CompareDate, "Date is %A, %d of %B, in year %Y" },
3075 { CompareBoth, "Date is %x, time is %X" },
3076 { CompareTime, "Time is %H:%M:%S or %I:%M:%S %p" },
3077 { CompareNone, "The day of year: %j, the week of year: %W" },
3078 { CompareDate, "ISO date without separators: %4Y%2m%2d" },
3079 };
3080
3081 static const Date formatTestDates[] =
3082 {
3083 { 29, wxDateTime::May, 1976, 18, 30, 00 },
3084 { 31, wxDateTime::Dec, 1999, 23, 30, 00 },
3085 #if 0
3086 // this test can't work for other centuries because it uses two digit
3087 // years in formats, so don't even try it
3088 { 29, wxDateTime::May, 2076, 18, 30, 00 },
3089 { 29, wxDateTime::Feb, 2400, 02, 15, 25 },
3090 { 01, wxDateTime::Jan, -52, 03, 16, 47 },
3091 #endif
3092 };
3093
3094 // an extra test (as it doesn't depend on date, don't do it in the loop)
3095 printf("%s\n", wxDateTime::Now().Format("Our timezone is %Z").c_str());
3096
3097 for ( size_t d = 0; d < WXSIZEOF(formatTestDates) + 1; d++ )
3098 {
3099 puts("");
3100
3101 wxDateTime dt = d == 0 ? wxDateTime::Now() : formatTestDates[d - 1].DT();
3102 for ( size_t n = 0; n < WXSIZEOF(formatTestFormats); n++ )
3103 {
3104 wxString s = dt.Format(formatTestFormats[n].format);
3105 printf("%s", s.c_str());
3106
3107 // what can we recover?
3108 int kind = formatTestFormats[n].compareKind;
3109
3110 // convert back
3111 wxDateTime dt2;
3112 const wxChar *result = dt2.ParseFormat(s, formatTestFormats[n].format);
3113 if ( !result )
3114 {
3115 // converion failed - should it have?
3116 if ( kind == CompareNone )
3117 puts(" (ok)");
3118 else
3119 puts(" (ERROR: conversion back failed)");
3120 }
3121 else if ( *result )
3122 {
3123 // should have parsed the entire string
3124 puts(" (ERROR: conversion back stopped too soon)");
3125 }
3126 else
3127 {
3128 bool equal = FALSE; // suppress compilaer warning
3129 switch ( kind )
3130 {
3131 case CompareBoth:
3132 equal = dt2 == dt;
3133 break;
3134
3135 case CompareDate:
3136 equal = dt.IsSameDate(dt2);
3137 break;
3138
3139 case CompareTime:
3140 equal = dt.IsSameTime(dt2);
3141 break;
3142 }
3143
3144 if ( !equal )
3145 {
3146 printf(" (ERROR: got back '%s' instead of '%s')\n",
3147 dt2.Format().c_str(), dt.Format().c_str());
3148 }
3149 else
3150 {
3151 puts(" (ok)");
3152 }
3153 }
3154 }
3155 }
3156 }
3157
3158 // test text -> wxDateTime conversion
3159 static void TestTimeParse()
3160 {
3161 puts("\n*** wxDateTime parse test ***");
3162
3163 struct ParseTestData
3164 {
3165 const char *format;
3166 Date date;
3167 bool good;
3168 };
3169
3170 static const ParseTestData parseTestDates[] =
3171 {
3172 { "Sat, 18 Dec 1999 00:46:40 +0100", { 18, wxDateTime::Dec, 1999, 00, 46, 40 }, TRUE },
3173 { "Wed, 1 Dec 1999 05:17:20 +0300", { 1, wxDateTime::Dec, 1999, 03, 17, 20 }, TRUE },
3174 };
3175
3176 for ( size_t n = 0; n < WXSIZEOF(parseTestDates); n++ )
3177 {
3178 const char *format = parseTestDates[n].format;
3179
3180 printf("%s => ", format);
3181
3182 wxDateTime dt;
3183 if ( dt.ParseRfc822Date(format) )
3184 {
3185 printf("%s ", dt.Format().c_str());
3186
3187 if ( parseTestDates[n].good )
3188 {
3189 wxDateTime dtReal = parseTestDates[n].date.DT();
3190 if ( dt == dtReal )
3191 {
3192 puts("(ok)");
3193 }
3194 else
3195 {
3196 printf("(ERROR: should be %s)\n", dtReal.Format().c_str());
3197 }
3198 }
3199 else
3200 {
3201 puts("(ERROR: bad format)");
3202 }
3203 }
3204 else
3205 {
3206 printf("bad format (%s)\n",
3207 parseTestDates[n].good ? "ERROR" : "ok");
3208 }
3209 }
3210 }
3211
3212 static void TestDateTimeInteractive()
3213 {
3214 puts("\n*** interactive wxDateTime tests ***");
3215
3216 char buf[128];
3217
3218 for ( ;; )
3219 {
3220 printf("Enter a date: ");
3221 if ( !fgets(buf, WXSIZEOF(buf), stdin) )
3222 break;
3223
3224 // kill the last '\n'
3225 buf[strlen(buf) - 1] = 0;
3226
3227 wxDateTime dt;
3228 const char *p = dt.ParseDate(buf);
3229 if ( !p )
3230 {
3231 printf("ERROR: failed to parse the date '%s'.\n", buf);
3232
3233 continue;
3234 }
3235 else if ( *p )
3236 {
3237 printf("WARNING: parsed only first %u characters.\n", p - buf);
3238 }
3239
3240 printf("%s: day %u, week of month %u/%u, week of year %u\n",
3241 dt.Format("%b %d, %Y").c_str(),
3242 dt.GetDayOfYear(),
3243 dt.GetWeekOfMonth(wxDateTime::Monday_First),
3244 dt.GetWeekOfMonth(wxDateTime::Sunday_First),
3245 dt.GetWeekOfYear(wxDateTime::Monday_First));
3246 }
3247
3248 puts("\n*** done ***");
3249 }
3250
3251 static void TestTimeMS()
3252 {
3253 puts("*** testing millisecond-resolution support in wxDateTime ***");
3254
3255 wxDateTime dt1 = wxDateTime::Now(),
3256 dt2 = wxDateTime::UNow();
3257
3258 printf("Now = %s\n", dt1.Format("%H:%M:%S:%l").c_str());
3259 printf("UNow = %s\n", dt2.Format("%H:%M:%S:%l").c_str());
3260 printf("Dummy loop: ");
3261 for ( int i = 0; i < 6000; i++ )
3262 {
3263 //for ( int j = 0; j < 10; j++ )
3264 {
3265 wxString s;
3266 s.Printf("%g", sqrt(i));
3267 }
3268
3269 if ( !(i % 100) )
3270 putchar('.');
3271 }
3272 puts(", done");
3273
3274 dt1 = dt2;
3275 dt2 = wxDateTime::UNow();
3276 printf("UNow = %s\n", dt2.Format("%H:%M:%S:%l").c_str());
3277
3278 printf("Loop executed in %s ms\n", (dt2 - dt1).Format("%l").c_str());
3279
3280 puts("\n*** done ***");
3281 }
3282
3283 static void TestTimeArithmetics()
3284 {
3285 puts("\n*** testing arithmetic operations on wxDateTime ***");
3286
3287 static const struct ArithmData
3288 {
3289 ArithmData(const wxDateSpan& sp, const char *nam)
3290 : span(sp), name(nam) { }
3291
3292 wxDateSpan span;
3293 const char *name;
3294 } testArithmData[] =
3295 {
3296 ArithmData(wxDateSpan::Day(), "day"),
3297 ArithmData(wxDateSpan::Week(), "week"),
3298 ArithmData(wxDateSpan::Month(), "month"),
3299 ArithmData(wxDateSpan::Year(), "year"),
3300 ArithmData(wxDateSpan(1, 2, 3, 4), "year, 2 months, 3 weeks, 4 days"),
3301 };
3302
3303 wxDateTime dt(29, wxDateTime::Dec, 1999), dt1, dt2;
3304
3305 for ( size_t n = 0; n < WXSIZEOF(testArithmData); n++ )
3306 {
3307 wxDateSpan span = testArithmData[n].span;
3308 dt1 = dt + span;
3309 dt2 = dt - span;
3310
3311 const char *name = testArithmData[n].name;
3312 printf("%s + %s = %s, %s - %s = %s\n",
3313 dt.FormatISODate().c_str(), name, dt1.FormatISODate().c_str(),
3314 dt.FormatISODate().c_str(), name, dt2.FormatISODate().c_str());
3315
3316 printf("Going back: %s", (dt1 - span).FormatISODate().c_str());
3317 if ( dt1 - span == dt )
3318 {
3319 puts(" (ok)");
3320 }
3321 else
3322 {
3323 printf(" (ERROR: should be %s)\n", dt.FormatISODate().c_str());
3324 }
3325
3326 printf("Going forward: %s", (dt2 + span).FormatISODate().c_str());
3327 if ( dt2 + span == dt )
3328 {
3329 puts(" (ok)");
3330 }
3331 else
3332 {
3333 printf(" (ERROR: should be %s)\n", dt.FormatISODate().c_str());
3334 }
3335
3336 printf("Double increment: %s", (dt2 + 2*span).FormatISODate().c_str());
3337 if ( dt2 + 2*span == dt1 )
3338 {
3339 puts(" (ok)");
3340 }
3341 else
3342 {
3343 printf(" (ERROR: should be %s)\n", dt2.FormatISODate().c_str());
3344 }
3345
3346 puts("");
3347 }
3348 }
3349
3350 static void TestTimeHolidays()
3351 {
3352 puts("\n*** testing wxDateTimeHolidayAuthority ***\n");
3353
3354 wxDateTime::Tm tm = wxDateTime(29, wxDateTime::May, 2000).GetTm();
3355 wxDateTime dtStart(1, tm.mon, tm.year),
3356 dtEnd = dtStart.GetLastMonthDay();
3357
3358 wxDateTimeArray hol;
3359 wxDateTimeHolidayAuthority::GetHolidaysInRange(dtStart, dtEnd, hol);
3360
3361 const wxChar *format = "%d-%b-%Y (%a)";
3362
3363 printf("All holidays between %s and %s:\n",
3364 dtStart.Format(format).c_str(), dtEnd.Format(format).c_str());
3365
3366 size_t count = hol.GetCount();
3367 for ( size_t n = 0; n < count; n++ )
3368 {
3369 printf("\t%s\n", hol[n].Format(format).c_str());
3370 }
3371
3372 puts("");
3373 }
3374
3375 static void TestTimeZoneBug()
3376 {
3377 puts("\n*** testing for DST/timezone bug ***\n");
3378
3379 wxDateTime date = wxDateTime(1, wxDateTime::Mar, 2000);
3380 for ( int i = 0; i < 31; i++ )
3381 {
3382 printf("Date %s: week day %s.\n",
3383 date.Format(_T("%d-%m-%Y")).c_str(),
3384 date.GetWeekDayName(date.GetWeekDay()).c_str());
3385
3386 date += wxDateSpan::Day();
3387 }
3388
3389 puts("");
3390 }
3391
3392 static void TestTimeSpanFormat()
3393 {
3394 puts("\n*** wxTimeSpan tests ***");
3395
3396 static const char *formats[] =
3397 {
3398 _T("(default) %H:%M:%S"),
3399 _T("%E weeks and %D days"),
3400 _T("%l milliseconds"),
3401 _T("(with ms) %H:%M:%S:%l"),
3402 _T("100%% of minutes is %M"), // test "%%"
3403 _T("%D days and %H hours"),
3404 };
3405
3406 wxTimeSpan ts1(1, 2, 3, 4),
3407 ts2(111, 222, 333);
3408 for ( size_t n = 0; n < WXSIZEOF(formats); n++ )
3409 {
3410 printf("ts1 = %s\tts2 = %s\n",
3411 ts1.Format(formats[n]).c_str(),
3412 ts2.Format(formats[n]).c_str());
3413 }
3414
3415 puts("");
3416 }
3417
3418 #if 0
3419
3420 // test compatibility with the old wxDate/wxTime classes
3421 static void TestTimeCompatibility()
3422 {
3423 puts("\n*** wxDateTime compatibility test ***");
3424
3425 printf("wxDate for JDN 0: %s\n", wxDate(0l).FormatDate().c_str());
3426 printf("wxDate for MJD 0: %s\n", wxDate(2400000).FormatDate().c_str());
3427
3428 double jdnNow = wxDateTime::Now().GetJDN();
3429 long jdnMidnight = (long)(jdnNow - 0.5);
3430 printf("wxDate for today: %s\n", wxDate(jdnMidnight).FormatDate().c_str());
3431
3432 jdnMidnight = wxDate().Set().GetJulianDate();
3433 printf("wxDateTime for today: %s\n",
3434 wxDateTime((double)(jdnMidnight + 0.5)).Format("%c", wxDateTime::GMT0).c_str());
3435
3436 int flags = wxEUROPEAN;//wxFULL;
3437 wxDate date;
3438 date.Set();
3439 printf("Today is %s\n", date.FormatDate(flags).c_str());
3440 for ( int n = 0; n < 7; n++ )
3441 {
3442 printf("Previous %s is %s\n",
3443 wxDateTime::GetWeekDayName((wxDateTime::WeekDay)n),
3444 date.Previous(n + 1).FormatDate(flags).c_str());
3445 }
3446 }
3447
3448 #endif // 0
3449
3450 #endif // TEST_DATETIME
3451
3452 // ----------------------------------------------------------------------------
3453 // threads
3454 // ----------------------------------------------------------------------------
3455
3456 #ifdef TEST_THREADS
3457
3458 #include <wx/thread.h>
3459
3460 static size_t gs_counter = (size_t)-1;
3461 static wxCriticalSection gs_critsect;
3462 static wxCondition gs_cond;
3463
3464 class MyJoinableThread : public wxThread
3465 {
3466 public:
3467 MyJoinableThread(size_t n) : wxThread(wxTHREAD_JOINABLE)
3468 { m_n = n; Create(); }
3469
3470 // thread execution starts here
3471 virtual ExitCode Entry();
3472
3473 private:
3474 size_t m_n;
3475 };
3476
3477 wxThread::ExitCode MyJoinableThread::Entry()
3478 {
3479 unsigned long res = 1;
3480 for ( size_t n = 1; n < m_n; n++ )
3481 {
3482 res *= n;
3483
3484 // it's a loooong calculation :-)
3485 Sleep(100);
3486 }
3487
3488 return (ExitCode)res;
3489 }
3490
3491 class MyDetachedThread : public wxThread
3492 {
3493 public:
3494 MyDetachedThread(size_t n, char ch)
3495 {
3496 m_n = n;
3497 m_ch = ch;
3498 m_cancelled = FALSE;
3499
3500 Create();
3501 }
3502
3503 // thread execution starts here
3504 virtual ExitCode Entry();
3505
3506 // and stops here
3507 virtual void OnExit();
3508
3509 private:
3510 size_t m_n; // number of characters to write
3511 char m_ch; // character to write
3512
3513 bool m_cancelled; // FALSE if we exit normally
3514 };
3515
3516 wxThread::ExitCode MyDetachedThread::Entry()
3517 {
3518 {
3519 wxCriticalSectionLocker lock(gs_critsect);
3520 if ( gs_counter == (size_t)-1 )
3521 gs_counter = 1;
3522 else
3523 gs_counter++;
3524 }
3525
3526 for ( size_t n = 0; n < m_n; n++ )
3527 {
3528 if ( TestDestroy() )
3529 {
3530 m_cancelled = TRUE;
3531
3532 break;
3533 }
3534
3535 putchar(m_ch);
3536 fflush(stdout);
3537
3538 wxThread::Sleep(100);
3539 }
3540
3541 return 0;
3542 }
3543
3544 void MyDetachedThread::OnExit()
3545 {
3546 wxLogTrace("thread", "Thread %ld is in OnExit", GetId());
3547
3548 wxCriticalSectionLocker lock(gs_critsect);
3549 if ( !--gs_counter && !m_cancelled )
3550 gs_cond.Signal();
3551 }
3552
3553 void TestDetachedThreads()
3554 {
3555 puts("\n*** Testing detached threads ***");
3556
3557 static const size_t nThreads = 3;
3558 MyDetachedThread *threads[nThreads];
3559 size_t n;
3560 for ( n = 0; n < nThreads; n++ )
3561 {
3562 threads[n] = new MyDetachedThread(10, 'A' + n);
3563 }
3564
3565 threads[0]->SetPriority(WXTHREAD_MIN_PRIORITY);
3566 threads[1]->SetPriority(WXTHREAD_MAX_PRIORITY);
3567
3568 for ( n = 0; n < nThreads; n++ )
3569 {
3570 threads[n]->Run();
3571 }
3572
3573 // wait until all threads terminate
3574 gs_cond.Wait();
3575
3576 puts("");
3577 }
3578
3579 void TestJoinableThreads()
3580 {
3581 puts("\n*** Testing a joinable thread (a loooong calculation...) ***");
3582
3583 // calc 10! in the background
3584 MyJoinableThread thread(10);
3585 thread.Run();
3586
3587 printf("\nThread terminated with exit code %lu.\n",
3588 (unsigned long)thread.Wait());
3589 }
3590
3591 void TestThreadSuspend()
3592 {
3593 puts("\n*** Testing thread suspend/resume functions ***");
3594
3595 MyDetachedThread *thread = new MyDetachedThread(15, 'X');
3596
3597 thread->Run();
3598
3599 // this is for this demo only, in a real life program we'd use another
3600 // condition variable which would be signaled from wxThread::Entry() to
3601 // tell us that the thread really started running - but here just wait a
3602 // bit and hope that it will be enough (the problem is, of course, that
3603 // the thread might still not run when we call Pause() which will result
3604 // in an error)
3605 wxThread::Sleep(300);
3606
3607 for ( size_t n = 0; n < 3; n++ )
3608 {
3609 thread->Pause();
3610
3611 puts("\nThread suspended");
3612 if ( n > 0 )
3613 {
3614 // don't sleep but resume immediately the first time
3615 wxThread::Sleep(300);
3616 }
3617 puts("Going to resume the thread");
3618
3619 thread->Resume();
3620 }
3621
3622 puts("Waiting until it terminates now");
3623
3624 // wait until the thread terminates
3625 gs_cond.Wait();
3626
3627 puts("");
3628 }
3629
3630 void TestThreadDelete()
3631 {
3632 // As above, using Sleep() is only for testing here - we must use some
3633 // synchronisation object instead to ensure that the thread is still
3634 // running when we delete it - deleting a detached thread which already
3635 // terminated will lead to a crash!
3636
3637 puts("\n*** Testing thread delete function ***");
3638
3639 MyDetachedThread *thread0 = new MyDetachedThread(30, 'W');
3640
3641 thread0->Delete();
3642
3643 puts("\nDeleted a thread which didn't start to run yet.");
3644
3645 MyDetachedThread *thread1 = new MyDetachedThread(30, 'Y');
3646
3647 thread1->Run();
3648
3649 wxThread::Sleep(300);
3650
3651 thread1->Delete();
3652
3653 puts("\nDeleted a running thread.");
3654
3655 MyDetachedThread *thread2 = new MyDetachedThread(30, 'Z');
3656
3657 thread2->Run();
3658
3659 wxThread::Sleep(300);
3660
3661 thread2->Pause();
3662
3663 thread2->Delete();
3664
3665 puts("\nDeleted a sleeping thread.");
3666
3667 MyJoinableThread thread3(20);
3668 thread3.Run();
3669
3670 thread3.Delete();
3671
3672 puts("\nDeleted a joinable thread.");
3673
3674 MyJoinableThread thread4(2);
3675 thread4.Run();
3676
3677 wxThread::Sleep(300);
3678
3679 thread4.Delete();
3680
3681 puts("\nDeleted a joinable thread which already terminated.");
3682
3683 puts("");
3684 }
3685
3686 #endif // TEST_THREADS
3687
3688 // ----------------------------------------------------------------------------
3689 // arrays
3690 // ----------------------------------------------------------------------------
3691
3692 #ifdef TEST_ARRAYS
3693
3694 static void PrintArray(const char* name, const wxArrayString& array)
3695 {
3696 printf("Dump of the array '%s'\n", name);
3697
3698 size_t nCount = array.GetCount();
3699 for ( size_t n = 0; n < nCount; n++ )
3700 {
3701 printf("\t%s[%u] = '%s'\n", name, n, array[n].c_str());
3702 }
3703 }
3704
3705 static void PrintArray(const char* name, const wxArrayInt& array)
3706 {
3707 printf("Dump of the array '%s'\n", name);
3708
3709 size_t nCount = array.GetCount();
3710 for ( size_t n = 0; n < nCount; n++ )
3711 {
3712 printf("\t%s[%u] = %d\n", name, n, array[n]);
3713 }
3714 }
3715
3716 int wxCMPFUNC_CONV StringLenCompare(const wxString& first,
3717 const wxString& second)
3718 {
3719 return first.length() - second.length();
3720 }
3721
3722 int wxCMPFUNC_CONV IntCompare(int *first,
3723 int *second)
3724 {
3725 return *first - *second;
3726 }
3727
3728 int wxCMPFUNC_CONV IntRevCompare(int *first,
3729 int *second)
3730 {
3731 return *second - *first;
3732 }
3733
3734 static void TestArrayOfInts()
3735 {
3736 puts("*** Testing wxArrayInt ***\n");
3737
3738 wxArrayInt a;
3739 a.Add(1);
3740 a.Add(17);
3741 a.Add(5);
3742 a.Add(3);
3743
3744 puts("Initially:");
3745 PrintArray("a", a);
3746
3747 puts("After sort:");
3748 a.Sort(IntCompare);
3749 PrintArray("a", a);
3750
3751 puts("After reverse sort:");
3752 a.Sort(IntRevCompare);
3753 PrintArray("a", a);
3754 }
3755
3756 #include "wx/dynarray.h"
3757
3758 WX_DECLARE_OBJARRAY(Bar, ArrayBars);
3759 #include "wx/arrimpl.cpp"
3760 WX_DEFINE_OBJARRAY(ArrayBars);
3761
3762 static void TestArrayOfObjects()
3763 {
3764 puts("*** Testing wxObjArray ***\n");
3765
3766 {
3767 ArrayBars bars;
3768 Bar bar("second bar");
3769
3770 printf("Initially: %u objects in the array, %u objects total.\n",
3771 bars.GetCount(), Bar::GetNumber());
3772
3773 bars.Add(new Bar("first bar"));
3774 bars.Add(bar);
3775
3776 printf("Now: %u objects in the array, %u objects total.\n",
3777 bars.GetCount(), Bar::GetNumber());
3778
3779 bars.Empty();
3780
3781 printf("After Empty(): %u objects in the array, %u objects total.\n",
3782 bars.GetCount(), Bar::GetNumber());
3783 }
3784
3785 printf("Finally: no more objects in the array, %u objects total.\n",
3786 Bar::GetNumber());
3787 }
3788
3789 #endif // TEST_ARRAYS
3790
3791 // ----------------------------------------------------------------------------
3792 // strings
3793 // ----------------------------------------------------------------------------
3794
3795 #ifdef TEST_STRINGS
3796
3797 #include "wx/timer.h"
3798 #include "wx/tokenzr.h"
3799
3800 static void TestStringConstruction()
3801 {
3802 puts("*** Testing wxString constructores ***");
3803
3804 #define TEST_CTOR(args, res) \
3805 { \
3806 wxString s args ; \
3807 printf("wxString%s = %s ", #args, s.c_str()); \
3808 if ( s == res ) \
3809 { \
3810 puts("(ok)"); \
3811 } \
3812 else \
3813 { \
3814 printf("(ERROR: should be %s)\n", res); \
3815 } \
3816 }
3817
3818 TEST_CTOR((_T('Z'), 4), _T("ZZZZ"));
3819 TEST_CTOR((_T("Hello"), 4), _T("Hell"));
3820 TEST_CTOR((_T("Hello"), 5), _T("Hello"));
3821 // TEST_CTOR((_T("Hello"), 6), _T("Hello")); -- should give assert failure
3822
3823 static const wxChar *s = _T("?really!");
3824 const wxChar *start = wxStrchr(s, _T('r'));
3825 const wxChar *end = wxStrchr(s, _T('!'));
3826 TEST_CTOR((start, end), _T("really"));
3827
3828 puts("");
3829 }
3830
3831 static void TestString()
3832 {
3833 wxStopWatch sw;
3834
3835 wxString a, b, c;
3836
3837 a.reserve (128);
3838 b.reserve (128);
3839 c.reserve (128);
3840
3841 for (int i = 0; i < 1000000; ++i)
3842 {
3843 a = "Hello";
3844 b = " world";
3845 c = "! How'ya doin'?";
3846 a += b;
3847 a += c;
3848 c = "Hello world! What's up?";
3849 if (c != a)
3850 c = "Doh!";
3851 }
3852
3853 printf ("TestString elapsed time: %ld\n", sw.Time());
3854 }
3855
3856 static void TestPChar()
3857 {
3858 wxStopWatch sw;
3859
3860 char a [128];
3861 char b [128];
3862 char c [128];
3863
3864 for (int i = 0; i < 1000000; ++i)
3865 {
3866 strcpy (a, "Hello");
3867 strcpy (b, " world");
3868 strcpy (c, "! How'ya doin'?");
3869 strcat (a, b);
3870 strcat (a, c);
3871 strcpy (c, "Hello world! What's up?");
3872 if (strcmp (c, a) == 0)
3873 strcpy (c, "Doh!");
3874 }
3875
3876 printf ("TestPChar elapsed time: %ld\n", sw.Time());
3877 }
3878
3879 static void TestStringSub()
3880 {
3881 wxString s("Hello, world!");
3882
3883 puts("*** Testing wxString substring extraction ***");
3884
3885 printf("String = '%s'\n", s.c_str());
3886 printf("Left(5) = '%s'\n", s.Left(5).c_str());
3887 printf("Right(6) = '%s'\n", s.Right(6).c_str());
3888 printf("Mid(3, 5) = '%s'\n", s(3, 5).c_str());
3889 printf("Mid(3) = '%s'\n", s.Mid(3).c_str());
3890 printf("substr(3, 5) = '%s'\n", s.substr(3, 5).c_str());
3891 printf("substr(3) = '%s'\n", s.substr(3).c_str());
3892
3893 static const wxChar *prefixes[] =
3894 {
3895 _T("Hello"),
3896 _T("Hello, "),
3897 _T("Hello, world!"),
3898 _T("Hello, world!!!"),
3899 _T(""),
3900 _T("Goodbye"),
3901 _T("Hi"),
3902 };
3903
3904 for ( size_t n = 0; n < WXSIZEOF(prefixes); n++ )
3905 {
3906 wxString prefix = prefixes[n], rest;
3907 bool rc = s.StartsWith(prefix, &rest);
3908 printf("StartsWith('%s') = %s", prefix.c_str(), rc ? "TRUE" : "FALSE");
3909 if ( rc )
3910 {
3911 printf(" (the rest is '%s')\n", rest.c_str());
3912 }
3913 else
3914 {
3915 putchar('\n');
3916 }
3917 }
3918
3919 puts("");
3920 }
3921
3922 static void TestStringFormat()
3923 {
3924 puts("*** Testing wxString formatting ***");
3925
3926 wxString s;
3927 s.Printf("%03d", 18);
3928
3929 printf("Number 18: %s\n", wxString::Format("%03d", 18).c_str());
3930 printf("Number 18: %s\n", s.c_str());
3931
3932 puts("");
3933 }
3934
3935 // returns "not found" for npos, value for all others
3936 static wxString PosToString(size_t res)
3937 {
3938 wxString s = res == wxString::npos ? wxString(_T("not found"))
3939 : wxString::Format(_T("%u"), res);
3940 return s;
3941 }
3942
3943 static void TestStringFind()
3944 {
3945 puts("*** Testing wxString find() functions ***");
3946
3947 static const wxChar *strToFind = _T("ell");
3948 static const struct StringFindTest
3949 {
3950 const wxChar *str;
3951 size_t start,
3952 result; // of searching "ell" in str
3953 } findTestData[] =
3954 {
3955 { _T("Well, hello world"), 0, 1 },
3956 { _T("Well, hello world"), 6, 7 },
3957 { _T("Well, hello world"), 9, wxString::npos },
3958 };
3959
3960 for ( size_t n = 0; n < WXSIZEOF(findTestData); n++ )
3961 {
3962 const StringFindTest& ft = findTestData[n];
3963 size_t res = wxString(ft.str).find(strToFind, ft.start);
3964
3965 printf(_T("Index of '%s' in '%s' starting from %u is %s "),
3966 strToFind, ft.str, ft.start, PosToString(res).c_str());
3967
3968 size_t resTrue = ft.result;
3969 if ( res == resTrue )
3970 {
3971 puts(_T("(ok)"));
3972 }
3973 else
3974 {
3975 printf(_T("(ERROR: should be %s)\n"),
3976 PosToString(resTrue).c_str());
3977 }
3978 }
3979
3980 puts("");
3981 }
3982
3983 static void TestStringTokenizer()
3984 {
3985 puts("*** Testing wxStringTokenizer ***");
3986
3987 static const wxChar *modeNames[] =
3988 {
3989 _T("default"),
3990 _T("return empty"),
3991 _T("return all empty"),
3992 _T("with delims"),
3993 _T("like strtok"),
3994 };
3995
3996 static const struct StringTokenizerTest
3997 {
3998 const wxChar *str; // string to tokenize
3999 const wxChar *delims; // delimiters to use
4000 size_t count; // count of token
4001 wxStringTokenizerMode mode; // how should we tokenize it
4002 } tokenizerTestData[] =
4003 {
4004 { _T(""), _T(" "), 0 },
4005 { _T("Hello, world"), _T(" "), 2 },
4006 { _T("Hello, world "), _T(" "), 2 },
4007 { _T("Hello, world"), _T(","), 2 },
4008 { _T("Hello, world!"), _T(",!"), 2 },
4009 { _T("Hello,, world!"), _T(",!"), 3 },
4010 { _T("Hello, world!"), _T(",!"), 3, wxTOKEN_RET_EMPTY_ALL },
4011 { _T("username:password:uid:gid:gecos:home:shell"), _T(":"), 7 },
4012 { _T("1 \t3\t4 6 "), wxDEFAULT_DELIMITERS, 4 },
4013 { _T("1 \t3\t4 6 "), wxDEFAULT_DELIMITERS, 6, wxTOKEN_RET_EMPTY },
4014 { _T("1 \t3\t4 6 "), wxDEFAULT_DELIMITERS, 9, wxTOKEN_RET_EMPTY_ALL },
4015 { _T("01/02/99"), _T("/-"), 3 },
4016 { _T("01-02/99"), _T("/-"), 3, wxTOKEN_RET_DELIMS },
4017 };
4018
4019 for ( size_t n = 0; n < WXSIZEOF(tokenizerTestData); n++ )
4020 {
4021 const StringTokenizerTest& tt = tokenizerTestData[n];
4022 wxStringTokenizer tkz(tt.str, tt.delims, tt.mode);
4023
4024 size_t count = tkz.CountTokens();
4025 printf(_T("String '%s' has %u tokens delimited by '%s' (mode = %s) "),
4026 MakePrintable(tt.str).c_str(),
4027 count,
4028 MakePrintable(tt.delims).c_str(),
4029 modeNames[tkz.GetMode()]);
4030 if ( count == tt.count )
4031 {
4032 puts(_T("(ok)"));
4033 }
4034 else
4035 {
4036 printf(_T("(ERROR: should be %u)\n"), tt.count);
4037
4038 continue;
4039 }
4040
4041 // if we emulate strtok(), check that we do it correctly
4042 wxChar *buf, *s = NULL, *last;
4043
4044 if ( tkz.GetMode() == wxTOKEN_STRTOK )
4045 {
4046 buf = new wxChar[wxStrlen(tt.str) + 1];
4047 wxStrcpy(buf, tt.str);
4048
4049 s = wxStrtok(buf, tt.delims, &last);
4050 }
4051 else
4052 {
4053 buf = NULL;
4054 }
4055
4056 // now show the tokens themselves
4057 size_t count2 = 0;
4058 while ( tkz.HasMoreTokens() )
4059 {
4060 wxString token = tkz.GetNextToken();
4061
4062 printf(_T("\ttoken %u: '%s'"),
4063 ++count2,
4064 MakePrintable(token).c_str());
4065
4066 if ( buf )
4067 {
4068 if ( token == s )
4069 {
4070 puts(" (ok)");
4071 }
4072 else
4073 {
4074 printf(" (ERROR: should be %s)\n", s);
4075 }
4076
4077 s = wxStrtok(NULL, tt.delims, &last);
4078 }
4079 else
4080 {
4081 // nothing to compare with
4082 puts("");
4083 }
4084 }
4085
4086 if ( count2 != count )
4087 {
4088 puts(_T("\tERROR: token count mismatch"));
4089 }
4090
4091 delete [] buf;
4092 }
4093
4094 puts("");
4095 }
4096
4097 static void TestStringReplace()
4098 {
4099 puts("*** Testing wxString::replace ***");
4100
4101 static const struct StringReplaceTestData
4102 {
4103 const wxChar *original; // original test string
4104 size_t start, len; // the part to replace
4105 const wxChar *replacement; // the replacement string
4106 const wxChar *result; // and the expected result
4107 } stringReplaceTestData[] =
4108 {
4109 { _T("012-AWORD-XYZ"), 4, 5, _T("BWORD"), _T("012-BWORD-XYZ") },
4110 { _T("increase"), 0, 2, _T("de"), _T("decrease") },
4111 { _T("wxWindow"), 8, 0, _T("s"), _T("wxWindows") },
4112 { _T("foobar"), 3, 0, _T("-"), _T("foo-bar") },
4113 { _T("barfoo"), 0, 6, _T("foobar"), _T("foobar") },
4114 };
4115
4116 for ( size_t n = 0; n < WXSIZEOF(stringReplaceTestData); n++ )
4117 {
4118 const StringReplaceTestData data = stringReplaceTestData[n];
4119
4120 wxString original = data.original;
4121 original.replace(data.start, data.len, data.replacement);
4122
4123 wxPrintf(_T("wxString(\"%s\").replace(%u, %u, %s) = %s "),
4124 data.original, data.start, data.len, data.replacement,
4125 original.c_str());
4126
4127 if ( original == data.result )
4128 {
4129 puts("(ok)");
4130 }
4131 else
4132 {
4133 wxPrintf(_T("(ERROR: should be '%s')\n"), data.result);
4134 }
4135 }
4136
4137 puts("");
4138 }
4139
4140 #endif // TEST_STRINGS
4141
4142 // ----------------------------------------------------------------------------
4143 // entry point
4144 // ----------------------------------------------------------------------------
4145
4146 int main(int argc, char **argv)
4147 {
4148 if ( !wxInitialize() )
4149 {
4150 fprintf(stderr, "Failed to initialize the wxWindows library, aborting.");
4151 }
4152
4153 #ifdef TEST_USLEEP
4154 puts("Sleeping for 3 seconds... z-z-z-z-z...");
4155 wxUsleep(3000);
4156 #endif // TEST_USLEEP
4157
4158 #ifdef TEST_CMDLINE
4159 static const wxCmdLineEntryDesc cmdLineDesc[] =
4160 {
4161 { wxCMD_LINE_SWITCH, "v", "verbose", "be verbose" },
4162 { wxCMD_LINE_SWITCH, "q", "quiet", "be quiet" },
4163
4164 { wxCMD_LINE_OPTION, "o", "output", "output file" },
4165 { wxCMD_LINE_OPTION, "i", "input", "input dir" },
4166 { wxCMD_LINE_OPTION, "s", "size", "output block size", wxCMD_LINE_VAL_NUMBER },
4167 { wxCMD_LINE_OPTION, "d", "date", "output file date", wxCMD_LINE_VAL_DATE },
4168
4169 { wxCMD_LINE_PARAM, NULL, NULL, "input file",
4170 wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_MULTIPLE },
4171
4172 { wxCMD_LINE_NONE }
4173 };
4174
4175 wxCmdLineParser parser(cmdLineDesc, argc, argv);
4176
4177 parser.AddOption("project_name", "", "full path to project file",
4178 wxCMD_LINE_VAL_STRING,
4179 wxCMD_LINE_OPTION_MANDATORY | wxCMD_LINE_NEEDS_SEPARATOR);
4180
4181 switch ( parser.Parse() )
4182 {
4183 case -1:
4184 wxLogMessage("Help was given, terminating.");
4185 break;
4186
4187 case 0:
4188 ShowCmdLine(parser);
4189 break;
4190
4191 default:
4192 wxLogMessage("Syntax error detected, aborting.");
4193 break;
4194 }
4195 #endif // TEST_CMDLINE
4196
4197 #ifdef TEST_STRINGS
4198 if ( 0 )
4199 {
4200 TestPChar();
4201 TestString();
4202 }
4203 TestStringSub();
4204 if ( 0 )
4205 {
4206 TestStringConstruction();
4207 TestStringFormat();
4208 TestStringFind();
4209 TestStringTokenizer();
4210 TestStringReplace();
4211 }
4212 #endif // TEST_STRINGS
4213
4214 #ifdef TEST_ARRAYS
4215 if ( 0 )
4216 {
4217 wxArrayString a1;
4218 a1.Add("tiger");
4219 a1.Add("cat");
4220 a1.Add("lion");
4221 a1.Add("dog");
4222 a1.Add("human");
4223 a1.Add("ape");
4224
4225 puts("*** Initially:");
4226
4227 PrintArray("a1", a1);
4228
4229 wxArrayString a2(a1);
4230 PrintArray("a2", a2);
4231
4232 wxSortedArrayString a3(a1);
4233 PrintArray("a3", a3);
4234
4235 puts("*** After deleting a string from a1");
4236 a1.Remove(2);
4237
4238 PrintArray("a1", a1);
4239 PrintArray("a2", a2);
4240 PrintArray("a3", a3);
4241
4242 puts("*** After reassigning a1 to a2 and a3");
4243 a3 = a2 = a1;
4244 PrintArray("a2", a2);
4245 PrintArray("a3", a3);
4246
4247 puts("*** After sorting a1");
4248 a1.Sort();
4249 PrintArray("a1", a1);
4250
4251 puts("*** After sorting a1 in reverse order");
4252 a1.Sort(TRUE);
4253 PrintArray("a1", a1);
4254
4255 puts("*** After sorting a1 by the string length");
4256 a1.Sort(StringLenCompare);
4257 PrintArray("a1", a1);
4258
4259 TestArrayOfObjects();
4260 }
4261 TestArrayOfInts();
4262 #endif // TEST_ARRAYS
4263
4264 #ifdef TEST_DIR
4265 TestDirEnum();
4266 #endif // TEST_DIR
4267
4268 #ifdef TEST_DLLLOADER
4269 TestDllLoad();
4270 #endif // TEST_DLLLOADER
4271
4272 #ifdef TEST_ENVIRON
4273 TestEnvironment();
4274 #endif // TEST_ENVIRON
4275
4276 #ifdef TEST_EXECUTE
4277 TestExecute();
4278 #endif // TEST_EXECUTE
4279
4280 #ifdef TEST_FILECONF
4281 TestFileConfRead();
4282 #endif // TEST_FILECONF
4283
4284 #ifdef TEST_LIST
4285 TestListCtor();
4286 #endif // TEST_LIST
4287
4288 #ifdef TEST_LOG
4289 wxString s;
4290 for ( size_t n = 0; n < 8000; n++ )
4291 {
4292 s << (char)('A' + (n % 26));
4293 }
4294
4295 wxString msg;
4296 msg.Printf("A very very long message: '%s', the end!\n", s.c_str());
4297
4298 // this one shouldn't be truncated
4299 printf(msg);
4300
4301 // but this one will because log functions use fixed size buffer
4302 // (note that it doesn't need '\n' at the end neither - will be added
4303 // by wxLog anyhow)
4304 wxLogMessage("A very very long message 2: '%s', the end!", s.c_str());
4305 #endif // TEST_LOG
4306
4307 #ifdef TEST_FILE
4308 if ( 0 )
4309 {
4310 TestFileRead();
4311 TestTextFileRead();
4312 }
4313 TestFileCopy();
4314 #endif // TEST_FILE
4315
4316 #ifdef TEST_FILENAME
4317 TestFileNameSplit();
4318 if ( 0 )
4319 {
4320 TestFileNameConstruction();
4321 TestFileNameCwd();
4322 TestFileNameComparison();
4323 TestFileNameOperations();
4324 }
4325 #endif // TEST_FILENAME
4326
4327 #ifdef TEST_THREADS
4328 int nCPUs = wxThread::GetCPUCount();
4329 printf("This system has %d CPUs\n", nCPUs);
4330 if ( nCPUs != -1 )
4331 wxThread::SetConcurrency(nCPUs);
4332
4333 if ( argc > 1 && argv[1][0] == 't' )
4334 wxLog::AddTraceMask("thread");
4335
4336 if ( 1 )
4337 TestDetachedThreads();
4338 if ( 1 )
4339 TestJoinableThreads();
4340 if ( 1 )
4341 TestThreadSuspend();
4342 if ( 1 )
4343 TestThreadDelete();
4344
4345 #endif // TEST_THREADS
4346
4347 #ifdef TEST_LONGLONG
4348 // seed pseudo random generator
4349 srand((unsigned)time(NULL));
4350
4351 if ( 0 )
4352 {
4353 TestSpeed();
4354 }
4355 if ( 0 )
4356 {
4357 TestMultiplication();
4358 TestDivision();
4359 TestAddition();
4360 TestLongLongConversion();
4361 TestBitOperations();
4362 }
4363 TestLongLongComparison();
4364 #endif // TEST_LONGLONG
4365
4366 #ifdef TEST_HASH
4367 TestHash();
4368 #endif // TEST_HASH
4369
4370 #ifdef TEST_MIME
4371 wxLog::AddTraceMask(_T("mime"));
4372 if ( 1 )
4373 {
4374 TestMimeEnum();
4375 TestMimeOverride();
4376 TestMimeFilename();
4377 }
4378 else
4379 TestMimeAssociate();
4380 #endif // TEST_MIME
4381
4382 #ifdef TEST_INFO_FUNCTIONS
4383 TestOsInfo();
4384 TestUserInfo();
4385 #endif // TEST_INFO_FUNCTIONS
4386
4387 #ifdef TEST_PATHLIST
4388 TestPathList();
4389 #endif // TEST_PATHLIST
4390
4391 #ifdef TEST_REGISTRY
4392 if ( 0 )
4393 TestRegistryRead();
4394 TestRegistryAssociation();
4395 #endif // TEST_REGISTRY
4396
4397 #ifdef TEST_SOCKETS
4398 if ( 0 )
4399 {
4400 TestSocketServer();
4401 }
4402 TestSocketClient();
4403 #endif // TEST_SOCKETS
4404
4405 #ifdef TEST_FTP
4406 wxLog::AddTraceMask(FTP_TRACE_MASK);
4407 if ( TestFtpConnect() )
4408 {
4409 TestFtpFileSize();
4410 if ( 0 )
4411 {
4412 TestFtpList();
4413 TestFtpDownload();
4414 TestFtpMisc();
4415 TestFtpUpload();
4416 }
4417 if ( 0 )
4418 TestFtpInteractive();
4419 }
4420 //else: connecting to the FTP server failed
4421
4422 if ( 0 )
4423 TestFtpWuFtpd();
4424 #endif // TEST_FTP
4425
4426 #ifdef TEST_STREAMS
4427 if ( 0 )
4428 TestFileStream();
4429 TestMemoryStream();
4430 #endif // TEST_STREAMS
4431
4432 #ifdef TEST_TIMER
4433 TestStopWatch();
4434 #endif // TEST_TIMER
4435
4436 #ifdef TEST_DATETIME
4437 if ( 0 )
4438 {
4439 TestTimeSet();
4440 TestTimeStatic();
4441 TestTimeRange();
4442 TestTimeZones();
4443 TestTimeTicks();
4444 TestTimeJDN();
4445 TestTimeDST();
4446 TestTimeWDays();
4447 TestTimeWNumber();
4448 TestTimeParse();
4449 TestTimeArithmetics();
4450 TestTimeHolidays();
4451 TestTimeFormat();
4452 TestTimeMS();
4453
4454 TestTimeZoneBug();
4455 }
4456 TestTimeSpanFormat();
4457 if ( 0 )
4458 TestDateTimeInteractive();
4459 #endif // TEST_DATETIME
4460
4461 #ifdef TEST_VCARD
4462 if ( 0 )
4463 TestVCardRead();
4464 TestVCardWrite();
4465 #endif // TEST_VCARD
4466
4467 #ifdef TEST_WCHAR
4468 TestUtf8();
4469 #endif // TEST_WCHAR
4470
4471 #ifdef TEST_ZIP
4472 if ( 0 )
4473 TestZipStreamRead();
4474 TestZipFileSystem();
4475 #endif // TEST_ZIP
4476
4477 #ifdef TEST_ZLIB
4478 if ( 0 )
4479 TestZlibStreamWrite();
4480 TestZlibStreamRead();
4481 #endif // TEST_ZLIB
4482
4483 wxUninitialize();
4484
4485 return 0;
4486 }
4487