comparison dmd/root/root.c @ 1194:1853dcd9b944

Moved some DMDFE files into a seperate dmd/root subdir to closer match the DMD file structure since 1.041.
author Tomas Lindquist Olsen <tomas.l.olsen gmail.com>
date Fri, 03 Apr 2009 17:02:52 +0200
parents
children e961851fb8be
comparison
equal deleted inserted replaced
1193:c271eca933fb 1194:1853dcd9b944
1
2 // Copyright (c) 1999-2009 by Digital Mars
3 // All Rights Reserved
4 // written by Walter Bright
5 // www.digitalmars.com
6 // License for redistribution is by either the Artistic License
7 // in artistic.txt, or the GNU General Public License in gnu.txt.
8 // See the included readme.txt for details.
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <stdarg.h>
13 #include <string.h>
14 #include <stdint.h>
15 #include <assert.h>
16
17 #if (defined (__SVR4) && defined (__sun))
18 #include <alloca.h>
19 #endif
20
21 #if _MSC_VER ||__MINGW32__
22 #include <malloc.h>
23 #include <string>
24 #endif
25
26 #if _WIN32
27 #include <windows.h>
28 #include <direct.h>
29 #endif
30
31 #if POSIX
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <fcntl.h>
35 #include <errno.h>
36 #include <unistd.h>
37 #include <utime.h>
38 #endif
39
40 #include "port.h"
41 #include "root.h"
42 #include "dchar.h"
43 #include "rmem.h"
44 #include "mars.h"
45
46 #if 0 //__SC__ //def DEBUG
47 extern "C" void __cdecl _assert(void *e, void *f, unsigned line)
48 {
49 printf("Assert('%s','%s',%d)\n",e,f,line);
50 fflush(stdout);
51 *(char *)0 = 0;
52 }
53 #endif
54
55
56 /*************************************
57 * Convert wchar string to ascii string.
58 */
59
60 char *wchar2ascii(wchar_t *us)
61 {
62 return wchar2ascii(us, wcslen(us));
63 }
64
65 char *wchar2ascii(wchar_t *us, unsigned len)
66 {
67 unsigned i;
68 char *p;
69
70 p = (char *)mem.malloc(len + 1);
71 for (i = 0; i <= len; i++)
72 p[i] = (char) us[i];
73 return p;
74 }
75
76 int wcharIsAscii(wchar_t *us)
77 {
78 return wcharIsAscii(us, wcslen(us));
79 }
80
81 int wcharIsAscii(wchar_t *us, unsigned len)
82 {
83 unsigned i;
84
85 for (i = 0; i <= len; i++)
86 {
87 if (us[i] & ~0xFF) // if high bits set
88 return 0; // it's not ascii
89 }
90 return 1;
91 }
92
93
94 /***********************************
95 * Compare length-prefixed strings (bstr).
96 */
97
98 int bstrcmp(unsigned char *b1, unsigned char *b2)
99 {
100 return (*b1 == *b2 && memcmp(b1 + 1, b2 + 1, *b2) == 0) ? 0 : 1;
101 }
102
103 /***************************************
104 * Convert bstr into a malloc'd string.
105 */
106
107 char *bstr2str(unsigned char *b)
108 {
109 char *s;
110 unsigned len;
111
112 len = *b;
113 s = (char *) mem.malloc(len + 1);
114 s[len] = 0;
115 return (char *)memcpy(s,b + 1,len);
116 }
117
118 /**************************************
119 * Print error message and exit.
120 */
121
122 void error(const char *format, ...)
123 {
124 va_list ap;
125
126 va_start(ap, format);
127 printf("Error: ");
128 vprintf(format, ap);
129 va_end( ap );
130 printf("\n");
131 fflush(stdout);
132
133 exit(EXIT_FAILURE);
134 }
135
136 #if M_UNICODE
137 void error(const dchar *format, ...)
138 {
139 va_list ap;
140
141 va_start(ap, format);
142 printf("Error: ");
143 vwprintf(format, ap);
144 va_end( ap );
145 printf("\n");
146 fflush(stdout);
147
148 exit(EXIT_FAILURE);
149 }
150 #endif
151
152 void error_mem()
153 {
154 error("out of memory");
155 }
156
157 /**************************************
158 * Print warning message.
159 */
160
161 void warning(const char *format, ...)
162 {
163 va_list ap;
164
165 va_start(ap, format);
166 printf("Warning: ");
167 vprintf(format, ap);
168 va_end( ap );
169 printf("\n");
170 fflush(stdout);
171 }
172
173 /****************************** Object ********************************/
174
175 int Object::equals(Object *o)
176 {
177 return o == this;
178 }
179
180 hash_t Object::hashCode()
181 {
182 return (hash_t) this;
183 }
184
185 int Object::compare(Object *obj)
186 {
187 return this - obj;
188 }
189
190 void Object::print()
191 {
192 printf("%s %p\n", toChars(), this);
193 }
194
195 char *Object::toChars()
196 {
197 return (char *)"Object";
198 }
199
200 dchar *Object::toDchars()
201 {
202 #if M_UNICODE
203 return L"Object";
204 #else
205 return toChars();
206 #endif
207 }
208
209 int Object::dyncast()
210 {
211 return 0;
212 }
213
214 void Object::toBuffer(OutBuffer *b)
215 {
216 b->writestring("Object");
217 }
218
219 void Object::mark()
220 {
221 }
222
223 /****************************** String ********************************/
224
225 String::String(char *str, int ref)
226 {
227 this->str = ref ? str : mem.strdup(str);
228 this->ref = ref;
229 }
230
231 String::~String()
232 {
233 mem.free(str);
234 }
235
236 void String::mark()
237 {
238 mem.mark(str);
239 }
240
241 hash_t String::calcHash(const char *str, size_t len)
242 {
243 hash_t hash = 0;
244
245 for (;;)
246 {
247 switch (len)
248 {
249 case 0:
250 return hash;
251
252 case 1:
253 hash *= 37;
254 hash += *(uint8_t *)str;
255 return hash;
256
257 case 2:
258 hash *= 37;
259 hash += *(uint16_t *)str;
260 return hash;
261
262 case 3:
263 hash *= 37;
264 hash += (*(uint16_t *)str << 8) +
265 ((uint8_t *)str)[2];
266 return hash;
267
268 default:
269 hash *= 37;
270 hash += *(uint32_t *)str;
271 str += 4;
272 len -= 4;
273 break;
274 }
275 }
276 }
277
278 hash_t String::calcHash(const char *str)
279 {
280 return calcHash(str, strlen(str));
281 }
282
283 hash_t String::hashCode()
284 {
285 return calcHash(str, strlen(str));
286 }
287
288 unsigned String::len()
289 {
290 return strlen(str);
291 }
292
293 int String::equals(Object *obj)
294 {
295 return strcmp(str,((String *)obj)->str) == 0;
296 }
297
298 int String::compare(Object *obj)
299 {
300 return strcmp(str,((String *)obj)->str);
301 }
302
303 char *String::toChars()
304 {
305 return str;
306 }
307
308 void String::print()
309 {
310 printf("String '%s'\n",str);
311 }
312
313
314 /****************************** FileName ********************************/
315
316 FileName::FileName(char *str, int ref)
317 : String(str,ref)
318 {
319 }
320
321 char *FileName::combine(const char *path, const char *name)
322 { char *f;
323 size_t pathlen;
324 size_t namelen;
325
326 if (!path || !*path)
327 return (char *)name;
328 pathlen = strlen(path);
329 namelen = strlen(name);
330 f = (char *)mem.malloc(pathlen + 1 + namelen + 1);
331 memcpy(f, path, pathlen);
332
333 if (
334 path[pathlen - 1] != '/'
335 #if _WIN32
336 && path[pathlen - 1] != '\\' && path[pathlen - 1] != ':'
337 #endif
338 )
339 { f[pathlen] = '/';
340 pathlen++;
341 }
342
343 memcpy(f + pathlen, name, namelen + 1);
344 return f;
345 }
346
347 FileName::FileName(char *path, char *name)
348 : String(combine(path,name),1)
349 {
350 }
351
352 // Split a path into an Array of paths
353 Array *FileName::splitPath(const char *path)
354 {
355 char c = 0; // unnecessary initializer is for VC /W4
356 const char *p;
357 OutBuffer buf;
358 Array *array;
359
360 array = new Array();
361 if (path)
362 {
363 p = path;
364 do
365 { char instring = 0;
366
367 while (isspace(*p)) // skip leading whitespace
368 p++;
369 buf.reserve(strlen(p) + 1); // guess size of path
370 // LDC remember first character
371 const char* start = p;
372 for (; ; p++)
373 {
374 c = *p;
375 switch (c)
376 {
377 case '"':
378 instring ^= 1; // toggle inside/outside of string
379 continue;
380
381 #if MACINTOSH
382 case ',':
383 #endif
384 #if _WIN32
385 case ';':
386 #endif
387 #if POSIX
388 case ':':
389 #endif
390 p++;
391 break; // note that ; cannot appear as part
392 // of a path, quotes won't protect it
393
394 case 0x1A: // ^Z means end of file
395 case 0:
396 break;
397
398 case '\r':
399 continue; // ignore carriage returns
400
401 #if POSIX
402 case '~':
403 // LDC don't expand unless first character of path
404 if (p != start)
405 goto Ldefault;
406 buf.writestring(getenv("HOME"));
407 continue;
408 #endif
409
410 case ' ':
411 case '\t': // tabs in filenames?
412 if (!instring) // if not in string
413 break; // treat as end of path
414 default:
415 Ldefault:
416 buf.writeByte(c);
417 continue;
418 }
419 break;
420 }
421 if (buf.offset) // if path is not empty
422 {
423 buf.writeByte(0); // to asciiz
424 array->push(buf.extractData());
425 }
426 } while (c);
427 }
428 return array;
429 }
430
431 hash_t FileName::hashCode()
432 {
433 #if _WIN32
434 // We need a different hashCode because it must be case-insensitive
435 size_t len = strlen(str);
436 hash_t hash = 0;
437 unsigned char *s = (unsigned char *)str;
438
439 for (;;)
440 {
441 switch (len)
442 {
443 case 0:
444 return hash;
445
446 case 1:
447 hash *= 37;
448 hash += *(uint8_t *)s | 0x20;
449 return hash;
450
451 case 2:
452 hash *= 37;
453 hash += *(uint16_t *)s | 0x2020;
454 return hash;
455
456 case 3:
457 hash *= 37;
458 hash += ((*(uint16_t *)s << 8) +
459 ((uint8_t *)s)[2]) | 0x202020;
460 break;
461
462 default:
463 hash *= 37;
464 hash += *(uint32_t *)s | 0x20202020;
465 s += 4;
466 len -= 4;
467 break;
468 }
469 }
470 #else
471 // darwin HFS is case insensitive, though...
472 return String::hashCode();
473 #endif
474 }
475
476 int FileName::compare(Object *obj)
477 {
478 #if _WIN32
479 return stricmp(str,((FileName *)obj)->str);
480 #else
481 return String::compare(obj);
482 #endif
483 }
484
485 int FileName::equals(Object *obj)
486 {
487 #if _WIN32
488 return stricmp(str,((FileName *)obj)->str) == 0;
489 #else
490 return String::equals(obj);
491 #endif
492 }
493
494 /************************************
495 * Return !=0 if absolute path name.
496 */
497
498 int FileName::absolute(const char *name)
499 {
500 return
501 #if _WIN32
502 (*name == '\\') ||
503 (*name == '/') ||
504 (*name && name[1] == ':') ||
505 #endif
506 (*name == '/');
507 }
508
509 /********************************
510 * Return filename extension (read-only).
511 * Points past '.' of extension.
512 * If there isn't one, return NULL.
513 */
514
515 char *FileName::ext(const char *str)
516 {
517 char *e;
518 size_t len = strlen(str);
519
520 e = (char *)str + len;
521 for (;;)
522 {
523 switch (*e)
524 { case '.':
525 return e + 1;
526
527 case '/':
528 break;
529
530 #if _WIN32
531 case '\\':
532 case ':':
533 break;
534 #endif
535 default:
536 if (e == str)
537 break;
538 e--;
539 continue;
540 }
541 return NULL;
542 }
543 }
544
545 char *FileName::ext()
546 {
547 return ext(str);
548 }
549
550 /********************************
551 * Return mem.malloc'd filename with extension removed.
552 */
553
554 char *FileName::removeExt(const char *str)
555 {
556 const char *e = ext(str);
557 if (e)
558 { size_t len = (e - str) - 1;
559 char *n = (char *)mem.malloc(len + 1);
560 memcpy(n, str, len);
561 n[len] = 0;
562 return n;
563 }
564 return mem.strdup(str);
565 }
566
567 /********************************
568 * Return filename name excluding path (read-only).
569 */
570
571 char *FileName::name(const char *str)
572 {
573 char *e;
574 size_t len = strlen(str);
575
576 e = (char *)str + len;
577 for (;;)
578 {
579 switch (*e)
580 {
581
582 case '/':
583 return e + 1;
584
585 #if _WIN32
586 case '\\':
587 case ':':
588 return e + 1;
589 #endif
590 default:
591 if (e == str)
592 break;
593 e--;
594 continue;
595 }
596 return e;
597 }
598 }
599
600 char *FileName::name()
601 {
602 return name(str);
603 }
604
605 /**************************************
606 * Return path portion of str.
607 * Path will does not include trailing path separator.
608 */
609
610 char *FileName::path(const char *str)
611 {
612 char *n = name(str);
613 char *path;
614 size_t pathlen;
615
616 if (n > str)
617 {
618
619 if (n[-1] == '/')
620 n--;
621
622 #if _WIN32
623 if (n[-1] == '\\')
624 n--;
625 #endif
626 }
627 pathlen = n - str;
628 path = (char *)mem.malloc(pathlen + 1);
629 memcpy(path, str, pathlen);
630 path[pathlen] = 0;
631 return path;
632 }
633
634 /**************************************
635 * Replace filename portion of path.
636 */
637
638 char *FileName::replaceName(char *path, char *name)
639 { char *f;
640 char *n;
641 size_t pathlen;
642 size_t namelen;
643
644 if (absolute(name))
645 return name;
646
647 n = FileName::name(path);
648 if (n == path)
649 return name;
650 pathlen = n - path;
651 namelen = strlen(name);
652 f = (char *)mem.malloc(pathlen + 1 + namelen + 1);
653 memcpy(f, path, pathlen);
654
655 if (
656 path[pathlen - 1] != '/'
657 #if _WIN32
658 && path[pathlen - 1] != '\\' && path[pathlen - 1] != ':'
659 #endif
660 )
661 { f[pathlen] = '/';
662 pathlen++;
663 }
664
665 memcpy(f + pathlen, name, namelen + 1);
666 return f;
667 }
668
669 /***************************
670 */
671
672 FileName *FileName::defaultExt(const char *name, const char *ext)
673 {
674 char *e;
675 char *s;
676 size_t len;
677 size_t extlen;
678
679 e = FileName::ext(name);
680 if (e) // if already has an extension
681 return new FileName((char *)name, 0);
682
683 len = strlen(name);
684 extlen = strlen(ext);
685 s = (char *)alloca(len + 1 + extlen + 1);
686 memcpy(s,name,len);
687 s[len] = '.';
688 memcpy(s + len + 1, ext, extlen + 1);
689 return new FileName(s, 0);
690 }
691
692 /***************************
693 */
694
695 FileName *FileName::forceExt(const char *name, const char *ext)
696 {
697 char *e;
698 char *s;
699 size_t len;
700 size_t extlen;
701
702 e = FileName::ext(name);
703 if (e) // if already has an extension
704 {
705 len = e - name;
706 extlen = strlen(ext);
707
708 s = (char *)alloca(len + extlen + 1);
709 memcpy(s,name,len);
710 memcpy(s + len, ext, extlen + 1);
711 return new FileName(s, 0);
712 }
713 else
714 return defaultExt(name, ext); // doesn't have one
715 }
716
717 /******************************
718 * Return !=0 if extensions match.
719 */
720
721 int FileName::equalsExt(const char *ext)
722 { const char *e;
723
724 e = FileName::ext();
725 if (!e && !ext)
726 return 1;
727 if (!e || !ext)
728 return 0;
729 #if POSIX
730 return strcmp(e,ext) == 0;
731 #endif
732 #if _WIN32
733 return stricmp(e,ext) == 0;
734 #endif
735 }
736
737 /*************************************
738 * Copy file from this to to.
739 */
740
741 void FileName::CopyTo(FileName *to)
742 {
743 File file(this);
744
745 #if _WIN32
746 file.touchtime = mem.malloc(sizeof(WIN32_FIND_DATAA)); // keep same file time
747 #endif
748 #if POSIX
749 file.touchtime = mem.malloc(sizeof(struct stat)); // keep same file time
750 #endif
751 file.readv();
752 file.name = to;
753 file.writev();
754 }
755
756 /*************************************
757 * Search Path for file.
758 * Input:
759 * cwd if !=0, search current directory before searching path
760 */
761
762 char *FileName::searchPath(Array *path, const char *name, int cwd)
763 {
764 if (absolute(name))
765 {
766 return exists(name) ? (char *)name : NULL;
767 }
768 if (cwd)
769 {
770 if (exists(name))
771 return (char *)name;
772 }
773 if (path)
774 { unsigned i;
775
776 for (i = 0; i < path->dim; i++)
777 {
778 char *p = (char *)path->data[i];
779 char *n = combine(p, name);
780
781 if (exists(n))
782 return n;
783 }
784 }
785 return NULL;
786 }
787
788 int FileName::exists(const char *name)
789 {
790 #if POSIX
791 struct stat st;
792
793 if (stat(name, &st) < 0)
794 return 0;
795 if (S_ISDIR(st.st_mode))
796 return 2;
797 return 1;
798 #endif
799 #if _WIN32
800 DWORD dw;
801 int result;
802
803 dw = GetFileAttributesA(name);
804 if (dw == -1L)
805 result = 0;
806 else if (dw & FILE_ATTRIBUTE_DIRECTORY)
807 result = 2;
808 else
809 result = 1;
810 return result;
811 #endif
812 }
813
814 void FileName::ensurePathExists(const char *path)
815 {
816 //printf("FileName::ensurePathExists(%s)\n", path ? path : "");
817 if (path && *path)
818 {
819 if (!exists(path))
820 {
821 char *p = FileName::path(path);
822 if (*p)
823 {
824 #if _WIN32
825 size_t len = strlen(p);
826 if (len > 2 && p[-1] == ':')
827 { mem.free(p);
828 return;
829 }
830 #endif
831 ensurePathExists(p);
832 mem.free(p);
833 }
834 #if _WIN32
835 if (path[strlen(path) - 1] != '\\')
836 #endif
837 #if POSIX
838 if (path[strlen(path) - 1] != '\\')
839 #endif
840 {
841 //printf("mkdir(%s)\n", path);
842 #if _WIN32
843 if (mkdir(path))
844 #endif
845 #if POSIX
846 if (mkdir(path, 0777))
847 #endif
848 error("cannot create directory %s", path);
849 }
850 }
851 }
852 }
853
854 /****************************** File ********************************/
855
856 File::File(FileName *n)
857 {
858 ref = 0;
859 buffer = NULL;
860 len = 0;
861 touchtime = NULL;
862 name = n;
863 }
864
865 File::File(char *n)
866 {
867 ref = 0;
868 buffer = NULL;
869 len = 0;
870 touchtime = NULL;
871 name = new FileName(n, 0);
872 }
873
874 File::~File()
875 {
876 if (buffer)
877 {
878 if (ref == 0)
879 mem.free(buffer);
880 #if _WIN32
881 else if (ref == 2)
882 UnmapViewOfFile(buffer);
883 #endif
884 }
885 if (touchtime)
886 mem.free(touchtime);
887 }
888
889 void File::mark()
890 {
891 mem.mark(buffer);
892 mem.mark(touchtime);
893 mem.mark(name);
894 }
895
896 /*************************************
897 */
898
899 int File::read()
900 {
901 #if POSIX
902 off_t size;
903 ssize_t numread;
904 int fd;
905 struct stat buf;
906 int result = 0;
907 char *name;
908
909 name = this->name->toChars();
910 //printf("File::read('%s')\n",name);
911 fd = open(name, O_RDONLY);
912 if (fd == -1)
913 { result = errno;
914 //printf("\topen error, errno = %d\n",errno);
915 goto err1;
916 }
917
918 if (!ref)
919 mem.free(buffer);
920 ref = 0; // we own the buffer now
921
922 //printf("\tfile opened\n");
923 if (fstat(fd, &buf))
924 {
925 printf("\tfstat error, errno = %d\n",errno);
926 goto err2;
927 }
928 size = buf.st_size;
929 buffer = (unsigned char *) mem.malloc(size + 2);
930 if (!buffer)
931 {
932 printf("\tmalloc error, errno = %d\n",errno);
933 goto err2;
934 }
935
936 numread = ::read(fd, buffer, size);
937 if (numread != size)
938 {
939 printf("\tread error, errno = %d\n",errno);
940 goto err2;
941 }
942
943 if (touchtime)
944 memcpy(touchtime, &buf, sizeof(buf));
945
946 if (close(fd) == -1)
947 {
948 printf("\tclose error, errno = %d\n",errno);
949 goto err;
950 }
951
952 len = size;
953
954 // Always store a wchar ^Z past end of buffer so scanner has a sentinel
955 buffer[size] = 0; // ^Z is obsolete, use 0
956 buffer[size + 1] = 0;
957 return 0;
958
959 err2:
960 close(fd);
961 err:
962 mem.free(buffer);
963 buffer = NULL;
964 len = 0;
965
966 err1:
967 result = 1;
968 return result;
969 #endif
970 #if _WIN32
971 DWORD size;
972 DWORD numread;
973 HANDLE h;
974 int result = 0;
975 char *name;
976
977 name = this->name->toChars();
978 h = CreateFileA(name,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,
979 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,0);
980 if (h == INVALID_HANDLE_VALUE)
981 goto err1;
982
983 if (!ref)
984 mem.free(buffer);
985 ref = 0;
986
987 size = GetFileSize(h,NULL);
988 buffer = (unsigned char *) mem.malloc(size + 2);
989 if (!buffer)
990 goto err2;
991
992 if (ReadFile(h,buffer,size,&numread,NULL) != TRUE)
993 goto err2;
994
995 if (numread != size)
996 goto err2;
997
998 if (touchtime)
999 {
1000 if (!GetFileTime(h, NULL, NULL, &((WIN32_FIND_DATAA *)touchtime)->ftLastWriteTime))
1001 goto err2;
1002 }
1003
1004 if (!CloseHandle(h))
1005 goto err;
1006
1007 len = size;
1008
1009 // Always store a wchar ^Z past end of buffer so scanner has a sentinel
1010 buffer[size] = 0; // ^Z is obsolete, use 0
1011 buffer[size + 1] = 0;
1012 return 0;
1013
1014 err2:
1015 CloseHandle(h);
1016 err:
1017 mem.free(buffer);
1018 buffer = NULL;
1019 len = 0;
1020
1021 err1:
1022 result = 1;
1023 return result;
1024 #endif
1025 }
1026
1027 /*****************************
1028 * Read a file with memory mapped file I/O.
1029 */
1030
1031 int File::mmread()
1032 {
1033 #if POSIX
1034 return read();
1035 #endif
1036 #if _WIN32
1037 HANDLE hFile;
1038 HANDLE hFileMap;
1039 DWORD size;
1040 char *name;
1041
1042 name = this->name->toChars();
1043 hFile = CreateFile(name, GENERIC_READ,
1044 FILE_SHARE_READ, NULL,
1045 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
1046 if (hFile == INVALID_HANDLE_VALUE)
1047 goto Lerr;
1048 size = GetFileSize(hFile, NULL);
1049 //printf(" file created, size %d\n", size);
1050
1051 hFileMap = CreateFileMapping(hFile,NULL,PAGE_READONLY,0,size,NULL);
1052 if (CloseHandle(hFile) != TRUE)
1053 goto Lerr;
1054
1055 if (hFileMap == NULL)
1056 goto Lerr;
1057
1058 //printf(" mapping created\n");
1059
1060 if (!ref)
1061 mem.free(buffer);
1062 ref = 2;
1063 buffer = (unsigned char *)MapViewOfFileEx(hFileMap, FILE_MAP_READ,0,0,size,NULL);
1064 if (CloseHandle(hFileMap) != TRUE)
1065 goto Lerr;
1066 if (buffer == NULL) // mapping view failed
1067 goto Lerr;
1068
1069 len = size;
1070 //printf(" buffer = %p\n", buffer);
1071
1072 return 0;
1073
1074 Lerr:
1075 return GetLastError(); // failure
1076 #endif
1077 }
1078
1079 /*********************************************
1080 * Write a file.
1081 * Returns:
1082 * 0 success
1083 */
1084
1085 int File::write()
1086 {
1087 #if POSIX
1088 int fd;
1089 ssize_t numwritten;
1090 char *name;
1091
1092 name = this->name->toChars();
1093 fd = open(name, O_CREAT | O_WRONLY | O_TRUNC, 0644);
1094 if (fd == -1)
1095 goto err;
1096
1097 numwritten = ::write(fd, buffer, len);
1098 if (len != numwritten)
1099 goto err2;
1100
1101 if (close(fd) == -1)
1102 goto err;
1103
1104 if (touchtime)
1105 { struct utimbuf ubuf;
1106
1107 ubuf.actime = ((struct stat *)touchtime)->st_atime;
1108 ubuf.modtime = ((struct stat *)touchtime)->st_mtime;
1109 if (utime(name, &ubuf))
1110 goto err;
1111 }
1112 return 0;
1113
1114 err2:
1115 close(fd);
1116 ::remove(name);
1117 err:
1118 return 1;
1119 #endif
1120 #if _WIN32
1121 HANDLE h;
1122 DWORD numwritten;
1123 char *name;
1124
1125 name = this->name->toChars();
1126 h = CreateFileA(name,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,
1127 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,NULL);
1128 if (h == INVALID_HANDLE_VALUE)
1129 goto err;
1130
1131 if (WriteFile(h,buffer,len,&numwritten,NULL) != TRUE)
1132 goto err2;
1133
1134 if (len != numwritten)
1135 goto err2;
1136
1137 if (touchtime) {
1138 SetFileTime(h, NULL, NULL, &((WIN32_FIND_DATAA *)touchtime)->ftLastWriteTime);
1139 }
1140 if (!CloseHandle(h))
1141 goto err;
1142 return 0;
1143
1144 err2:
1145 CloseHandle(h);
1146 DeleteFileA(name);
1147 err:
1148 return 1;
1149 #endif
1150 }
1151
1152 /*********************************************
1153 * Append to a file.
1154 * Returns:
1155 * 0 success
1156 */
1157
1158 int File::append()
1159 {
1160 #if POSIX
1161 return 1;
1162 #endif
1163 #if _WIN32
1164 HANDLE h;
1165 DWORD numwritten;
1166 char *name;
1167
1168 name = this->name->toChars();
1169 h = CreateFileA(name,GENERIC_WRITE,0,NULL,OPEN_ALWAYS,
1170 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,NULL);
1171 if (h == INVALID_HANDLE_VALUE)
1172 goto err;
1173
1174 #if 1
1175 SetFilePointer(h, 0, NULL, FILE_END);
1176 #else // INVALID_SET_FILE_POINTER doesn't seem to have a definition
1177 if (SetFilePointer(h, 0, NULL, FILE_END) == INVALID_SET_FILE_POINTER)
1178 goto err;
1179 #endif
1180
1181 if (WriteFile(h,buffer,len,&numwritten,NULL) != TRUE)
1182 goto err2;
1183
1184 if (len != numwritten)
1185 goto err2;
1186
1187 if (touchtime) {
1188 SetFileTime(h, NULL, NULL, &((WIN32_FIND_DATAA *)touchtime)->ftLastWriteTime);
1189 }
1190 if (!CloseHandle(h))
1191 goto err;
1192 return 0;
1193
1194 err2:
1195 CloseHandle(h);
1196 err:
1197 return 1;
1198 #endif
1199 }
1200
1201 /**************************************
1202 */
1203
1204 void File::readv()
1205 {
1206 if (read())
1207 error("Error reading file '%s'\n",name->toChars());
1208 }
1209
1210 /**************************************
1211 */
1212
1213 void File::mmreadv()
1214 {
1215 if (mmread())
1216 readv();
1217 }
1218
1219 void File::writev()
1220 {
1221 if (write())
1222 error("Error writing file '%s'\n",name->toChars());
1223 }
1224
1225 void File::appendv()
1226 {
1227 if (write())
1228 error("Error appending to file '%s'\n",name->toChars());
1229 }
1230
1231 /*******************************************
1232 * Return !=0 if file exists.
1233 * 0: file doesn't exist
1234 * 1: normal file
1235 * 2: directory
1236 */
1237
1238 int File::exists()
1239 {
1240 #if POSIX
1241 return 0;
1242 #endif
1243 #if _WIN32
1244 DWORD dw;
1245 int result;
1246 char *name;
1247
1248 name = this->name->toChars();
1249 if (touchtime)
1250 dw = ((WIN32_FIND_DATAA *)touchtime)->dwFileAttributes;
1251 else
1252 dw = GetFileAttributesA(name);
1253 if (dw == -1L)
1254 result = 0;
1255 else if (dw & FILE_ATTRIBUTE_DIRECTORY)
1256 result = 2;
1257 else
1258 result = 1;
1259 return result;
1260 #endif
1261 }
1262
1263 void File::remove()
1264 {
1265 #if POSIX
1266 ::remove(this->name->toChars());
1267 #endif
1268 #if _WIN32
1269 DeleteFileA(this->name->toChars());
1270 #endif
1271 }
1272
1273 Array *File::match(char *n)
1274 {
1275 return match(new FileName(n, 0));
1276 }
1277
1278 Array *File::match(FileName *n)
1279 {
1280 #if POSIX
1281 return NULL;
1282 #endif
1283 #if _WIN32
1284 HANDLE h;
1285 WIN32_FIND_DATAA fileinfo;
1286 Array *a;
1287 char *c;
1288 char *name;
1289
1290 a = new Array();
1291 c = n->toChars();
1292 name = n->name();
1293 h = FindFirstFileA(c,&fileinfo);
1294 if (h != INVALID_HANDLE_VALUE)
1295 {
1296 do
1297 {
1298 // Glue path together with name
1299 char *fn;
1300 File *f;
1301
1302 fn = (char *)mem.malloc(name - c + strlen(fileinfo.cFileName) + 1);
1303 memcpy(fn, c, name - c);
1304 strcpy(fn + (name - c), fileinfo.cFileName);
1305 f = new File(fn);
1306 f->touchtime = mem.malloc(sizeof(WIN32_FIND_DATAA));
1307 memcpy(f->touchtime, &fileinfo, sizeof(fileinfo));
1308 a->push(f);
1309 } while (FindNextFileA(h,&fileinfo) != FALSE);
1310 FindClose(h);
1311 }
1312 return a;
1313 #endif
1314 }
1315
1316 int File::compareTime(File *f)
1317 {
1318 #if POSIX
1319 return 0;
1320 #endif
1321 #if _WIN32
1322 if (!touchtime)
1323 stat();
1324 if (!f->touchtime)
1325 f->stat();
1326 return CompareFileTime(&((WIN32_FIND_DATAA *)touchtime)->ftLastWriteTime, &((WIN32_FIND_DATAA *)f->touchtime)->ftLastWriteTime);
1327 #endif
1328 }
1329
1330 void File::stat()
1331 {
1332 #if POSIX
1333 if (!touchtime)
1334 {
1335 touchtime = mem.calloc(1, sizeof(struct stat));
1336 }
1337 #endif
1338 #if _WIN32
1339 HANDLE h;
1340
1341 if (!touchtime)
1342 {
1343 touchtime = mem.calloc(1, sizeof(WIN32_FIND_DATAA));
1344 }
1345 h = FindFirstFileA(name->toChars(),(WIN32_FIND_DATAA *)touchtime);
1346 if (h != INVALID_HANDLE_VALUE)
1347 {
1348 FindClose(h);
1349 }
1350 #endif
1351 }
1352
1353 void File::checkoffset(size_t offset, size_t nbytes)
1354 {
1355 if (offset > len || offset + nbytes > len)
1356 error("Corrupt file '%s': offset x%zx off end of file",toChars(),offset);
1357 }
1358
1359 char *File::toChars()
1360 {
1361 return name->toChars();
1362 }
1363
1364
1365 /************************* OutBuffer *************************/
1366
1367 OutBuffer::OutBuffer()
1368 {
1369 data = NULL;
1370 offset = 0;
1371 size = 0;
1372 }
1373
1374 OutBuffer::~OutBuffer()
1375 {
1376 mem.free(data);
1377 }
1378
1379 void *OutBuffer::extractData()
1380 {
1381 void *p;
1382
1383 p = (void *)data;
1384 data = NULL;
1385 offset = 0;
1386 size = 0;
1387 return p;
1388 }
1389
1390 void OutBuffer::mark()
1391 {
1392 mem.mark(data);
1393 }
1394
1395 void OutBuffer::reserve(unsigned nbytes)
1396 {
1397 //printf("OutBuffer::reserve: size = %d, offset = %d, nbytes = %d\n", size, offset, nbytes);
1398 if (size - offset < nbytes)
1399 {
1400 #if defined (__x86_64__)
1401 size = (offset + nbytes) * 2 + 2;
1402 #else
1403 size = (offset + nbytes) * 2;
1404 #endif
1405 data = (unsigned char *)mem.realloc(data, size);
1406 }
1407 }
1408
1409 void OutBuffer::reset()
1410 {
1411 offset = 0;
1412 }
1413
1414 void OutBuffer::setsize(unsigned size)
1415 {
1416 offset = size;
1417 }
1418
1419 void OutBuffer::write(const void *data, unsigned nbytes)
1420 {
1421 reserve(nbytes);
1422 memcpy(this->data + offset, data, nbytes);
1423 offset += nbytes;
1424 }
1425
1426 void OutBuffer::writebstring(unsigned char *string)
1427 {
1428 write(string,*string + 1);
1429 }
1430
1431 void OutBuffer::writestring(const char *string)
1432 {
1433 write(string,strlen(string));
1434 }
1435
1436 void OutBuffer::writedstring(const char *string)
1437 {
1438 #if M_UNICODE
1439 for (; *string; string++)
1440 {
1441 writedchar(*string);
1442 }
1443 #else
1444 write(string,strlen(string));
1445 #endif
1446 }
1447
1448 void OutBuffer::writedstring(const wchar_t *string)
1449 {
1450 #if M_UNICODE
1451 write(string,wcslen(string) * sizeof(wchar_t));
1452 #else
1453 for (; *string; string++)
1454 {
1455 writedchar(*string);
1456 }
1457 #endif
1458 }
1459
1460 void OutBuffer::prependstring(const char *string)
1461 { unsigned len;
1462
1463 len = strlen(string);
1464 reserve(len);
1465 memmove(data + len, data, offset);
1466 memcpy(data, string, len);
1467 offset += len;
1468 }
1469
1470 void OutBuffer::writenl()
1471 {
1472 #if _WIN32
1473 #if M_UNICODE
1474 write4(0x000A000D); // newline is CR,LF on Microsoft OS's
1475 #else
1476 writeword(0x0A0D); // newline is CR,LF on Microsoft OS's
1477 #endif
1478 #else
1479 #if M_UNICODE
1480 writeword('\n');
1481 #else
1482 writeByte('\n');
1483 #endif
1484 #endif
1485 }
1486
1487 void OutBuffer::writeByte(unsigned b)
1488 {
1489 reserve(1);
1490 this->data[offset] = (unsigned char)b;
1491 offset++;
1492 }
1493
1494 void OutBuffer::writeUTF8(unsigned b)
1495 {
1496 reserve(6);
1497 if (b <= 0x7F)
1498 {
1499 this->data[offset] = (unsigned char)b;
1500 offset++;
1501 }
1502 else if (b <= 0x7FF)
1503 {
1504 this->data[offset + 0] = (unsigned char)((b >> 6) | 0xC0);
1505 this->data[offset + 1] = (unsigned char)((b & 0x3F) | 0x80);
1506 offset += 2;
1507 }
1508 else if (b <= 0xFFFF)
1509 {
1510 this->data[offset + 0] = (unsigned char)((b >> 12) | 0xE0);
1511 this->data[offset + 1] = (unsigned char)(((b >> 6) & 0x3F) | 0x80);
1512 this->data[offset + 2] = (unsigned char)((b & 0x3F) | 0x80);
1513 offset += 3;
1514 }
1515 else if (b <= 0x1FFFFF)
1516 {
1517 this->data[offset + 0] = (unsigned char)((b >> 18) | 0xF0);
1518 this->data[offset + 1] = (unsigned char)(((b >> 12) & 0x3F) | 0x80);
1519 this->data[offset + 2] = (unsigned char)(((b >> 6) & 0x3F) | 0x80);
1520 this->data[offset + 3] = (unsigned char)((b & 0x3F) | 0x80);
1521 offset += 4;
1522 }
1523 else if (b <= 0x3FFFFFF)
1524 {
1525 this->data[offset + 0] = (unsigned char)((b >> 24) | 0xF8);
1526 this->data[offset + 1] = (unsigned char)(((b >> 18) & 0x3F) | 0x80);
1527 this->data[offset + 2] = (unsigned char)(((b >> 12) & 0x3F) | 0x80);
1528 this->data[offset + 3] = (unsigned char)(((b >> 6) & 0x3F) | 0x80);
1529 this->data[offset + 4] = (unsigned char)((b & 0x3F) | 0x80);
1530 offset += 5;
1531 }
1532 else if (b <= 0x7FFFFFFF)
1533 {
1534 this->data[offset + 0] = (unsigned char)((b >> 30) | 0xFC);
1535 this->data[offset + 1] = (unsigned char)(((b >> 24) & 0x3F) | 0x80);
1536 this->data[offset + 2] = (unsigned char)(((b >> 18) & 0x3F) | 0x80);
1537 this->data[offset + 3] = (unsigned char)(((b >> 12) & 0x3F) | 0x80);
1538 this->data[offset + 4] = (unsigned char)(((b >> 6) & 0x3F) | 0x80);
1539 this->data[offset + 5] = (unsigned char)((b & 0x3F) | 0x80);
1540 offset += 6;
1541 }
1542 else
1543 assert(0);
1544 }
1545
1546 void OutBuffer::writedchar(unsigned b)
1547 {
1548 reserve(Dchar_mbmax * sizeof(dchar));
1549 offset = (unsigned char *)Dchar::put((dchar *)(this->data + offset), (dchar)b) -
1550 this->data;
1551 }
1552
1553 void OutBuffer::prependbyte(unsigned b)
1554 {
1555 reserve(1);
1556 memmove(data + 1, data, offset);
1557 data[0] = (unsigned char)b;
1558 offset++;
1559 }
1560
1561 void OutBuffer::writeword(unsigned w)
1562 {
1563 reserve(2);
1564 *(unsigned short *)(this->data + offset) = (unsigned short)w;
1565 offset += 2;
1566 }
1567
1568 void OutBuffer::writeUTF16(unsigned w)
1569 {
1570 reserve(4);
1571 if (w <= 0xFFFF)
1572 {
1573 *(unsigned short *)(this->data + offset) = (unsigned short)w;
1574 offset += 2;
1575 }
1576 else if (w <= 0x10FFFF)
1577 {
1578 *(unsigned short *)(this->data + offset) = (unsigned short)((w >> 10) + 0xD7C0);
1579 *(unsigned short *)(this->data + offset + 2) = (unsigned short)((w & 0x3FF) | 0xDC00);
1580 offset += 4;
1581 }
1582 else
1583 assert(0);
1584 }
1585
1586 void OutBuffer::write4(unsigned w)
1587 {
1588 reserve(4);
1589 *(unsigned long *)(this->data + offset) = w;
1590 offset += 4;
1591 }
1592
1593 void OutBuffer::write(OutBuffer *buf)
1594 {
1595 if (buf)
1596 { reserve(buf->offset);
1597 memcpy(data + offset, buf->data, buf->offset);
1598 offset += buf->offset;
1599 }
1600 }
1601
1602 void OutBuffer::write(Object *obj)
1603 {
1604 if (obj)
1605 {
1606 writestring(obj->toChars());
1607 }
1608 }
1609
1610 void OutBuffer::fill0(unsigned nbytes)
1611 {
1612 reserve(nbytes);
1613 memset(data + offset,0,nbytes);
1614 offset += nbytes;
1615 }
1616
1617 void OutBuffer::align(unsigned size)
1618 { unsigned nbytes;
1619
1620 nbytes = ((offset + size - 1) & ~(size - 1)) - offset;
1621 fill0(nbytes);
1622 }
1623
1624
1625 ////////////////////////////////////////////////////////////////
1626 // The compiler shipped with Visual Studio 2005 (and possible
1627 // other versions) does not support C99 printf format specfiers
1628 // such as %z and %j
1629 #if _MSC_VER
1630 using std::string;
1631 using std::wstring;
1632
1633 template<typename S>
1634 inline void
1635 search_and_replace(S& str, const S& what, const S& replacement)
1636 {
1637 assert(!what.empty());
1638 size_t pos = str.find(what);
1639 while (pos != S::npos)
1640 {
1641 str.replace(pos, what.size(), replacement);
1642 pos = str.find(what, pos + replacement.size());
1643 }
1644 }
1645 #define WORKAROUND_C99_SPECIFIERS_BUG(S,tmp,f) \
1646 S tmp = f; \
1647 search_and_replace(fmt, S("%z"), S("%l")); \
1648 search_and_replace(fmt, S("%j"), S("%i")); \
1649 f = tmp.c_str();
1650 #else
1651 #define WORKAROUND_C99_SPECIFIERS_BUG(S,tmp,f)
1652 #endif
1653
1654 void OutBuffer::vprintf(const char *format, va_list args)
1655 {
1656 char buffer[128];
1657 char *p;
1658 unsigned psize;
1659 int count;
1660
1661 WORKAROUND_C99_SPECIFIERS_BUG(string, fmt, format);
1662
1663 p = buffer;
1664 psize = sizeof(buffer);
1665 for (;;)
1666 {
1667 #if _WIN32
1668 count = _vsnprintf(p,psize,format,args);
1669 if (count != -1)
1670 break;
1671 psize *= 2;
1672 #elif POSIX
1673 va_list va;
1674 va_copy(va, args);
1675 /*
1676 The functions vprintf(), vfprintf(), vsprintf(), vsnprintf()
1677 are equivalent to the functions printf(), fprintf(), sprintf(),
1678 snprintf(), respectively, except that they are called with a
1679 va_list instead of a variable number of arguments. These
1680 functions do not call the va_end macro. Consequently, the value
1681 of ap is undefined after the call. The application should call
1682 va_end(ap) itself afterwards.
1683 */
1684 count = vsnprintf(p,psize,format,va);
1685 va_end(va);
1686 if (count == -1)
1687 psize *= 2;
1688 else if (count >= psize)
1689 psize = count + 1;
1690 else
1691 break;
1692 #endif
1693 p = (char *) alloca(psize); // buffer too small, try again with larger size
1694 }
1695 write(p,count);
1696 }
1697
1698 #if M_UNICODE
1699 void OutBuffer::vprintf(const wchar_t *format, va_list args)
1700 {
1701 dchar buffer[128];
1702 dchar *p;
1703 unsigned psize;
1704 int count;
1705
1706 WORKAROUND_C99_SPECIFIERS_BUG(wstring, fmt, format);
1707
1708 p = buffer;
1709 psize = sizeof(buffer) / sizeof(buffer[0]);
1710 for (;;)
1711 {
1712 #if _WIN32
1713 count = _vsnwprintf(p,psize,format,args);
1714 if (count != -1)
1715 break;
1716 psize *= 2;
1717 #endif
1718 #if POSIX
1719 va_list va;
1720 va_copy(va, args);
1721 count = vsnwprintf(p,psize,format,va);
1722 va_end(va);
1723
1724 if (count == -1)
1725 psize *= 2;
1726 else if (count >= psize)
1727 psize = count + 1;
1728 else
1729 break;
1730 #endif
1731 p = (dchar *) alloca(psize * 2); // buffer too small, try again with larger size
1732 }
1733 write(p,count * 2);
1734 }
1735 #endif
1736
1737 void OutBuffer::printf(const char *format, ...)
1738 {
1739 va_list ap;
1740 va_start(ap, format);
1741 vprintf(format,ap);
1742 va_end(ap);
1743 }
1744
1745 #if M_UNICODE
1746 void OutBuffer::printf(const wchar_t *format, ...)
1747 {
1748 va_list ap;
1749 va_start(ap, format);
1750 vprintf(format,ap);
1751 va_end(ap);
1752 }
1753 #endif
1754
1755 void OutBuffer::bracket(char left, char right)
1756 {
1757 reserve(2);
1758 memmove(data + 1, data, offset);
1759 data[0] = left;
1760 data[offset + 1] = right;
1761 offset += 2;
1762 }
1763
1764 /******************
1765 * Insert left at i, and right at j.
1766 * Return index just past right.
1767 */
1768
1769 unsigned OutBuffer::bracket(unsigned i, const char *left, unsigned j, const char *right)
1770 {
1771 size_t leftlen = strlen(left);
1772 size_t rightlen = strlen(right);
1773 reserve(leftlen + rightlen);
1774 insert(i, left, leftlen);
1775 insert(j + leftlen, right, rightlen);
1776 return j + leftlen + rightlen;
1777 }
1778
1779 void OutBuffer::spread(unsigned offset, unsigned nbytes)
1780 {
1781 reserve(nbytes);
1782 memmove(data + offset + nbytes, data + offset,
1783 this->offset - offset);
1784 this->offset += nbytes;
1785 }
1786
1787 /****************************************
1788 * Returns: offset + nbytes
1789 */
1790
1791 unsigned OutBuffer::insert(unsigned offset, const void *p, unsigned nbytes)
1792 {
1793 spread(offset, nbytes);
1794 memmove(data + offset, p, nbytes);
1795 return offset + nbytes;
1796 }
1797
1798 void OutBuffer::remove(unsigned offset, unsigned nbytes)
1799 {
1800 memmove(data + offset, data + offset + nbytes, this->offset - (offset + nbytes));
1801 this->offset -= nbytes;
1802 }
1803
1804 char *OutBuffer::toChars()
1805 {
1806 writeByte(0);
1807 return (char *)data;
1808 }
1809
1810 /********************************* Bits ****************************/
1811
1812 Bits::Bits()
1813 {
1814 data = NULL;
1815 bitdim = 0;
1816 allocdim = 0;
1817 }
1818
1819 Bits::~Bits()
1820 {
1821 mem.free(data);
1822 }
1823
1824 void Bits::mark()
1825 {
1826 mem.mark(data);
1827 }
1828
1829 void Bits::resize(unsigned bitdim)
1830 {
1831 unsigned allocdim;
1832 unsigned mask;
1833
1834 allocdim = (bitdim + 31) / 32;
1835 data = (unsigned *)mem.realloc(data, allocdim * sizeof(data[0]));
1836 if (this->allocdim < allocdim)
1837 memset(data + this->allocdim, 0, (allocdim - this->allocdim) * sizeof(data[0]));
1838
1839 // Clear other bits in last word
1840 mask = (1 << (bitdim & 31)) - 1;
1841 if (mask)
1842 data[allocdim - 1] &= ~mask;
1843
1844 this->bitdim = bitdim;
1845 this->allocdim = allocdim;
1846 }
1847
1848 void Bits::set(unsigned bitnum)
1849 {
1850 data[bitnum / 32] |= 1 << (bitnum & 31);
1851 }
1852
1853 void Bits::clear(unsigned bitnum)
1854 {
1855 data[bitnum / 32] &= ~(1 << (bitnum & 31));
1856 }
1857
1858 int Bits::test(unsigned bitnum)
1859 {
1860 return data[bitnum / 32] & (1 << (bitnum & 31));
1861 }
1862
1863 void Bits::set()
1864 { unsigned mask;
1865
1866 memset(data, ~0, allocdim * sizeof(data[0]));
1867
1868 // Clear other bits in last word
1869 mask = (1 << (bitdim & 31)) - 1;
1870 if (mask)
1871 data[allocdim - 1] &= mask;
1872 }
1873
1874 void Bits::clear()
1875 {
1876 memset(data, 0, allocdim * sizeof(data[0]));
1877 }
1878
1879 void Bits::copy(Bits *from)
1880 {
1881 assert(bitdim == from->bitdim);
1882 memcpy(data, from->data, allocdim * sizeof(data[0]));
1883 }
1884
1885 Bits *Bits::clone()
1886 {
1887 Bits *b;
1888
1889 b = new Bits();
1890 b->resize(bitdim);
1891 b->copy(this);
1892 return b;
1893 }
1894
1895 void Bits::sub(Bits *b)
1896 {
1897 unsigned u;
1898
1899 for (u = 0; u < allocdim; u++)
1900 data[u] &= ~b->data[u];
1901 }
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916