1 /** 2 * Compiler implementation of the D programming language 3 * http://dlang.org 4 * 5 * Copyright: Copyright (c) 1999-2016 by Digital Mars, All Rights Reserved 6 * Authors: Walter Bright, http://www.digitalmars.com 7 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 8 * Source: $(DMDSRC root/_outbuffer.d) 9 */ 10 11 module ddmd.root.outbuffer; 12 13 import core.stdc.stdarg; 14 import core.stdc.stdio; 15 import core.stdc..string; 16 import ddmd.root.rmem; 17 import ddmd.root.rootobject; 18 19 struct OutBuffer 20 { 21 ubyte* data; 22 size_t offset; 23 size_t size; 24 int level; 25 bool doindent; 26 private bool notlinehead; 27 28 extern (C++) ~this() nothrow 29 { 30 mem.xfree(data); 31 } 32 33 extern (C++) char* extractData() nothrow 34 { 35 char* p; 36 p = cast(char*)data; 37 data = null; 38 offset = 0; 39 size = 0; 40 return p; 41 } 42 43 extern (C++) void reserve(size_t nbytes) nothrow 44 { 45 //printf("OutBuffer::reserve: size = %d, offset = %d, nbytes = %d\n", size, offset, nbytes); 46 if (size - offset < nbytes) 47 { 48 size = (offset + nbytes) * 2; 49 size = (size + 15) & ~15; 50 data = cast(ubyte*)mem.xrealloc(data, size); 51 } 52 } 53 54 extern (C++) void setsize(size_t size) nothrow 55 { 56 offset = size; 57 } 58 59 extern (C++) void reset() nothrow 60 { 61 offset = 0; 62 } 63 64 private void indent() nothrow 65 { 66 if (level) 67 { 68 reserve(level); 69 data[offset .. offset + level] = '\t'; 70 offset += level; 71 } 72 notlinehead = true; 73 } 74 75 extern (C++) void write(const(void)* data, size_t nbytes) nothrow 76 { 77 if (doindent && !notlinehead) 78 indent(); 79 reserve(nbytes); 80 memcpy(this.data + offset, data, nbytes); 81 offset += nbytes; 82 } 83 84 extern (C++) void writebstring(char* string) nothrow 85 { 86 write(string, *string + 1); 87 } 88 89 extern (C++) void writestring(const(char)* string) nothrow 90 { 91 write(string, strlen(string)); 92 } 93 94 void writestring(const(char)[] s) nothrow 95 { 96 write(s.ptr, s.length); 97 } 98 99 void writestring(string s) nothrow 100 { 101 write(s.ptr, s.length); 102 } 103 104 extern (C++) void prependstring(const(char)* string) nothrow 105 { 106 size_t len = strlen(string); 107 reserve(len); 108 memmove(data + len, data, offset); 109 memcpy(data, string, len); 110 offset += len; 111 } 112 113 // write newline 114 extern (C++) void writenl() nothrow 115 { 116 version (Windows) 117 { 118 writeword(0x0A0D); // newline is CR,LF on Microsoft OS's 119 } 120 else 121 { 122 writeByte('\n'); 123 } 124 if (doindent) 125 notlinehead = false; 126 } 127 128 extern (C++) void writeByte(uint b) nothrow 129 { 130 if (doindent && !notlinehead && b != '\n') 131 indent(); 132 reserve(1); 133 this.data[offset] = cast(ubyte)b; 134 offset++; 135 } 136 137 extern (C++) void writeUTF8(uint b) nothrow 138 { 139 reserve(6); 140 if (b <= 0x7F) 141 { 142 this.data[offset] = cast(ubyte)b; 143 offset++; 144 } 145 else if (b <= 0x7FF) 146 { 147 this.data[offset + 0] = cast(ubyte)((b >> 6) | 0xC0); 148 this.data[offset + 1] = cast(ubyte)((b & 0x3F) | 0x80); 149 offset += 2; 150 } 151 else if (b <= 0xFFFF) 152 { 153 this.data[offset + 0] = cast(ubyte)((b >> 12) | 0xE0); 154 this.data[offset + 1] = cast(ubyte)(((b >> 6) & 0x3F) | 0x80); 155 this.data[offset + 2] = cast(ubyte)((b & 0x3F) | 0x80); 156 offset += 3; 157 } 158 else if (b <= 0x1FFFFF) 159 { 160 this.data[offset + 0] = cast(ubyte)((b >> 18) | 0xF0); 161 this.data[offset + 1] = cast(ubyte)(((b >> 12) & 0x3F) | 0x80); 162 this.data[offset + 2] = cast(ubyte)(((b >> 6) & 0x3F) | 0x80); 163 this.data[offset + 3] = cast(ubyte)((b & 0x3F) | 0x80); 164 offset += 4; 165 } 166 else if (b <= 0x3FFFFFF) 167 { 168 this.data[offset + 0] = cast(ubyte)((b >> 24) | 0xF8); 169 this.data[offset + 1] = cast(ubyte)(((b >> 18) & 0x3F) | 0x80); 170 this.data[offset + 2] = cast(ubyte)(((b >> 12) & 0x3F) | 0x80); 171 this.data[offset + 3] = cast(ubyte)(((b >> 6) & 0x3F) | 0x80); 172 this.data[offset + 4] = cast(ubyte)((b & 0x3F) | 0x80); 173 offset += 5; 174 } 175 else if (b <= 0x7FFFFFFF) 176 { 177 this.data[offset + 0] = cast(ubyte)((b >> 30) | 0xFC); 178 this.data[offset + 1] = cast(ubyte)(((b >> 24) & 0x3F) | 0x80); 179 this.data[offset + 2] = cast(ubyte)(((b >> 18) & 0x3F) | 0x80); 180 this.data[offset + 3] = cast(ubyte)(((b >> 12) & 0x3F) | 0x80); 181 this.data[offset + 4] = cast(ubyte)(((b >> 6) & 0x3F) | 0x80); 182 this.data[offset + 5] = cast(ubyte)((b & 0x3F) | 0x80); 183 offset += 6; 184 } 185 else 186 assert(0); 187 } 188 189 extern (C++) void prependbyte(uint b) nothrow 190 { 191 reserve(1); 192 memmove(data + 1, data, offset); 193 data[0] = cast(ubyte)b; 194 offset++; 195 } 196 197 extern (C++) void writewchar(uint w) nothrow 198 { 199 version (Windows) 200 { 201 writeword(w); 202 } 203 else 204 { 205 write4(w); 206 } 207 } 208 209 extern (C++) void writeword(uint w) nothrow 210 { 211 version (Windows) 212 { 213 uint newline = 0x0A0D; 214 } 215 else 216 { 217 uint newline = '\n'; 218 } 219 if (doindent && !notlinehead && w != newline) 220 indent(); 221 222 reserve(2); 223 *cast(ushort*)(this.data + offset) = cast(ushort)w; 224 offset += 2; 225 } 226 227 extern (C++) void writeUTF16(uint w) nothrow 228 { 229 reserve(4); 230 if (w <= 0xFFFF) 231 { 232 *cast(ushort*)(this.data + offset) = cast(ushort)w; 233 offset += 2; 234 } 235 else if (w <= 0x10FFFF) 236 { 237 *cast(ushort*)(this.data + offset) = cast(ushort)((w >> 10) + 0xD7C0); 238 *cast(ushort*)(this.data + offset + 2) = cast(ushort)((w & 0x3FF) | 0xDC00); 239 offset += 4; 240 } 241 else 242 assert(0); 243 } 244 245 extern (C++) void write4(uint w) nothrow 246 { 247 version (Windows) 248 { 249 bool notnewline = w != 0x000A000D; 250 } 251 else 252 { 253 bool notnewline = true; 254 } 255 if (doindent && !notlinehead && notnewline) 256 indent(); 257 reserve(4); 258 *cast(uint*)(this.data + offset) = w; 259 offset += 4; 260 } 261 262 extern (C++) void write(const OutBuffer* buf) nothrow 263 { 264 if (buf) 265 { 266 reserve(buf.offset); 267 memcpy(data + offset, buf.data, buf.offset); 268 offset += buf.offset; 269 } 270 } 271 272 extern (C++) void write(RootObject obj) /*nothrow*/ 273 { 274 if (obj) 275 { 276 writestring(obj.toChars()); 277 } 278 } 279 280 extern (C++) void fill0(size_t nbytes) nothrow 281 { 282 reserve(nbytes); 283 memset(data + offset, 0, nbytes); 284 offset += nbytes; 285 } 286 287 extern (C++) void vprintf(const(char)* format, va_list args) /*nothrow*/ 288 { 289 int count; 290 if (doindent) 291 write(null, 0); // perform indent 292 uint psize = 128; 293 for (;;) 294 { 295 reserve(psize); 296 version (Windows) 297 { 298 count = _vsnprintf(cast(char*)data + offset, psize, format, args); 299 if (count != -1) 300 break; 301 psize *= 2; 302 } 303 else version (Posix) 304 { 305 va_list va; 306 va_copy(va, args); 307 /* 308 The functions vprintf(), vfprintf(), vsprintf(), vsnprintf() 309 are equivalent to the functions printf(), fprintf(), sprintf(), 310 snprintf(), respectively, except that they are called with a 311 va_list instead of a variable number of arguments. These 312 functions do not call the va_end macro. Consequently, the value 313 of ap is undefined after the call. The application should call 314 va_end(ap) itself afterwards. 315 */ 316 count = vsnprintf(cast(char*)data + offset, psize, format, va); 317 va_end(va); 318 if (count == -1) 319 psize *= 2; 320 else if (count >= psize) 321 psize = count + 1; 322 else 323 break; 324 } 325 else 326 { 327 assert(0); 328 } 329 } 330 offset += count; 331 } 332 333 extern (C++) void printf(const(char)* format, ...) /*nothrow*/ 334 { 335 va_list ap; 336 va_start(ap, format); 337 vprintf(format, ap); 338 va_end(ap); 339 } 340 341 extern (C++) void bracket(char left, char right) nothrow 342 { 343 reserve(2); 344 memmove(data + 1, data, offset); 345 data[0] = left; 346 data[offset + 1] = right; 347 offset += 2; 348 } 349 350 /****************** 351 * Insert left at i, and right at j. 352 * Return index just past right. 353 */ 354 extern (C++) size_t bracket(size_t i, const(char)* left, size_t j, const(char)* right) nothrow 355 { 356 size_t leftlen = strlen(left); 357 size_t rightlen = strlen(right); 358 reserve(leftlen + rightlen); 359 insert(i, left, leftlen); 360 insert(j + leftlen, right, rightlen); 361 return j + leftlen + rightlen; 362 } 363 364 extern (C++) void spread(size_t offset, size_t nbytes) nothrow 365 { 366 reserve(nbytes); 367 memmove(data + offset + nbytes, data + offset, this.offset - offset); 368 this.offset += nbytes; 369 } 370 371 /**************************************** 372 * Returns: offset + nbytes 373 */ 374 extern (C++) size_t insert(size_t offset, const(void)* p, size_t nbytes) nothrow 375 { 376 spread(offset, nbytes); 377 memmove(data + offset, p, nbytes); 378 return offset + nbytes; 379 } 380 381 size_t insert(size_t offset, const(char)[] s) nothrow 382 { 383 return insert(offset, s.ptr, s.length); 384 } 385 386 extern (C++) void remove(size_t offset, size_t nbytes) nothrow 387 { 388 memmove(data + offset, data + offset + nbytes, this.offset - (offset + nbytes)); 389 this.offset -= nbytes; 390 } 391 392 extern (D) const(char)[] peekSlice() nothrow 393 { 394 return (cast(const char*)data)[0 .. offset]; 395 } 396 397 // Append terminating null if necessary and get view of internal buffer 398 extern (C++) char* peekString() nothrow 399 { 400 if (!offset || data[offset - 1] != '\0') 401 { 402 writeByte(0); 403 offset--; // allow appending more 404 } 405 return cast(char*)data; 406 } 407 408 // Append terminating null if necessary and take ownership of data 409 extern (C++) char* extractString() nothrow 410 { 411 if (!offset || data[offset - 1] != '\0') 412 writeByte(0); 413 return extractData(); 414 } 415 }