Mercurial > projects > ldc
diff dmd/root.c @ 1:c53b6e3fe49a trunk
[svn r5] Initial commit. Most things are very rough.
author | lindquist |
---|---|
date | Sat, 01 Sep 2007 21:43:27 +0200 |
parents | |
children | 297690b5d4a5 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/root.c Sat Sep 01 21:43:27 2007 +0200 @@ -0,0 +1,1835 @@ + +// Copyright (c) 1999-2006 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <stdint.h> +#include <assert.h> + +#if _MSC_VER +#include <malloc.h> +#endif + +#if _WIN32 +#include <windows.h> +#include <direct.h> +#endif + +#if linux +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> +#include <unistd.h> +#include <utime.h> +#endif + +#include "port.h" +#include "root.h" +#include "dchar.h" +#include "mem.h" + +#if 0 //__SC__ //def DEBUG +extern "C" void __cdecl _assert(void *e, void *f, unsigned line) +{ + printf("Assert('%s','%s',%d)\n",e,f,line); + fflush(stdout); + *(char *)0 = 0; +} +#endif + +/************************************* + * Convert wchar string to ascii string. + */ + +char *wchar2ascii(wchar_t *us) +{ + return wchar2ascii(us, wcslen(us)); +} + +char *wchar2ascii(wchar_t *us, unsigned len) +{ + unsigned i; + char *p; + + p = (char *)mem.malloc(len + 1); + for (i = 0; i <= len; i++) + p[i] = (char) us[i]; + return p; +} + +int wcharIsAscii(wchar_t *us) +{ + return wcharIsAscii(us, wcslen(us)); +} + +int wcharIsAscii(wchar_t *us, unsigned len) +{ + unsigned i; + + for (i = 0; i <= len; i++) + { + if (us[i] & ~0xFF) // if high bits set + return 0; // it's not ascii + } + return 1; +} + + +/*********************************** + * Compare length-prefixed strings (bstr). + */ + +int bstrcmp(unsigned char *b1, unsigned char *b2) +{ + return (*b1 == *b2 && memcmp(b1 + 1, b2 + 1, *b2) == 0) ? 0 : 1; +} + +/*************************************** + * Convert bstr into a malloc'd string. + */ + +char *bstr2str(unsigned char *b) +{ + char *s; + unsigned len; + + len = *b; + s = (char *) mem.malloc(len + 1); + s[len] = 0; + return (char *)memcpy(s,b + 1,len); +} + +/************************************** + * Print error message and exit. + */ + +void error(const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + printf("Error: "); + vprintf(format, ap); + va_end( ap ); + printf("\n"); + fflush(stdout); + + exit(EXIT_FAILURE); +} + +#if M_UNICODE +void error(const dchar *format, ...) +{ + va_list ap; + + va_start(ap, format); + printf("Error: "); + vwprintf(format, ap); + va_end( ap ); + printf("\n"); + fflush(stdout); + + exit(EXIT_FAILURE); +} +#endif + +void error_mem() +{ + error("out of memory"); +} + +/************************************** + * Print warning message. + */ + +void warning(const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + printf("Warning: "); + vprintf(format, ap); + va_end( ap ); + printf("\n"); + fflush(stdout); +} + +/****************************** Object ********************************/ + +int Object::equals(Object *o) +{ + return o == this; +} + +hash_t Object::hashCode() +{ + return (hash_t) this; +} + +int Object::compare(Object *obj) +{ + return this - obj; +} + +void Object::print() +{ + printf("%s %p\n", toChars(), this); +} + +char *Object::toChars() +{ + return "Object"; +} + +dchar *Object::toDchars() +{ +#if M_UNICODE + return L"Object"; +#else + return toChars(); +#endif +} + +int Object::dyncast() +{ + return 0; +} + +void Object::toBuffer(OutBuffer *b) +{ + b->writestring("Object"); +} + +void Object::mark() +{ +} + +/****************************** String ********************************/ + +String::String(char *str, int ref) +{ + this->str = ref ? str : mem.strdup(str); + this->ref = ref; +} + +String::~String() +{ + mem.free(str); +} + +void String::mark() +{ + mem.mark(str); +} + +hash_t String::calcHash(const char *str, size_t len) +{ + hash_t hash = 0; + + for (;;) + { + switch (len) + { + case 0: + return hash; + + case 1: + hash *= 37; + hash += *(uint8_t *)str; + return hash; + + case 2: + hash *= 37; + hash += *(uint16_t *)str; + return hash; + + case 3: + hash *= 37; + hash += (*(uint16_t *)str << 8) + + ((uint8_t *)str)[2]; + return hash; + + default: + hash *= 37; + hash += *(uint32_t *)str; + str += 4; + len -= 4; + break; + } + } +} + +hash_t String::calcHash(const char *str) +{ + return calcHash(str, strlen(str)); +} + +hash_t String::hashCode() +{ + return calcHash(str, strlen(str)); +} + +unsigned String::len() +{ + return strlen(str); +} + +int String::equals(Object *obj) +{ + return strcmp(str,((String *)obj)->str) == 0; +} + +int String::compare(Object *obj) +{ + return strcmp(str,((String *)obj)->str); +} + +char *String::toChars() +{ + return str; +} + +void String::print() +{ + printf("String '%s'\n",str); +} + + +/****************************** FileName ********************************/ + +FileName::FileName(char *str, int ref) + : String(str,ref) +{ +} + +char *FileName::combine(char *path, char *name) +{ char *f; + size_t pathlen; + size_t namelen; + + if (!path || !*path) + return name; + pathlen = strlen(path); + namelen = strlen(name); + f = (char *)mem.malloc(pathlen + 1 + namelen + 1); + memcpy(f, path, pathlen); +#if linux + if (path[pathlen - 1] != '/') + { f[pathlen] = '/'; + pathlen++; + } +#endif +#if _WIN32 + if (path[pathlen - 1] != '\\' && path[pathlen - 1] != ':') + { f[pathlen] = '\\'; + pathlen++; + } +#endif + memcpy(f + pathlen, name, namelen + 1); + return f; +} + +FileName::FileName(char *path, char *name) + : String(combine(path,name),1) +{ +} + +// Split a path into an Array of paths +Array *FileName::splitPath(const char *path) +{ + char c = 0; // unnecessary initializer is for VC /W4 + const char *p; + OutBuffer buf; + Array *array; + + array = new Array(); + if (path) + { + p = path; + do + { char instring = 0; + + while (isspace(*p)) // skip leading whitespace + p++; + buf.reserve(strlen(p) + 1); // guess size of path + for (; ; p++) + { + c = *p; + switch (c) + { + case '"': + instring ^= 1; // toggle inside/outside of string + continue; + +#if MACINTOSH + case ',': +#endif +#if _WIN32 + case ';': +#endif +#if linux + case ':': +#endif + p++; + break; // note that ; cannot appear as part + // of a path, quotes won't protect it + + case 0x1A: // ^Z means end of file + case 0: + break; + + case '\r': + continue; // ignore carriage returns + +#if linux + case '~': + buf.writestring(getenv("HOME")); + continue; +#endif + + case ' ': + case '\t': // tabs in filenames? + if (!instring) // if not in string + break; // treat as end of path + default: + buf.writeByte(c); + continue; + } + break; + } + if (buf.offset) // if path is not empty + { + buf.writeByte(0); // to asciiz + array->push(buf.extractData()); + } + } while (c); + } + return array; +} + +hash_t FileName::hashCode() +{ +#if _WIN32 + // We need a different hashCode because it must be case-insensitive + size_t len = strlen(str); + hash_t hash = 0; + unsigned char *s = (unsigned char *)str; + + for (;;) + { + switch (len) + { + case 0: + return hash; + + case 1: + hash *= 37; + hash += *(uint8_t *)s | 0x20; + return hash; + + case 2: + hash *= 37; + hash += *(uint16_t *)s | 0x2020; + return hash; + + case 3: + hash *= 37; + hash += ((*(uint16_t *)s << 8) + + ((uint8_t *)s)[2]) | 0x202020; + break; + + default: + hash *= 37; + hash += *(uint32_t *)s | 0x20202020; + s += 4; + len -= 4; + break; + } + } +#else + // darwin HFS is case insensitive, though... + return String::hashCode(); +#endif +} + +int FileName::compare(Object *obj) +{ +#if _WIN32 + return stricmp(str,((FileName *)obj)->str); +#else + return String::compare(obj); +#endif +} + +int FileName::equals(Object *obj) +{ +#if _WIN32 + return stricmp(str,((FileName *)obj)->str) == 0; +#else + return String::equals(obj); +#endif +} + +/************************************ + * Return !=0 if absolute path name. + */ + +int FileName::absolute(const char *name) +{ +#if _WIN32 + return (*name == '\\') || + (*name == '/') || + (*name && name[1] == ':'); +#endif +#if linux + return (*name == '/'); +#endif +} + +/******************************** + * Return filename extension (read-only). + * If there isn't one, return NULL. + */ + +char *FileName::ext(const char *str) +{ + char *e; + size_t len = strlen(str); + + e = (char *)str + len; + for (;;) + { + switch (*e) + { case '.': + return e + 1; +#if linux + case '/': + break; +#endif +#if _WIN32 + case '\\': + case ':': + break; +#endif + default: + if (e == str) + break; + e--; + continue; + } + return NULL; + } +} + +char *FileName::ext() +{ + return ext(str); +} + +/******************************** + * Return filename name excluding path (read-only). + */ + +char *FileName::name(const char *str) +{ + char *e; + size_t len = strlen(str); + + e = (char *)str + len; + for (;;) + { + switch (*e) + { +#if linux + case '/': + return e + 1; +#endif +#if _WIN32 + case '\\': + case ':': + return e + 1; +#endif + default: + if (e == str) + break; + e--; + continue; + } + return e; + } +} + +char *FileName::name() +{ + return name(str); +} + +/************************************** + * Return path portion of str. + * Path will does not include trailing path separator. + */ + +char *FileName::path(const char *str) +{ + char *n = name(str); + char *path; + size_t pathlen; + + if (n > str) + { +#if linux + if (n[-1] == '/') + n--; +#endif +#if _WIN32 + if (n[-1] == '\\') + n--; +#endif + } + pathlen = n - str; + path = (char *)mem.malloc(pathlen + 1); + memcpy(path, str, pathlen); + path[pathlen] = 0; + return path; +} + +/************************************** + * Replace filename portion of path. + */ + +char *FileName::replaceName(char *path, char *name) +{ char *f; + char *n; + size_t pathlen; + size_t namelen; + + if (absolute(name)) + return name; + + n = FileName::name(path); + if (n == path) + return name; + pathlen = n - path; + namelen = strlen(name); + f = (char *)mem.malloc(pathlen + 1 + namelen + 1); + memcpy(f, path, pathlen); +#if linux + if (path[pathlen - 1] != '/') + { f[pathlen] = '/'; + pathlen++; + } +#endif +#if _WIN32 + if (path[pathlen - 1] != '\\' && path[pathlen - 1] != ':') + { f[pathlen] = '\\'; + pathlen++; + } +#endif + memcpy(f + pathlen, name, namelen + 1); + return f; +} + +/*************************** + */ + +FileName *FileName::defaultExt(const char *name, const char *ext) +{ + char *e; + char *s; + size_t len; + size_t extlen; + + e = FileName::ext(name); + if (e) // if already has an extension + return new FileName((char *)name, 0); + + len = strlen(name); + extlen = strlen(ext); + s = (char *)alloca(len + 1 + extlen + 1); + memcpy(s,name,len); + s[len] = '.'; + memcpy(s + len + 1, ext, extlen + 1); + return new FileName(s, 0); +} + +/*************************** + */ + +FileName *FileName::forceExt(const char *name, const char *ext) +{ + char *e; + char *s; + size_t len; + size_t extlen; + + e = FileName::ext(name); + if (e) // if already has an extension + { + len = e - name; + extlen = strlen(ext); + + s = (char *)alloca(len + extlen + 1); + memcpy(s,name,len); + memcpy(s + len, ext, extlen + 1); + return new FileName(s, 0); + } + else + return defaultExt(name, ext); // doesn't have one +} + +/****************************** + * Return !=0 if extensions match. + */ + +int FileName::equalsExt(const char *ext) +{ const char *e; + + e = FileName::ext(); + if (!e && !ext) + return 1; + if (!e || !ext) + return 0; +#if linux + return strcmp(e,ext) == 0; +#endif +#if _WIN32 + return stricmp(e,ext) == 0; +#endif +} + +/************************************* + * Copy file from this to to. + */ + +void FileName::CopyTo(FileName *to) +{ + File file(this); + +#if _WIN32 + file.touchtime = mem.malloc(sizeof(WIN32_FIND_DATAA)); // keep same file time +#endif +#if linux + file.touchtime = mem.malloc(sizeof(struct stat)); // keep same file time +#endif + file.readv(); + file.name = to; + file.writev(); +} + +/************************************* + * Search Path for file. + * Input: + * cwd if !=0, search current directory before searching path + */ + +char *FileName::searchPath(Array *path, char *name, int cwd) +{ + if (absolute(name)) + { + return exists(name) ? name : NULL; + } + if (cwd) + { + if (exists(name)) + return name; + } + if (path) + { unsigned i; + + for (i = 0; i < path->dim; i++) + { + char *p = (char *)path->data[i]; + char *n = combine(p, name); + + if (exists(n)) + return n; + } + } + return NULL; +} + +int FileName::exists(const char *name) +{ +#if linux + struct stat st; + + if (stat(name, &st) < 0) + return 0; + if (S_ISDIR(st.st_mode)) + return 2; + return 1; +#endif +#if _WIN32 + DWORD dw; + int result; + + dw = GetFileAttributesA(name); + if (dw == -1L) + result = 0; + else if (dw & FILE_ATTRIBUTE_DIRECTORY) + result = 2; + else + result = 1; + return result; +#endif +} + +void FileName::ensurePathExists(const char *path) +{ + //printf("FileName::ensurePathExists(%s)\n", path ? path : ""); + if (path && *path) + { + if (!exists(path)) + { + char *p = FileName::path(path); + if (*p) + { +#if _WIN32 + size_t len = strlen(p); + if (len > 2 && p[-1] == ':') + { mem.free(p); + return; + } +#endif + ensurePathExists(p); + mem.free(p); + } +#if _WIN32 + if (path[strlen(path) - 1] != '\\') +#endif +#if linux + if (path[strlen(path) - 1] != '\\') +#endif + { + //printf("mkdir(%s)\n", path); +#if _WIN32 + if (mkdir(path)) +#endif +#if linux + if (mkdir(path, 0777)) +#endif + error("cannot create directory %s", path); + } + } + } +} + +/****************************** File ********************************/ + +File::File(FileName *n) +{ + ref = 0; + buffer = NULL; + len = 0; + touchtime = NULL; + name = n; +} + +File::File(char *n) +{ + ref = 0; + buffer = NULL; + len = 0; + touchtime = NULL; + name = new FileName(n, 0); +} + +File::~File() +{ + if (buffer) + { + if (ref == 0) + mem.free(buffer); +#if _WIN32 + else if (ref == 2) + UnmapViewOfFile(buffer); +#endif + } + if (touchtime) + mem.free(touchtime); +} + +void File::mark() +{ + mem.mark(buffer); + mem.mark(touchtime); + mem.mark(name); +} + +/************************************* + */ + +int File::read() +{ +#if linux + off_t size; + ssize_t numread; + int fd; + struct stat buf; + int result = 0; + char *name; + + name = this->name->toChars(); + //printf("File::read('%s')\n",name); + fd = open(name, O_RDONLY); + if (fd == -1) + { result = errno; + //printf("\topen error, errno = %d\n",errno); + goto err1; + } + + if (!ref) + mem.free(buffer); + ref = 0; // we own the buffer now + + //printf("\tfile opened\n"); + if (fstat(fd, &buf)) + { + printf("\tfstat error, errno = %d\n",errno); + goto err2; + } + size = buf.st_size; + buffer = (unsigned char *) mem.malloc(size + 2); + if (!buffer) + { + printf("\tmalloc error, errno = %d\n",errno); + goto err2; + } + + numread = ::read(fd, buffer, size); + if (numread != size) + { + printf("\tread error, errno = %d\n",errno); + goto err2; + } + + if (touchtime) + memcpy(touchtime, &buf, sizeof(buf)); + + if (close(fd) == -1) + { + printf("\tclose error, errno = %d\n",errno); + goto err; + } + + len = size; + + // Always store a wchar ^Z past end of buffer so scanner has a sentinel + buffer[size] = 0; // ^Z is obsolete, use 0 + buffer[size + 1] = 0; + return 0; + +err2: + close(fd); +err: + mem.free(buffer); + buffer = NULL; + len = 0; + +err1: + result = 1; + return result; +#endif +#if _WIN32 + DWORD size; + DWORD numread; + HANDLE h; + int result = 0; + char *name; + + name = this->name->toChars(); + h = CreateFileA(name,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,0); + if (h == INVALID_HANDLE_VALUE) + goto err1; + + if (!ref) + mem.free(buffer); + ref = 0; + + size = GetFileSize(h,NULL); + buffer = (unsigned char *) mem.malloc(size + 2); + if (!buffer) + goto err2; + + if (ReadFile(h,buffer,size,&numread,NULL) != TRUE) + goto err2; + + if (numread != size) + goto err2; + + if (touchtime) + { + if (!GetFileTime(h, NULL, NULL, &((WIN32_FIND_DATAA *)touchtime)->ftLastWriteTime)) + goto err2; + } + + if (!CloseHandle(h)) + goto err; + + len = size; + + // Always store a wchar ^Z past end of buffer so scanner has a sentinel + buffer[size] = 0; // ^Z is obsolete, use 0 + buffer[size + 1] = 0; + return 0; + +err2: + CloseHandle(h); +err: + mem.free(buffer); + buffer = NULL; + len = 0; + +err1: + result = 1; + return result; +#endif +} + +/***************************** + * Read a file with memory mapped file I/O. + */ + +int File::mmread() +{ +#if linux + return read(); +#endif +#if _WIN32 + HANDLE hFile; + HANDLE hFileMap; + DWORD size; + char *name; + + name = this->name->toChars(); + hFile = CreateFile(name, GENERIC_READ, + FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) + goto Lerr; + size = GetFileSize(hFile, NULL); + //printf(" file created, size %d\n", size); + + hFileMap = CreateFileMapping(hFile,NULL,PAGE_READONLY,0,size,NULL); + if (CloseHandle(hFile) != TRUE) + goto Lerr; + + if (hFileMap == NULL) + goto Lerr; + + //printf(" mapping created\n"); + + if (!ref) + mem.free(buffer); + ref = 2; + buffer = (unsigned char *)MapViewOfFileEx(hFileMap, FILE_MAP_READ,0,0,size,NULL); + if (CloseHandle(hFileMap) != TRUE) + goto Lerr; + if (buffer == NULL) // mapping view failed + goto Lerr; + + len = size; + //printf(" buffer = %p\n", buffer); + + return 0; + +Lerr: + return GetLastError(); // failure +#endif +} + +/********************************************* + * Write a file. + * Returns: + * 0 success + */ + +int File::write() +{ +#if linux + int fd; + ssize_t numwritten; + char *name; + + name = this->name->toChars(); + fd = open(name, O_CREAT | O_WRONLY | O_TRUNC, 0660); + if (fd == -1) + goto err; + + numwritten = ::write(fd, buffer, len); + if (len != numwritten) + goto err2; + + if (close(fd) == -1) + goto err; + + if (touchtime) + { struct utimbuf ubuf; + + ubuf.actime = ((struct stat *)touchtime)->st_atime; + ubuf.modtime = ((struct stat *)touchtime)->st_mtime; + if (utime(name, &ubuf)) + goto err; + } + return 0; + +err2: + close(fd); + ::remove(name); +err: + return 1; +#endif +#if _WIN32 + HANDLE h; + DWORD numwritten; + char *name; + + name = this->name->toChars(); + h = CreateFileA(name,GENERIC_WRITE,0,NULL,CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,NULL); + if (h == INVALID_HANDLE_VALUE) + goto err; + + if (WriteFile(h,buffer,len,&numwritten,NULL) != TRUE) + goto err2; + + if (len != numwritten) + goto err2; + + if (touchtime) { + SetFileTime(h, NULL, NULL, &((WIN32_FIND_DATAA *)touchtime)->ftLastWriteTime); + } + if (!CloseHandle(h)) + goto err; + return 0; + +err2: + CloseHandle(h); + DeleteFileA(name); +err: + return 1; +#endif +} + +/********************************************* + * Append to a file. + * Returns: + * 0 success + */ + +int File::append() +{ +#if linux + return 1; +#endif +#if _WIN32 + HANDLE h; + DWORD numwritten; + char *name; + + name = this->name->toChars(); + h = CreateFileA(name,GENERIC_WRITE,0,NULL,OPEN_ALWAYS, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,NULL); + if (h == INVALID_HANDLE_VALUE) + goto err; + +#if 1 + SetFilePointer(h, 0, NULL, FILE_END); +#else // INVALID_SET_FILE_POINTER doesn't seem to have a definition + if (SetFilePointer(h, 0, NULL, FILE_END) == INVALID_SET_FILE_POINTER) + goto err; +#endif + + if (WriteFile(h,buffer,len,&numwritten,NULL) != TRUE) + goto err2; + + if (len != numwritten) + goto err2; + + if (touchtime) { + SetFileTime(h, NULL, NULL, &((WIN32_FIND_DATAA *)touchtime)->ftLastWriteTime); + } + if (!CloseHandle(h)) + goto err; + return 0; + +err2: + CloseHandle(h); +err: + return 1; +#endif +} + +/************************************** + */ + +void File::readv() +{ + if (read()) + error("Error reading file '%s'\n",name->toChars()); +} + +/************************************** + */ + +void File::mmreadv() +{ + if (mmread()) + readv(); +} + +void File::writev() +{ + if (write()) + error("Error writing file '%s'\n",name->toChars()); +} + +void File::appendv() +{ + if (write()) + error("Error appending to file '%s'\n",name->toChars()); +} + +/******************************************* + * Return !=0 if file exists. + * 0: file doesn't exist + * 1: normal file + * 2: directory + */ + +int File::exists() +{ +#if linux + return 0; +#endif +#if _WIN32 + DWORD dw; + int result; + char *name; + + name = this->name->toChars(); + if (touchtime) + dw = ((WIN32_FIND_DATAA *)touchtime)->dwFileAttributes; + else + dw = GetFileAttributesA(name); + if (dw == -1L) + result = 0; + else if (dw & FILE_ATTRIBUTE_DIRECTORY) + result = 2; + else + result = 1; + return result; +#endif +} + +void File::remove() +{ +#if linux + ::remove(this->name->toChars()); +#endif +#if _WIN32 + DeleteFileA(this->name->toChars()); +#endif +} + +Array *File::match(char *n) +{ + return match(new FileName(n, 0)); +} + +Array *File::match(FileName *n) +{ +#if linux + return NULL; +#endif +#if _WIN32 + HANDLE h; + WIN32_FIND_DATAA fileinfo; + Array *a; + char *c; + char *name; + + a = new Array(); + c = n->toChars(); + name = n->name(); + h = FindFirstFileA(c,&fileinfo); + if (h != INVALID_HANDLE_VALUE) + { + do + { + // Glue path together with name + char *fn; + File *f; + + fn = (char *)mem.malloc(name - c + strlen(fileinfo.cFileName) + 1); + memcpy(fn, c, name - c); + strcpy(fn + (name - c), fileinfo.cFileName); + f = new File(fn); + f->touchtime = mem.malloc(sizeof(WIN32_FIND_DATAA)); + memcpy(f->touchtime, &fileinfo, sizeof(fileinfo)); + a->push(f); + } while (FindNextFileA(h,&fileinfo) != FALSE); + FindClose(h); + } + return a; +#endif +} + +int File::compareTime(File *f) +{ +#if linux + return 0; +#endif +#if _WIN32 + if (!touchtime) + stat(); + if (!f->touchtime) + f->stat(); + return CompareFileTime(&((WIN32_FIND_DATAA *)touchtime)->ftLastWriteTime, &((WIN32_FIND_DATAA *)f->touchtime)->ftLastWriteTime); +#endif +} + +void File::stat() +{ +#if linux + if (!touchtime) + { + touchtime = mem.calloc(1, sizeof(struct stat)); + } +#endif +#if _WIN32 + HANDLE h; + + if (!touchtime) + { + touchtime = mem.calloc(1, sizeof(WIN32_FIND_DATAA)); + } + h = FindFirstFileA(name->toChars(),(WIN32_FIND_DATAA *)touchtime); + if (h != INVALID_HANDLE_VALUE) + { + FindClose(h); + } +#endif +} + +void File::checkoffset(size_t offset, size_t nbytes) +{ + if (offset > len || offset + nbytes > len) + error("Corrupt file '%s': offset x%zx off end of file",toChars(),offset); +} + +char *File::toChars() +{ + return name->toChars(); +} + + +/************************* OutBuffer *************************/ + +OutBuffer::OutBuffer() +{ + data = NULL; + offset = 0; + size = 0; +} + +OutBuffer::~OutBuffer() +{ + mem.free(data); +} + +void *OutBuffer::extractData() +{ + void *p; + + p = (void *)data; + data = NULL; + offset = 0; + size = 0; + return p; +} + +void OutBuffer::mark() +{ + mem.mark(data); +} + +void OutBuffer::reserve(unsigned nbytes) +{ + //printf("OutBuffer::reserve: size = %d, offset = %d, nbytes = %d\n", size, offset, nbytes); + if (size - offset < nbytes) + { + size = (offset + nbytes) * 2; + data = (unsigned char *)mem.realloc(data, size); + } +} + +void OutBuffer::reset() +{ + offset = 0; +} + +void OutBuffer::setsize(unsigned size) +{ + offset = size; +} + +void OutBuffer::write(const void *data, unsigned nbytes) +{ + reserve(nbytes); + memcpy(this->data + offset, data, nbytes); + offset += nbytes; +} + +void OutBuffer::writebstring(unsigned char *string) +{ + write(string,*string + 1); +} + +void OutBuffer::writestring(char *string) +{ + write(string,strlen(string)); +} + +void OutBuffer::writedstring(const char *string) +{ +#if M_UNICODE + for (; *string; string++) + { + writedchar(*string); + } +#else + write(string,strlen(string)); +#endif +} + +void OutBuffer::writedstring(const wchar_t *string) +{ +#if M_UNICODE + write(string,wcslen(string) * sizeof(wchar_t)); +#else + for (; *string; string++) + { + writedchar(*string); + } +#endif +} + +void OutBuffer::prependstring(char *string) +{ unsigned len; + + len = strlen(string); + reserve(len); + memmove(data + len, data, offset); + memcpy(data, string, len); + offset += len; +} + +void OutBuffer::writenl() +{ +#if _WIN32 +#if M_UNICODE + write4(0x000A000D); // newline is CR,LF on Microsoft OS's +#else + writeword(0x0A0D); // newline is CR,LF on Microsoft OS's +#endif +#else +#if M_UNICODE + writeword('\n'); +#else + writeByte('\n'); +#endif +#endif +} + +void OutBuffer::writeByte(unsigned b) +{ + reserve(1); + this->data[offset] = (unsigned char)b; + offset++; +} + +void OutBuffer::writeUTF8(unsigned b) +{ + reserve(6); + if (b <= 0x7F) + { + this->data[offset] = (unsigned char)b; + offset++; + } + else if (b <= 0x7FF) + { + this->data[offset + 0] = (unsigned char)((b >> 6) | 0xC0); + this->data[offset + 1] = (unsigned char)((b & 0x3F) | 0x80); + offset += 2; + } + else if (b <= 0xFFFF) + { + this->data[offset + 0] = (unsigned char)((b >> 12) | 0xE0); + this->data[offset + 1] = (unsigned char)(((b >> 6) & 0x3F) | 0x80); + this->data[offset + 2] = (unsigned char)((b & 0x3F) | 0x80); + offset += 3; + } + else if (b <= 0x1FFFFF) + { + this->data[offset + 0] = (unsigned char)((b >> 18) | 0xF0); + this->data[offset + 1] = (unsigned char)(((b >> 12) & 0x3F) | 0x80); + this->data[offset + 2] = (unsigned char)(((b >> 6) & 0x3F) | 0x80); + this->data[offset + 3] = (unsigned char)((b & 0x3F) | 0x80); + offset += 4; + } + else if (b <= 0x3FFFFFF) + { + this->data[offset + 0] = (unsigned char)((b >> 24) | 0xF8); + this->data[offset + 1] = (unsigned char)(((b >> 18) & 0x3F) | 0x80); + this->data[offset + 2] = (unsigned char)(((b >> 12) & 0x3F) | 0x80); + this->data[offset + 3] = (unsigned char)(((b >> 6) & 0x3F) | 0x80); + this->data[offset + 4] = (unsigned char)((b & 0x3F) | 0x80); + offset += 5; + } + else if (b <= 0x7FFFFFFF) + { + this->data[offset + 0] = (unsigned char)((b >> 30) | 0xFC); + this->data[offset + 1] = (unsigned char)(((b >> 24) & 0x3F) | 0x80); + this->data[offset + 2] = (unsigned char)(((b >> 18) & 0x3F) | 0x80); + this->data[offset + 3] = (unsigned char)(((b >> 12) & 0x3F) | 0x80); + this->data[offset + 4] = (unsigned char)(((b >> 6) & 0x3F) | 0x80); + this->data[offset + 5] = (unsigned char)((b & 0x3F) | 0x80); + offset += 6; + } + else + assert(0); +} + +void OutBuffer::writedchar(unsigned b) +{ + reserve(Dchar_mbmax * sizeof(dchar)); + offset = (unsigned char *)Dchar::put((dchar *)(this->data + offset), (dchar)b) - + this->data; +} + +void OutBuffer::prependbyte(unsigned b) +{ + reserve(1); + memmove(data + 1, data, offset); + data[0] = (unsigned char)b; + offset++; +} + +void OutBuffer::writeword(unsigned w) +{ + reserve(2); + *(unsigned short *)(this->data + offset) = (unsigned short)w; + offset += 2; +} + +void OutBuffer::writeUTF16(unsigned w) +{ + reserve(4); + if (w <= 0xFFFF) + { + *(unsigned short *)(this->data + offset) = (unsigned short)w; + offset += 2; + } + else if (w <= 0x10FFFF) + { + *(unsigned short *)(this->data + offset) = (unsigned short)((w >> 10) + 0xD7C0); + *(unsigned short *)(this->data + offset + 2) = (unsigned short)((w & 0x3FF) | 0xDC00); + offset += 4; + } + else + assert(0); +} + +void OutBuffer::write4(unsigned w) +{ + reserve(4); + *(unsigned long *)(this->data + offset) = w; + offset += 4; +} + +void OutBuffer::write(OutBuffer *buf) +{ + if (buf) + { reserve(buf->offset); + memcpy(data + offset, buf->data, buf->offset); + offset += buf->offset; + } +} + +void OutBuffer::write(Object *obj) +{ + if (obj) + { + writestring(obj->toChars()); + } +} + +void OutBuffer::fill0(unsigned nbytes) +{ + reserve(nbytes); + memset(data + offset,0,nbytes); + offset += nbytes; +} + +void OutBuffer::align(unsigned size) +{ unsigned nbytes; + + nbytes = ((offset + size - 1) & ~(size - 1)) - offset; + fill0(nbytes); +} + +void OutBuffer::vprintf(const char *format, va_list args) +{ + char buffer[128]; + char *p; + unsigned psize; + int count; + + p = buffer; + psize = sizeof(buffer); + for (;;) + { +#if _WIN32 + count = _vsnprintf(p,psize,format,args); + if (count != -1) + break; + psize *= 2; +#endif +#if linux + count = vsnprintf(p,psize,format,args); + if (count == -1) + psize *= 2; + else if (count >= psize) + psize = count + 1; + else + break; +#endif + p = (char *) alloca(psize); // buffer too small, try again with larger size + } + write(p,count); +} + +#if M_UNICODE +void OutBuffer::vprintf(const wchar_t *format, va_list args) +{ + dchar buffer[128]; + dchar *p; + unsigned psize; + int count; + + p = buffer; + psize = sizeof(buffer) / sizeof(buffer[0]); + for (;;) + { +#if _WIN32 + count = _vsnwprintf(p,psize,format,args); + if (count != -1) + break; + psize *= 2; +#endif +#if linux + count = vsnwprintf(p,psize,format,args); + if (count == -1) + psize *= 2; + else if (count >= psize) + psize = count + 1; + else + break; +#endif + p = (dchar *) alloca(psize * 2); // buffer too small, try again with larger size + } + write(p,count * 2); +} +#endif + +void OutBuffer::printf(const char *format, ...) +{ + va_list ap; + va_start(ap, format); + vprintf(format,ap); + va_end(ap); +} + +#if M_UNICODE +void OutBuffer::printf(const wchar_t *format, ...) +{ + va_list ap; + va_start(ap, format); + vprintf(format,ap); + va_end(ap); +} +#endif + +void OutBuffer::bracket(char left, char right) +{ + reserve(2); + memmove(data + 1, data, offset); + data[0] = left; + data[offset + 1] = right; + offset += 2; +} + +/****************** + * Insert left at i, and right at j. + * Return index just past right. + */ + +unsigned OutBuffer::bracket(unsigned i, char *left, unsigned j, char *right) +{ + size_t leftlen = strlen(left); + size_t rightlen = strlen(right); + reserve(leftlen + rightlen); + insert(i, left, leftlen); + insert(j + leftlen, right, rightlen); + return j + leftlen + rightlen; +} + +void OutBuffer::spread(unsigned offset, unsigned nbytes) +{ + reserve(nbytes); + memmove(data + offset + nbytes, data + offset, + this->offset - offset); + this->offset += nbytes; +} + +/**************************************** + * Returns: offset + nbytes + */ + +unsigned OutBuffer::insert(unsigned offset, const void *p, unsigned nbytes) +{ + spread(offset, nbytes); + memmove(data + offset, p, nbytes); + return offset + nbytes; +} + +void OutBuffer::remove(unsigned offset, unsigned nbytes) +{ + memmove(data + offset, data + offset + nbytes, this->offset - (offset + nbytes)); + this->offset -= nbytes; +} + +char *OutBuffer::toChars() +{ + writeByte(0); + return (char *)data; +} + +/********************************* Bits ****************************/ + +Bits::Bits() +{ + data = NULL; + bitdim = 0; + allocdim = 0; +} + +Bits::~Bits() +{ + mem.free(data); +} + +void Bits::mark() +{ + mem.mark(data); +} + +void Bits::resize(unsigned bitdim) +{ + unsigned allocdim; + unsigned mask; + + allocdim = (bitdim + 31) / 32; + data = (unsigned *)mem.realloc(data, allocdim * sizeof(data[0])); + if (this->allocdim < allocdim) + memset(data + this->allocdim, 0, (allocdim - this->allocdim) * sizeof(data[0])); + + // Clear other bits in last word + mask = (1 << (bitdim & 31)) - 1; + if (mask) + data[allocdim - 1] &= ~mask; + + this->bitdim = bitdim; + this->allocdim = allocdim; +} + +void Bits::set(unsigned bitnum) +{ + data[bitnum / 32] |= 1 << (bitnum & 31); +} + +void Bits::clear(unsigned bitnum) +{ + data[bitnum / 32] &= ~(1 << (bitnum & 31)); +} + +int Bits::test(unsigned bitnum) +{ + return data[bitnum / 32] & (1 << (bitnum & 31)); +} + +void Bits::set() +{ unsigned mask; + + memset(data, ~0, allocdim * sizeof(data[0])); + + // Clear other bits in last word + mask = (1 << (bitdim & 31)) - 1; + if (mask) + data[allocdim - 1] &= mask; +} + +void Bits::clear() +{ + memset(data, 0, allocdim * sizeof(data[0])); +} + +void Bits::copy(Bits *from) +{ + assert(bitdim == from->bitdim); + memcpy(data, from->data, allocdim * sizeof(data[0])); +} + +Bits *Bits::clone() +{ + Bits *b; + + b = new Bits(); + b->resize(bitdim); + b->copy(this); + return b; +} + +void Bits::sub(Bits *b) +{ + unsigned u; + + for (u = 0; u < allocdim; u++) + data[u] &= ~b->data[u]; +} + + + + + + + + + + + + + + +