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