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
extractData()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
reserve(size_t nbytes)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
reset()35 void OutBuffer::reset()
36 {
37 offset = 0;
38 }
39
setsize(size_t size)40 void OutBuffer::setsize(size_t size)
41 {
42 offset = size;
43 }
44
write(const void * data,size_t nbytes)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
writebstring(utf8_t * string)65 void OutBuffer::writebstring(utf8_t *string)
66 {
67 write(string,*string + 1);
68 }
69
writestring(const char * string)70 void OutBuffer::writestring(const char *string)
71 {
72 write(string,strlen(string));
73 }
74
prependstring(const char * string)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
writenl()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
writeByte(unsigned b)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
writeUTF8(unsigned b)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
prependbyte(unsigned b)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
writewchar(unsigned w)176 void OutBuffer::writewchar(unsigned w)
177 {
178 #if _WIN32
179 writeword(w);
180 #else
181 write4(w);
182 #endif
183 }
184
writeword(unsigned w)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
writeUTF16(unsigned w)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
write4(unsigned w)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
write(OutBuffer * buf)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
write(RootObject * obj)263 void OutBuffer::write(RootObject *obj)
264 {
265 if (obj)
266 {
267 writestring(obj->toChars());
268 }
269 }
270
fill0(size_t nbytes)271 void OutBuffer::fill0(size_t nbytes)
272 {
273 reserve(nbytes);
274 memset(data + offset,0,nbytes);
275 offset += nbytes;
276 }
277
vprintf(const char * format,va_list args)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
printf(const char * format,...)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 /**************************************
329 * Convert `u` to a string and append it to the buffer.
330 * Params:
331 * u = integral value to append
332 */
print(unsigned long long u)333 void OutBuffer::print(unsigned long long u)
334 {
335 unsigned long long value = u;
336 char buf[20];
337 const unsigned radix = 10;
338
339 size_t i = sizeof(buf);
340 do
341 {
342 if (value < radix)
343 {
344 unsigned char x = (unsigned char)value;
345 buf[--i] = (char)(x + '0');
346 break;
347 }
348 else
349 {
350 unsigned char x = (unsigned char)(value % radix);
351 value = value / radix;
352 buf[--i] = (char)(x + '0');
353 }
354 } while (value);
355
356 write(buf + i, sizeof(buf) - i);
357 }
358
bracket(char left,char right)359 void OutBuffer::bracket(char left, char right)
360 {
361 reserve(2);
362 memmove(data + 1, data, offset);
363 data[0] = left;
364 data[offset + 1] = right;
365 offset += 2;
366 }
367
368 /******************
369 * Insert left at i, and right at j.
370 * Return index just past right.
371 */
372
bracket(size_t i,const char * left,size_t j,const char * right)373 size_t OutBuffer::bracket(size_t i, const char *left, size_t j, const char *right)
374 {
375 size_t leftlen = strlen(left);
376 size_t rightlen = strlen(right);
377 reserve(leftlen + rightlen);
378 insert(i, left, leftlen);
379 insert(j + leftlen, right, rightlen);
380 return j + leftlen + rightlen;
381 }
382
spread(size_t offset,size_t nbytes)383 void OutBuffer::spread(size_t offset, size_t nbytes)
384 {
385 reserve(nbytes);
386 memmove(data + offset + nbytes, data + offset,
387 this->offset - offset);
388 this->offset += nbytes;
389 }
390
391 /****************************************
392 * Returns: offset + nbytes
393 */
394
insert(size_t offset,const void * p,size_t nbytes)395 size_t OutBuffer::insert(size_t offset, const void *p, size_t nbytes)
396 {
397 spread(offset, nbytes);
398 memmove(data + offset, p, nbytes);
399 return offset + nbytes;
400 }
401
remove(size_t offset,size_t nbytes)402 void OutBuffer::remove(size_t offset, size_t nbytes)
403 {
404 memmove(data + offset, data + offset + nbytes, this->offset - (offset + nbytes));
405 this->offset -= nbytes;
406 }
407
peekString()408 char *OutBuffer::peekString()
409 {
410 if (!offset || data[offset-1] != '\0')
411 {
412 writeByte(0);
413 offset--; // allow appending more
414 }
415 return (char *)data;
416 }
417
extractString()418 char *OutBuffer::extractString()
419 {
420 if (!offset || data[offset-1] != '\0')
421 writeByte(0);
422 return extractData();
423 }
424