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