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