Document search flags
[delight/core.git] / dmd2 / root.c
blob73b519af6040fbc89ed10838d9db739bc40278a4
2 // Copyright (c) 1999-2006 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.
10 /* NOTE: This file has been patched from the original DMD distribution to
11 work with the GDC compiler.
13 Modified by David Friedman, December 2006
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <stdarg.h>
19 #include <string.h>
20 #include <stdint.h>
21 #include <assert.h>
23 #include "gdc_alloca.h"
25 #if _WIN32
26 #include <windows.h>
27 #include <direct.h>
28 #endif
30 #ifndef _WIN32
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <fcntl.h>
34 #include <errno.h>
35 #include <unistd.h>
36 #include <utime.h>
37 #endif
39 #include "port.h"
40 #include "root.h"
41 #include "dchar.h"
42 #include "mem.h"
44 #if 0 //__SC__ //def DEBUG
45 extern "C" void __cdecl _assert(void *e, void *f, unsigned line)
47 printf("Assert('%s','%s',%d)\n",e,f,line);
48 fflush(stdout);
49 *(char *)0 = 0;
51 #endif
53 #ifndef IN_GCC
54 /*************************************
55 * Convert wchar string to ascii string.
58 char *wchar2ascii(wchar_t *us)
60 return wchar2ascii(us, wcslen(us));
63 char *wchar2ascii(wchar_t *us, unsigned len)
65 unsigned i;
66 char *p;
68 p = (char *)mem.malloc(len + 1);
69 for (i = 0; i <= len; i++)
70 p[i] = (char) us[i];
71 return p;
74 int wcharIsAscii(wchar_t *us)
76 return wcharIsAscii(us, wcslen(us));
79 int wcharIsAscii(wchar_t *us, unsigned len)
81 unsigned i;
83 for (i = 0; i <= len; i++)
85 if (us[i] & ~0xFF) // if high bits set
86 return 0; // it's not ascii
88 return 1;
90 #endif
93 /***********************************
94 * Compare length-prefixed strings (bstr).
97 int bstrcmp(unsigned char *b1, unsigned char *b2)
99 return (*b1 == *b2 && memcmp(b1 + 1, b2 + 1, *b2) == 0) ? 0 : 1;
102 /***************************************
103 * Convert bstr into a malloc'd string.
106 char *bstr2str(unsigned char *b)
108 char *s;
109 unsigned len;
111 len = *b;
112 s = (char *) mem.malloc(len + 1);
113 s[len] = 0;
114 return (char *)memcpy(s,b + 1,len);
117 /**************************************
118 * Print error message and exit.
121 void error(const char *format, ...)
123 va_list ap;
125 va_start(ap, format);
126 fprintf(stderr, "Error: ");
127 vfprintf(stderr, format, ap);
128 va_end( ap );
129 fprintf(stderr, "\n");
130 fflush(stderr);
132 exit(EXIT_FAILURE);
135 #if M_UNICODE
136 void error(const dchar *format, ...)
138 va_list ap;
140 va_start(ap, format);
141 fprintf(stderr, "Error: ");
142 vfwprintf(stderr, format, ap);
143 va_end( ap );
144 printf(stderr, "\n");
145 fflush(stderr);
147 exit(EXIT_FAILURE);
149 #endif
151 void error_mem()
153 error("out of memory");
156 /**************************************
157 * Print warning message.
160 void warning(const char *format, ...)
162 va_list ap;
164 va_start(ap, format);
165 fprintf(stderr, "Warning: ");
166 vfprintf(stderr, format, ap);
167 va_end( ap );
168 fprintf(stderr, "\n");
169 fflush(stderr);
172 /****************************** Object ********************************/
174 int Object::equals(Object *o)
176 return o == this;
179 hash_t Object::hashCode()
181 return (hash_t) this;
184 int Object::compare(Object *obj)
186 return this - obj;
189 void Object::print()
191 fprintf(stderr, "%s %p\n", toChars(), this);
194 char *Object::toChars()
196 return "Object";
199 dchar *Object::toDchars()
201 #if M_UNICODE
202 return L"Object";
203 #else
204 return toChars();
205 #endif
208 int Object::dyncast()
210 return 0;
213 void Object::toBuffer(OutBuffer *b)
215 b->writestring("Object");
218 void Object::mark()
222 /****************************** String ********************************/
224 String::String(char *str, int ref)
226 this->str = ref ? str : mem.strdup(str);
227 this->ref = ref;
230 String::~String()
232 mem.free(str);
235 void String::mark()
237 mem.mark(str);
240 hash_t String::calcHash(const char *str, size_t len)
242 hash_t hash = 0;
244 for (;;)
246 switch (len)
248 case 0:
249 return hash;
251 case 1:
252 hash *= 37;
253 hash += *(uint8_t *)str;
254 return hash;
256 case 2:
257 hash *= 37;
258 hash += *(uint16_t *)str;
259 return hash;
261 case 3:
262 hash *= 37;
263 hash += (*(uint16_t *)str << 8) +
264 ((uint8_t *)str)[2];
265 return hash;
267 default:
268 hash *= 37;
269 hash += *(uint32_t *)str;
270 str += 4;
271 len -= 4;
272 break;
277 hash_t String::calcHash(const char *str)
279 return calcHash(str, strlen(str));
282 hash_t String::hashCode()
284 return calcHash(str, strlen(str));
287 unsigned String::len()
289 return strlen(str);
292 int String::equals(Object *obj)
294 return strcmp(str,((String *)obj)->str) == 0;
297 int String::compare(Object *obj)
299 return strcmp(str,((String *)obj)->str);
302 char *String::toChars()
304 return str;
307 void String::print()
309 fprintf(stderr, "String '%s'\n",str);
313 /****************************** FileName ********************************/
315 FileName::FileName(char *str, int ref)
316 : String(str,ref)
320 char *FileName::combine(char *path, char *name)
321 { char *f;
322 size_t pathlen;
323 size_t namelen;
325 if (!path || !*path)
326 return name;
327 pathlen = strlen(path);
328 namelen = strlen(name);
329 f = (char *)mem.malloc(pathlen + 1 + namelen + 1);
330 memcpy(f, path, pathlen);
331 #ifndef _WIN32
332 if (path[pathlen - 1] != '/')
333 { f[pathlen] = '/';
334 pathlen++;
336 #endif
337 #if _WIN32
338 if (path[pathlen - 1] != '\\' && path[pathlen - 1] != ':' && path[pathlen - 1] != '/')
339 { f[pathlen] = '\\';
340 pathlen++;
342 #endif
343 memcpy(f + pathlen, name, namelen + 1);
344 return f;
347 FileName::FileName(char *path, char *name)
348 : String(combine(path,name),1)
352 // Split a path into an Array of paths
353 Array *FileName::splitPath(const char *path)
355 char c = 0; // unnecessary initializer is for VC /W4
356 const char *p;
357 OutBuffer buf;
358 Array *array;
360 array = new Array();
361 if (path)
363 p = path;
365 { char instring = 0;
367 while (isspace(*p)) // skip leading whitespace
368 p++;
369 buf.reserve(strlen(p) + 1); // guess size of path
370 for (; ; p++)
372 c = *p;
373 switch (c)
375 case '"':
376 instring ^= 1; // toggle inside/outside of string
377 continue;
379 #if MACINTOSH
380 case ',':
381 #endif
382 #if _WIN32
383 case ';':
384 #endif
385 #ifndef _WIN32
386 case ':':
387 #endif
388 p++;
389 break; // note that ; cannot appear as part
390 // of a path, quotes won't protect it
392 case 0x1A: // ^Z means end of file
393 case 0:
394 break;
396 case '\r':
397 continue; // ignore carriage returns
399 #ifndef _WIN32
400 case '~':
401 buf.writestring(getenv("HOME"));
402 continue;
403 #endif
405 case ' ':
406 case '\t': // tabs in filenames?
407 if (!instring) // if not in string
408 break; // treat as end of path
409 default:
410 buf.writeByte(c);
411 continue;
413 break;
415 if (buf.offset) // if path is not empty
417 buf.writeByte(0); // to asciiz
418 array->push(buf.extractData());
420 } while (c);
422 return array;
425 hash_t FileName::hashCode()
427 #if _WIN32
428 // We need a different hashCode because it must be case-insensitive
429 size_t len = strlen(str);
430 hash_t hash = 0;
431 unsigned char *s = (unsigned char *)str;
433 for (;;)
435 switch (len)
437 case 0:
438 return hash;
440 case 1:
441 hash *= 37;
442 hash += *(uint8_t *)s | 0x20;
443 return hash;
445 case 2:
446 hash *= 37;
447 hash += *(uint16_t *)s | 0x2020;
448 return hash;
450 case 3:
451 hash *= 37;
452 hash += ((*(uint16_t *)s << 8) +
453 ((uint8_t *)s)[2]) | 0x202020;
454 break;
456 default:
457 hash *= 37;
458 hash += *(uint32_t *)s | 0x20202020;
459 s += 4;
460 len -= 4;
461 break;
464 #else
465 // darwin HFS is case insensitive, though...
466 return String::hashCode();
467 #endif
470 int FileName::compare(Object *obj)
472 #if _WIN32
473 return stricmp(str,((FileName *)obj)->str);
474 #else
475 return String::compare(obj);
476 #endif
479 int FileName::equals(Object *obj)
481 #if _WIN32
482 return stricmp(str,((FileName *)obj)->str) == 0;
483 #else
484 return String::equals(obj);
485 #endif
488 /************************************
489 * Return !=0 if absolute path name.
492 int FileName::absolute(const char *name)
494 #if _WIN32
495 return (*name == '\\') ||
496 (*name == '/') ||
497 (*name && name[1] == ':');
498 #endif
499 #ifndef _WIN32
500 return (*name == '/');
501 #endif
504 /********************************
505 * Return filename extension (read-only).
506 * Points past '.' of extension.
507 * If there isn't one, return NULL.
510 char *FileName::ext(const char *str)
512 char *e;
513 size_t len = strlen(str);
515 e = (char *)str + len;
516 for (;;)
518 switch (*e)
519 { case '.':
520 return e + 1;
521 #ifndef _WIN32
522 case '/':
523 break;
524 #endif
525 #if _WIN32
526 case '\\':
527 case ':':
528 case '/':
529 break;
530 #endif
531 default:
532 if (e == str)
533 break;
534 e--;
535 continue;
537 return NULL;
541 char *FileName::ext()
543 return ext(str);
546 /********************************
547 * Return mem.malloc'd filename with extension removed.
550 char *FileName::removeExt(const char *str)
552 const char *e = ext(str);
553 if (e)
554 { size_t len = (e - str) - 1;
555 char *n = (char *)mem.malloc(len + 1);
556 memcpy(n, str, len);
557 n[len] = 0;
558 return n;
560 return mem.strdup(str);
563 /********************************
564 * Return filename name excluding path (read-only).
567 char *FileName::name(const char *str)
569 char *e;
570 size_t len = strlen(str);
572 e = (char *)str + len;
573 for (;;)
575 switch (*e)
577 #ifndef _WIN32
578 case '/':
579 return e + 1;
580 #endif
581 #if _WIN32
582 case '/':
583 case '\\':
584 case ':':
585 return e + 1;
586 #endif
587 default:
588 if (e == str)
589 break;
590 e--;
591 continue;
593 return e;
597 char *FileName::name()
599 return name(str);
602 /**************************************
603 * Return path portion of str.
604 * Path will does not include trailing path separator.
607 char *FileName::path(const char *str)
609 char *n = name(str);
610 char *path;
611 size_t pathlen;
613 if (n > str)
615 #ifndef _WIN32
616 if (n[-1] == '/')
617 n--;
618 #endif
619 #if _WIN32
620 if (n[-1] == '\\' || n[-1] == '/')
621 n--;
622 #endif
624 pathlen = n - str;
625 path = (char *)mem.malloc(pathlen + 1);
626 memcpy(path, str, pathlen);
627 path[pathlen] = 0;
628 return path;
631 /**************************************
632 * Replace filename portion of path.
635 char *FileName::replaceName(char *path, char *name)
636 { char *f;
637 char *n;
638 size_t pathlen;
639 size_t namelen;
641 if (absolute(name))
642 return name;
644 n = FileName::name(path);
645 if (n == path)
646 return name;
647 pathlen = n - path;
648 namelen = strlen(name);
649 f = (char *)mem.malloc(pathlen + 1 + namelen + 1);
650 memcpy(f, path, pathlen);
651 #ifndef _WIN32
652 if (path[pathlen - 1] != '/')
653 { f[pathlen] = '/';
654 pathlen++;
656 #endif
657 #if _WIN32
658 if (path[pathlen - 1] != '\\' && path[pathlen - 1] != ':' && path[pathlen - 1] != '/')
659 { f[pathlen] = '\\';
660 pathlen++;
662 #endif
663 memcpy(f + pathlen, name, namelen + 1);
664 return f;
667 /***************************
670 FileName *FileName::defaultExt(const char *name, const char *ext)
672 char *e;
673 char *s;
674 size_t len;
675 size_t extlen;
677 e = FileName::ext(name);
678 if (e) // if already has an extension
679 return new FileName((char *)name, 0);
681 len = strlen(name);
682 extlen = strlen(ext);
683 s = (char *)alloca(len + 1 + extlen + 1);
684 memcpy(s,name,len);
685 s[len] = '.';
686 memcpy(s + len + 1, ext, extlen + 1);
687 return new FileName(s, 0);
690 /***************************
693 FileName *FileName::forceExt(const char *name, const char *ext)
695 char *e;
696 char *s;
697 size_t len;
698 size_t extlen;
700 e = FileName::ext(name);
701 if (e) // if already has an extension
703 len = e - name;
704 extlen = strlen(ext);
706 s = (char *)alloca(len + extlen + 1);
707 memcpy(s,name,len);
708 memcpy(s + len, ext, extlen + 1);
709 return new FileName(s, 0);
711 else
712 return defaultExt(name, ext); // doesn't have one
715 /******************************
716 * Return !=0 if extensions match.
719 int FileName::equalsExt(const char *ext)
720 { const char *e;
722 e = FileName::ext();
723 if (!e && !ext)
724 return 1;
725 if (!e || !ext)
726 return 0;
727 #ifndef _WIN32
728 return strcmp(e,ext) == 0;
729 #endif
730 #if _WIN32
731 return stricmp(e,ext) == 0;
732 #endif
735 /*************************************
736 * Copy file from this to to.
739 void FileName::CopyTo(FileName *to)
741 File file(this);
743 #if _WIN32
744 file.touchtime = mem.malloc(sizeof(WIN32_FIND_DATAA)); // keep same file time
745 #endif
746 #ifndef _WIN32
747 file.touchtime = mem.malloc(sizeof(struct stat)); // keep same file time
748 #endif
749 file.readv();
750 file.name = to;
751 file.writev();
754 /*************************************
755 * Search Path for file.
756 * Input:
757 * cwd if !=0, search current directory before searching path
760 char *FileName::searchPath(Array *path, char *name, int cwd)
762 if (absolute(name))
764 return exists(name) ? name : NULL;
766 if (cwd)
768 if (exists(name))
769 return name;
771 if (path)
772 { unsigned i;
774 for (i = 0; i < path->dim; i++)
776 char *p = (char *)path->data[i];
777 char *n = combine(p, name);
779 if (exists(n))
780 return n;
783 return NULL;
786 int FileName::exists(const char *name)
788 #ifndef _WIN32
789 struct stat st;
791 if (stat(name, &st) < 0)
792 return 0;
793 if (S_ISDIR(st.st_mode))
794 return 2;
795 return 1;
796 #endif
797 #if _WIN32
798 DWORD dw;
799 int result;
801 dw = GetFileAttributesA(name);
802 if (dw == -1L)
803 result = 0;
804 else if (dw & FILE_ATTRIBUTE_DIRECTORY)
805 result = 2;
806 else
807 result = 1;
808 return result;
809 #endif
812 void FileName::ensurePathExists(const char *path)
814 //printf("FileName::ensurePathExists(%s)\n", path ? path : "");
815 if (path && *path)
817 if (!exists(path))
819 char *p = FileName::path(path);
820 if (*p)
822 #if _WIN32
823 size_t len = strlen(p);
824 if (len > 2 && p[-1] == ':')
825 { mem.free(p);
826 return;
828 #endif
829 ensurePathExists(p);
830 mem.free(p);
832 #if _WIN32
833 if (path[strlen(path) - 1] != '\\')
834 #endif
835 #if linux
836 if (path[strlen(path) - 1] != '\\')
837 #endif
839 //printf("mkdir(%s)\n", path);
840 #if _WIN32
841 if (mkdir(path))
842 #else
843 if (mkdir(path, 0777))
844 #endif
845 error("cannot create directory %s", path);
851 /****************************** File ********************************/
853 File::File(FileName *n)
855 ref = 0;
856 buffer = NULL;
857 len = 0;
858 touchtime = NULL;
859 name = n;
862 File::File(char *n)
864 ref = 0;
865 buffer = NULL;
866 len = 0;
867 touchtime = NULL;
868 name = new FileName(n, 0);
871 File::~File()
873 if (buffer)
875 if (ref == 0)
876 mem.free(buffer);
877 #if _WIN32
878 else if (ref == 2)
879 UnmapViewOfFile(buffer);
880 #endif
882 if (touchtime)
883 mem.free(touchtime);
886 void File::mark()
888 mem.mark(buffer);
889 mem.mark(touchtime);
890 mem.mark(name);
893 /*************************************
896 int File::read()
898 #ifndef _WIN32
899 off_t size;
900 ssize_t numread;
901 int fd;
902 struct stat buf;
903 int result = 0;
904 char *name;
906 name = this->name->toChars();
907 //printf("File::read('%s')\n",name);
908 fd = open(name, O_RDONLY);
909 if (fd == -1)
910 { result = errno;
911 //printf("\topen error, errno = %d\n",errno);
912 goto err1;
915 if (!ref)
916 mem.free(buffer);
917 ref = 0; // we own the buffer now
919 //printf("\tfile opened\n");
920 if (fstat(fd, &buf))
922 fprintf(stderr, "\tfstat error, errno = %d\n",errno);
923 goto err2;
925 size = buf.st_size;
926 buffer = (unsigned char *) mem.malloc(size + 2);
927 if (!buffer)
929 fprintf(stderr, "\tmalloc error, errno = %d\n",errno);
930 goto err2;
933 numread = ::read(fd, buffer, size);
934 if (numread != size)
936 fprintf(stderr, "\tread error, errno = %d\n",errno);
937 goto err2;
940 if (touchtime)
941 memcpy(touchtime, &buf, sizeof(buf));
943 if (close(fd) == -1)
945 fprintf(stderr, "\tclose error, errno = %d\n",errno);
946 goto err;
949 len = size;
951 // Always store a wchar ^Z past end of buffer so scanner has a sentinel
952 buffer[size] = 0; // ^Z is obsolete, use 0
953 buffer[size + 1] = 0;
954 return 0;
956 err2:
957 close(fd);
958 err:
959 mem.free(buffer);
960 buffer = NULL;
961 len = 0;
963 err1:
964 result = 1;
965 return result;
966 #endif
967 #if _WIN32
968 DWORD size;
969 DWORD numread;
970 HANDLE h;
971 int result = 0;
972 char *name;
974 name = this->name->toChars();
975 h = CreateFileA(name,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,
976 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,0);
977 if (h == INVALID_HANDLE_VALUE)
978 goto err1;
980 if (!ref)
981 mem.free(buffer);
982 ref = 0;
984 size = GetFileSize(h,NULL);
985 buffer = (unsigned char *) mem.malloc(size + 2);
986 if (!buffer)
987 goto err2;
989 if (ReadFile(h,buffer,size,&numread,NULL) != TRUE)
990 goto err2;
992 if (numread != size)
993 goto err2;
995 if (touchtime)
997 if (!GetFileTime(h, NULL, NULL, &((WIN32_FIND_DATAA *)touchtime)->ftLastWriteTime))
998 goto err2;
1001 if (!CloseHandle(h))
1002 goto err;
1004 len = size;
1006 // Always store a wchar ^Z past end of buffer so scanner has a sentinel
1007 buffer[size] = 0; // ^Z is obsolete, use 0
1008 buffer[size + 1] = 0;
1009 return 0;
1011 err2:
1012 CloseHandle(h);
1013 err:
1014 mem.free(buffer);
1015 buffer = NULL;
1016 len = 0;
1018 err1:
1019 result = 1;
1020 return result;
1021 #endif
1024 /*****************************
1025 * Read a file with memory mapped file I/O.
1028 int File::mmread()
1030 #ifndef _WIN32
1031 return read();
1032 #endif
1033 #if _WIN32
1034 HANDLE hFile;
1035 HANDLE hFileMap;
1036 DWORD size;
1037 char *name;
1039 name = this->name->toChars();
1040 hFile = CreateFile(name, GENERIC_READ,
1041 FILE_SHARE_READ, NULL,
1042 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
1043 if (hFile == INVALID_HANDLE_VALUE)
1044 goto Lerr;
1045 size = GetFileSize(hFile, NULL);
1046 //printf(" file created, size %d\n", size);
1048 hFileMap = CreateFileMapping(hFile,NULL,PAGE_READONLY,0,size,NULL);
1049 if (CloseHandle(hFile) != TRUE)
1050 goto Lerr;
1052 if (hFileMap == NULL)
1053 goto Lerr;
1055 //printf(" mapping created\n");
1057 if (!ref)
1058 mem.free(buffer);
1059 ref = 2;
1060 buffer = (unsigned char *)MapViewOfFileEx(hFileMap, FILE_MAP_READ,0,0,size,NULL);
1061 if (CloseHandle(hFileMap) != TRUE)
1062 goto Lerr;
1063 if (buffer == NULL) // mapping view failed
1064 goto Lerr;
1066 len = size;
1067 //printf(" buffer = %p\n", buffer);
1069 return 0;
1071 Lerr:
1072 return GetLastError(); // failure
1073 #endif
1076 /*********************************************
1077 * Write a file.
1078 * Returns:
1079 * 0 success
1082 int File::write()
1084 #ifndef _WIN32
1085 int fd;
1086 ssize_t numwritten;
1087 char *name;
1089 name = this->name->toChars();
1090 fd = open(name, O_CREAT | O_WRONLY | O_TRUNC, 0644);
1091 if (fd == -1)
1092 goto err;
1094 numwritten = ::write(fd, buffer, len);
1095 if (len != numwritten)
1096 goto err2;
1098 if (close(fd) == -1)
1099 goto err;
1101 if (touchtime)
1102 { struct utimbuf ubuf;
1104 ubuf.actime = ((struct stat *)touchtime)->st_atime;
1105 ubuf.modtime = ((struct stat *)touchtime)->st_mtime;
1106 if (utime(name, &ubuf))
1107 goto err;
1109 return 0;
1111 err2:
1112 close(fd);
1113 ::remove(name);
1114 err:
1115 return 1;
1116 #endif
1117 #if _WIN32
1118 HANDLE h;
1119 DWORD numwritten;
1120 char *name;
1122 name = this->name->toChars();
1123 h = CreateFileA(name,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,
1124 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,NULL);
1125 if (h == INVALID_HANDLE_VALUE)
1126 goto err;
1128 if (WriteFile(h,buffer,len,&numwritten,NULL) != TRUE)
1129 goto err2;
1131 if (len != numwritten)
1132 goto err2;
1134 if (touchtime) {
1135 SetFileTime(h, NULL, NULL, &((WIN32_FIND_DATAA *)touchtime)->ftLastWriteTime);
1137 if (!CloseHandle(h))
1138 goto err;
1139 return 0;
1141 err2:
1142 CloseHandle(h);
1143 DeleteFileA(name);
1144 err:
1145 return 1;
1146 #endif
1149 /*********************************************
1150 * Append to a file.
1151 * Returns:
1152 * 0 success
1155 int File::append()
1157 #ifndef _WIN32
1158 return 1;
1159 #endif
1160 #if _WIN32
1161 HANDLE h;
1162 DWORD numwritten;
1163 char *name;
1165 name = this->name->toChars();
1166 h = CreateFileA(name,GENERIC_WRITE,0,NULL,OPEN_ALWAYS,
1167 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,NULL);
1168 if (h == INVALID_HANDLE_VALUE)
1169 goto err;
1171 #if 1
1172 SetFilePointer(h, 0, NULL, FILE_END);
1173 #else // INVALID_SET_FILE_POINTER doesn't seem to have a definition
1174 if (SetFilePointer(h, 0, NULL, FILE_END) == INVALID_SET_FILE_POINTER)
1175 goto err;
1176 #endif
1178 if (WriteFile(h,buffer,len,&numwritten,NULL) != TRUE)
1179 goto err2;
1181 if (len != numwritten)
1182 goto err2;
1184 if (touchtime) {
1185 SetFileTime(h, NULL, NULL, &((WIN32_FIND_DATAA *)touchtime)->ftLastWriteTime);
1187 if (!CloseHandle(h))
1188 goto err;
1189 return 0;
1191 err2:
1192 CloseHandle(h);
1193 err:
1194 return 1;
1195 #endif
1198 /**************************************
1201 void File::readv()
1203 if (read())
1204 error("Error reading file '%s'\n",name->toChars());
1207 /**************************************
1210 void File::mmreadv()
1212 if (mmread())
1213 readv();
1216 void File::writev()
1218 if (write())
1219 error("Error writing file '%s'\n",name->toChars());
1222 void File::appendv()
1224 if (write())
1225 error("Error appending to file '%s'\n",name->toChars());
1228 /*******************************************
1229 * Return !=0 if file exists.
1230 * 0: file doesn't exist
1231 * 1: normal file
1232 * 2: directory
1235 int File::exists()
1237 #ifndef _WIN32
1238 return 0;
1239 #endif
1240 #if _WIN32
1241 DWORD dw;
1242 int result;
1243 char *name;
1245 name = this->name->toChars();
1246 if (touchtime)
1247 dw = ((WIN32_FIND_DATAA *)touchtime)->dwFileAttributes;
1248 else
1249 dw = GetFileAttributesA(name);
1250 if (dw == -1L)
1251 result = 0;
1252 else if (dw & FILE_ATTRIBUTE_DIRECTORY)
1253 result = 2;
1254 else
1255 result = 1;
1256 return result;
1257 #endif
1260 void File::remove()
1262 #ifndef _WIN32
1263 ::remove(this->name->toChars());
1264 #endif
1265 #if _WIN32
1266 DeleteFileA(this->name->toChars());
1267 #endif
1270 Array *File::match(char *n)
1272 return match(new FileName(n, 0));
1275 Array *File::match(FileName *n)
1277 #ifndef _WIN32
1278 return NULL;
1279 #endif
1280 #if _WIN32
1281 HANDLE h;
1282 WIN32_FIND_DATAA fileinfo;
1283 Array *a;
1284 char *c;
1285 char *name;
1287 a = new Array();
1288 c = n->toChars();
1289 name = n->name();
1290 h = FindFirstFileA(c,&fileinfo);
1291 if (h != INVALID_HANDLE_VALUE)
1295 // Glue path together with name
1296 char *fn;
1297 File *f;
1299 fn = (char *)mem.malloc(name - c + strlen(fileinfo.cFileName) + 1);
1300 memcpy(fn, c, name - c);
1301 strcpy(fn + (name - c), fileinfo.cFileName);
1302 f = new File(fn);
1303 f->touchtime = mem.malloc(sizeof(WIN32_FIND_DATAA));
1304 memcpy(f->touchtime, &fileinfo, sizeof(fileinfo));
1305 a->push(f);
1306 } while (FindNextFileA(h,&fileinfo) != FALSE);
1307 FindClose(h);
1309 return a;
1310 #endif
1313 int File::compareTime(File *f)
1315 #ifndef _WIN32
1316 return 0;
1317 #endif
1318 #if _WIN32
1319 if (!touchtime)
1320 stat();
1321 if (!f->touchtime)
1322 f->stat();
1323 return CompareFileTime(&((WIN32_FIND_DATAA *)touchtime)->ftLastWriteTime, &((WIN32_FIND_DATAA *)f->touchtime)->ftLastWriteTime);
1324 #endif
1327 void File::stat()
1329 #ifndef _WIN32
1330 if (!touchtime)
1332 touchtime = mem.calloc(1, sizeof(struct stat));
1334 #endif
1335 #if _WIN32
1336 HANDLE h;
1338 if (!touchtime)
1340 touchtime = mem.calloc(1, sizeof(WIN32_FIND_DATAA));
1342 h = FindFirstFileA(name->toChars(),(WIN32_FIND_DATAA *)touchtime);
1343 if (h != INVALID_HANDLE_VALUE)
1345 FindClose(h);
1347 #endif
1350 void File::checkoffset(size_t offset, size_t nbytes)
1352 if (offset > len || offset + nbytes > len)
1353 error("Corrupt file '%s': offset x%"PRIxSIZE" off end of file",toChars(),offset);
1356 char *File::toChars()
1358 return name->toChars();
1362 /************************* OutBuffer *************************/
1364 OutBuffer::OutBuffer()
1366 data = NULL;
1367 offset = 0;
1368 size = 0;
1371 OutBuffer::~OutBuffer()
1373 mem.free(data);
1376 void *OutBuffer::extractData()
1378 void *p;
1380 p = (void *)data;
1381 data = NULL;
1382 offset = 0;
1383 size = 0;
1384 return p;
1387 void OutBuffer::mark()
1389 mem.mark(data);
1392 void OutBuffer::reserve(unsigned nbytes)
1394 //printf("OutBuffer::reserve: size = %d, offset = %d, nbytes = %d\n", size, offset, nbytes);
1395 if (size - offset < nbytes)
1397 size = (offset + nbytes) * 2;
1398 data = (unsigned char *)mem.realloc(data, size);
1402 void OutBuffer::reset()
1404 offset = 0;
1407 void OutBuffer::setsize(unsigned size)
1409 offset = size;
1412 void OutBuffer::write(const void *data, unsigned nbytes)
1414 reserve(nbytes);
1415 memcpy(this->data + offset, data, nbytes);
1416 offset += nbytes;
1419 void OutBuffer::writebstring(unsigned char *string)
1421 write(string,*string + 1);
1424 void OutBuffer::writestring(const char *string)
1426 write(string,strlen(string));
1429 void OutBuffer::writedstring(const char *string)
1431 #if M_UNICODE
1432 for (; *string; string++)
1434 writedchar(*string);
1436 #else
1437 write(string,strlen(string));
1438 #endif
1441 void OutBuffer::writedstring(const wchar_t *string)
1443 #if M_UNICODE
1444 write(string,wcslen(string) * sizeof(wchar_t));
1445 #else
1446 for (; *string; string++)
1448 writedchar(*string);
1450 #endif
1453 void OutBuffer::prependstring(char *string)
1454 { unsigned len;
1456 len = strlen(string);
1457 reserve(len);
1458 memmove(data + len, data, offset);
1459 memcpy(data, string, len);
1460 offset += len;
1463 void OutBuffer::writenl()
1465 #if _WIN32
1466 #if M_UNICODE
1467 write4(0x000A000D); // newline is CR,LF on Microsoft OS's
1468 #else
1469 writeword(0x0A0D); // newline is CR,LF on Microsoft OS's
1470 #endif
1471 #else
1472 #if M_UNICODE
1473 writeword('\n');
1474 #else
1475 writeByte('\n');
1476 #endif
1477 #endif
1480 void OutBuffer::writeByte(unsigned b)
1482 reserve(1);
1483 this->data[offset] = (unsigned char)b;
1484 offset++;
1487 void OutBuffer::writeUTF8(unsigned b)
1489 reserve(6);
1490 if (b <= 0x7F)
1492 this->data[offset] = (unsigned char)b;
1493 offset++;
1495 else if (b <= 0x7FF)
1497 this->data[offset + 0] = (unsigned char)((b >> 6) | 0xC0);
1498 this->data[offset + 1] = (unsigned char)((b & 0x3F) | 0x80);
1499 offset += 2;
1501 else if (b <= 0xFFFF)
1503 this->data[offset + 0] = (unsigned char)((b >> 12) | 0xE0);
1504 this->data[offset + 1] = (unsigned char)(((b >> 6) & 0x3F) | 0x80);
1505 this->data[offset + 2] = (unsigned char)((b & 0x3F) | 0x80);
1506 offset += 3;
1508 else if (b <= 0x1FFFFF)
1510 this->data[offset + 0] = (unsigned char)((b >> 18) | 0xF0);
1511 this->data[offset + 1] = (unsigned char)(((b >> 12) & 0x3F) | 0x80);
1512 this->data[offset + 2] = (unsigned char)(((b >> 6) & 0x3F) | 0x80);
1513 this->data[offset + 3] = (unsigned char)((b & 0x3F) | 0x80);
1514 offset += 4;
1516 else if (b <= 0x3FFFFFF)
1518 this->data[offset + 0] = (unsigned char)((b >> 24) | 0xF8);
1519 this->data[offset + 1] = (unsigned char)(((b >> 18) & 0x3F) | 0x80);
1520 this->data[offset + 2] = (unsigned char)(((b >> 12) & 0x3F) | 0x80);
1521 this->data[offset + 3] = (unsigned char)(((b >> 6) & 0x3F) | 0x80);
1522 this->data[offset + 4] = (unsigned char)((b & 0x3F) | 0x80);
1523 offset += 5;
1525 else if (b <= 0x7FFFFFFF)
1527 this->data[offset + 0] = (unsigned char)((b >> 30) | 0xFC);
1528 this->data[offset + 1] = (unsigned char)(((b >> 24) & 0x3F) | 0x80);
1529 this->data[offset + 2] = (unsigned char)(((b >> 18) & 0x3F) | 0x80);
1530 this->data[offset + 3] = (unsigned char)(((b >> 12) & 0x3F) | 0x80);
1531 this->data[offset + 4] = (unsigned char)(((b >> 6) & 0x3F) | 0x80);
1532 this->data[offset + 5] = (unsigned char)((b & 0x3F) | 0x80);
1533 offset += 6;
1535 else
1536 assert(0);
1539 void OutBuffer::writedchar(unsigned b)
1541 reserve(Dchar_mbmax * sizeof(dchar));
1542 offset = (unsigned char *)Dchar::put((dchar *)(this->data + offset), (dchar)b) -
1543 this->data;
1546 void OutBuffer::prependbyte(unsigned b)
1548 reserve(1);
1549 memmove(data + 1, data, offset);
1550 data[0] = (unsigned char)b;
1551 offset++;
1554 void OutBuffer::writeword(unsigned w)
1556 reserve(2);
1557 *(unsigned short *)(this->data + offset) = (unsigned short)w;
1558 offset += 2;
1561 void OutBuffer::writeUTF16(unsigned w)
1563 reserve(4);
1564 if (w <= 0xFFFF)
1566 *(unsigned short *)(this->data + offset) = (unsigned short)w;
1567 offset += 2;
1569 else if (w <= 0x10FFFF)
1571 *(unsigned short *)(this->data + offset) = (unsigned short)((w >> 10) + 0xD7C0);
1572 *(unsigned short *)(this->data + offset + 2) = (unsigned short)((w & 0x3FF) | 0xDC00);
1573 offset += 4;
1575 else
1576 assert(0);
1579 void OutBuffer::write4(unsigned w)
1581 reserve(4);
1582 *(uint32_t *)(this->data + offset) = w;
1583 offset += 4;
1586 void OutBuffer::write(OutBuffer *buf)
1588 if (buf)
1589 { reserve(buf->offset);
1590 memcpy(data + offset, buf->data, buf->offset);
1591 offset += buf->offset;
1595 void OutBuffer::write(Object *obj)
1597 if (obj)
1599 writestring(obj->toChars());
1603 void OutBuffer::fill0(unsigned nbytes)
1605 reserve(nbytes);
1606 memset(data + offset,0,nbytes);
1607 offset += nbytes;
1610 void OutBuffer::align(unsigned size)
1611 { unsigned nbytes;
1613 nbytes = ((offset + size - 1) & ~(size - 1)) - offset;
1614 fill0(nbytes);
1617 void OutBuffer::vprintf(const char *format, va_list args)
1619 char buffer[128];
1620 char *p;
1621 unsigned psize;
1622 int count;
1623 va_list args_copy;
1625 p = buffer;
1626 psize = sizeof(buffer);
1627 for (;;)
1629 va_copy(args_copy, args);
1630 #if _WIN32
1631 count = _vsnprintf(p,psize,format,args_copy);
1632 if (count != -1)
1633 break;
1634 psize *= 2;
1635 #endif
1636 #ifndef _WIN32
1637 count = vsnprintf(p,psize,format,args_copy);
1638 if (count == -1)
1639 psize *= 2;
1640 else if (count >= psize)
1641 psize = count + 1;
1642 else
1643 break;
1644 #endif
1645 p = (char *) alloca(psize); // buffer too small, try again with larger size
1647 write(p,count);
1650 #if M_UNICODE
1651 void OutBuffer::vprintf(const wchar_t *format, va_list args)
1653 dchar buffer[128];
1654 dchar *p;
1655 unsigned psize;
1656 int count;
1657 va_list args_copy;
1659 p = buffer;
1660 psize = sizeof(buffer) / sizeof(buffer[0]);
1661 for (;;)
1663 #if _WIN32
1664 count = _vsnwprintf(p,psize,format,args_copy);
1665 if (count != -1)
1666 break;
1667 psize *= 2;
1668 #endif
1669 #ifndef _WIN32
1670 count = vsnwprintf(p,psize,format,args_copy);
1671 if (count == -1)
1672 psize *= 2;
1673 else if (count >= psize)
1674 psize = count + 1;
1675 else
1676 break;
1677 #endif
1678 p = (dchar *) alloca(psize * 2); // buffer too small, try again with larger size
1680 write(p,count * 2);
1682 #endif
1684 void OutBuffer::printf(const char *format, ...)
1686 va_list ap;
1687 va_start(ap, format);
1688 vprintf(format,ap);
1689 va_end(ap);
1692 #if M_UNICODE
1693 void OutBuffer::printf(const wchar_t *format, ...)
1695 va_list ap;
1696 va_start(ap, format);
1697 vprintf(format,ap);
1698 va_end(ap);
1700 #endif
1702 void OutBuffer::bracket(char left, char right)
1704 reserve(2);
1705 memmove(data + 1, data, offset);
1706 data[0] = left;
1707 data[offset + 1] = right;
1708 offset += 2;
1711 /******************
1712 * Insert left at i, and right at j.
1713 * Return index just past right.
1716 unsigned OutBuffer::bracket(unsigned i, char *left, unsigned j, char *right)
1718 size_t leftlen = strlen(left);
1719 size_t rightlen = strlen(right);
1720 reserve(leftlen + rightlen);
1721 insert(i, left, leftlen);
1722 insert(j + leftlen, right, rightlen);
1723 return j + leftlen + rightlen;
1726 void OutBuffer::spread(unsigned offset, unsigned nbytes)
1728 reserve(nbytes);
1729 memmove(data + offset + nbytes, data + offset,
1730 this->offset - offset);
1731 this->offset += nbytes;
1734 /****************************************
1735 * Returns: offset + nbytes
1738 unsigned OutBuffer::insert(unsigned offset, const void *p, unsigned nbytes)
1740 spread(offset, nbytes);
1741 memmove(data + offset, p, nbytes);
1742 return offset + nbytes;
1745 void OutBuffer::remove(unsigned offset, unsigned nbytes)
1747 memmove(data + offset, data + offset + nbytes, this->offset - (offset + nbytes));
1748 this->offset -= nbytes;
1751 char *OutBuffer::toChars()
1753 writeByte(0);
1754 return (char *)data;
1757 /********************************* Bits ****************************/
1759 Bits::Bits()
1761 data = NULL;
1762 bitdim = 0;
1763 allocdim = 0;
1766 Bits::~Bits()
1768 mem.free(data);
1771 void Bits::mark()
1773 mem.mark(data);
1776 void Bits::resize(unsigned bitdim)
1778 unsigned allocdim;
1779 unsigned mask;
1781 allocdim = (bitdim + 31) / 32;
1782 data = (unsigned *)mem.realloc(data, allocdim * sizeof(data[0]));
1783 if (this->allocdim < allocdim)
1784 memset(data + this->allocdim, 0, (allocdim - this->allocdim) * sizeof(data[0]));
1786 // Clear other bits in last word
1787 mask = (1 << (bitdim & 31)) - 1;
1788 if (mask)
1789 data[allocdim - 1] &= ~mask;
1791 this->bitdim = bitdim;
1792 this->allocdim = allocdim;
1795 void Bits::set(unsigned bitnum)
1797 data[bitnum / 32] |= 1 << (bitnum & 31);
1800 void Bits::clear(unsigned bitnum)
1802 data[bitnum / 32] &= ~(1 << (bitnum & 31));
1805 int Bits::test(unsigned bitnum)
1807 return data[bitnum / 32] & (1 << (bitnum & 31));
1810 void Bits::set()
1811 { unsigned mask;
1813 memset(data, ~0, allocdim * sizeof(data[0]));
1815 // Clear other bits in last word
1816 mask = (1 << (bitdim & 31)) - 1;
1817 if (mask)
1818 data[allocdim - 1] &= mask;
1821 void Bits::clear()
1823 memset(data, 0, allocdim * sizeof(data[0]));
1826 void Bits::copy(Bits *from)
1828 assert(bitdim == from->bitdim);
1829 memcpy(data, from->data, allocdim * sizeof(data[0]));
1832 Bits *Bits::clone()
1834 Bits *b;
1836 b = new Bits();
1837 b->resize(bitdim);
1838 b->copy(this);
1839 return b;
1842 void Bits::sub(Bits *b)
1844 unsigned u;
1846 for (u = 0; u < allocdim; u++)
1847 data[u] &= ~b->data[u];