diff 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
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/root/root.c	Fri Apr 03 17:02:52 2009 +0200
@@ -0,0 +1,1916 @@
+
+// Copyright (c) 1999-2009 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 (defined (__SVR4) && defined (__sun))
+#include <alloca.h>
+#endif
+
+#if _MSC_VER ||__MINGW32__
+#include <malloc.h>
+#include <string>
+#endif
+
+#if _WIN32
+#include <windows.h>
+#include <direct.h>
+#endif
+
+#if POSIX
+#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 "rmem.h"
+#include "mars.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 (char *)"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(const char *path, const char *name)
+{   char *f;
+    size_t pathlen;
+    size_t namelen;
+
+    if (!path || !*path)
+	return (char *)name;
+    pathlen = strlen(path);
+    namelen = strlen(name);
+    f = (char *)mem.malloc(pathlen + 1 + namelen + 1);
+    memcpy(f, path, pathlen);
+
+    if (
+	path[pathlen - 1] != '/'
+#if _WIN32
+	&& path[pathlen - 1] != '\\' && path[pathlen - 1] != ':'
+#endif
+    )
+    {	f[pathlen] = '/';
+	pathlen++;
+    }
+
+    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
+            // LDC remember first character
+            const char* start = p;
+	    for (; ; p++)
+	    {
+		c = *p;
+		switch (c)
+		{
+		    case '"':
+			instring ^= 1;	// toggle inside/outside of string
+			continue;
+
+#if MACINTOSH
+		    case ',':
+#endif
+#if _WIN32
+		    case ';':
+#endif
+#if POSIX
+		    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 POSIX
+		    case '~':
+                        // LDC don't expand unless first character of path
+                        if (p != start)
+                            goto Ldefault;
+			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:
+                    Ldefault:
+			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)
+{
+    return
+#if _WIN32
+	(*name == '\\') ||
+	(*name == '/')  ||
+	(*name && name[1] == ':') ||
+#endif
+	(*name == '/');
+}
+
+/********************************
+ * Return filename extension (read-only).
+ * Points past '.' of extension.
+ * 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;
+
+	    case '/':
+	        break;
+
+#if _WIN32
+	    case '\\':
+	    case ':':
+		break;
+#endif
+	    default:
+		if (e == str)
+		    break;
+		e--;
+		continue;
+	}
+	return NULL;
+    }
+}
+
+char *FileName::ext()
+{
+    return ext(str);
+}
+
+/********************************
+ * Return mem.malloc'd filename with extension removed.
+ */
+
+char *FileName::removeExt(const char *str)
+{
+    const char *e = ext(str);
+    if (e)
+    {	size_t len = (e - str) - 1;
+	char *n = (char *)mem.malloc(len + 1);
+	memcpy(n, str, len);
+	n[len] = 0;
+	return n;
+    }
+    return mem.strdup(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)
+	{
+
+	    case '/':
+	       return e + 1;
+
+#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 (n[-1] == '/')
+	    n--;
+
+#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  (
+	path[pathlen - 1] != '/'
+#if _WIN32
+	&& path[pathlen - 1] != '\\' && path[pathlen - 1] != ':'
+#endif
+	)
+    {	f[pathlen] = '/';
+	pathlen++;
+    }
+
+    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 POSIX
+    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 POSIX
+    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, const char *name, int cwd)
+{
+    if (absolute(name))
+    {
+	return exists(name) ? (char *)name : NULL;
+    }
+    if (cwd)
+    {
+	if (exists(name))
+	    return (char *)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 POSIX
+    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 POSIX
+	    if (path[strlen(path) - 1] != '\\')
+#endif
+	    {
+		//printf("mkdir(%s)\n", path);
+#if _WIN32
+		if (mkdir(path))
+#endif
+#if POSIX
+		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 POSIX
+    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 POSIX
+    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 POSIX
+    int fd;
+    ssize_t numwritten;
+    char *name;
+
+    name = this->name->toChars();
+    fd = open(name, O_CREAT | O_WRONLY | O_TRUNC, 0644);
+    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 POSIX
+    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 POSIX
+    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 POSIX
+    ::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 POSIX
+    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 POSIX
+    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 POSIX
+    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)
+    {
+#if defined (__x86_64__)
+	size = (offset + nbytes) * 2 + 2;
+#else
+	size = (offset + nbytes) * 2;
+#endif
+	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(const 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(const 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);
+}
+
+
+////////////////////////////////////////////////////////////////
+// The compiler shipped with Visual Studio 2005 (and possible
+// other versions) does not support C99 printf format specfiers
+// such as %z and %j
+#if _MSC_VER
+using std::string;
+using std::wstring;
+
+template<typename S>
+inline void 
+search_and_replace(S& str, const S& what, const S& replacement)
+{
+    assert(!what.empty());
+    size_t pos = str.find(what);
+    while (pos != S::npos) 
+    {
+        str.replace(pos, what.size(), replacement);
+        pos = str.find(what, pos + replacement.size());
+    }
+}
+#define WORKAROUND_C99_SPECIFIERS_BUG(S,tmp,f) \
+    S tmp = f;                                 \
+    search_and_replace(fmt, S("%z"), S("%l")); \
+    search_and_replace(fmt, S("%j"), S("%i")); \
+    f = tmp.c_str();
+#else
+#define WORKAROUND_C99_SPECIFIERS_BUG(S,tmp,f)
+#endif
+
+void OutBuffer::vprintf(const char *format, va_list args)
+{
+    char buffer[128];
+    char *p;
+    unsigned psize;
+    int count;
+
+    WORKAROUND_C99_SPECIFIERS_BUG(string, fmt, format);
+
+    p = buffer;
+    psize = sizeof(buffer);
+    for (;;)
+    {
+#if _WIN32
+	count = _vsnprintf(p,psize,format,args);
+	if (count != -1)
+	    break;
+	psize *= 2;
+#elif POSIX
+        va_list va;
+        va_copy(va, args);
+/*
+  The functions vprintf(), vfprintf(), vsprintf(), vsnprintf()
+  are equivalent to the functions printf(), fprintf(), sprintf(),
+  snprintf(), respectively, except that they are called with a
+  va_list instead of a variable number of arguments. These
+  functions do not call the va_end macro. Consequently, the value
+  of ap is undefined after the call. The application should call
+  va_end(ap) itself afterwards.
+ */
+	count = vsnprintf(p,psize,format,va);
+        va_end(va);
+	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;
+
+    WORKAROUND_C99_SPECIFIERS_BUG(wstring, fmt, format);
+
+    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 POSIX
+        va_list va;
+        va_copy(va, args);
+	count = vsnwprintf(p,psize,format,va);
+        va_end(va); 
+
+	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, const char *left, unsigned j, const 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];
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+