/* Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) * https://github.com/D-Programming-Language/dmd/blob/master/src/root/outbuffer.c */ #include "dsystem.h" #include "outbuffer.h" #include "object.h" char *OutBuffer::extractData() { char *p; p = (char *)data; data = NULL; offset = 0; size = 0; return p; } void OutBuffer::reserve(size_t nbytes) { //printf("OutBuffer::reserve: size = %d, offset = %d, nbytes = %d\n", size, offset, nbytes); if (size - offset < nbytes) { size = (offset + nbytes) * 2; size = (size + 15) & ~15; data = (unsigned char *)mem.xrealloc(data, size); } } void OutBuffer::reset() { offset = 0; } void OutBuffer::setsize(size_t size) { offset = size; } void OutBuffer::write(const void *data, size_t nbytes) { if (doindent && !notlinehead) { if (level) { reserve(level); for (int i = 0; i < level; i++) { this->data[offset] = '\t'; offset++; } } notlinehead = 1; } reserve(nbytes); memcpy(this->data + offset, data, nbytes); offset += nbytes; } void OutBuffer::writebstring(utf8_t *string) { write(string,*string + 1); } void OutBuffer::writestring(const char *string) { write(string,strlen(string)); } void OutBuffer::prependstring(const char *string) { size_t len = strlen(string); reserve(len); memmove(data + len, data, offset); memcpy(data, string, len); offset += len; } void OutBuffer::writenl() { #if _WIN32 writeword(0x0A0D); // newline is CR,LF on Microsoft OS's #else writeByte('\n'); #endif if (doindent) notlinehead = 0; } void OutBuffer::writeByte(unsigned b) { if (doindent && !notlinehead && b != '\n') { if (level) { reserve(level); for (int i = 0; i < level; i++) { this->data[offset] = '\t'; offset++; } } notlinehead = 1; } 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::prependbyte(unsigned b) { reserve(1); memmove(data + 1, data, offset); data[0] = (unsigned char)b; offset++; } void OutBuffer::writewchar(unsigned w) { #if _WIN32 writeword(w); #else write4(w); #endif } void OutBuffer::writeword(unsigned w) { #if _WIN32 unsigned newline = 0x0A0D; #else unsigned newline = '\n'; #endif if (doindent && !notlinehead && w != newline) { if (level) { reserve(level); for (int i = 0; i < level; i++) { this->data[offset] = '\t'; offset++; } } notlinehead = 1; } 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) { #if _WIN32 bool notnewline = w != 0x000A000D; #else bool notnewline = true; #endif if (doindent && !notlinehead && notnewline) { if (level) { reserve(level); for (int i = 0; i < level; i++) { this->data[offset] = '\t'; offset++; } } notlinehead = 1; } reserve(4); *(unsigned *)(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(RootObject *obj) { if (obj) { writestring(obj->toChars()); } } void OutBuffer::fill0(size_t nbytes) { reserve(nbytes); memset(data + offset,0,nbytes); offset += nbytes; } void OutBuffer::vprintf(const char *format, va_list args) { int count; if (doindent) write(NULL, 0); // perform indent int psize = 128; for (;;) { reserve(psize); #if _WIN32 count = _vsnprintf((char *)data + offset,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((char *)data + offset,psize,format,va); va_end(va); if (count == -1) psize *= 2; else if (count >= psize) psize = count + 1; else break; #else assert(0); #endif } offset += count; } void OutBuffer::printf(const char *format, ...) { va_list ap; va_start(ap, format); vprintf(format,ap); va_end(ap); } /************************************** * Convert `u` to a string and append it to the buffer. * Params: * u = integral value to append */ void OutBuffer::print(unsigned long long u) { unsigned long long value = u; char buf[20]; const unsigned radix = 10; size_t i = sizeof(buf); do { if (value < radix) { unsigned char x = (unsigned char)value; buf[--i] = (char)(x + '0'); break; } else { unsigned char x = (unsigned char)(value % radix); value = value / radix; buf[--i] = (char)(x + '0'); } } while (value); write(buf + i, sizeof(buf) - i); } 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. */ size_t OutBuffer::bracket(size_t i, const char *left, size_t 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(size_t offset, size_t nbytes) { reserve(nbytes); memmove(data + offset + nbytes, data + offset, this->offset - offset); this->offset += nbytes; } /**************************************** * Returns: offset + nbytes */ size_t OutBuffer::insert(size_t offset, const void *p, size_t nbytes) { spread(offset, nbytes); memmove(data + offset, p, nbytes); return offset + nbytes; } void OutBuffer::remove(size_t offset, size_t nbytes) { memmove(data + offset, data + offset + nbytes, this->offset - (offset + nbytes)); this->offset -= nbytes; } char *OutBuffer::peekString() { if (!offset || data[offset-1] != '\0') { writeByte(0); offset--; // allow appending more } return (char *)data; } char *OutBuffer::extractString() { if (!offset || data[offset-1] != '\0') writeByte(0); return extractData(); }