Mercurial > projects > ldc
annotate dmd/root.c @ 468:45a67b6f1310
Removed the 'needsstorage' thing from Dsymbol. Arguments are not always given storage when applicable. This is not longer treat specially
in this regard. Code for accessing nested variables and contexts rewritten. Probably more. Fairly well tested.
author | Tomas Lindquist Olsen <tomas.l.olsen@gmail.com> |
---|---|
date | Mon, 04 Aug 2008 02:59:34 +0200 |
parents | f7ba5f705d59 |
children | f79bbd1d0b27 |
rev | line source |
---|---|
336 | 1 |
2 // Copyright (c) 1999-2006 by Digital Mars | |
3 // All Rights Reserved | |
4 // written by Walter Bright | |
5 // www.digitalmars.com | |
6 // License for redistribution is by either the Artistic License | |
7 // in artistic.txt, or the GNU General Public License in gnu.txt. | |
8 // See the included readme.txt for details. | |
9 | |
10 #include <stdio.h> | |
11 #include <stdlib.h> | |
12 #include <stdarg.h> | |
13 #include <string.h> | |
14 #include <stdint.h> | |
15 #include <assert.h> | |
16 | |
17 #if _MSC_VER ||__MINGW32__ | |
18 #include <malloc.h> | |
19 #endif | |
20 | |
21 #if _WIN32 | |
22 #include <windows.h> | |
23 #include <direct.h> | |
24 #endif | |
25 | |
26 #if linux | |
27 #include <sys/types.h> | |
28 #include <sys/stat.h> | |
29 #include <fcntl.h> | |
30 #include <errno.h> | |
31 #include <unistd.h> | |
32 #include <utime.h> | |
33 #endif | |
34 | |
35 #include "port.h" | |
36 #include "root.h" | |
37 #include "dchar.h" | |
38 #include "mem.h" | |
39 #include "mars.h" | |
40 | |
41 #if 0 //__SC__ //def DEBUG | |
42 extern "C" void __cdecl _assert(void *e, void *f, unsigned line) | |
43 { | |
44 printf("Assert('%s','%s',%d)\n",e,f,line); | |
45 fflush(stdout); | |
46 *(char *)0 = 0; | |
47 } | |
48 #endif | |
49 | |
50 /************************************* | |
51 * Convert wchar string to ascii string. | |
52 */ | |
53 | |
54 char *wchar2ascii(wchar_t *us) | |
55 { | |
56 return wchar2ascii(us, wcslen(us)); | |
57 } | |
58 | |
59 char *wchar2ascii(wchar_t *us, unsigned len) | |
60 { | |
61 unsigned i; | |
62 char *p; | |
63 | |
64 p = (char *)mem.malloc(len + 1); | |
65 for (i = 0; i <= len; i++) | |
66 p[i] = (char) us[i]; | |
67 return p; | |
68 } | |
69 | |
70 int wcharIsAscii(wchar_t *us) | |
71 { | |
72 return wcharIsAscii(us, wcslen(us)); | |
73 } | |
74 | |
75 int wcharIsAscii(wchar_t *us, unsigned len) | |
76 { | |
77 unsigned i; | |
78 | |
79 for (i = 0; i <= len; i++) | |
80 { | |
81 if (us[i] & ~0xFF) // if high bits set | |
82 return 0; // it's not ascii | |
83 } | |
84 return 1; | |
85 } | |
86 | |
87 | |
88 /*********************************** | |
89 * Compare length-prefixed strings (bstr). | |
90 */ | |
91 | |
92 int bstrcmp(unsigned char *b1, unsigned char *b2) | |
93 { | |
94 return (*b1 == *b2 && memcmp(b1 + 1, b2 + 1, *b2) == 0) ? 0 : 1; | |
95 } | |
96 | |
97 /*************************************** | |
98 * Convert bstr into a malloc'd string. | |
99 */ | |
100 | |
101 char *bstr2str(unsigned char *b) | |
102 { | |
103 char *s; | |
104 unsigned len; | |
105 | |
106 len = *b; | |
107 s = (char *) mem.malloc(len + 1); | |
108 s[len] = 0; | |
109 return (char *)memcpy(s,b + 1,len); | |
110 } | |
111 | |
112 /************************************** | |
113 * Print error message and exit. | |
114 */ | |
115 | |
116 void error(const char *format, ...) | |
117 { | |
118 va_list ap; | |
119 | |
120 va_start(ap, format); | |
121 printf("Error: "); | |
122 vprintf(format, ap); | |
123 va_end( ap ); | |
124 printf("\n"); | |
125 fflush(stdout); | |
126 | |
127 exit(EXIT_FAILURE); | |
128 } | |
129 | |
130 #if M_UNICODE | |
131 void error(const dchar *format, ...) | |
132 { | |
133 va_list ap; | |
134 | |
135 va_start(ap, format); | |
136 printf("Error: "); | |
137 vwprintf(format, ap); | |
138 va_end( ap ); | |
139 printf("\n"); | |
140 fflush(stdout); | |
141 | |
142 exit(EXIT_FAILURE); | |
143 } | |
144 #endif | |
145 | |
146 void error_mem() | |
147 { | |
148 error("out of memory"); | |
149 } | |
150 | |
151 /************************************** | |
152 * Print warning message. | |
153 */ | |
154 | |
155 void warning(const char *format, ...) | |
156 { | |
157 va_list ap; | |
158 | |
159 va_start(ap, format); | |
160 printf("Warning: "); | |
161 vprintf(format, ap); | |
162 va_end( ap ); | |
163 printf("\n"); | |
164 fflush(stdout); | |
165 } | |
166 | |
167 /****************************** Object ********************************/ | |
168 | |
169 int Object::equals(Object *o) | |
170 { | |
171 return o == this; | |
172 } | |
173 | |
174 hash_t Object::hashCode() | |
175 { | |
176 return (hash_t) this; | |
177 } | |
178 | |
179 int Object::compare(Object *obj) | |
180 { | |
181 return this - obj; | |
182 } | |
183 | |
184 void Object::print() | |
185 { | |
186 printf("%s %p\n", toChars(), this); | |
187 } | |
188 | |
189 char *Object::toChars() | |
190 { | |
191 return "Object"; | |
192 } | |
193 | |
194 dchar *Object::toDchars() | |
195 { | |
196 #if M_UNICODE | |
197 return L"Object"; | |
198 #else | |
199 return toChars(); | |
200 #endif | |
201 } | |
202 | |
203 int Object::dyncast() | |
204 { | |
205 return 0; | |
206 } | |
207 | |
208 void Object::toBuffer(OutBuffer *b) | |
209 { | |
210 b->writestring("Object"); | |
211 } | |
212 | |
213 void Object::mark() | |
214 { | |
215 } | |
216 | |
217 /****************************** String ********************************/ | |
218 | |
219 String::String(char *str, int ref) | |
220 { | |
221 this->str = ref ? str : mem.strdup(str); | |
222 this->ref = ref; | |
223 } | |
224 | |
225 String::~String() | |
226 { | |
227 mem.free(str); | |
228 } | |
229 | |
230 void String::mark() | |
231 { | |
232 mem.mark(str); | |
233 } | |
234 | |
235 hash_t String::calcHash(const char *str, size_t len) | |
236 { | |
237 hash_t hash = 0; | |
238 | |
239 for (;;) | |
240 { | |
241 switch (len) | |
242 { | |
243 case 0: | |
244 return hash; | |
245 | |
246 case 1: | |
247 hash *= 37; | |
248 hash += *(uint8_t *)str; | |
249 return hash; | |
250 | |
251 case 2: | |
252 hash *= 37; | |
253 hash += *(uint16_t *)str; | |
254 return hash; | |
255 | |
256 case 3: | |
257 hash *= 37; | |
258 hash += (*(uint16_t *)str << 8) + | |
259 ((uint8_t *)str)[2]; | |
260 return hash; | |
261 | |
262 default: | |
263 hash *= 37; | |
264 hash += *(uint32_t *)str; | |
265 str += 4; | |
266 len -= 4; | |
267 break; | |
268 } | |
269 } | |
270 } | |
271 | |
272 hash_t String::calcHash(const char *str) | |
273 { | |
274 return calcHash(str, strlen(str)); | |
275 } | |
276 | |
277 hash_t String::hashCode() | |
278 { | |
279 return calcHash(str, strlen(str)); | |
280 } | |
281 | |
282 unsigned String::len() | |
283 { | |
284 return strlen(str); | |
285 } | |
286 | |
287 int String::equals(Object *obj) | |
288 { | |
289 return strcmp(str,((String *)obj)->str) == 0; | |
290 } | |
291 | |
292 int String::compare(Object *obj) | |
293 { | |
294 return strcmp(str,((String *)obj)->str); | |
295 } | |
296 | |
297 char *String::toChars() | |
298 { | |
299 return str; | |
300 } | |
301 | |
302 void String::print() | |
303 { | |
304 printf("String '%s'\n",str); | |
305 } | |
306 | |
307 | |
308 /****************************** FileName ********************************/ | |
309 | |
310 FileName::FileName(char *str, int ref) | |
311 : String(str,ref) | |
312 { | |
313 } | |
314 | |
315 char *FileName::combine(char *path, char *name) | |
316 { char *f; | |
317 size_t pathlen; | |
318 size_t namelen; | |
319 | |
320 if (!path || !*path) | |
321 return name; | |
322 pathlen = strlen(path); | |
323 namelen = strlen(name); | |
324 f = (char *)mem.malloc(pathlen + 1 + namelen + 1); | |
325 memcpy(f, path, pathlen); | |
429
6bd99cc5eb08
Allow / as a path separator on Windows.
Christian Kamm <kamm incasoftware de>
parents:
336
diff
changeset
|
326 |
462
f7ba5f705d59
Path combining on Windows didn't work with / properly.
Christian Kamm <kamm incasoftware de>
parents:
431
diff
changeset
|
327 if ( |
f7ba5f705d59
Path combining on Windows didn't work with / properly.
Christian Kamm <kamm incasoftware de>
parents:
431
diff
changeset
|
328 path[pathlen - 1] != '/' |
f7ba5f705d59
Path combining on Windows didn't work with / properly.
Christian Kamm <kamm incasoftware de>
parents:
431
diff
changeset
|
329 #if _WIN32 |
f7ba5f705d59
Path combining on Windows didn't work with / properly.
Christian Kamm <kamm incasoftware de>
parents:
431
diff
changeset
|
330 && path[pathlen - 1] != '\\' && path[pathlen - 1] != ':' |
f7ba5f705d59
Path combining on Windows didn't work with / properly.
Christian Kamm <kamm incasoftware de>
parents:
431
diff
changeset
|
331 #endif |
f7ba5f705d59
Path combining on Windows didn't work with / properly.
Christian Kamm <kamm incasoftware de>
parents:
431
diff
changeset
|
332 ) |
336 | 333 { f[pathlen] = '/'; |
334 pathlen++; | |
335 } | |
429
6bd99cc5eb08
Allow / as a path separator on Windows.
Christian Kamm <kamm incasoftware de>
parents:
336
diff
changeset
|
336 |
336 | 337 memcpy(f + pathlen, name, namelen + 1); |
338 return f; | |
339 } | |
340 | |
341 FileName::FileName(char *path, char *name) | |
342 : String(combine(path,name),1) | |
343 { | |
344 } | |
345 | |
346 // Split a path into an Array of paths | |
347 Array *FileName::splitPath(const char *path) | |
348 { | |
349 char c = 0; // unnecessary initializer is for VC /W4 | |
350 const char *p; | |
351 OutBuffer buf; | |
352 Array *array; | |
353 | |
354 array = new Array(); | |
355 if (path) | |
356 { | |
357 p = path; | |
358 do | |
359 { char instring = 0; | |
360 | |
361 while (isspace(*p)) // skip leading whitespace | |
362 p++; | |
363 buf.reserve(strlen(p) + 1); // guess size of path | |
364 for (; ; p++) | |
365 { | |
366 c = *p; | |
367 switch (c) | |
368 { | |
369 case '"': | |
370 instring ^= 1; // toggle inside/outside of string | |
371 continue; | |
372 | |
373 #if MACINTOSH | |
374 case ',': | |
375 #endif | |
376 #if _WIN32 | |
377 case ';': | |
378 #endif | |
379 #if linux | |
380 case ':': | |
381 #endif | |
382 p++; | |
383 break; // note that ; cannot appear as part | |
384 // of a path, quotes won't protect it | |
385 | |
386 case 0x1A: // ^Z means end of file | |
387 case 0: | |
388 break; | |
389 | |
390 case '\r': | |
391 continue; // ignore carriage returns | |
392 | |
393 #if linux | |
394 case '~': | |
395 buf.writestring(getenv("HOME")); | |
396 continue; | |
397 #endif | |
398 | |
399 case ' ': | |
400 case '\t': // tabs in filenames? | |
401 if (!instring) // if not in string | |
402 break; // treat as end of path | |
403 default: | |
404 buf.writeByte(c); | |
405 continue; | |
406 } | |
407 break; | |
408 } | |
409 if (buf.offset) // if path is not empty | |
410 { | |
411 buf.writeByte(0); // to asciiz | |
412 array->push(buf.extractData()); | |
413 } | |
414 } while (c); | |
415 } | |
416 return array; | |
417 } | |
418 | |
419 hash_t FileName::hashCode() | |
420 { | |
421 #if _WIN32 | |
422 // We need a different hashCode because it must be case-insensitive | |
423 size_t len = strlen(str); | |
424 hash_t hash = 0; | |
425 unsigned char *s = (unsigned char *)str; | |
426 | |
427 for (;;) | |
428 { | |
429 switch (len) | |
430 { | |
431 case 0: | |
432 return hash; | |
433 | |
434 case 1: | |
435 hash *= 37; | |
436 hash += *(uint8_t *)s | 0x20; | |
437 return hash; | |
438 | |
439 case 2: | |
440 hash *= 37; | |
441 hash += *(uint16_t *)s | 0x2020; | |
442 return hash; | |
443 | |
444 case 3: | |
445 hash *= 37; | |
446 hash += ((*(uint16_t *)s << 8) + | |
447 ((uint8_t *)s)[2]) | 0x202020; | |
448 break; | |
449 | |
450 default: | |
451 hash *= 37; | |
452 hash += *(uint32_t *)s | 0x20202020; | |
453 s += 4; | |
454 len -= 4; | |
455 break; | |
456 } | |
457 } | |
458 #else | |
459 // darwin HFS is case insensitive, though... | |
460 return String::hashCode(); | |
461 #endif | |
462 } | |
463 | |
464 int FileName::compare(Object *obj) | |
465 { | |
466 #if _WIN32 | |
467 return stricmp(str,((FileName *)obj)->str); | |
468 #else | |
469 return String::compare(obj); | |
470 #endif | |
471 } | |
472 | |
473 int FileName::equals(Object *obj) | |
474 { | |
475 #if _WIN32 | |
476 return stricmp(str,((FileName *)obj)->str) == 0; | |
477 #else | |
478 return String::equals(obj); | |
479 #endif | |
480 } | |
481 | |
482 /************************************ | |
483 * Return !=0 if absolute path name. | |
484 */ | |
485 | |
486 int FileName::absolute(const char *name) | |
487 { | |
429
6bd99cc5eb08
Allow / as a path separator on Windows.
Christian Kamm <kamm incasoftware de>
parents:
336
diff
changeset
|
488 return |
336 | 489 #if _WIN32 |
429
6bd99cc5eb08
Allow / as a path separator on Windows.
Christian Kamm <kamm incasoftware de>
parents:
336
diff
changeset
|
490 (*name == '\\') || |
6bd99cc5eb08
Allow / as a path separator on Windows.
Christian Kamm <kamm incasoftware de>
parents:
336
diff
changeset
|
491 (*name == '/') || |
6bd99cc5eb08
Allow / as a path separator on Windows.
Christian Kamm <kamm incasoftware de>
parents:
336
diff
changeset
|
492 (*name && name[1] == ':') || |
336 | 493 #endif |
429
6bd99cc5eb08
Allow / as a path separator on Windows.
Christian Kamm <kamm incasoftware de>
parents:
336
diff
changeset
|
494 (*name == '/'); |
336 | 495 } |
496 | |
497 /******************************** | |
498 * Return filename extension (read-only). | |
499 * Points past '.' of extension. | |
500 * If there isn't one, return NULL. | |
501 */ | |
502 | |
503 char *FileName::ext(const char *str) | |
504 { | |
505 char *e; | |
506 size_t len = strlen(str); | |
507 | |
508 e = (char *)str + len; | |
509 for (;;) | |
510 { | |
511 switch (*e) | |
512 { case '.': | |
513 return e + 1; | |
429
6bd99cc5eb08
Allow / as a path separator on Windows.
Christian Kamm <kamm incasoftware de>
parents:
336
diff
changeset
|
514 |
336 | 515 case '/': |
516 break; | |
429
6bd99cc5eb08
Allow / as a path separator on Windows.
Christian Kamm <kamm incasoftware de>
parents:
336
diff
changeset
|
517 |
336 | 518 #if _WIN32 |
519 case '\\': | |
520 case ':': | |
521 break; | |
522 #endif | |
523 default: | |
524 if (e == str) | |
525 break; | |
526 e--; | |
527 continue; | |
528 } | |
529 return NULL; | |
530 } | |
531 } | |
532 | |
533 char *FileName::ext() | |
534 { | |
535 return ext(str); | |
536 } | |
537 | |
538 /******************************** | |
539 * Return mem.malloc'd filename with extension removed. | |
540 */ | |
541 | |
542 char *FileName::removeExt(const char *str) | |
543 { | |
544 const char *e = ext(str); | |
545 if (e) | |
546 { size_t len = (e - str) - 1; | |
547 char *n = (char *)mem.malloc(len + 1); | |
548 memcpy(n, str, len); | |
549 n[len] = 0; | |
550 return n; | |
551 } | |
552 return mem.strdup(str); | |
553 } | |
554 | |
555 /******************************** | |
556 * Return filename name excluding path (read-only). | |
557 */ | |
558 | |
559 char *FileName::name(const char *str) | |
560 { | |
561 char *e; | |
562 size_t len = strlen(str); | |
563 | |
564 e = (char *)str + len; | |
565 for (;;) | |
566 { | |
567 switch (*e) | |
568 { | |
429
6bd99cc5eb08
Allow / as a path separator on Windows.
Christian Kamm <kamm incasoftware de>
parents:
336
diff
changeset
|
569 |
336 | 570 case '/': |
571 return e + 1; | |
429
6bd99cc5eb08
Allow / as a path separator on Windows.
Christian Kamm <kamm incasoftware de>
parents:
336
diff
changeset
|
572 |
336 | 573 #if _WIN32 |
574 case '\\': | |
575 case ':': | |
576 return e + 1; | |
577 #endif | |
578 default: | |
579 if (e == str) | |
580 break; | |
581 e--; | |
582 continue; | |
583 } | |
584 return e; | |
585 } | |
586 } | |
587 | |
588 char *FileName::name() | |
589 { | |
590 return name(str); | |
591 } | |
592 | |
593 /************************************** | |
594 * Return path portion of str. | |
595 * Path will does not include trailing path separator. | |
596 */ | |
597 | |
598 char *FileName::path(const char *str) | |
599 { | |
600 char *n = name(str); | |
601 char *path; | |
602 size_t pathlen; | |
603 | |
604 if (n > str) | |
605 { | |
429
6bd99cc5eb08
Allow / as a path separator on Windows.
Christian Kamm <kamm incasoftware de>
parents:
336
diff
changeset
|
606 |
336 | 607 if (n[-1] == '/') |
608 n--; | |
429
6bd99cc5eb08
Allow / as a path separator on Windows.
Christian Kamm <kamm incasoftware de>
parents:
336
diff
changeset
|
609 |
336 | 610 #if _WIN32 |
611 if (n[-1] == '\\') | |
612 n--; | |
613 #endif | |
614 } | |
615 pathlen = n - str; | |
616 path = (char *)mem.malloc(pathlen + 1); | |
617 memcpy(path, str, pathlen); | |
618 path[pathlen] = 0; | |
619 return path; | |
620 } | |
621 | |
622 /************************************** | |
623 * Replace filename portion of path. | |
624 */ | |
625 | |
626 char *FileName::replaceName(char *path, char *name) | |
627 { char *f; | |
628 char *n; | |
629 size_t pathlen; | |
630 size_t namelen; | |
631 | |
632 if (absolute(name)) | |
633 return name; | |
634 | |
635 n = FileName::name(path); | |
636 if (n == path) | |
637 return name; | |
638 pathlen = n - path; | |
639 namelen = strlen(name); | |
640 f = (char *)mem.malloc(pathlen + 1 + namelen + 1); | |
641 memcpy(f, path, pathlen); | |
429
6bd99cc5eb08
Allow / as a path separator on Windows.
Christian Kamm <kamm incasoftware de>
parents:
336
diff
changeset
|
642 |
431
3dd9ae9ea708
Another fix to DMD's path code.
Christian Kamm <kamm incasoftware de>
parents:
430
diff
changeset
|
643 if ( |
3dd9ae9ea708
Another fix to DMD's path code.
Christian Kamm <kamm incasoftware de>
parents:
430
diff
changeset
|
644 path[pathlen - 1] != '/' |
3dd9ae9ea708
Another fix to DMD's path code.
Christian Kamm <kamm incasoftware de>
parents:
430
diff
changeset
|
645 #if _WIN32 |
3dd9ae9ea708
Another fix to DMD's path code.
Christian Kamm <kamm incasoftware de>
parents:
430
diff
changeset
|
646 && path[pathlen - 1] != '\\' && path[pathlen - 1] != ':' |
3dd9ae9ea708
Another fix to DMD's path code.
Christian Kamm <kamm incasoftware de>
parents:
430
diff
changeset
|
647 #endif |
3dd9ae9ea708
Another fix to DMD's path code.
Christian Kamm <kamm incasoftware de>
parents:
430
diff
changeset
|
648 ) |
336 | 649 { f[pathlen] = '/'; |
650 pathlen++; | |
651 } | |
429
6bd99cc5eb08
Allow / as a path separator on Windows.
Christian Kamm <kamm incasoftware de>
parents:
336
diff
changeset
|
652 |
336 | 653 memcpy(f + pathlen, name, namelen + 1); |
654 return f; | |
655 } | |
656 | |
657 /*************************** | |
658 */ | |
659 | |
660 FileName *FileName::defaultExt(const char *name, const char *ext) | |
661 { | |
662 char *e; | |
663 char *s; | |
664 size_t len; | |
665 size_t extlen; | |
666 | |
667 e = FileName::ext(name); | |
668 if (e) // if already has an extension | |
669 return new FileName((char *)name, 0); | |
670 | |
671 len = strlen(name); | |
672 extlen = strlen(ext); | |
673 s = (char *)alloca(len + 1 + extlen + 1); | |
674 memcpy(s,name,len); | |
675 s[len] = '.'; | |
676 memcpy(s + len + 1, ext, extlen + 1); | |
677 return new FileName(s, 0); | |
678 } | |
679 | |
680 /*************************** | |
681 */ | |
682 | |
683 FileName *FileName::forceExt(const char *name, const char *ext) | |
684 { | |
685 char *e; | |
686 char *s; | |
687 size_t len; | |
688 size_t extlen; | |
689 | |
690 e = FileName::ext(name); | |
691 if (e) // if already has an extension | |
692 { | |
693 len = e - name; | |
694 extlen = strlen(ext); | |
695 | |
696 s = (char *)alloca(len + extlen + 1); | |
697 memcpy(s,name,len); | |
698 memcpy(s + len, ext, extlen + 1); | |
699 return new FileName(s, 0); | |
700 } | |
701 else | |
702 return defaultExt(name, ext); // doesn't have one | |
703 } | |
704 | |
705 /****************************** | |
706 * Return !=0 if extensions match. | |
707 */ | |
708 | |
709 int FileName::equalsExt(const char *ext) | |
710 { const char *e; | |
711 | |
712 e = FileName::ext(); | |
713 if (!e && !ext) | |
714 return 1; | |
715 if (!e || !ext) | |
716 return 0; | |
717 #if linux | |
718 return strcmp(e,ext) == 0; | |
719 #endif | |
720 #if _WIN32 | |
721 return stricmp(e,ext) == 0; | |
722 #endif | |
723 } | |
724 | |
725 /************************************* | |
726 * Copy file from this to to. | |
727 */ | |
728 | |
729 void FileName::CopyTo(FileName *to) | |
730 { | |
731 File file(this); | |
732 | |
733 #if _WIN32 | |
734 file.touchtime = mem.malloc(sizeof(WIN32_FIND_DATAA)); // keep same file time | |
735 #endif | |
736 #if linux | |
737 file.touchtime = mem.malloc(sizeof(struct stat)); // keep same file time | |
738 #endif | |
739 file.readv(); | |
740 file.name = to; | |
741 file.writev(); | |
742 } | |
743 | |
744 /************************************* | |
745 * Search Path for file. | |
746 * Input: | |
747 * cwd if !=0, search current directory before searching path | |
748 */ | |
749 | |
750 char *FileName::searchPath(Array *path, char *name, int cwd) | |
751 { | |
752 if (absolute(name)) | |
753 { | |
754 return exists(name) ? name : NULL; | |
755 } | |
756 if (cwd) | |
757 { | |
758 if (exists(name)) | |
759 return name; | |
760 } | |
761 if (path) | |
762 { unsigned i; | |
763 | |
764 for (i = 0; i < path->dim; i++) | |
765 { | |
766 char *p = (char *)path->data[i]; | |
767 char *n = combine(p, name); | |
768 | |
769 if (exists(n)) | |
770 return n; | |
771 } | |
772 } | |
773 return NULL; | |
774 } | |
775 | |
776 int FileName::exists(const char *name) | |
777 { | |
778 #if linux | |
779 struct stat st; | |
780 | |
781 if (stat(name, &st) < 0) | |
782 return 0; | |
783 if (S_ISDIR(st.st_mode)) | |
784 return 2; | |
785 return 1; | |
786 #endif | |
787 #if _WIN32 | |
788 DWORD dw; | |
789 int result; | |
790 | |
791 dw = GetFileAttributesA(name); | |
792 if (dw == -1L) | |
793 result = 0; | |
794 else if (dw & FILE_ATTRIBUTE_DIRECTORY) | |
795 result = 2; | |
796 else | |
797 result = 1; | |
798 return result; | |
799 #endif | |
800 } | |
801 | |
802 void FileName::ensurePathExists(const char *path) | |
803 { | |
804 //printf("FileName::ensurePathExists(%s)\n", path ? path : ""); | |
805 if (path && *path) | |
806 { | |
807 if (!exists(path)) | |
808 { | |
809 char *p = FileName::path(path); | |
810 if (*p) | |
811 { | |
812 #if _WIN32 | |
813 size_t len = strlen(p); | |
814 if (len > 2 && p[-1] == ':') | |
815 { mem.free(p); | |
816 return; | |
817 } | |
818 #endif | |
819 ensurePathExists(p); | |
820 mem.free(p); | |
821 } | |
822 #if _WIN32 | |
823 if (path[strlen(path) - 1] != '\\') | |
824 #endif | |
825 #if linux | |
826 if (path[strlen(path) - 1] != '\\') | |
827 #endif | |
828 { | |
829 //printf("mkdir(%s)\n", path); | |
830 #if _WIN32 | |
831 if (mkdir(path)) | |
832 #endif | |
833 #if linux | |
834 if (mkdir(path, 0777)) | |
835 #endif | |
836 error("cannot create directory %s", path); | |
837 } | |
838 } | |
839 } | |
840 } | |
841 | |
842 /****************************** File ********************************/ | |
843 | |
844 File::File(FileName *n) | |
845 { | |
846 ref = 0; | |
847 buffer = NULL; | |
848 len = 0; | |
849 touchtime = NULL; | |
850 name = n; | |
851 } | |
852 | |
853 File::File(char *n) | |
854 { | |
855 ref = 0; | |
856 buffer = NULL; | |
857 len = 0; | |
858 touchtime = NULL; | |
859 name = new FileName(n, 0); | |
860 } | |
861 | |
862 File::~File() | |
863 { | |
864 if (buffer) | |
865 { | |
866 if (ref == 0) | |
867 mem.free(buffer); | |
868 #if _WIN32 | |
869 else if (ref == 2) | |
870 UnmapViewOfFile(buffer); | |
871 #endif | |
872 } | |
873 if (touchtime) | |
874 mem.free(touchtime); | |
875 } | |
876 | |
877 void File::mark() | |
878 { | |
879 mem.mark(buffer); | |
880 mem.mark(touchtime); | |
881 mem.mark(name); | |
882 } | |
883 | |
884 /************************************* | |
885 */ | |
886 | |
887 int File::read() | |
888 { | |
889 #if linux | |
890 off_t size; | |
891 ssize_t numread; | |
892 int fd; | |
893 struct stat buf; | |
894 int result = 0; | |
895 char *name; | |
896 | |
897 name = this->name->toChars(); | |
898 //printf("File::read('%s')\n",name); | |
899 fd = open(name, O_RDONLY); | |
900 if (fd == -1) | |
901 { result = errno; | |
902 //printf("\topen error, errno = %d\n",errno); | |
903 goto err1; | |
904 } | |
905 | |
906 if (!ref) | |
907 mem.free(buffer); | |
908 ref = 0; // we own the buffer now | |
909 | |
910 //printf("\tfile opened\n"); | |
911 if (fstat(fd, &buf)) | |
912 { | |
913 printf("\tfstat error, errno = %d\n",errno); | |
914 goto err2; | |
915 } | |
916 size = buf.st_size; | |
917 buffer = (unsigned char *) mem.malloc(size + 2); | |
918 if (!buffer) | |
919 { | |
920 printf("\tmalloc error, errno = %d\n",errno); | |
921 goto err2; | |
922 } | |
923 | |
924 numread = ::read(fd, buffer, size); | |
925 if (numread != size) | |
926 { | |
927 printf("\tread error, errno = %d\n",errno); | |
928 goto err2; | |
929 } | |
930 | |
931 if (touchtime) | |
932 memcpy(touchtime, &buf, sizeof(buf)); | |
933 | |
934 if (close(fd) == -1) | |
935 { | |
936 printf("\tclose error, errno = %d\n",errno); | |
937 goto err; | |
938 } | |
939 | |
940 len = size; | |
941 | |
942 // Always store a wchar ^Z past end of buffer so scanner has a sentinel | |
943 buffer[size] = 0; // ^Z is obsolete, use 0 | |
944 buffer[size + 1] = 0; | |
945 return 0; | |
946 | |
947 err2: | |
948 close(fd); | |
949 err: | |
950 mem.free(buffer); | |
951 buffer = NULL; | |
952 len = 0; | |
953 | |
954 err1: | |
955 result = 1; | |
956 return result; | |
957 #endif | |
958 #if _WIN32 | |
959 DWORD size; | |
960 DWORD numread; | |
961 HANDLE h; | |
962 int result = 0; | |
963 char *name; | |
964 | |
965 name = this->name->toChars(); | |
966 h = CreateFileA(name,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING, | |
967 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,0); | |
968 if (h == INVALID_HANDLE_VALUE) | |
969 goto err1; | |
970 | |
971 if (!ref) | |
972 mem.free(buffer); | |
973 ref = 0; | |
974 | |
975 size = GetFileSize(h,NULL); | |
976 buffer = (unsigned char *) mem.malloc(size + 2); | |
977 if (!buffer) | |
978 goto err2; | |
979 | |
980 if (ReadFile(h,buffer,size,&numread,NULL) != TRUE) | |
981 goto err2; | |
982 | |
983 if (numread != size) | |
984 goto err2; | |
985 | |
986 if (touchtime) | |
987 { | |
988 if (!GetFileTime(h, NULL, NULL, &((WIN32_FIND_DATAA *)touchtime)->ftLastWriteTime)) | |
989 goto err2; | |
990 } | |
991 | |
992 if (!CloseHandle(h)) | |
993 goto err; | |
994 | |
995 len = size; | |
996 | |
997 // Always store a wchar ^Z past end of buffer so scanner has a sentinel | |
998 buffer[size] = 0; // ^Z is obsolete, use 0 | |
999 buffer[size + 1] = 0; | |
1000 return 0; | |
1001 | |
1002 err2: | |
1003 CloseHandle(h); | |
1004 err: | |
1005 mem.free(buffer); | |
1006 buffer = NULL; | |
1007 len = 0; | |
1008 | |
1009 err1: | |
1010 result = 1; | |
1011 return result; | |
1012 #endif | |
1013 } | |
1014 | |
1015 /***************************** | |
1016 * Read a file with memory mapped file I/O. | |
1017 */ | |
1018 | |
1019 int File::mmread() | |
1020 { | |
1021 #if linux | |
1022 return read(); | |
1023 #endif | |
1024 #if _WIN32 | |
1025 HANDLE hFile; | |
1026 HANDLE hFileMap; | |
1027 DWORD size; | |
1028 char *name; | |
1029 | |
1030 name = this->name->toChars(); | |
1031 hFile = CreateFile(name, GENERIC_READ, | |
1032 FILE_SHARE_READ, NULL, | |
1033 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); | |
1034 if (hFile == INVALID_HANDLE_VALUE) | |
1035 goto Lerr; | |
1036 size = GetFileSize(hFile, NULL); | |
1037 //printf(" file created, size %d\n", size); | |
1038 | |
1039 hFileMap = CreateFileMapping(hFile,NULL,PAGE_READONLY,0,size,NULL); | |
1040 if (CloseHandle(hFile) != TRUE) | |
1041 goto Lerr; | |
1042 | |
1043 if (hFileMap == NULL) | |
1044 goto Lerr; | |
1045 | |
1046 //printf(" mapping created\n"); | |
1047 | |
1048 if (!ref) | |
1049 mem.free(buffer); | |
1050 ref = 2; | |
1051 buffer = (unsigned char *)MapViewOfFileEx(hFileMap, FILE_MAP_READ,0,0,size,NULL); | |
1052 if (CloseHandle(hFileMap) != TRUE) | |
1053 goto Lerr; | |
1054 if (buffer == NULL) // mapping view failed | |
1055 goto Lerr; | |
1056 | |
1057 len = size; | |
1058 //printf(" buffer = %p\n", buffer); | |
1059 | |
1060 return 0; | |
1061 | |
1062 Lerr: | |
1063 return GetLastError(); // failure | |
1064 #endif | |
1065 } | |
1066 | |
1067 /********************************************* | |
1068 * Write a file. | |
1069 * Returns: | |
1070 * 0 success | |
1071 */ | |
1072 | |
1073 int File::write() | |
1074 { | |
1075 #if linux | |
1076 int fd; | |
1077 ssize_t numwritten; | |
1078 char *name; | |
1079 | |
1080 name = this->name->toChars(); | |
1081 fd = open(name, O_CREAT | O_WRONLY | O_TRUNC, 0644); | |
1082 if (fd == -1) | |
1083 goto err; | |
1084 | |
1085 numwritten = ::write(fd, buffer, len); | |
1086 if (len != numwritten) | |
1087 goto err2; | |
1088 | |
1089 if (close(fd) == -1) | |
1090 goto err; | |
1091 | |
1092 if (touchtime) | |
1093 { struct utimbuf ubuf; | |
1094 | |
1095 ubuf.actime = ((struct stat *)touchtime)->st_atime; | |
1096 ubuf.modtime = ((struct stat *)touchtime)->st_mtime; | |
1097 if (utime(name, &ubuf)) | |
1098 goto err; | |
1099 } | |
1100 return 0; | |
1101 | |
1102 err2: | |
1103 close(fd); | |
1104 ::remove(name); | |
1105 err: | |
1106 return 1; | |
1107 #endif | |
1108 #if _WIN32 | |
1109 HANDLE h; | |
1110 DWORD numwritten; | |
1111 char *name; | |
1112 | |
1113 name = this->name->toChars(); | |
1114 h = CreateFileA(name,GENERIC_WRITE,0,NULL,CREATE_ALWAYS, | |
1115 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,NULL); | |
1116 if (h == INVALID_HANDLE_VALUE) | |
1117 goto err; | |
1118 | |
1119 if (WriteFile(h,buffer,len,&numwritten,NULL) != TRUE) | |
1120 goto err2; | |
1121 | |
1122 if (len != numwritten) | |
1123 goto err2; | |
1124 | |
1125 if (touchtime) { | |
1126 SetFileTime(h, NULL, NULL, &((WIN32_FIND_DATAA *)touchtime)->ftLastWriteTime); | |
1127 } | |
1128 if (!CloseHandle(h)) | |
1129 goto err; | |
1130 return 0; | |
1131 | |
1132 err2: | |
1133 CloseHandle(h); | |
1134 DeleteFileA(name); | |
1135 err: | |
1136 return 1; | |
1137 #endif | |
1138 } | |
1139 | |
1140 /********************************************* | |
1141 * Append to a file. | |
1142 * Returns: | |
1143 * 0 success | |
1144 */ | |
1145 | |
1146 int File::append() | |
1147 { | |
1148 #if linux | |
1149 return 1; | |
1150 #endif | |
1151 #if _WIN32 | |
1152 HANDLE h; | |
1153 DWORD numwritten; | |
1154 char *name; | |
1155 | |
1156 name = this->name->toChars(); | |
1157 h = CreateFileA(name,GENERIC_WRITE,0,NULL,OPEN_ALWAYS, | |
1158 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,NULL); | |
1159 if (h == INVALID_HANDLE_VALUE) | |
1160 goto err; | |
1161 | |
1162 #if 1 | |
1163 SetFilePointer(h, 0, NULL, FILE_END); | |
1164 #else // INVALID_SET_FILE_POINTER doesn't seem to have a definition | |
1165 if (SetFilePointer(h, 0, NULL, FILE_END) == INVALID_SET_FILE_POINTER) | |
1166 goto err; | |
1167 #endif | |
1168 | |
1169 if (WriteFile(h,buffer,len,&numwritten,NULL) != TRUE) | |
1170 goto err2; | |
1171 | |
1172 if (len != numwritten) | |
1173 goto err2; | |
1174 | |
1175 if (touchtime) { | |
1176 SetFileTime(h, NULL, NULL, &((WIN32_FIND_DATAA *)touchtime)->ftLastWriteTime); | |
1177 } | |
1178 if (!CloseHandle(h)) | |
1179 goto err; | |
1180 return 0; | |
1181 | |
1182 err2: | |
1183 CloseHandle(h); | |
1184 err: | |
1185 return 1; | |
1186 #endif | |
1187 } | |
1188 | |
1189 /************************************** | |
1190 */ | |
1191 | |
1192 void File::readv() | |
1193 { | |
1194 if (read()) | |
1195 error("Error reading file '%s'\n",name->toChars()); | |
1196 } | |
1197 | |
1198 /************************************** | |
1199 */ | |
1200 | |
1201 void File::mmreadv() | |
1202 { | |
1203 if (mmread()) | |
1204 readv(); | |
1205 } | |
1206 | |
1207 void File::writev() | |
1208 { | |
1209 if (write()) | |
1210 error("Error writing file '%s'\n",name->toChars()); | |
1211 } | |
1212 | |
1213 void File::appendv() | |
1214 { | |
1215 if (write()) | |
1216 error("Error appending to file '%s'\n",name->toChars()); | |
1217 } | |
1218 | |
1219 /******************************************* | |
1220 * Return !=0 if file exists. | |
1221 * 0: file doesn't exist | |
1222 * 1: normal file | |
1223 * 2: directory | |
1224 */ | |
1225 | |
1226 int File::exists() | |
1227 { | |
1228 #if linux | |
1229 return 0; | |
1230 #endif | |
1231 #if _WIN32 | |
1232 DWORD dw; | |
1233 int result; | |
1234 char *name; | |
1235 | |
1236 name = this->name->toChars(); | |
1237 if (touchtime) | |
1238 dw = ((WIN32_FIND_DATAA *)touchtime)->dwFileAttributes; | |
1239 else | |
1240 dw = GetFileAttributesA(name); | |
1241 if (dw == -1L) | |
1242 result = 0; | |
1243 else if (dw & FILE_ATTRIBUTE_DIRECTORY) | |
1244 result = 2; | |
1245 else | |
1246 result = 1; | |
1247 return result; | |
1248 #endif | |
1249 } | |
1250 | |
1251 void File::remove() | |
1252 { | |
1253 #if linux | |
1254 ::remove(this->name->toChars()); | |
1255 #endif | |
1256 #if _WIN32 | |
1257 DeleteFileA(this->name->toChars()); | |
1258 #endif | |
1259 } | |
1260 | |
1261 Array *File::match(char *n) | |
1262 { | |
1263 return match(new FileName(n, 0)); | |
1264 } | |
1265 | |
1266 Array *File::match(FileName *n) | |
1267 { | |
1268 #if linux | |
1269 return NULL; | |
1270 #endif | |
1271 #if _WIN32 | |
1272 HANDLE h; | |
1273 WIN32_FIND_DATAA fileinfo; | |
1274 Array *a; | |
1275 char *c; | |
1276 char *name; | |
1277 | |
1278 a = new Array(); | |
1279 c = n->toChars(); | |
1280 name = n->name(); | |
1281 h = FindFirstFileA(c,&fileinfo); | |
1282 if (h != INVALID_HANDLE_VALUE) | |
1283 { | |
1284 do | |
1285 { | |
1286 // Glue path together with name | |
1287 char *fn; | |
1288 File *f; | |
1289 | |
1290 fn = (char *)mem.malloc(name - c + strlen(fileinfo.cFileName) + 1); | |
1291 memcpy(fn, c, name - c); | |
1292 strcpy(fn + (name - c), fileinfo.cFileName); | |
1293 f = new File(fn); | |
1294 f->touchtime = mem.malloc(sizeof(WIN32_FIND_DATAA)); | |
1295 memcpy(f->touchtime, &fileinfo, sizeof(fileinfo)); | |
1296 a->push(f); | |
1297 } while (FindNextFileA(h,&fileinfo) != FALSE); | |
1298 FindClose(h); | |
1299 } | |
1300 return a; | |
1301 #endif | |
1302 } | |
1303 | |
1304 int File::compareTime(File *f) | |
1305 { | |
1306 #if linux | |
1307 return 0; | |
1308 #endif | |
1309 #if _WIN32 | |
1310 if (!touchtime) | |
1311 stat(); | |
1312 if (!f->touchtime) | |
1313 f->stat(); | |
1314 return CompareFileTime(&((WIN32_FIND_DATAA *)touchtime)->ftLastWriteTime, &((WIN32_FIND_DATAA *)f->touchtime)->ftLastWriteTime); | |
1315 #endif | |
1316 } | |
1317 | |
1318 void File::stat() | |
1319 { | |
1320 #if linux | |
1321 if (!touchtime) | |
1322 { | |
1323 touchtime = mem.calloc(1, sizeof(struct stat)); | |
1324 } | |
1325 #endif | |
1326 #if _WIN32 | |
1327 HANDLE h; | |
1328 | |
1329 if (!touchtime) | |
1330 { | |
1331 touchtime = mem.calloc(1, sizeof(WIN32_FIND_DATAA)); | |
1332 } | |
1333 h = FindFirstFileA(name->toChars(),(WIN32_FIND_DATAA *)touchtime); | |
1334 if (h != INVALID_HANDLE_VALUE) | |
1335 { | |
1336 FindClose(h); | |
1337 } | |
1338 #endif | |
1339 } | |
1340 | |
1341 void File::checkoffset(size_t offset, size_t nbytes) | |
1342 { | |
1343 if (offset > len || offset + nbytes > len) | |
1344 error("Corrupt file '%s': offset x%"PRIxSIZE" off end of file",toChars(),offset); | |
1345 } | |
1346 | |
1347 char *File::toChars() | |
1348 { | |
1349 return name->toChars(); | |
1350 } | |
1351 | |
1352 | |
1353 /************************* OutBuffer *************************/ | |
1354 | |
1355 OutBuffer::OutBuffer() | |
1356 { | |
1357 data = NULL; | |
1358 offset = 0; | |
1359 size = 0; | |
1360 } | |
1361 | |
1362 OutBuffer::~OutBuffer() | |
1363 { | |
1364 mem.free(data); | |
1365 } | |
1366 | |
1367 void *OutBuffer::extractData() | |
1368 { | |
1369 void *p; | |
1370 | |
1371 p = (void *)data; | |
1372 data = NULL; | |
1373 offset = 0; | |
1374 size = 0; | |
1375 return p; | |
1376 } | |
1377 | |
1378 void OutBuffer::mark() | |
1379 { | |
1380 mem.mark(data); | |
1381 } | |
1382 | |
1383 void OutBuffer::reserve(unsigned nbytes) | |
1384 { | |
1385 //printf("OutBuffer::reserve: size = %d, offset = %d, nbytes = %d\n", size, offset, nbytes); | |
1386 if (size - offset < nbytes) | |
1387 { | |
1388 size = (offset + nbytes) * 2; | |
1389 data = (unsigned char *)mem.realloc(data, size); | |
1390 } | |
1391 } | |
1392 | |
1393 void OutBuffer::reset() | |
1394 { | |
1395 offset = 0; | |
1396 } | |
1397 | |
1398 void OutBuffer::setsize(unsigned size) | |
1399 { | |
1400 offset = size; | |
1401 } | |
1402 | |
1403 void OutBuffer::write(const void *data, unsigned nbytes) | |
1404 { | |
1405 reserve(nbytes); | |
1406 memcpy(this->data + offset, data, nbytes); | |
1407 offset += nbytes; | |
1408 } | |
1409 | |
1410 void OutBuffer::writebstring(unsigned char *string) | |
1411 { | |
1412 write(string,*string + 1); | |
1413 } | |
1414 | |
1415 void OutBuffer::writestring(const char *string) | |
1416 { | |
1417 write(string,strlen(string)); | |
1418 } | |
1419 | |
1420 void OutBuffer::writedstring(const char *string) | |
1421 { | |
1422 #if M_UNICODE | |
1423 for (; *string; string++) | |
1424 { | |
1425 writedchar(*string); | |
1426 } | |
1427 #else | |
1428 write(string,strlen(string)); | |
1429 #endif | |
1430 } | |
1431 | |
1432 void OutBuffer::writedstring(const wchar_t *string) | |
1433 { | |
1434 #if M_UNICODE | |
1435 write(string,wcslen(string) * sizeof(wchar_t)); | |
1436 #else | |
1437 for (; *string; string++) | |
1438 { | |
1439 writedchar(*string); | |
1440 } | |
1441 #endif | |
1442 } | |
1443 | |
1444 void OutBuffer::prependstring(char *string) | |
1445 { unsigned len; | |
1446 | |
1447 len = strlen(string); | |
1448 reserve(len); | |
1449 memmove(data + len, data, offset); | |
1450 memcpy(data, string, len); | |
1451 offset += len; | |
1452 } | |
1453 | |
1454 void OutBuffer::writenl() | |
1455 { | |
1456 #if _WIN32 | |
1457 #if M_UNICODE | |
1458 write4(0x000A000D); // newline is CR,LF on Microsoft OS's | |
1459 #else | |
1460 writeword(0x0A0D); // newline is CR,LF on Microsoft OS's | |
1461 #endif | |
1462 #else | |
1463 #if M_UNICODE | |
1464 writeword('\n'); | |
1465 #else | |
1466 writeByte('\n'); | |
1467 #endif | |
1468 #endif | |
1469 } | |
1470 | |
1471 void OutBuffer::writeByte(unsigned b) | |
1472 { | |
1473 reserve(1); | |
1474 this->data[offset] = (unsigned char)b; | |
1475 offset++; | |
1476 } | |
1477 | |
1478 void OutBuffer::writeUTF8(unsigned b) | |
1479 { | |
1480 reserve(6); | |
1481 if (b <= 0x7F) | |
1482 { | |
1483 this->data[offset] = (unsigned char)b; | |
1484 offset++; | |
1485 } | |
1486 else if (b <= 0x7FF) | |
1487 { | |
1488 this->data[offset + 0] = (unsigned char)((b >> 6) | 0xC0); | |
1489 this->data[offset + 1] = (unsigned char)((b & 0x3F) | 0x80); | |
1490 offset += 2; | |
1491 } | |
1492 else if (b <= 0xFFFF) | |
1493 { | |
1494 this->data[offset + 0] = (unsigned char)((b >> 12) | 0xE0); | |
1495 this->data[offset + 1] = (unsigned char)(((b >> 6) & 0x3F) | 0x80); | |
1496 this->data[offset + 2] = (unsigned char)((b & 0x3F) | 0x80); | |
1497 offset += 3; | |
1498 } | |
1499 else if (b <= 0x1FFFFF) | |
1500 { | |
1501 this->data[offset + 0] = (unsigned char)((b >> 18) | 0xF0); | |
1502 this->data[offset + 1] = (unsigned char)(((b >> 12) & 0x3F) | 0x80); | |
1503 this->data[offset + 2] = (unsigned char)(((b >> 6) & 0x3F) | 0x80); | |
1504 this->data[offset + 3] = (unsigned char)((b & 0x3F) | 0x80); | |
1505 offset += 4; | |
1506 } | |
1507 else if (b <= 0x3FFFFFF) | |
1508 { | |
1509 this->data[offset + 0] = (unsigned char)((b >> 24) | 0xF8); | |
1510 this->data[offset + 1] = (unsigned char)(((b >> 18) & 0x3F) | 0x80); | |
1511 this->data[offset + 2] = (unsigned char)(((b >> 12) & 0x3F) | 0x80); | |
1512 this->data[offset + 3] = (unsigned char)(((b >> 6) & 0x3F) | 0x80); | |
1513 this->data[offset + 4] = (unsigned char)((b & 0x3F) | 0x80); | |
1514 offset += 5; | |
1515 } | |
1516 else if (b <= 0x7FFFFFFF) | |
1517 { | |
1518 this->data[offset + 0] = (unsigned char)((b >> 30) | 0xFC); | |
1519 this->data[offset + 1] = (unsigned char)(((b >> 24) & 0x3F) | 0x80); | |
1520 this->data[offset + 2] = (unsigned char)(((b >> 18) & 0x3F) | 0x80); | |
1521 this->data[offset + 3] = (unsigned char)(((b >> 12) & 0x3F) | 0x80); | |
1522 this->data[offset + 4] = (unsigned char)(((b >> 6) & 0x3F) | 0x80); | |
1523 this->data[offset + 5] = (unsigned char)((b & 0x3F) | 0x80); | |
1524 offset += 6; | |
1525 } | |
1526 else | |
1527 assert(0); | |
1528 } | |
1529 | |
1530 void OutBuffer::writedchar(unsigned b) | |
1531 { | |
1532 reserve(Dchar_mbmax * sizeof(dchar)); | |
1533 offset = (unsigned char *)Dchar::put((dchar *)(this->data + offset), (dchar)b) - | |
1534 this->data; | |
1535 } | |
1536 | |
1537 void OutBuffer::prependbyte(unsigned b) | |
1538 { | |
1539 reserve(1); | |
1540 memmove(data + 1, data, offset); | |
1541 data[0] = (unsigned char)b; | |
1542 offset++; | |
1543 } | |
1544 | |
1545 void OutBuffer::writeword(unsigned w) | |
1546 { | |
1547 reserve(2); | |
1548 *(unsigned short *)(this->data + offset) = (unsigned short)w; | |
1549 offset += 2; | |
1550 } | |
1551 | |
1552 void OutBuffer::writeUTF16(unsigned w) | |
1553 { | |
1554 reserve(4); | |
1555 if (w <= 0xFFFF) | |
1556 { | |
1557 *(unsigned short *)(this->data + offset) = (unsigned short)w; | |
1558 offset += 2; | |
1559 } | |
1560 else if (w <= 0x10FFFF) | |
1561 { | |
1562 *(unsigned short *)(this->data + offset) = (unsigned short)((w >> 10) + 0xD7C0); | |
1563 *(unsigned short *)(this->data + offset + 2) = (unsigned short)((w & 0x3FF) | 0xDC00); | |
1564 offset += 4; | |
1565 } | |
1566 else | |
1567 assert(0); | |
1568 } | |
1569 | |
1570 void OutBuffer::write4(unsigned w) | |
1571 { | |
1572 reserve(4); | |
1573 *(unsigned long *)(this->data + offset) = w; | |
1574 offset += 4; | |
1575 } | |
1576 | |
1577 void OutBuffer::write(OutBuffer *buf) | |
1578 { | |
1579 if (buf) | |
1580 { reserve(buf->offset); | |
1581 memcpy(data + offset, buf->data, buf->offset); | |
1582 offset += buf->offset; | |
1583 } | |
1584 } | |
1585 | |
1586 void OutBuffer::write(Object *obj) | |
1587 { | |
1588 if (obj) | |
1589 { | |
1590 writestring(obj->toChars()); | |
1591 } | |
1592 } | |
1593 | |
1594 void OutBuffer::fill0(unsigned nbytes) | |
1595 { | |
1596 reserve(nbytes); | |
1597 memset(data + offset,0,nbytes); | |
1598 offset += nbytes; | |
1599 } | |
1600 | |
1601 void OutBuffer::align(unsigned size) | |
1602 { unsigned nbytes; | |
1603 | |
1604 nbytes = ((offset + size - 1) & ~(size - 1)) - offset; | |
1605 fill0(nbytes); | |
1606 } | |
1607 | |
1608 void OutBuffer::vprintf(const char *format, va_list args) | |
1609 { | |
1610 char buffer[128]; | |
1611 char *p; | |
1612 unsigned psize; | |
1613 int count; | |
1614 | |
1615 p = buffer; | |
1616 psize = sizeof(buffer); | |
1617 for (;;) | |
1618 { | |
1619 #if _WIN32 | |
1620 count = _vsnprintf(p,psize,format,args); | |
1621 if (count != -1) | |
1622 break; | |
1623 psize *= 2; | |
1624 #endif | |
1625 #if linux | |
1626 count = vsnprintf(p,psize,format,args); | |
1627 if (count == -1) | |
1628 psize *= 2; | |
1629 else if (count >= psize) | |
1630 psize = count + 1; | |
1631 else | |
1632 break; | |
1633 #endif | |
1634 p = (char *) alloca(psize); // buffer too small, try again with larger size | |
1635 } | |
1636 write(p,count); | |
1637 } | |
1638 | |
1639 #if M_UNICODE | |
1640 void OutBuffer::vprintf(const wchar_t *format, va_list args) | |
1641 { | |
1642 dchar buffer[128]; | |
1643 dchar *p; | |
1644 unsigned psize; | |
1645 int count; | |
1646 | |
1647 p = buffer; | |
1648 psize = sizeof(buffer) / sizeof(buffer[0]); | |
1649 for (;;) | |
1650 { | |
1651 #if _WIN32 | |
1652 count = _vsnwprintf(p,psize,format,args); | |
1653 if (count != -1) | |
1654 break; | |
1655 psize *= 2; | |
1656 #endif | |
1657 #if linux | |
1658 count = vsnwprintf(p,psize,format,args); | |
1659 if (count == -1) | |
1660 psize *= 2; | |
1661 else if (count >= psize) | |
1662 psize = count + 1; | |
1663 else | |
1664 break; | |
1665 #endif | |
1666 p = (dchar *) alloca(psize * 2); // buffer too small, try again with larger size | |
1667 } | |
1668 write(p,count * 2); | |
1669 } | |
1670 #endif | |
1671 | |
1672 void OutBuffer::printf(const char *format, ...) | |
1673 { | |
1674 va_list ap; | |
1675 va_start(ap, format); | |
1676 vprintf(format,ap); | |
1677 va_end(ap); | |
1678 } | |
1679 | |
1680 #if M_UNICODE | |
1681 void OutBuffer::printf(const wchar_t *format, ...) | |
1682 { | |
1683 va_list ap; | |
1684 va_start(ap, format); | |
1685 vprintf(format,ap); | |
1686 va_end(ap); | |
1687 } | |
1688 #endif | |
1689 | |
1690 void OutBuffer::bracket(char left, char right) | |
1691 { | |
1692 reserve(2); | |
1693 memmove(data + 1, data, offset); | |
1694 data[0] = left; | |
1695 data[offset + 1] = right; | |
1696 offset += 2; | |
1697 } | |
1698 | |
1699 /****************** | |
1700 * Insert left at i, and right at j. | |
1701 * Return index just past right. | |
1702 */ | |
1703 | |
1704 unsigned OutBuffer::bracket(unsigned i, char *left, unsigned j, char *right) | |
1705 { | |
1706 size_t leftlen = strlen(left); | |
1707 size_t rightlen = strlen(right); | |
1708 reserve(leftlen + rightlen); | |
1709 insert(i, left, leftlen); | |
1710 insert(j + leftlen, right, rightlen); | |
1711 return j + leftlen + rightlen; | |
1712 } | |
1713 | |
1714 void OutBuffer::spread(unsigned offset, unsigned nbytes) | |
1715 { | |
1716 reserve(nbytes); | |
1717 memmove(data + offset + nbytes, data + offset, | |
1718 this->offset - offset); | |
1719 this->offset += nbytes; | |
1720 } | |
1721 | |
1722 /**************************************** | |
1723 * Returns: offset + nbytes | |
1724 */ | |
1725 | |
1726 unsigned OutBuffer::insert(unsigned offset, const void *p, unsigned nbytes) | |
1727 { | |
1728 spread(offset, nbytes); | |
1729 memmove(data + offset, p, nbytes); | |
1730 return offset + nbytes; | |
1731 } | |
1732 | |
1733 void OutBuffer::remove(unsigned offset, unsigned nbytes) | |
1734 { | |
1735 memmove(data + offset, data + offset + nbytes, this->offset - (offset + nbytes)); | |
1736 this->offset -= nbytes; | |
1737 } | |
1738 | |
1739 char *OutBuffer::toChars() | |
1740 { | |
1741 writeByte(0); | |
1742 return (char *)data; | |
1743 } | |
1744 | |
1745 /********************************* Bits ****************************/ | |
1746 | |
1747 Bits::Bits() | |
1748 { | |
1749 data = NULL; | |
1750 bitdim = 0; | |
1751 allocdim = 0; | |
1752 } | |
1753 | |
1754 Bits::~Bits() | |
1755 { | |
1756 mem.free(data); | |
1757 } | |
1758 | |
1759 void Bits::mark() | |
1760 { | |
1761 mem.mark(data); | |
1762 } | |
1763 | |
1764 void Bits::resize(unsigned bitdim) | |
1765 { | |
1766 unsigned allocdim; | |
1767 unsigned mask; | |
1768 | |
1769 allocdim = (bitdim + 31) / 32; | |
1770 data = (unsigned *)mem.realloc(data, allocdim * sizeof(data[0])); | |
1771 if (this->allocdim < allocdim) | |
1772 memset(data + this->allocdim, 0, (allocdim - this->allocdim) * sizeof(data[0])); | |
1773 | |
1774 // Clear other bits in last word | |
1775 mask = (1 << (bitdim & 31)) - 1; | |
1776 if (mask) | |
1777 data[allocdim - 1] &= ~mask; | |
1778 | |
1779 this->bitdim = bitdim; | |
1780 this->allocdim = allocdim; | |
1781 } | |
1782 | |
1783 void Bits::set(unsigned bitnum) | |
1784 { | |
1785 data[bitnum / 32] |= 1 << (bitnum & 31); | |
1786 } | |
1787 | |
1788 void Bits::clear(unsigned bitnum) | |
1789 { | |
1790 data[bitnum / 32] &= ~(1 << (bitnum & 31)); | |
1791 } | |
1792 | |
1793 int Bits::test(unsigned bitnum) | |
1794 { | |
1795 return data[bitnum / 32] & (1 << (bitnum & 31)); | |
1796 } | |
1797 | |
1798 void Bits::set() | |
1799 { unsigned mask; | |
1800 | |
1801 memset(data, ~0, allocdim * sizeof(data[0])); | |
1802 | |
1803 // Clear other bits in last word | |
1804 mask = (1 << (bitdim & 31)) - 1; | |
1805 if (mask) | |
1806 data[allocdim - 1] &= mask; | |
1807 } | |
1808 | |
1809 void Bits::clear() | |
1810 { | |
1811 memset(data, 0, allocdim * sizeof(data[0])); | |
1812 } | |
1813 | |
1814 void Bits::copy(Bits *from) | |
1815 { | |
1816 assert(bitdim == from->bitdim); | |
1817 memcpy(data, from->data, allocdim * sizeof(data[0])); | |
1818 } | |
1819 | |
1820 Bits *Bits::clone() | |
1821 { | |
1822 Bits *b; | |
1823 | |
1824 b = new Bits(); | |
1825 b->resize(bitdim); | |
1826 b->copy(this); | |
1827 return b; | |
1828 } | |
1829 | |
1830 void Bits::sub(Bits *b) | |
1831 { | |
1832 unsigned u; | |
1833 | |
1834 for (u = 0; u < allocdim; u++) | |
1835 data[u] &= ~b->data[u]; | |
1836 } | |
1837 | |
1838 | |
1839 | |
1840 | |
1841 | |
1842 | |
1843 | |
1844 | |
1845 | |
1846 | |
1847 | |
1848 | |
1849 | |
1850 | |
1851 |