Mercurial > projects > ldc
view dmd2/root/root.c @ 1455:89e38fbfef1f
Automated merge with http://hg.dsource.org/projects/ldc
author | Robert Clipsham <robert@octarineparrot.com> |
---|---|
date | Mon, 01 Jun 2009 19:02:20 +0100 |
parents | 638d16625da2 |
children | a1666b613c15 |
line wrap: on
line source
// 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. #define POSIX (linux || __APPLE__ || __FreeBSD__ || __sun&&__SVR4) #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" #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 POSIX if (path[pathlen - 1] != '/') { f[pathlen] = '/'; pathlen++; } #elif _WIN32 if (path[pathlen - 1] != '\\' && path[pathlen - 1] != '/' && path[pathlen - 1] != ':') { f[pathlen] = '\\'; pathlen++; } #else assert(0); #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 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) { return compare(str, ((FileName *)obj)->str); } int FileName::compare(const char *name1, const char *name2) { #if _WIN32 return stricmp(name1, name2); #else return strcmp(name1, name2); #endif } int FileName::equals(Object *obj) { return compare(obj) == 0; } int FileName::equals(const char *name1, const char *name2) { return compare(name1, name2) == 0; } /************************************ * Return !=0 if absolute path name. */ int FileName::absolute(const char *name) { #if _WIN32 return (*name == '\\') || (*name == '/') || (*name && name[1] == ':'); #elif POSIX return (*name == '/'); #else assert(0); #endif } /******************************** * 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; #if POSIX case '/': break; #endif #if _WIN32 case '\\': 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) { #if POSIX case '/': return e + 1; #endif #if _WIN32 case '/': case '\\': return e + 1; case ':': /* The ':' is a drive letter only if it is the second * character or the last character, * otherwise it is an ADS (Alternate Data Stream) separator. * Consider ADS separators as part of the file name. */ if (e == str + 1 || e == str + len - 1) 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 POSIX if (n[-1] == '/') n--; #elif _WIN32 if (n[-1] == '\\' || n[-1] == '/') n--; #else assert(0); #endif } pathlen = n - str; path = (char *)mem.malloc(pathlen + 1); memcpy(path, str, pathlen); path[pathlen] = 0; return path; } /************************************** * Replace filename portion of path. */ const char *FileName::replaceName(const char *path, const 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 POSIX if (path[pathlen - 1] != '/') { f[pathlen] = '/'; pathlen++; } #elif _WIN32 if (path[pathlen - 1] != '\\' && path[pathlen - 1] != '/' && path[pathlen - 1] != ':') { f[pathlen] = '\\'; pathlen++; } #else assert(0); #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 POSIX return strcmp(e,ext) == 0; #elif _WIN32 return stricmp(e,ext) == 0; #else assert(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 #elif POSIX file.touchtime = mem.malloc(sizeof(struct stat)); // keep same file time #else assert(0); #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; #elif _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; #else assert(0); #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(path); if (len > 2 && p[-1] == ':' && path + 2 == p) { 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; #elif _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; #else assert(0); #endif } /***************************** * Read a file with memory mapped file I/O. */ int File::mmread() { #if POSIX return read(); #elif _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 #else assert(0); #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; #elif _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; #else assert(0); #endif } /********************************************* * Append to a file. * Returns: * 0 success */ int File::append() { #if POSIX return 1; #elif _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; #else assert(0); #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; #elif _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; #else assert(0); #endif } void File::remove() { #if POSIX ::remove(this->name->toChars()); #elif _WIN32 DeleteFileA(this->name->toChars()); #else assert(0); #endif } Array *File::match(char *n) { return match(new FileName(n, 0)); } Array *File::match(FileName *n) { #if POSIX return NULL; #elif _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; #else assert(0); #endif } int File::compareTime(File *f) { #if POSIX return 0; #elif _WIN32 if (!touchtime) stat(); if (!f->touchtime) f->stat(); return CompareFileTime(&((WIN32_FIND_DATAA *)touchtime)->ftLastWriteTime, &((WIN32_FIND_DATAA *)f->touchtime)->ftLastWriteTime); #else assert(0); #endif } void File::stat() { #if POSIX if (!touchtime) { touchtime = mem.calloc(1, sizeof(struct stat)); } #elif _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); } #else assert(0); #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(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; #else assert(0); #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; #elif 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; #else assert(0); #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]; }