ldc/dmd2/root.c
Tomas Lindquist Olsen b7bea99dbb Merged DMD 2.021 frontend.
Removed generated files from dmd/dmd2 dirs.
2008-12-13 16:14:37 +01:00

1903 lines
34 KiB
C

// 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 ||__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 "mem.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
for (; ; p++)
{
c = *p;
switch (c)
{
case '"':
instring ^= 1; // toggle inside/outside of string
continue;
#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 '~':
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)
{
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%"PRIxSIZE" 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];
}