Mercurial > projects > ldc
annotate dmd/root.c @ 650:aa6a0b7968f7
Added test case for bug #100
Removed dubious check for not emitting static private global in other modules without access. This should be handled properly somewhere else, it's causing unresolved global errors for stuff that should work (in MiniD)
author | Tomas Lindquist Olsen <tomas.l.olsen@gmail.com> |
---|---|
date | Sun, 05 Oct 2008 17:28:15 +0200 |
parents | cbd6c8073a32 |
children | 50383e476c7e |
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 | |
571
cbd6c8073a32
Changed all '#if linux || __APPLE__' to '#if POSIX' so we can support other platforms too, thanx for the suggestion anders.
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
535
diff
changeset
|
26 #if POSIX |
336 | 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 _WIN32 | |
374 case ';': | |
375 #endif | |
571
cbd6c8073a32
Changed all '#if linux || __APPLE__' to '#if POSIX' so we can support other platforms too, thanx for the suggestion anders.
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
535
diff
changeset
|
376 #if POSIX |
336 | 377 case ':': |
378 #endif | |
379 p++; | |
380 break; // note that ; cannot appear as part | |
381 // of a path, quotes won't protect it | |
382 | |
383 case 0x1A: // ^Z means end of file | |
384 case 0: | |
385 break; | |
386 | |
387 case '\r': | |
388 continue; // ignore carriage returns | |
389 | |
571
cbd6c8073a32
Changed all '#if linux || __APPLE__' to '#if POSIX' so we can support other platforms too, thanx for the suggestion anders.
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
535
diff
changeset
|
390 #if POSIX |
336 | 391 case '~': |
392 buf.writestring(getenv("HOME")); | |
393 continue; | |
394 #endif | |
395 | |
396 case ' ': | |
397 case '\t': // tabs in filenames? | |
398 if (!instring) // if not in string | |
399 break; // treat as end of path | |
400 default: | |
401 buf.writeByte(c); | |
402 continue; | |
403 } | |
404 break; | |
405 } | |
406 if (buf.offset) // if path is not empty | |
407 { | |
408 buf.writeByte(0); // to asciiz | |
409 array->push(buf.extractData()); | |
410 } | |
411 } while (c); | |
412 } | |
413 return array; | |
414 } | |
415 | |
416 hash_t FileName::hashCode() | |
417 { | |
418 #if _WIN32 | |
419 // We need a different hashCode because it must be case-insensitive | |
420 size_t len = strlen(str); | |
421 hash_t hash = 0; | |
422 unsigned char *s = (unsigned char *)str; | |
423 | |
424 for (;;) | |
425 { | |
426 switch (len) | |
427 { | |
428 case 0: | |
429 return hash; | |
430 | |
431 case 1: | |
432 hash *= 37; | |
433 hash += *(uint8_t *)s | 0x20; | |
434 return hash; | |
435 | |
436 case 2: | |
437 hash *= 37; | |
438 hash += *(uint16_t *)s | 0x2020; | |
439 return hash; | |
440 | |
441 case 3: | |
442 hash *= 37; | |
443 hash += ((*(uint16_t *)s << 8) + | |
444 ((uint8_t *)s)[2]) | 0x202020; | |
445 break; | |
446 | |
447 default: | |
448 hash *= 37; | |
449 hash += *(uint32_t *)s | 0x20202020; | |
450 s += 4; | |
451 len -= 4; | |
452 break; | |
453 } | |
454 } | |
455 #else | |
456 // darwin HFS is case insensitive, though... | |
457 return String::hashCode(); | |
458 #endif | |
459 } | |
460 | |
461 int FileName::compare(Object *obj) | |
462 { | |
463 #if _WIN32 | |
464 return stricmp(str,((FileName *)obj)->str); | |
465 #else | |
466 return String::compare(obj); | |
467 #endif | |
468 } | |
469 | |
470 int FileName::equals(Object *obj) | |
471 { | |
472 #if _WIN32 | |
473 return stricmp(str,((FileName *)obj)->str) == 0; | |
474 #else | |
475 return String::equals(obj); | |
476 #endif | |
477 } | |
478 | |
479 /************************************ | |
480 * Return !=0 if absolute path name. | |
481 */ | |
482 | |
483 int FileName::absolute(const char *name) | |
484 { | |
429
6bd99cc5eb08
Allow / as a path separator on Windows.
Christian Kamm <kamm incasoftware de>
parents:
336
diff
changeset
|
485 return |
336 | 486 #if _WIN32 |
429
6bd99cc5eb08
Allow / as a path separator on Windows.
Christian Kamm <kamm incasoftware de>
parents:
336
diff
changeset
|
487 (*name == '\\') || |
6bd99cc5eb08
Allow / as a path separator on Windows.
Christian Kamm <kamm incasoftware de>
parents:
336
diff
changeset
|
488 (*name == '/') || |
6bd99cc5eb08
Allow / as a path separator on Windows.
Christian Kamm <kamm incasoftware de>
parents:
336
diff
changeset
|
489 (*name && name[1] == ':') || |
336 | 490 #endif |
429
6bd99cc5eb08
Allow / as a path separator on Windows.
Christian Kamm <kamm incasoftware de>
parents:
336
diff
changeset
|
491 (*name == '/'); |
336 | 492 } |
493 | |
494 /******************************** | |
495 * Return filename extension (read-only). | |
496 * Points past '.' of extension. | |
497 * If there isn't one, return NULL. | |
498 */ | |
499 | |
500 char *FileName::ext(const char *str) | |
501 { | |
502 char *e; | |
503 size_t len = strlen(str); | |
504 | |
505 e = (char *)str + len; | |
506 for (;;) | |
507 { | |
508 switch (*e) | |
509 { case '.': | |
510 return e + 1; | |
429
6bd99cc5eb08
Allow / as a path separator on Windows.
Christian Kamm <kamm incasoftware de>
parents:
336
diff
changeset
|
511 |
336 | 512 case '/': |
513 break; | |
429
6bd99cc5eb08
Allow / as a path separator on Windows.
Christian Kamm <kamm incasoftware de>
parents:
336
diff
changeset
|
514 |
336 | 515 #if _WIN32 |
516 case '\\': | |
517 case ':': | |
518 break; | |
519 #endif | |
520 default: | |
521 if (e == str) | |
522 break; | |
523 e--; | |
524 continue; | |
525 } | |
526 return NULL; | |
527 } | |
528 } | |
529 | |
530 char *FileName::ext() | |
531 { | |
532 return ext(str); | |
533 } | |
534 | |
535 /******************************** | |
536 * Return mem.malloc'd filename with extension removed. | |
537 */ | |
538 | |
539 char *FileName::removeExt(const char *str) | |
540 { | |
541 const char *e = ext(str); | |
542 if (e) | |
543 { size_t len = (e - str) - 1; | |
544 char *n = (char *)mem.malloc(len + 1); | |
545 memcpy(n, str, len); | |
546 n[len] = 0; | |
547 return n; | |
548 } | |
549 return mem.strdup(str); | |
550 } | |
551 | |
552 /******************************** | |
553 * Return filename name excluding path (read-only). | |
554 */ | |
555 | |
556 char *FileName::name(const char *str) | |
557 { | |
558 char *e; | |
559 size_t len = strlen(str); | |
560 | |
561 e = (char *)str + len; | |
562 for (;;) | |
563 { | |
564 switch (*e) | |
565 { | |
429
6bd99cc5eb08
Allow / as a path separator on Windows.
Christian Kamm <kamm incasoftware de>
parents:
336
diff
changeset
|
566 |
336 | 567 case '/': |
568 return e + 1; | |
429
6bd99cc5eb08
Allow / as a path separator on Windows.
Christian Kamm <kamm incasoftware de>
parents:
336
diff
changeset
|
569 |
336 | 570 #if _WIN32 |
571 case '\\': | |
572 case ':': | |
573 return e + 1; | |
574 #endif | |
575 default: | |
576 if (e == str) | |
577 break; | |
578 e--; | |
579 continue; | |
580 } | |
581 return e; | |
582 } | |
583 } | |
584 | |
585 char *FileName::name() | |
586 { | |
587 return name(str); | |
588 } | |
589 | |
590 /************************************** | |
591 * Return path portion of str. | |
592 * Path will does not include trailing path separator. | |
593 */ | |
594 | |
595 char *FileName::path(const char *str) | |
596 { | |
597 char *n = name(str); | |
598 char *path; | |
599 size_t pathlen; | |
600 | |
601 if (n > str) | |
602 { | |
429
6bd99cc5eb08
Allow / as a path separator on Windows.
Christian Kamm <kamm incasoftware de>
parents:
336
diff
changeset
|
603 |
336 | 604 if (n[-1] == '/') |
605 n--; | |
429
6bd99cc5eb08
Allow / as a path separator on Windows.
Christian Kamm <kamm incasoftware de>
parents:
336
diff
changeset
|
606 |
336 | 607 #if _WIN32 |
608 if (n[-1] == '\\') | |
609 n--; | |
610 #endif | |
611 } | |
612 pathlen = n - str; | |
613 path = (char *)mem.malloc(pathlen + 1); | |
614 memcpy(path, str, pathlen); | |
615 path[pathlen] = 0; | |
616 return path; | |
617 } | |
618 | |
619 /************************************** | |
620 * Replace filename portion of path. | |
621 */ | |
622 | |
623 char *FileName::replaceName(char *path, char *name) | |
624 { char *f; | |
625 char *n; | |
626 size_t pathlen; | |
627 size_t namelen; | |
628 | |
629 if (absolute(name)) | |
630 return name; | |
631 | |
632 n = FileName::name(path); | |
633 if (n == path) | |
634 return name; | |
635 pathlen = n - path; | |
636 namelen = strlen(name); | |
637 f = (char *)mem.malloc(pathlen + 1 + namelen + 1); | |
638 memcpy(f, path, pathlen); | |
429
6bd99cc5eb08
Allow / as a path separator on Windows.
Christian Kamm <kamm incasoftware de>
parents:
336
diff
changeset
|
639 |
431
3dd9ae9ea708
Another fix to DMD's path code.
Christian Kamm <kamm incasoftware de>
parents:
430
diff
changeset
|
640 if ( |
3dd9ae9ea708
Another fix to DMD's path code.
Christian Kamm <kamm incasoftware de>
parents:
430
diff
changeset
|
641 path[pathlen - 1] != '/' |
3dd9ae9ea708
Another fix to DMD's path code.
Christian Kamm <kamm incasoftware de>
parents:
430
diff
changeset
|
642 #if _WIN32 |
3dd9ae9ea708
Another fix to DMD's path code.
Christian Kamm <kamm incasoftware de>
parents:
430
diff
changeset
|
643 && path[pathlen - 1] != '\\' && path[pathlen - 1] != ':' |
3dd9ae9ea708
Another fix to DMD's path code.
Christian Kamm <kamm incasoftware de>
parents:
430
diff
changeset
|
644 #endif |
3dd9ae9ea708
Another fix to DMD's path code.
Christian Kamm <kamm incasoftware de>
parents:
430
diff
changeset
|
645 ) |
336 | 646 { f[pathlen] = '/'; |
647 pathlen++; | |
648 } | |
429
6bd99cc5eb08
Allow / as a path separator on Windows.
Christian Kamm <kamm incasoftware de>
parents:
336
diff
changeset
|
649 |
336 | 650 memcpy(f + pathlen, name, namelen + 1); |
651 return f; | |
652 } | |
653 | |
654 /*************************** | |
655 */ | |
656 | |
657 FileName *FileName::defaultExt(const char *name, const char *ext) | |
658 { | |
659 char *e; | |
660 char *s; | |
661 size_t len; | |
662 size_t extlen; | |
663 | |
664 e = FileName::ext(name); | |
665 if (e) // if already has an extension | |
666 return new FileName((char *)name, 0); | |
667 | |
668 len = strlen(name); | |
669 extlen = strlen(ext); | |
670 s = (char *)alloca(len + 1 + extlen + 1); | |
671 memcpy(s,name,len); | |
672 s[len] = '.'; | |
673 memcpy(s + len + 1, ext, extlen + 1); | |
674 return new FileName(s, 0); | |
675 } | |
676 | |
677 /*************************** | |
678 */ | |
679 | |
680 FileName *FileName::forceExt(const char *name, const char *ext) | |
681 { | |
682 char *e; | |
683 char *s; | |
684 size_t len; | |
685 size_t extlen; | |
686 | |
687 e = FileName::ext(name); | |
688 if (e) // if already has an extension | |
689 { | |
690 len = e - name; | |
691 extlen = strlen(ext); | |
692 | |
693 s = (char *)alloca(len + extlen + 1); | |
694 memcpy(s,name,len); | |
695 memcpy(s + len, ext, extlen + 1); | |
696 return new FileName(s, 0); | |
697 } | |
698 else | |
699 return defaultExt(name, ext); // doesn't have one | |
700 } | |
701 | |
702 /****************************** | |
703 * Return !=0 if extensions match. | |
704 */ | |
705 | |
706 int FileName::equalsExt(const char *ext) | |
707 { const char *e; | |
708 | |
709 e = FileName::ext(); | |
710 if (!e && !ext) | |
711 return 1; | |
712 if (!e || !ext) | |
713 return 0; | |
571
cbd6c8073a32
Changed all '#if linux || __APPLE__' to '#if POSIX' so we can support other platforms too, thanx for the suggestion anders.
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
535
diff
changeset
|
714 #if POSIX |
336 | 715 return strcmp(e,ext) == 0; |
716 #endif | |
717 #if _WIN32 | |
718 return stricmp(e,ext) == 0; | |
719 #endif | |
720 } | |
721 | |
722 /************************************* | |
723 * Copy file from this to to. | |
724 */ | |
725 | |
726 void FileName::CopyTo(FileName *to) | |
727 { | |
728 File file(this); | |
729 | |
730 #if _WIN32 | |
731 file.touchtime = mem.malloc(sizeof(WIN32_FIND_DATAA)); // keep same file time | |
732 #endif | |
571
cbd6c8073a32
Changed all '#if linux || __APPLE__' to '#if POSIX' so we can support other platforms too, thanx for the suggestion anders.
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
535
diff
changeset
|
733 #if POSIX |
336 | 734 file.touchtime = mem.malloc(sizeof(struct stat)); // keep same file time |
735 #endif | |
736 file.readv(); | |
737 file.name = to; | |
738 file.writev(); | |
739 } | |
740 | |
741 /************************************* | |
742 * Search Path for file. | |
743 * Input: | |
744 * cwd if !=0, search current directory before searching path | |
745 */ | |
746 | |
747 char *FileName::searchPath(Array *path, char *name, int cwd) | |
748 { | |
749 if (absolute(name)) | |
750 { | |
751 return exists(name) ? name : NULL; | |
752 } | |
753 if (cwd) | |
754 { | |
755 if (exists(name)) | |
756 return name; | |
757 } | |
758 if (path) | |
759 { unsigned i; | |
760 | |
761 for (i = 0; i < path->dim; i++) | |
762 { | |
763 char *p = (char *)path->data[i]; | |
764 char *n = combine(p, name); | |
765 | |
766 if (exists(n)) | |
767 return n; | |
768 } | |
769 } | |
770 return NULL; | |
771 } | |
772 | |
773 int FileName::exists(const char *name) | |
774 { | |
571
cbd6c8073a32
Changed all '#if linux || __APPLE__' to '#if POSIX' so we can support other platforms too, thanx for the suggestion anders.
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
535
diff
changeset
|
775 #if POSIX |
336 | 776 struct stat st; |
777 | |
778 if (stat(name, &st) < 0) | |
779 return 0; | |
780 if (S_ISDIR(st.st_mode)) | |
781 return 2; | |
782 return 1; | |
783 #endif | |
784 #if _WIN32 | |
785 DWORD dw; | |
786 int result; | |
787 | |
788 dw = GetFileAttributesA(name); | |
789 if (dw == -1L) | |
790 result = 0; | |
791 else if (dw & FILE_ATTRIBUTE_DIRECTORY) | |
792 result = 2; | |
793 else | |
794 result = 1; | |
795 return result; | |
796 #endif | |
797 } | |
798 | |
799 void FileName::ensurePathExists(const char *path) | |
800 { | |
801 //printf("FileName::ensurePathExists(%s)\n", path ? path : ""); | |
802 if (path && *path) | |
803 { | |
804 if (!exists(path)) | |
805 { | |
806 char *p = FileName::path(path); | |
807 if (*p) | |
808 { | |
809 #if _WIN32 | |
810 size_t len = strlen(p); | |
811 if (len > 2 && p[-1] == ':') | |
812 { mem.free(p); | |
813 return; | |
814 } | |
815 #endif | |
816 ensurePathExists(p); | |
817 mem.free(p); | |
818 } | |
819 #if _WIN32 | |
820 if (path[strlen(path) - 1] != '\\') | |
821 #endif | |
571
cbd6c8073a32
Changed all '#if linux || __APPLE__' to '#if POSIX' so we can support other platforms too, thanx for the suggestion anders.
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
535
diff
changeset
|
822 #if POSIX |
336 | 823 if (path[strlen(path) - 1] != '\\') |
824 #endif | |
825 { | |
826 //printf("mkdir(%s)\n", path); | |
827 #if _WIN32 | |
828 if (mkdir(path)) | |
829 #endif | |
571
cbd6c8073a32
Changed all '#if linux || __APPLE__' to '#if POSIX' so we can support other platforms too, thanx for the suggestion anders.
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
535
diff
changeset
|
830 #if POSIX |
336 | 831 if (mkdir(path, 0777)) |
832 #endif | |
833 error("cannot create directory %s", path); | |
834 } | |
835 } | |
836 } | |
837 } | |
838 | |
839 /****************************** File ********************************/ | |
840 | |
841 File::File(FileName *n) | |
842 { | |
843 ref = 0; | |
844 buffer = NULL; | |
845 len = 0; | |
846 touchtime = NULL; | |
847 name = n; | |
848 } | |
849 | |
850 File::File(char *n) | |
851 { | |
852 ref = 0; | |
853 buffer = NULL; | |
854 len = 0; | |
855 touchtime = NULL; | |
856 name = new FileName(n, 0); | |
857 } | |
858 | |
859 File::~File() | |
860 { | |
861 if (buffer) | |
862 { | |
863 if (ref == 0) | |
864 mem.free(buffer); | |
865 #if _WIN32 | |
866 else if (ref == 2) | |
867 UnmapViewOfFile(buffer); | |
868 #endif | |
869 } | |
870 if (touchtime) | |
871 mem.free(touchtime); | |
872 } | |
873 | |
874 void File::mark() | |
875 { | |
876 mem.mark(buffer); | |
877 mem.mark(touchtime); | |
878 mem.mark(name); | |
879 } | |
880 | |
881 /************************************* | |
882 */ | |
883 | |
884 int File::read() | |
885 { | |
571
cbd6c8073a32
Changed all '#if linux || __APPLE__' to '#if POSIX' so we can support other platforms too, thanx for the suggestion anders.
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
535
diff
changeset
|
886 #if POSIX |
336 | 887 off_t size; |
888 ssize_t numread; | |
889 int fd; | |
890 struct stat buf; | |
891 int result = 0; | |
892 char *name; | |
893 | |
894 name = this->name->toChars(); | |
895 //printf("File::read('%s')\n",name); | |
896 fd = open(name, O_RDONLY); | |
897 if (fd == -1) | |
898 { result = errno; | |
899 //printf("\topen error, errno = %d\n",errno); | |
900 goto err1; | |
901 } | |
902 | |
903 if (!ref) | |
904 mem.free(buffer); | |
905 ref = 0; // we own the buffer now | |
906 | |
907 //printf("\tfile opened\n"); | |
908 if (fstat(fd, &buf)) | |
909 { | |
910 printf("\tfstat error, errno = %d\n",errno); | |
911 goto err2; | |
912 } | |
913 size = buf.st_size; | |
914 buffer = (unsigned char *) mem.malloc(size + 2); | |
915 if (!buffer) | |
916 { | |
917 printf("\tmalloc error, errno = %d\n",errno); | |
918 goto err2; | |
919 } | |
920 | |
921 numread = ::read(fd, buffer, size); | |
922 if (numread != size) | |
923 { | |
924 printf("\tread error, errno = %d\n",errno); | |
925 goto err2; | |
926 } | |
927 | |
928 if (touchtime) | |
929 memcpy(touchtime, &buf, sizeof(buf)); | |
930 | |
931 if (close(fd) == -1) | |
932 { | |
933 printf("\tclose error, errno = %d\n",errno); | |
934 goto err; | |
935 } | |
936 | |
937 len = size; | |
938 | |
939 // Always store a wchar ^Z past end of buffer so scanner has a sentinel | |
940 buffer[size] = 0; // ^Z is obsolete, use 0 | |
941 buffer[size + 1] = 0; | |
942 return 0; | |
943 | |
944 err2: | |
945 close(fd); | |
946 err: | |
947 mem.free(buffer); | |
948 buffer = NULL; | |
949 len = 0; | |
950 | |
951 err1: | |
952 result = 1; | |
953 return result; | |
954 #endif | |
955 #if _WIN32 | |
956 DWORD size; | |
957 DWORD numread; | |
958 HANDLE h; | |
959 int result = 0; | |
960 char *name; | |
961 | |
962 name = this->name->toChars(); | |
963 h = CreateFileA(name,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING, | |
964 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,0); | |
965 if (h == INVALID_HANDLE_VALUE) | |
966 goto err1; | |
967 | |
968 if (!ref) | |
969 mem.free(buffer); | |
970 ref = 0; | |
971 | |
972 size = GetFileSize(h,NULL); | |
973 buffer = (unsigned char *) mem.malloc(size + 2); | |
974 if (!buffer) | |
975 goto err2; | |
976 | |
977 if (ReadFile(h,buffer,size,&numread,NULL) != TRUE) | |
978 goto err2; | |
979 | |
980 if (numread != size) | |
981 goto err2; | |
982 | |
983 if (touchtime) | |
984 { | |
985 if (!GetFileTime(h, NULL, NULL, &((WIN32_FIND_DATAA *)touchtime)->ftLastWriteTime)) | |
986 goto err2; | |
987 } | |
988 | |
989 if (!CloseHandle(h)) | |
990 goto err; | |
991 | |
992 len = size; | |
993 | |
994 // Always store a wchar ^Z past end of buffer so scanner has a sentinel | |
995 buffer[size] = 0; // ^Z is obsolete, use 0 | |
996 buffer[size + 1] = 0; | |
997 return 0; | |
998 | |
999 err2: | |
1000 CloseHandle(h); | |
1001 err: | |
1002 mem.free(buffer); | |
1003 buffer = NULL; | |
1004 len = 0; | |
1005 | |
1006 err1: | |
1007 result = 1; | |
1008 return result; | |
1009 #endif | |
1010 } | |
1011 | |
1012 /***************************** | |
1013 * Read a file with memory mapped file I/O. | |
1014 */ | |
1015 | |
1016 int File::mmread() | |
1017 { | |
571
cbd6c8073a32
Changed all '#if linux || __APPLE__' to '#if POSIX' so we can support other platforms too, thanx for the suggestion anders.
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
535
diff
changeset
|
1018 #if POSIX |
336 | 1019 return read(); |
1020 #endif | |
1021 #if _WIN32 | |
1022 HANDLE hFile; | |
1023 HANDLE hFileMap; | |
1024 DWORD size; | |
1025 char *name; | |
1026 | |
1027 name = this->name->toChars(); | |
1028 hFile = CreateFile(name, GENERIC_READ, | |
1029 FILE_SHARE_READ, NULL, | |
1030 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); | |
1031 if (hFile == INVALID_HANDLE_VALUE) | |
1032 goto Lerr; | |
1033 size = GetFileSize(hFile, NULL); | |
1034 //printf(" file created, size %d\n", size); | |
1035 | |
1036 hFileMap = CreateFileMapping(hFile,NULL,PAGE_READONLY,0,size,NULL); | |
1037 if (CloseHandle(hFile) != TRUE) | |
1038 goto Lerr; | |
1039 | |
1040 if (hFileMap == NULL) | |
1041 goto Lerr; | |
1042 | |
1043 //printf(" mapping created\n"); | |
1044 | |
1045 if (!ref) | |
1046 mem.free(buffer); | |
1047 ref = 2; | |
1048 buffer = (unsigned char *)MapViewOfFileEx(hFileMap, FILE_MAP_READ,0,0,size,NULL); | |
1049 if (CloseHandle(hFileMap) != TRUE) | |
1050 goto Lerr; | |
1051 if (buffer == NULL) // mapping view failed | |
1052 goto Lerr; | |
1053 | |
1054 len = size; | |
1055 //printf(" buffer = %p\n", buffer); | |
1056 | |
1057 return 0; | |
1058 | |
1059 Lerr: | |
1060 return GetLastError(); // failure | |
1061 #endif | |
1062 } | |
1063 | |
1064 /********************************************* | |
1065 * Write a file. | |
1066 * Returns: | |
1067 * 0 success | |
1068 */ | |
1069 | |
1070 int File::write() | |
1071 { | |
571
cbd6c8073a32
Changed all '#if linux || __APPLE__' to '#if POSIX' so we can support other platforms too, thanx for the suggestion anders.
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
535
diff
changeset
|
1072 #if POSIX |
336 | 1073 int fd; |
1074 ssize_t numwritten; | |
1075 char *name; | |
1076 | |
1077 name = this->name->toChars(); | |
1078 fd = open(name, O_CREAT | O_WRONLY | O_TRUNC, 0644); | |
1079 if (fd == -1) | |
1080 goto err; | |
1081 | |
1082 numwritten = ::write(fd, buffer, len); | |
1083 if (len != numwritten) | |
1084 goto err2; | |
1085 | |
1086 if (close(fd) == -1) | |
1087 goto err; | |
1088 | |
1089 if (touchtime) | |
1090 { struct utimbuf ubuf; | |
1091 | |
1092 ubuf.actime = ((struct stat *)touchtime)->st_atime; | |
1093 ubuf.modtime = ((struct stat *)touchtime)->st_mtime; | |
1094 if (utime(name, &ubuf)) | |
1095 goto err; | |
1096 } | |
1097 return 0; | |
1098 | |
1099 err2: | |
1100 close(fd); | |
1101 ::remove(name); | |
1102 err: | |
1103 return 1; | |
1104 #endif | |
1105 #if _WIN32 | |
1106 HANDLE h; | |
1107 DWORD numwritten; | |
1108 char *name; | |
1109 | |
1110 name = this->name->toChars(); | |
1111 h = CreateFileA(name,GENERIC_WRITE,0,NULL,CREATE_ALWAYS, | |
1112 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,NULL); | |
1113 if (h == INVALID_HANDLE_VALUE) | |
1114 goto err; | |
1115 | |
1116 if (WriteFile(h,buffer,len,&numwritten,NULL) != TRUE) | |
1117 goto err2; | |
1118 | |
1119 if (len != numwritten) | |
1120 goto err2; | |
1121 | |
1122 if (touchtime) { | |
1123 SetFileTime(h, NULL, NULL, &((WIN32_FIND_DATAA *)touchtime)->ftLastWriteTime); | |
1124 } | |
1125 if (!CloseHandle(h)) | |
1126 goto err; | |
1127 return 0; | |
1128 | |
1129 err2: | |
1130 CloseHandle(h); | |
1131 DeleteFileA(name); | |
1132 err: | |
1133 return 1; | |
1134 #endif | |
1135 } | |
1136 | |
1137 /********************************************* | |
1138 * Append to a file. | |
1139 * Returns: | |
1140 * 0 success | |
1141 */ | |
1142 | |
1143 int File::append() | |
1144 { | |
571
cbd6c8073a32
Changed all '#if linux || __APPLE__' to '#if POSIX' so we can support other platforms too, thanx for the suggestion anders.
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
535
diff
changeset
|
1145 #if POSIX |
336 | 1146 return 1; |
1147 #endif | |
1148 #if _WIN32 | |
1149 HANDLE h; | |
1150 DWORD numwritten; | |
1151 char *name; | |
1152 | |
1153 name = this->name->toChars(); | |
1154 h = CreateFileA(name,GENERIC_WRITE,0,NULL,OPEN_ALWAYS, | |
1155 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,NULL); | |
1156 if (h == INVALID_HANDLE_VALUE) | |
1157 goto err; | |
1158 | |
1159 #if 1 | |
1160 SetFilePointer(h, 0, NULL, FILE_END); | |
1161 #else // INVALID_SET_FILE_POINTER doesn't seem to have a definition | |
1162 if (SetFilePointer(h, 0, NULL, FILE_END) == INVALID_SET_FILE_POINTER) | |
1163 goto err; | |
1164 #endif | |
1165 | |
1166 if (WriteFile(h,buffer,len,&numwritten,NULL) != TRUE) | |
1167 goto err2; | |
1168 | |
1169 if (len != numwritten) | |
1170 goto err2; | |
1171 | |
1172 if (touchtime) { | |
1173 SetFileTime(h, NULL, NULL, &((WIN32_FIND_DATAA *)touchtime)->ftLastWriteTime); | |
1174 } | |
1175 if (!CloseHandle(h)) | |
1176 goto err; | |
1177 return 0; | |
1178 | |
1179 err2: | |
1180 CloseHandle(h); | |
1181 err: | |
1182 return 1; | |
1183 #endif | |
1184 } | |
1185 | |
1186 /************************************** | |
1187 */ | |
1188 | |
1189 void File::readv() | |
1190 { | |
1191 if (read()) | |
1192 error("Error reading file '%s'\n",name->toChars()); | |
1193 } | |
1194 | |
1195 /************************************** | |
1196 */ | |
1197 | |
1198 void File::mmreadv() | |
1199 { | |
1200 if (mmread()) | |
1201 readv(); | |
1202 } | |
1203 | |
1204 void File::writev() | |
1205 { | |
1206 if (write()) | |
1207 error("Error writing file '%s'\n",name->toChars()); | |
1208 } | |
1209 | |
1210 void File::appendv() | |
1211 { | |
1212 if (write()) | |
1213 error("Error appending to file '%s'\n",name->toChars()); | |
1214 } | |
1215 | |
1216 /******************************************* | |
1217 * Return !=0 if file exists. | |
1218 * 0: file doesn't exist | |
1219 * 1: normal file | |
1220 * 2: directory | |
1221 */ | |
1222 | |
1223 int File::exists() | |
1224 { | |
571
cbd6c8073a32
Changed all '#if linux || __APPLE__' to '#if POSIX' so we can support other platforms too, thanx for the suggestion anders.
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
535
diff
changeset
|
1225 #if POSIX |
336 | 1226 return 0; |
1227 #endif | |
1228 #if _WIN32 | |
1229 DWORD dw; | |
1230 int result; | |
1231 char *name; | |
1232 | |
1233 name = this->name->toChars(); | |
1234 if (touchtime) | |
1235 dw = ((WIN32_FIND_DATAA *)touchtime)->dwFileAttributes; | |
1236 else | |
1237 dw = GetFileAttributesA(name); | |
1238 if (dw == -1L) | |
1239 result = 0; | |
1240 else if (dw & FILE_ATTRIBUTE_DIRECTORY) | |
1241 result = 2; | |
1242 else | |
1243 result = 1; | |
1244 return result; | |
1245 #endif | |
1246 } | |
1247 | |
1248 void File::remove() | |
1249 { | |
571
cbd6c8073a32
Changed all '#if linux || __APPLE__' to '#if POSIX' so we can support other platforms too, thanx for the suggestion anders.
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
535
diff
changeset
|
1250 #if POSIX |
336 | 1251 ::remove(this->name->toChars()); |
1252 #endif | |
1253 #if _WIN32 | |
1254 DeleteFileA(this->name->toChars()); | |
1255 #endif | |
1256 } | |
1257 | |
1258 Array *File::match(char *n) | |
1259 { | |
1260 return match(new FileName(n, 0)); | |
1261 } | |
1262 | |
1263 Array *File::match(FileName *n) | |
1264 { | |
571
cbd6c8073a32
Changed all '#if linux || __APPLE__' to '#if POSIX' so we can support other platforms too, thanx for the suggestion anders.
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
535
diff
changeset
|
1265 #if POSIX |
336 | 1266 return NULL; |
1267 #endif | |
1268 #if _WIN32 | |
1269 HANDLE h; | |
1270 WIN32_FIND_DATAA fileinfo; | |
1271 Array *a; | |
1272 char *c; | |
1273 char *name; | |
1274 | |
1275 a = new Array(); | |
1276 c = n->toChars(); | |
1277 name = n->name(); | |
1278 h = FindFirstFileA(c,&fileinfo); | |
1279 if (h != INVALID_HANDLE_VALUE) | |
1280 { | |
1281 do | |
1282 { | |
1283 // Glue path together with name | |
1284 char *fn; | |
1285 File *f; | |
1286 | |
1287 fn = (char *)mem.malloc(name - c + strlen(fileinfo.cFileName) + 1); | |
1288 memcpy(fn, c, name - c); | |
1289 strcpy(fn + (name - c), fileinfo.cFileName); | |
1290 f = new File(fn); | |
1291 f->touchtime = mem.malloc(sizeof(WIN32_FIND_DATAA)); | |
1292 memcpy(f->touchtime, &fileinfo, sizeof(fileinfo)); | |
1293 a->push(f); | |
1294 } while (FindNextFileA(h,&fileinfo) != FALSE); | |
1295 FindClose(h); | |
1296 } | |
1297 return a; | |
1298 #endif | |
1299 } | |
1300 | |
1301 int File::compareTime(File *f) | |
1302 { | |
571
cbd6c8073a32
Changed all '#if linux || __APPLE__' to '#if POSIX' so we can support other platforms too, thanx for the suggestion anders.
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
535
diff
changeset
|
1303 #if POSIX |
336 | 1304 return 0; |
1305 #endif | |
1306 #if _WIN32 | |
1307 if (!touchtime) | |
1308 stat(); | |
1309 if (!f->touchtime) | |
1310 f->stat(); | |
1311 return CompareFileTime(&((WIN32_FIND_DATAA *)touchtime)->ftLastWriteTime, &((WIN32_FIND_DATAA *)f->touchtime)->ftLastWriteTime); | |
1312 #endif | |
1313 } | |
1314 | |
1315 void File::stat() | |
1316 { | |
571
cbd6c8073a32
Changed all '#if linux || __APPLE__' to '#if POSIX' so we can support other platforms too, thanx for the suggestion anders.
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
535
diff
changeset
|
1317 #if POSIX |
336 | 1318 if (!touchtime) |
1319 { | |
1320 touchtime = mem.calloc(1, sizeof(struct stat)); | |
1321 } | |
1322 #endif | |
1323 #if _WIN32 | |
1324 HANDLE h; | |
1325 | |
1326 if (!touchtime) | |
1327 { | |
1328 touchtime = mem.calloc(1, sizeof(WIN32_FIND_DATAA)); | |
1329 } | |
1330 h = FindFirstFileA(name->toChars(),(WIN32_FIND_DATAA *)touchtime); | |
1331 if (h != INVALID_HANDLE_VALUE) | |
1332 { | |
1333 FindClose(h); | |
1334 } | |
1335 #endif | |
1336 } | |
1337 | |
1338 void File::checkoffset(size_t offset, size_t nbytes) | |
1339 { | |
1340 if (offset > len || offset + nbytes > len) | |
1341 error("Corrupt file '%s': offset x%"PRIxSIZE" off end of file",toChars(),offset); | |
1342 } | |
1343 | |
1344 char *File::toChars() | |
1345 { | |
1346 return name->toChars(); | |
1347 } | |
1348 | |
1349 | |
1350 /************************* OutBuffer *************************/ | |
1351 | |
1352 OutBuffer::OutBuffer() | |
1353 { | |
1354 data = NULL; | |
1355 offset = 0; | |
1356 size = 0; | |
1357 } | |
1358 | |
1359 OutBuffer::~OutBuffer() | |
1360 { | |
1361 mem.free(data); | |
1362 } | |
1363 | |
1364 void *OutBuffer::extractData() | |
1365 { | |
1366 void *p; | |
1367 | |
1368 p = (void *)data; | |
1369 data = NULL; | |
1370 offset = 0; | |
1371 size = 0; | |
1372 return p; | |
1373 } | |
1374 | |
1375 void OutBuffer::mark() | |
1376 { | |
1377 mem.mark(data); | |
1378 } | |
1379 | |
1380 void OutBuffer::reserve(unsigned nbytes) | |
1381 { | |
1382 //printf("OutBuffer::reserve: size = %d, offset = %d, nbytes = %d\n", size, offset, nbytes); | |
1383 if (size - offset < nbytes) | |
1384 { | |
1385 size = (offset + nbytes) * 2; | |
1386 data = (unsigned char *)mem.realloc(data, size); | |
1387 } | |
1388 } | |
1389 | |
1390 void OutBuffer::reset() | |
1391 { | |
1392 offset = 0; | |
1393 } | |
1394 | |
1395 void OutBuffer::setsize(unsigned size) | |
1396 { | |
1397 offset = size; | |
1398 } | |
1399 | |
1400 void OutBuffer::write(const void *data, unsigned nbytes) | |
1401 { | |
1402 reserve(nbytes); | |
1403 memcpy(this->data + offset, data, nbytes); | |
1404 offset += nbytes; | |
1405 } | |
1406 | |
1407 void OutBuffer::writebstring(unsigned char *string) | |
1408 { | |
1409 write(string,*string + 1); | |
1410 } | |
1411 | |
1412 void OutBuffer::writestring(const char *string) | |
1413 { | |
1414 write(string,strlen(string)); | |
1415 } | |
1416 | |
1417 void OutBuffer::writedstring(const char *string) | |
1418 { | |
1419 #if M_UNICODE | |
1420 for (; *string; string++) | |
1421 { | |
1422 writedchar(*string); | |
1423 } | |
1424 #else | |
1425 write(string,strlen(string)); | |
1426 #endif | |
1427 } | |
1428 | |
1429 void OutBuffer::writedstring(const wchar_t *string) | |
1430 { | |
1431 #if M_UNICODE | |
1432 write(string,wcslen(string) * sizeof(wchar_t)); | |
1433 #else | |
1434 for (; *string; string++) | |
1435 { | |
1436 writedchar(*string); | |
1437 } | |
1438 #endif | |
1439 } | |
1440 | |
1441 void OutBuffer::prependstring(char *string) | |
1442 { unsigned len; | |
1443 | |
1444 len = strlen(string); | |
1445 reserve(len); | |
1446 memmove(data + len, data, offset); | |
1447 memcpy(data, string, len); | |
1448 offset += len; | |
1449 } | |
1450 | |
1451 void OutBuffer::writenl() | |
1452 { | |
1453 #if _WIN32 | |
1454 #if M_UNICODE | |
1455 write4(0x000A000D); // newline is CR,LF on Microsoft OS's | |
1456 #else | |
1457 writeword(0x0A0D); // newline is CR,LF on Microsoft OS's | |
1458 #endif | |
1459 #else | |
1460 #if M_UNICODE | |
1461 writeword('\n'); | |
1462 #else | |
1463 writeByte('\n'); | |
1464 #endif | |
1465 #endif | |
1466 } | |
1467 | |
1468 void OutBuffer::writeByte(unsigned b) | |
1469 { | |
1470 reserve(1); | |
1471 this->data[offset] = (unsigned char)b; | |
1472 offset++; | |
1473 } | |
1474 | |
1475 void OutBuffer::writeUTF8(unsigned b) | |
1476 { | |
1477 reserve(6); | |
1478 if (b <= 0x7F) | |
1479 { | |
1480 this->data[offset] = (unsigned char)b; | |
1481 offset++; | |
1482 } | |
1483 else if (b <= 0x7FF) | |
1484 { | |
1485 this->data[offset + 0] = (unsigned char)((b >> 6) | 0xC0); | |
1486 this->data[offset + 1] = (unsigned char)((b & 0x3F) | 0x80); | |
1487 offset += 2; | |
1488 } | |
1489 else if (b <= 0xFFFF) | |
1490 { | |
1491 this->data[offset + 0] = (unsigned char)((b >> 12) | 0xE0); | |
1492 this->data[offset + 1] = (unsigned char)(((b >> 6) & 0x3F) | 0x80); | |
1493 this->data[offset + 2] = (unsigned char)((b & 0x3F) | 0x80); | |
1494 offset += 3; | |
1495 } | |
1496 else if (b <= 0x1FFFFF) | |
1497 { | |
1498 this->data[offset + 0] = (unsigned char)((b >> 18) | 0xF0); | |
1499 this->data[offset + 1] = (unsigned char)(((b >> 12) & 0x3F) | 0x80); | |
1500 this->data[offset + 2] = (unsigned char)(((b >> 6) & 0x3F) | 0x80); | |
1501 this->data[offset + 3] = (unsigned char)((b & 0x3F) | 0x80); | |
1502 offset += 4; | |
1503 } | |
1504 else if (b <= 0x3FFFFFF) | |
1505 { | |
1506 this->data[offset + 0] = (unsigned char)((b >> 24) | 0xF8); | |
1507 this->data[offset + 1] = (unsigned char)(((b >> 18) & 0x3F) | 0x80); | |
1508 this->data[offset + 2] = (unsigned char)(((b >> 12) & 0x3F) | 0x80); | |
1509 this->data[offset + 3] = (unsigned char)(((b >> 6) & 0x3F) | 0x80); | |
1510 this->data[offset + 4] = (unsigned char)((b & 0x3F) | 0x80); | |
1511 offset += 5; | |
1512 } | |
1513 else if (b <= 0x7FFFFFFF) | |
1514 { | |
1515 this->data[offset + 0] = (unsigned char)((b >> 30) | 0xFC); | |
1516 this->data[offset + 1] = (unsigned char)(((b >> 24) & 0x3F) | 0x80); | |
1517 this->data[offset + 2] = (unsigned char)(((b >> 18) & 0x3F) | 0x80); | |
1518 this->data[offset + 3] = (unsigned char)(((b >> 12) & 0x3F) | 0x80); | |
1519 this->data[offset + 4] = (unsigned char)(((b >> 6) & 0x3F) | 0x80); | |
1520 this->data[offset + 5] = (unsigned char)((b & 0x3F) | 0x80); | |
1521 offset += 6; | |
1522 } | |
1523 else | |
1524 assert(0); | |
1525 } | |
1526 | |
1527 void OutBuffer::writedchar(unsigned b) | |
1528 { | |
1529 reserve(Dchar_mbmax * sizeof(dchar)); | |
1530 offset = (unsigned char *)Dchar::put((dchar *)(this->data + offset), (dchar)b) - | |
1531 this->data; | |
1532 } | |
1533 | |
1534 void OutBuffer::prependbyte(unsigned b) | |
1535 { | |
1536 reserve(1); | |
1537 memmove(data + 1, data, offset); | |
1538 data[0] = (unsigned char)b; | |
1539 offset++; | |
1540 } | |
1541 | |
1542 void OutBuffer::writeword(unsigned w) | |
1543 { | |
1544 reserve(2); | |
1545 *(unsigned short *)(this->data + offset) = (unsigned short)w; | |
1546 offset += 2; | |
1547 } | |
1548 | |
1549 void OutBuffer::writeUTF16(unsigned w) | |
1550 { | |
1551 reserve(4); | |
1552 if (w <= 0xFFFF) | |
1553 { | |
1554 *(unsigned short *)(this->data + offset) = (unsigned short)w; | |
1555 offset += 2; | |
1556 } | |
1557 else if (w <= 0x10FFFF) | |
1558 { | |
1559 *(unsigned short *)(this->data + offset) = (unsigned short)((w >> 10) + 0xD7C0); | |
1560 *(unsigned short *)(this->data + offset + 2) = (unsigned short)((w & 0x3FF) | 0xDC00); | |
1561 offset += 4; | |
1562 } | |
1563 else | |
1564 assert(0); | |
1565 } | |
1566 | |
1567 void OutBuffer::write4(unsigned w) | |
1568 { | |
1569 reserve(4); | |
1570 *(unsigned long *)(this->data + offset) = w; | |
1571 offset += 4; | |
1572 } | |
1573 | |
1574 void OutBuffer::write(OutBuffer *buf) | |
1575 { | |
1576 if (buf) | |
1577 { reserve(buf->offset); | |
1578 memcpy(data + offset, buf->data, buf->offset); | |
1579 offset += buf->offset; | |
1580 } | |
1581 } | |
1582 | |
1583 void OutBuffer::write(Object *obj) | |
1584 { | |
1585 if (obj) | |
1586 { | |
1587 writestring(obj->toChars()); | |
1588 } | |
1589 } | |
1590 | |
1591 void OutBuffer::fill0(unsigned nbytes) | |
1592 { | |
1593 reserve(nbytes); | |
1594 memset(data + offset,0,nbytes); | |
1595 offset += nbytes; | |
1596 } | |
1597 | |
1598 void OutBuffer::align(unsigned size) | |
1599 { unsigned nbytes; | |
1600 | |
1601 nbytes = ((offset + size - 1) & ~(size - 1)) - offset; | |
1602 fill0(nbytes); | |
1603 } | |
1604 | |
1605 void OutBuffer::vprintf(const char *format, va_list args) | |
1606 { | |
1607 char buffer[128]; | |
1608 char *p; | |
1609 unsigned psize; | |
1610 int count; | |
1611 | |
1612 p = buffer; | |
1613 psize = sizeof(buffer); | |
1614 for (;;) | |
1615 { | |
1616 #if _WIN32 | |
1617 count = _vsnprintf(p,psize,format,args); | |
1618 if (count != -1) | |
1619 break; | |
1620 psize *= 2; | |
1621 #endif | |
571
cbd6c8073a32
Changed all '#if linux || __APPLE__' to '#if POSIX' so we can support other platforms too, thanx for the suggestion anders.
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
535
diff
changeset
|
1622 #if POSIX |
336 | 1623 count = vsnprintf(p,psize,format,args); |
1624 if (count == -1) | |
1625 psize *= 2; | |
1626 else if (count >= psize) | |
1627 psize = count + 1; | |
1628 else | |
1629 break; | |
1630 #endif | |
1631 p = (char *) alloca(psize); // buffer too small, try again with larger size | |
1632 } | |
1633 write(p,count); | |
1634 } | |
1635 | |
1636 #if M_UNICODE | |
1637 void OutBuffer::vprintf(const wchar_t *format, va_list args) | |
1638 { | |
1639 dchar buffer[128]; | |
1640 dchar *p; | |
1641 unsigned psize; | |
1642 int count; | |
1643 | |
1644 p = buffer; | |
1645 psize = sizeof(buffer) / sizeof(buffer[0]); | |
1646 for (;;) | |
1647 { | |
1648 #if _WIN32 | |
1649 count = _vsnwprintf(p,psize,format,args); | |
1650 if (count != -1) | |
1651 break; | |
1652 psize *= 2; | |
1653 #endif | |
571
cbd6c8073a32
Changed all '#if linux || __APPLE__' to '#if POSIX' so we can support other platforms too, thanx for the suggestion anders.
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
535
diff
changeset
|
1654 #if POSIX |
336 | 1655 count = vsnwprintf(p,psize,format,args); |
1656 if (count == -1) | |
1657 psize *= 2; | |
1658 else if (count >= psize) | |
1659 psize = count + 1; | |
1660 else | |
1661 break; | |
1662 #endif | |
1663 p = (dchar *) alloca(psize * 2); // buffer too small, try again with larger size | |
1664 } | |
1665 write(p,count * 2); | |
1666 } | |
1667 #endif | |
1668 | |
1669 void OutBuffer::printf(const char *format, ...) | |
1670 { | |
1671 va_list ap; | |
1672 va_start(ap, format); | |
1673 vprintf(format,ap); | |
1674 va_end(ap); | |
1675 } | |
1676 | |
1677 #if M_UNICODE | |
1678 void OutBuffer::printf(const wchar_t *format, ...) | |
1679 { | |
1680 va_list ap; | |
1681 va_start(ap, format); | |
1682 vprintf(format,ap); | |
1683 va_end(ap); | |
1684 } | |
1685 #endif | |
1686 | |
1687 void OutBuffer::bracket(char left, char right) | |
1688 { | |
1689 reserve(2); | |
1690 memmove(data + 1, data, offset); | |
1691 data[0] = left; | |
1692 data[offset + 1] = right; | |
1693 offset += 2; | |
1694 } | |
1695 | |
1696 /****************** | |
1697 * Insert left at i, and right at j. | |
1698 * Return index just past right. | |
1699 */ | |
1700 | |
1701 unsigned OutBuffer::bracket(unsigned i, char *left, unsigned j, char *right) | |
1702 { | |
1703 size_t leftlen = strlen(left); | |
1704 size_t rightlen = strlen(right); | |
1705 reserve(leftlen + rightlen); | |
1706 insert(i, left, leftlen); | |
1707 insert(j + leftlen, right, rightlen); | |
1708 return j + leftlen + rightlen; | |
1709 } | |
1710 | |
1711 void OutBuffer::spread(unsigned offset, unsigned nbytes) | |
1712 { | |
1713 reserve(nbytes); | |
1714 memmove(data + offset + nbytes, data + offset, | |
1715 this->offset - offset); | |
1716 this->offset += nbytes; | |
1717 } | |
1718 | |
1719 /**************************************** | |
1720 * Returns: offset + nbytes | |
1721 */ | |
1722 | |
1723 unsigned OutBuffer::insert(unsigned offset, const void *p, unsigned nbytes) | |
1724 { | |
1725 spread(offset, nbytes); | |
1726 memmove(data + offset, p, nbytes); | |
1727 return offset + nbytes; | |
1728 } | |
1729 | |
1730 void OutBuffer::remove(unsigned offset, unsigned nbytes) | |
1731 { | |
1732 memmove(data + offset, data + offset + nbytes, this->offset - (offset + nbytes)); | |
1733 this->offset -= nbytes; | |
1734 } | |
1735 | |
1736 char *OutBuffer::toChars() | |
1737 { | |
1738 writeByte(0); | |
1739 return (char *)data; | |
1740 } | |
1741 | |
1742 /********************************* Bits ****************************/ | |
1743 | |
1744 Bits::Bits() | |
1745 { | |
1746 data = NULL; | |
1747 bitdim = 0; | |
1748 allocdim = 0; | |
1749 } | |
1750 | |
1751 Bits::~Bits() | |
1752 { | |
1753 mem.free(data); | |
1754 } | |
1755 | |
1756 void Bits::mark() | |
1757 { | |
1758 mem.mark(data); | |
1759 } | |
1760 | |
1761 void Bits::resize(unsigned bitdim) | |
1762 { | |
1763 unsigned allocdim; | |
1764 unsigned mask; | |
1765 | |
1766 allocdim = (bitdim + 31) / 32; | |
1767 data = (unsigned *)mem.realloc(data, allocdim * sizeof(data[0])); | |
1768 if (this->allocdim < allocdim) | |
1769 memset(data + this->allocdim, 0, (allocdim - this->allocdim) * sizeof(data[0])); | |
1770 | |
1771 // Clear other bits in last word | |
1772 mask = (1 << (bitdim & 31)) - 1; | |
1773 if (mask) | |
1774 data[allocdim - 1] &= ~mask; | |
1775 | |
1776 this->bitdim = bitdim; | |
1777 this->allocdim = allocdim; | |
1778 } | |
1779 | |
1780 void Bits::set(unsigned bitnum) | |
1781 { | |
1782 data[bitnum / 32] |= 1 << (bitnum & 31); | |
1783 } | |
1784 | |
1785 void Bits::clear(unsigned bitnum) | |
1786 { | |
1787 data[bitnum / 32] &= ~(1 << (bitnum & 31)); | |
1788 } | |
1789 | |
1790 int Bits::test(unsigned bitnum) | |
1791 { | |
1792 return data[bitnum / 32] & (1 << (bitnum & 31)); | |
1793 } | |
1794 | |
1795 void Bits::set() | |
1796 { unsigned mask; | |
1797 | |
1798 memset(data, ~0, allocdim * sizeof(data[0])); | |
1799 | |
1800 // Clear other bits in last word | |
1801 mask = (1 << (bitdim & 31)) - 1; | |
1802 if (mask) | |
1803 data[allocdim - 1] &= mask; | |
1804 } | |
1805 | |
1806 void Bits::clear() | |
1807 { | |
1808 memset(data, 0, allocdim * sizeof(data[0])); | |
1809 } | |
1810 | |
1811 void Bits::copy(Bits *from) | |
1812 { | |
1813 assert(bitdim == from->bitdim); | |
1814 memcpy(data, from->data, allocdim * sizeof(data[0])); | |
1815 } | |
1816 | |
1817 Bits *Bits::clone() | |
1818 { | |
1819 Bits *b; | |
1820 | |
1821 b = new Bits(); | |
1822 b->resize(bitdim); | |
1823 b->copy(this); | |
1824 return b; | |
1825 } | |
1826 | |
1827 void Bits::sub(Bits *b) | |
1828 { | |
1829 unsigned u; | |
1830 | |
1831 for (u = 0; u < allocdim; u++) | |
1832 data[u] &= ~b->data[u]; | |
1833 } | |
1834 | |
1835 | |
1836 | |
1837 | |
1838 | |
1839 | |
1840 | |
1841 | |
1842 | |
1843 | |
1844 | |
1845 | |
1846 | |
1847 | |
1848 |