diff -uNr dmd-0.119/dmd/src/dmd/access.c dmd-0.120/dmd/src/dmd/access.c --- dmd-0.119/dmd/src/dmd/access.c 2004-11-05 01:17:26.000000000 +0100 +++ dmd-0.120/dmd/src/dmd/access.c 2005-04-02 10:51:42.000000000 +0200 @@ -1,5 +1,5 @@ -// Copyright (c) 1999-2004 by Digital Mars +// Copyright (c) 1999-2005 by Digital Mars // All Rights Reserved // written by Walter Bright // www.digitalmars.com @@ -21,10 +21,11 @@ #include "attrib.h" #include "scope.h" #include "id.h" +#include "mtype.h" #include "declaration.h" #include "aggregate.h" #include "expression.h" -#include "mtype.h" +#include "module.h" #define LOG 0 diff -uNr dmd-0.119/dmd/src/dmd/attrib.c dmd-0.120/dmd/src/dmd/attrib.c --- dmd-0.119/dmd/src/dmd/attrib.c 2005-03-08 21:59:56.000000000 +0100 +++ dmd-0.120/dmd/src/dmd/attrib.c 2005-04-01 16:07:38.000000000 +0200 @@ -17,14 +17,15 @@ #include "../root/mem.h" #endif -#include "declaration.h" #include "init.h" +#include "declaration.h" #include "attrib.h" #include "debcond.h" #include "scope.h" #include "id.h" #include "expression.h" #include "dsymbol.h" +#include "aggregate.h" extern void obj_includelib(char *name); diff -uNr dmd-0.119/dmd/src/dmd/cast.c dmd-0.120/dmd/src/dmd/cast.c --- dmd-0.119/dmd/src/dmd/cast.c 2005-03-16 19:12:04.000000000 +0100 +++ dmd-0.120/dmd/src/dmd/cast.c 2005-04-02 17:40:32.000000000 +0200 @@ -99,28 +99,34 @@ if (type->equals(t)) return MATCHexact; - switch (type->toBasetype()->ty) + enum TY ty = type->toBasetype()->ty; + switch (ty) { case Tbit: value &= 1; + ty = Tint32; break; case Tint8: value = (signed char)value; + ty = Tint32; break; case Tchar: case Tuns8: value &= 0xFF; + ty = Tint32; break; case Tint16: value = (short)value; + ty = Tint32; break; case Tuns16: case Twchar: value &= 0xFFFF; + ty = Tint32; break; case Tint32: @@ -130,6 +136,7 @@ case Tuns32: case Tdchar: value &= 0xFFFFFFFF; + ty = Tuns32; break; default: @@ -137,7 +144,8 @@ } // Only allow conversion if no change in value - switch (t->toBasetype()->ty) + enum TY toty = t->toBasetype()->ty; + switch (toty) { case Tbit: if (value & ~1) @@ -167,12 +175,18 @@ goto Lyes; case Tint32: - if ((int)value != value) + if (ty == Tuns32) + { + } + else if ((int)value != value) goto Lno; goto Lyes; case Tuns32: - if ((unsigned)value != value) + if (ty == Tint32) + { + } + else if ((unsigned)value != value) goto Lno; goto Lyes; diff -uNr dmd-0.119/dmd/src/dmd/class.c dmd-0.120/dmd/src/dmd/class.c --- dmd-0.119/dmd/src/dmd/class.c 2005-03-16 12:13:30.000000000 +0100 +++ dmd-0.120/dmd/src/dmd/class.c 2005-03-20 15:43:36.000000000 +0100 @@ -480,7 +480,7 @@ /* cd->baseClass might not be set if cd is forward referenced. */ - if (!cd->baseClass && cd->baseclasses.dim) + if (!cd->baseClass && cd->baseclasses.dim && !cd->isInterfaceDeclaration()) { cd->error("base class is forward referenced by %s", toChars()); } diff -uNr dmd-0.119/dmd/src/dmd/constfold.c dmd-0.120/dmd/src/dmd/constfold.c --- dmd-0.119/dmd/src/dmd/constfold.c 2005-03-17 12:18:08.000000000 +0100 +++ dmd-0.120/dmd/src/dmd/constfold.c 2005-04-02 18:00:04.000000000 +0200 @@ -116,19 +116,59 @@ return e1; } - if (type->toBasetype()->ty == Tbit) + Type *tb = type->toBasetype(); + if (tb->ty == Tbit) return new IntegerExp(loc, e1->toInteger() != 0, type); if (type->isintegral()) return new IntegerExp(loc, e1->toInteger(), type); - if (type->isreal()) - return new RealExp(loc, e1->toReal(), type); - if (type->isimaginary()) - return new ImaginaryExp(loc, e1->toImaginary(), type); - if (type->iscomplex()) - return new ComplexExp(loc, e1->toComplex(), type); - if (type->isscalar()) + if (tb->isreal()) + { real_t value = e1->toReal(); + +#if 0 + if (tb->ty == Tfloat32) + { float f = (float)value; + value = f; + } + else if (tb->ty == Tfloat64) + value = (double)value; +#endif + return new RealExp(loc, value, type); + } + if (tb->isimaginary()) + { real_t value = e1->toImaginary(); +#if 0 + if (tb->ty == Timaginary32) + value = (float)value; + else if (tb->ty == Timaginary64) + value = (double)value; +#endif + return new ImaginaryExp(loc, value, type); + } + if (tb->iscomplex()) + { complex_t value = e1->toComplex(); + +#if 0 +#if __DMC__ + if (tb->ty == Tcomplex32) + value = (_Complex float)value; + else if (tb->ty == Tcomplex64) + value = (_Complex double)value; +#else + if (tb->ty == Tcomplex32) + { value.re = (float)value.re; + value.im = (float)value.im; + } + else if (tb->ty == Tcomplex64) + { value.re = (double)value.re; + value.im = (double)value.im; + } +#endif +#endif + return new ComplexExp(loc, value, type); + } + if (tb->isscalar()) return new IntegerExp(loc, e1->toInteger(), type); - if (type->toBasetype()->ty != Tvoid) + if (tb->ty != Tvoid) error("cannot cast %s to %s", e1->type->toChars(), type->toChars()); return this; } diff -uNr dmd-0.119/dmd/src/dmd/debcond.c dmd-0.120/dmd/src/dmd/debcond.c --- dmd-0.119/dmd/src/dmd/debcond.c 2005-03-17 23:06:22.000000000 +0100 +++ dmd-0.120/dmd/src/dmd/debcond.c 2005-04-05 21:00:54.000000000 +0200 @@ -1,5 +1,5 @@ -// Copyright (c) 1999-2004 by Digital Mars +// Copyright (c) 1999-2005 by Digital Mars // All Rights Reserved // written by Walter Bright // www.digitalmars.com @@ -10,10 +10,13 @@ #include #include +#include "id.h" +#include "init.h" #include "declaration.h" #include "identifier.h" #include "expression.h" #include "debcond.h" +#include "module.h" int findCondition(Array *ids, Identifier *ident) { @@ -112,7 +115,7 @@ { static char* reserved[] = { - "DigitalMars", "X86", "AMD64", + "DigitalMars", "X86", "X86_64", "Windows", "Win32", "Win64", "linux", "LittleEndian", "BigEndian", diff -uNr dmd-0.119/dmd/src/dmd/declaration.c dmd-0.120/dmd/src/dmd/declaration.c --- dmd-0.119/dmd/src/dmd/declaration.c 2005-03-17 23:14:06.000000000 +0100 +++ dmd-0.120/dmd/src/dmd/declaration.c 2005-04-05 15:40:04.000000000 +0200 @@ -1,5 +1,5 @@ -// Copyright (c) 1999-2004 by Digital Mars +// Copyright (c) 1999-2005 by Digital Mars // All Rights Reserved // written by Walter Bright // www.digitalmars.com @@ -10,16 +10,16 @@ #include #include -#include "declaration.h" #include "init.h" +#include "declaration.h" #include "attrib.h" -#include "template.h" #include "mtype.h" +#include "template.h" #include "scope.h" #include "aggregate.h" #include "module.h" #include "id.h" - +#include "expression.h" /********************************* Declaration ****************************/ @@ -104,20 +104,25 @@ void TypedefDeclaration::semantic(Scope *sc) { - //printf("TypedefDeclaration::semantic()\n"); - if (!sem) + //printf("TypedefDeclaration::semantic(%s) sem = %d\n", toChars(), sem); + if (sem == 0) { sem = 1; basetype = basetype->semantic(loc, sc); + sem = 2; if (sc->parent->isFuncDeclaration() && init) semantic2(sc); } + else if (sem == 1) + { + error("circular definition"); + } } void TypedefDeclaration::semantic2(Scope *sc) { //printf("TypedefDeclaration::semantic2()\n"); - if (sem == 1) - { sem = 2; + if (sem == 2) + { sem = 3; if (init) { init = init->semantic(sc, basetype); @@ -389,6 +394,7 @@ //printf("VarDeclaration::semantic('%s', parent = '%s')\n", toChars(), sc->parent->toChars()); type = type->semantic(loc, sc); + type->checkDeprecated(loc, sc); linkage = sc->linkage; this->parent = sc->parent; //printf("this = %p, parent = %p, '%s'\n", this, parent, parent->toChars()); @@ -542,6 +548,7 @@ } ie->exp = new AssignExp(loc, e1, ie->exp); ie->exp = ie->exp->semantic(sc); + ie->exp->optimize(WANTvalue); } else { diff -uNr dmd-0.119/dmd/src/dmd/declaration.h dmd-0.120/dmd/src/dmd/declaration.h --- dmd-0.119/dmd/src/dmd/declaration.h 2005-03-10 01:20:56.000000000 +0100 +++ dmd-0.120/dmd/src/dmd/declaration.h 2005-04-05 15:32:28.000000000 +0200 @@ -105,7 +105,10 @@ { Type *basetype; Initializer *init; - int sem; // !=0 if semantic() has been run + int sem; // 0: semantic() has not been run + // 1: semantic() is in progress + // 2: semantic() has been run + // 3: semantic2() has been run TypedefDeclaration(Identifier *ident, Type *basetype, Initializer *init); Dsymbol *syntaxCopy(Dsymbol *); diff -uNr dmd-0.119/dmd/src/dmd/dsymbol.c dmd-0.120/dmd/src/dmd/dsymbol.c --- dmd-0.119/dmd/src/dmd/dsymbol.c 2005-03-07 12:10:34.000000000 +0100 +++ dmd-0.120/dmd/src/dmd/dsymbol.c 2005-04-01 16:16:16.000000000 +0200 @@ -22,7 +22,8 @@ #include "expression.h" #include "statement.h" #include "declaration.h" - +#include "id.h" +#include "scope.h" /****************************** Dsymbol ******************************/ @@ -331,6 +332,26 @@ //fatal(); } +void Dsymbol::checkDeprecated(Loc loc, Scope *sc) +{ + if (!global.params.useDeprecated && isDeprecated()) + { + // Don't complain if we're inside a deprecated symbol's scope + for (Dsymbol *sp = sc->parent; sp; sp = sp->parent) + { if (sp->isDeprecated()) + return; + } + + for (; sc; sc = sc->enclosing) + { + if (sc->scopesym && sc->scopesym->isDeprecated()) + return; + } + + error(loc, "is deprecated"); + } +} + /********************************** * Determine which Module a Dsymbol is in. */ diff -uNr dmd-0.119/dmd/src/dmd/dsymbol.h dmd-0.120/dmd/src/dmd/dsymbol.h --- dmd-0.119/dmd/src/dmd/dsymbol.h 2004-12-30 00:17:50.000000000 +0100 +++ dmd-0.120/dmd/src/dmd/dsymbol.h 2005-03-25 20:26:10.000000000 +0100 @@ -90,6 +90,7 @@ int isAnonymous(); void error(Loc loc, const char *format, ...); void error(const char *format, ...); + void checkDeprecated(Loc loc, Scope *sc); Module *getModule(); Dsymbol *pastMixin(); Dsymbol *toParent(); diff -uNr dmd-0.119/dmd/src/dmd/expression.c dmd-0.120/dmd/src/dmd/expression.c --- dmd-0.119/dmd/src/dmd/expression.c 2005-03-17 22:11:44.000000000 +0100 +++ dmd-0.120/dmd/src/dmd/expression.c 2005-04-05 16:43:36.000000000 +0200 @@ -256,6 +256,7 @@ arg = arg->castTo(tb->next->arrayOf()); } } + arg = arg->optimize(WANTvalue); arguments->data[i] = (void *) arg; } @@ -462,22 +463,7 @@ void Expression::checkDeprecated(Scope *sc, Dsymbol *s) { - if (!global.params.useDeprecated && s->isDeprecated()) - { - // Don't complain if we're inside a deprecated symbol's scope - for (Dsymbol *sp = sc->parent; sp; sp = sp->parent) - { if (sp->isDeprecated()) - return; - } - - for (; sc; sc = sc->enclosing) - { - if (sc->scopesym && sc->scopesym->isDeprecated()) - return; - } - - error("%s %s is deprecated", s->kind(), s->toChars()); - } + s->checkDeprecated(loc, sc); } /***************************** @@ -1815,7 +1801,7 @@ #if LOGSEMANTIC printf("SymOffExp::semantic('%s')\n", toChars()); #endif - var->semantic(sc); + //var->semantic(sc); type = var->type->pointerTo(); return this; } @@ -1838,7 +1824,7 @@ VarExp::VarExp(Loc loc, Declaration *var) : Expression(loc, TOKvar, sizeof(VarExp)) { - //printf("VarExp('%s')\n", var->toChars()); + //printf("VarExp(this = %p, '%s')\n", this, var->toChars()); this->var = var; this->type = var->type; } @@ -2103,6 +2089,27 @@ /************************************************************/ +HaltExp::HaltExp(Loc loc) + : Expression(loc, TOKhalt, sizeof(HaltExp)) +{ +} + +Expression *HaltExp::semantic(Scope *sc) +{ +#if LOGSEMANTIC + printf("HaltExp::semantic()\n"); +#endif + type = Type::tvoid; + return this; +} + +void HaltExp::toCBuffer(OutBuffer *buf) +{ + buf->writestring("halt"); +} + +/************************************************************/ + UnaExp::UnaExp(Loc loc, enum TOK op, int size, Expression *e1) : Expression(loc, op, size) { @@ -2260,6 +2267,11 @@ e1 = resolveProperties(sc, e1); // BUG: see if we can do compile time elimination of the Assert e1 = e1->checkToBoolean(); + if (!global.params.useAssert && e1->isBool(FALSE)) + { Expression *e = new HaltExp(loc); + e = e->semantic(sc); + return e; + } type = Type::tvoid; return this; } @@ -4605,12 +4617,15 @@ else if (t2->isintegral()) e = scaleFactor(); else - error("incompatible types for -"); + { error("incompatible types for -"); + return new IntegerExp(0); + } } else if (t2->ty == Tpointer) { type = e2->type; error("can't subtract pointer from %s", e1->type->toChars()); + return new IntegerExp(0); } else { diff -uNr dmd-0.119/dmd/src/dmd/expression.h dmd-0.120/dmd/src/dmd/expression.h --- dmd-0.119/dmd/src/dmd/expression.h 2005-03-10 01:16:08.000000000 +0100 +++ dmd-0.120/dmd/src/dmd/expression.h 2005-03-18 19:47:56.000000000 +0100 @@ -408,6 +408,15 @@ void toCBuffer(OutBuffer *buf); }; +struct HaltExp : Expression +{ + HaltExp(Loc loc); + Expression *semantic(Scope *sc); + void toCBuffer(OutBuffer *buf); + + elem *toElem(IRState *irs); +}; + /****************************************************************/ struct UnaExp : Expression diff -uNr dmd-0.119/dmd/src/dmd/func.c dmd-0.120/dmd/src/dmd/func.c --- dmd-0.119/dmd/src/dmd/func.c 2005-03-18 01:06:28.000000000 +0100 +++ dmd-0.120/dmd/src/dmd/func.c 2005-04-01 16:09:12.000000000 +0200 @@ -11,8 +11,8 @@ #include #include "mars.h" -#include "declaration.h" #include "init.h" +#include "declaration.h" #include "attrib.h" #include "expression.h" #include "scope.h" @@ -636,7 +636,8 @@ else if (type->next->ty != Tvoid && !inlineAsm) { if (offend) - { + { Expression *e; + if (global.params.warnings) { printf("warning - "); error("no return at end of function"); @@ -647,11 +648,13 @@ { /* Add an assert(0); where the missing return * should be. */ - Expression *e = new AssertExp(endloc, new IntegerExp(0, 0, Type::tint32)); - e = e->semantic(sc2); - Statement *s = new ExpStatement(0, e); - fbody = new CompoundStatement(0, fbody, s); + e = new AssertExp(endloc, new IntegerExp(0, 0, Type::tint32)); } + else + e = new HaltExp(endloc); + e = e->semantic(sc2); + Statement *s = new ExpStatement(0, e); + fbody = new CompoundStatement(0, fbody, s); } } } diff -uNr dmd-0.119/dmd/src/dmd/html.c dmd-0.120/dmd/src/dmd/html.c --- dmd-0.119/dmd/src/dmd/html.c 2005-03-07 14:41:14.000000000 +0100 +++ dmd-0.120/dmd/src/dmd/html.c 2005-04-01 16:09:30.000000000 +0200 @@ -18,6 +18,7 @@ #include #include +#include "mars.h" #include "html.h" #include diff -uNr dmd-0.119/dmd/src/dmd/html.h dmd-0.120/dmd/src/dmd/html.h --- dmd-0.119/dmd/src/dmd/html.h 2005-03-03 19:37:34.000000000 +0100 +++ dmd-0.120/dmd/src/dmd/html.h 2005-04-01 16:10:52.000000000 +0200 @@ -27,7 +27,9 @@ void extractCode(OutBuffer *buf); void skipTag(); void skipString(); + unsigned char *skipWhite(unsigned char *q); void scanComment(); + int isCommentStart(); int charEntity(); static int namedEntity(unsigned char *p, int length); }; diff -uNr dmd-0.119/dmd/src/dmd/identifier.c dmd-0.120/dmd/src/dmd/identifier.c --- dmd-0.119/dmd/src/dmd/identifier.c 2004-12-18 15:32:38.000000000 +0100 +++ dmd-0.120/dmd/src/dmd/identifier.c 2005-04-01 16:11:12.000000000 +0200 @@ -13,6 +13,7 @@ #include "root.h" #include "identifier.h" #include "mars.h" +#include "lexer.h" Identifier::Identifier(const char *string, int value) { diff -uNr dmd-0.119/dmd/src/dmd/idgen.c dmd-0.120/dmd/src/dmd/idgen.c --- dmd-0.119/dmd/src/dmd/idgen.c 2005-03-17 23:07:52.000000000 +0100 +++ dmd-0.120/dmd/src/dmd/idgen.c 2005-03-26 00:42:22.000000000 +0100 @@ -59,6 +59,7 @@ { "delegate" }, { "line" }, { "empty", "" }, + { "p" }, { "TypeInfo" }, { "TypeInfo_Class" }, diff -uNr dmd-0.119/dmd/src/dmd/inline.c dmd-0.120/dmd/src/dmd/inline.c --- dmd-0.119/dmd/src/dmd/inline.c 2005-02-27 19:16:32.000000000 +0100 +++ dmd-0.120/dmd/src/dmd/inline.c 2005-04-05 23:12:40.000000000 +0200 @@ -752,7 +752,8 @@ for (int i = 0; i < catches->dim; i++) { Catch *c = (Catch *)catches->data[i]; - c->handler = c->handler->inlineScan(iss); + if (c->handler) + c->handler = c->handler->inlineScan(iss); } } return this; diff -uNr dmd-0.119/dmd/src/dmd/lexer.c dmd-0.120/dmd/src/dmd/lexer.c --- dmd-0.119/dmd/src/dmd/lexer.c 2005-03-16 14:58:50.000000000 +0100 +++ dmd-0.120/dmd/src/dmd/lexer.c 2005-04-02 12:07:48.000000000 +0200 @@ -38,6 +38,7 @@ #include "utf.h" #include "identifier.h" #include "id.h" +#include "module.h" #if _WIN32 && __DMC__ // from \dm\src\include\setlocal.h @@ -1768,37 +1769,29 @@ p--; stringbuffer.writeByte(0); - errno = 0; #if _WIN32 && __DMC__ char *save = __locale_decpoint; __locale_decpoint = "."; #endif + t->float80value = strtold((char *)stringbuffer.data, NULL); + errno = 0; switch (*p) { case 'F': case 'f': -#if 0 - t->float80value = strtod((char *)stringbuffer.data, NULL); -#else - t->float80value = strtof((char *)stringbuffer.data, NULL); -#endif + strtof((char *)stringbuffer.data, NULL); result = TOKfloat32v; p++; break; default: - t->float80value = strtod((char *)stringbuffer.data, NULL); + strtod((char *)stringbuffer.data, NULL); result = TOKfloat64v; break; case 'L': case 'l': -#if 0 - t->float80value = strtod((char *)stringbuffer.data, NULL); -#else - t->float80value = strtold((char *)stringbuffer.data, NULL); -#endif result = TOKfloat80v; p++; break; diff -uNr dmd-0.119/dmd/src/dmd/lexer.h dmd-0.120/dmd/src/dmd/lexer.h --- dmd-0.119/dmd/src/dmd/lexer.h 2005-03-14 16:38:12.000000000 +0100 +++ dmd-0.120/dmd/src/dmd/lexer.h 2005-03-18 19:53:20.000000000 +0100 @@ -102,6 +102,7 @@ // Leaf operators TOKidentifier, TOKstring, TOKthis, TOKsuper, + TOKhalt, // Basic types TOKvoid, diff -uNr dmd-0.119/dmd/src/dmd/mangle.c dmd-0.120/dmd/src/dmd/mangle.c --- dmd-0.119/dmd/src/dmd/mangle.c 2005-03-17 19:30:56.000000000 +0100 +++ dmd-0.120/dmd/src/dmd/mangle.c 2005-04-01 16:12:00.000000000 +0200 @@ -1,5 +1,5 @@ -// Copyright (c) 1999-2004 by Digital Mars +// Copyright (c) 1999-2005 by Digital Mars // All Rights Reserved // written by Walter Bright // www.digitalmars.com @@ -14,6 +14,7 @@ #include "root.h" +#include "init.h" #include "declaration.h" #include "aggregate.h" #include "mtype.h" diff -uNr dmd-0.119/dmd/src/dmd/mars.c dmd-0.120/dmd/src/dmd/mars.c --- dmd-0.119/dmd/src/dmd/mars.c 2005-03-14 12:58:30.000000000 +0100 +++ dmd-0.120/dmd/src/dmd/mars.c 2005-03-22 10:59:52.000000000 +0100 @@ -49,7 +49,7 @@ copyright = "Copyright (c) 1999-2005 by Digital Mars"; written = "written by Walter Bright"; - version = "v0.119"; + version = "v0.120"; global.structalign = 8; memset(¶ms, 0, sizeof(Param)); @@ -129,7 +129,6 @@ -c do not link\n\ -d allow deprecated features\n\ -g add symbolic debug info\n\ - -gt add trace profiling hooks\n\ -v verbose\n\ -O optimize\n\ -odobjdir write object files to directory objdir\n\ @@ -141,6 +140,7 @@ -debug=level compile in debug code <= level\n\ -debug=ident compile in debug code identified by ident\n\ -inline do function inlining\n\ + -profile profile runtime performance of generated code\n\ -release compile release version\n\ -unittest compile in unit tests\n\ -version=level compile in version code >= level\n\ @@ -228,6 +228,10 @@ else if (strcmp(p + 1, "g") == 0) global.params.symdebug = 1; else if (strcmp(p + 1, "gt") == 0) + { error("use -profile instead of -gt\n"); + global.params.trace = 1; + } + else if (strcmp(p + 1, "profile") == 0) global.params.trace = 1; else if (strcmp(p + 1, "v") == 0) global.params.verbose = 1; diff -uNr dmd-0.119/dmd/src/dmd/mars.h dmd-0.120/dmd/src/dmd/mars.h --- dmd-0.119/dmd/src/dmd/mars.h 2005-02-28 21:15:10.000000000 +0100 +++ dmd-0.120/dmd/src/dmd/mars.h 2005-04-05 21:01:30.000000000 +0200 @@ -25,7 +25,7 @@ char symdebug; // insert debug symbolic information char optimize; // run optimizer char cpu; // target CPU - char isAMD64; // generate AMD64 bit code + char isX86_64; // generate X86_64 bit code char isLinux; // generate code for linux char scheduler; // which scheduler to use char useDeprecated; // allow use of deprecated features diff -uNr dmd-0.119/dmd/src/dmd/mtype.c dmd-0.120/dmd/src/dmd/mtype.c --- dmd-0.119/dmd/src/dmd/mtype.c 2005-03-17 22:42:38.000000000 +0100 +++ dmd-0.120/dmd/src/dmd/mtype.c 2005-04-05 21:01:30.000000000 +0200 @@ -1,5 +1,5 @@ -// Copyright (c) 1999-2004 by Digital Mars +// Copyright (c) 1999-2005 by Digital Mars // All Rights Reserved // written by Walter Bright // www.digitalmars.com @@ -171,7 +171,7 @@ basic[basetab[i]] = new TypeBasic(basetab[i]); basic[Terror] = basic[Tint32]; - if (global.params.isAMD64) + if (global.params.isX86_64) { PTRSIZE = 8; if (global.params.isLinux) @@ -409,6 +409,24 @@ return isscalar(); } +/********************************* + * Check type to see if it is based on a deprecated symbol. + */ + +void Type::checkDeprecated(Loc loc, Scope *sc) +{ + Type *t; + Dsymbol *s; + + for (t = this; t; t = t->next) + { + s = t->toDsymbol(sc); + if (s) + s->checkDeprecated(loc, sc); + } +} + + Expression *Type::defaultInit() { #if LOGDEFAULTINIT @@ -1246,9 +1264,24 @@ return MATCHnomatch; if (to->ty == Tbit) return MATCHnomatch; - // Disallow implicit conversion of floating point to integer - if (flags & TFLAGSfloating && ((TypeBasic *)to)->flags & TFLAGSintegral) - return MATCHnomatch; + TypeBasic *tob = (TypeBasic *)to; + if (flags & TFLAGSfloating) + { + // Disallow implicit conversion of floating point to integer + if (tob->flags & TFLAGSintegral) + return MATCHnomatch; + + assert(tob->flags & TFLAGSfloating); + + // Disallow implicit conversion from complex to non-complex + if (flags & TFLAGScomplex && !(tob->flags & TFLAGScomplex)) + return MATCHnomatch; + + // Disallow implicit conversion to-from real and imaginary + if ((flags & (TFLAGSreal | TFLAGSimaginary)) != + (tob->flags & (TFLAGSreal | TFLAGSimaginary))) + return MATCHnomatch; + } return MATCHconvert; } @@ -2827,7 +2860,16 @@ //printf("TypeIdentifier::semantic(%s)\n", toChars()); resolve(loc, sc, &e, &t, &s); - if (!t) + if (t) + { + if (t->ty == Ttypedef) + { TypeTypedef *tt = (TypeTypedef *)t; + + if (tt->sym->sem == 1) + error(loc, "circular reference of typedef %s", tt->toChars()); + } + } + else { #ifdef DEBUG printf("1: "); @@ -3219,6 +3261,7 @@ Type *TypeTypedef::semantic(Loc loc, Scope *sc) { + //printf("TypeTypedef::semantic(%s), sem = %d\n", toChars(), sym->sem); sym->semantic(sc); return merge(); } diff -uNr dmd-0.119/dmd/src/dmd/mtype.h dmd-0.120/dmd/src/dmd/mtype.h --- dmd-0.119/dmd/src/dmd/mtype.h 2005-02-28 21:11:54.000000000 +0100 +++ dmd-0.120/dmd/src/dmd/mtype.h 2005-03-25 20:28:32.000000000 +0100 @@ -192,6 +192,7 @@ virtual int isauto(); virtual int isString(); virtual int checkBoolean(); // if can be converted to boolean value + void checkDeprecated(Loc loc, Scope *sc); Type *pointerTo(); Type *referenceTo(); Type *arrayOf(); diff -uNr dmd-0.119/dmd/src/dmd/optimize.c dmd-0.120/dmd/src/dmd/optimize.c --- dmd-0.119/dmd/src/dmd/optimize.c 2004-12-01 16:44:10.000000000 +0100 +++ dmd-0.120/dmd/src/dmd/optimize.c 2005-04-04 01:11:24.000000000 +0200 @@ -1,5 +1,5 @@ -// Copyright (c) 1999-2004 by Digital Mars +// Copyright (c) 1999-2005 by Digital Mars // All Rights Reserved // written by Walter Bright // www.digitalmars.com diff -uNr dmd-0.119/dmd/src/dmd/parse.c dmd-0.120/dmd/src/dmd/parse.c --- dmd-0.119/dmd/src/dmd/parse.c 2005-03-17 21:10:16.000000000 +0100 +++ dmd-0.120/dmd/src/dmd/parse.c 2005-04-04 16:17:22.000000000 +0200 @@ -16,6 +16,7 @@ #include "init.h" #include "attrib.h" #include "debcond.h" +#include "mtype.h" #include "template.h" #include "staticassert.h" #include "expression.h" @@ -27,7 +28,6 @@ #include "aggregate.h" #include "enum.h" #include "id.h" -#include "mtype.h" #include "version.h" // How multiple declarations are parsed. @@ -1130,13 +1130,19 @@ } tp_ident = token.ident; nextToken(); - if (token.value == TOKassign) // : Type + if (token.value == TOKcolon) // : Type + { + nextToken(); + tp_spectype = parseBasicType(); + tp_spectype = parseDeclarator(tp_spectype, NULL); + } + if (token.value == TOKassign) // = Type { nextToken(); tp_defaulttype = parseBasicType(); tp_defaulttype = parseDeclarator(tp_defaulttype, NULL); } - tp = new TemplateAliasParameter(loc, tp_ident, tp_defaulttype); + tp = new TemplateAliasParameter(loc, tp_ident, tp_spectype, tp_defaulttype); } else if (t->value == TOKcolon || t->value == TOKassign || t->value == TOKcomma || t->value == TOKrparen) @@ -1153,7 +1159,7 @@ tp_spectype = parseBasicType(); tp_spectype = parseDeclarator(tp_spectype, NULL); } - if (token.value == TOKassign) // : Type + if (token.value == TOKassign) // = Type { nextToken(); tp_defaulttype = parseBasicType(); diff -uNr dmd-0.119/dmd/src/dmd/scope.c dmd-0.120/dmd/src/dmd/scope.c --- dmd-0.119/dmd/src/dmd/scope.c 2005-03-13 15:20:48.000000000 +0100 +++ dmd-0.120/dmd/src/dmd/scope.c 2005-04-02 10:52:22.000000000 +0200 @@ -1,5 +1,5 @@ -// Copyright (c) 1999-2004 by Digital Mars +// Copyright (c) 1999-2005 by Digital Mars // All Rights Reserved // written by Walter Bright // www.digitalmars.com @@ -13,9 +13,11 @@ #include "root.h" #include "mars.h" +#include "init.h" #include "identifier.h" #include "scope.h" #include "attrib.h" +#include "dsymbol.h" #include "declaration.h" #include "aggregate.h" #include "module.h" diff -uNr dmd-0.119/dmd/src/dmd/statement.c dmd-0.120/dmd/src/dmd/statement.c --- dmd-0.119/dmd/src/dmd/statement.c 2005-03-17 21:11:24.000000000 +0100 +++ dmd-0.120/dmd/src/dmd/statement.c 2005-04-05 15:50:48.000000000 +0200 @@ -322,6 +322,7 @@ } body = new CompoundStatement(0, a); s = new TryFinallyStatement(0, body, finalbody); + s = s->semantic(sc); statements->data[i + 1] = s; statements->setDim(i + 2); } @@ -1300,19 +1301,24 @@ } // Generate runtime error if the default is hit - if (global.params.useSwitchError) - { - Array *a = new Array(); - CompoundStatement *cs; + Array *a = new Array(); + CompoundStatement *cs; + Statement *s; - a->reserve(4); - a->push(body); - a->push(new BreakStatement(loc, NULL)); - sc->sw->sdefault = new DefaultStatement(loc, new SwitchErrorStatement(loc)); - a->push(sc->sw->sdefault); - cs = new CompoundStatement(loc, a); - body = cs; + if (global.params.useSwitchError) + s = new SwitchErrorStatement(loc); + else + { Expression *e = new HaltExp(loc); + s = new ExpStatement(loc, e); } + + a->reserve(4); + a->push(body); + a->push(new BreakStatement(loc, NULL)); + sc->sw->sdefault = new DefaultStatement(loc, s); + a->push(sc->sw->sdefault); + cs = new CompoundStatement(loc, a); + body = cs; } sc->pop(); @@ -1696,6 +1702,14 @@ return gs; } + if (exp && tbret->ty == Tvoid) + { Statement *s; + + s = new ExpStatement(loc, exp); + exp = NULL; + return new CompoundStatement(loc, s, this); + } + return this; } @@ -2083,7 +2097,8 @@ { Catch *c; c = (Catch *)catches->data[i]; - result |= c->handler->fallOffEnd(); + if (c->handler) + result |= c->handler->fallOffEnd(); } return result; } @@ -2104,7 +2119,8 @@ { Catch *c = new Catch(loc, (type ? type->syntaxCopy() : NULL), - ident, handler->syntaxCopy()); + ident, + (handler ? handler->syntaxCopy() : NULL)); return c; } @@ -2174,7 +2190,11 @@ void TryFinallyStatement::toCBuffer(OutBuffer *buf) { - buf->printf("TryFinallyStatement::toCBuffer()"); + buf->printf("try\n{\n"); + body->toCBuffer(buf); + buf->printf("}\nfinally\n{\n"); + finalbody->toCBuffer(buf); + buf->writeByte('}'); buf->writenl(); } @@ -2233,6 +2253,14 @@ return FALSE; } +void ThrowStatement::toCBuffer(OutBuffer *buf) +{ + buf->printf("throw "); + exp->toCBuffer(buf); + buf->writeByte(';'); + buf->writenl(); +} + /******************************** VolatileStatement **************************/ VolatileStatement::VolatileStatement(Loc loc, Statement *statement) diff -uNr dmd-0.119/dmd/src/dmd/statement.h dmd-0.120/dmd/src/dmd/statement.h --- dmd-0.119/dmd/src/dmd/statement.h 2005-03-13 16:30:00.000000000 +0100 +++ dmd-0.120/dmd/src/dmd/statement.h 2005-03-21 11:43:16.000000000 +0100 @@ -531,6 +531,7 @@ ThrowStatement(Loc loc, Expression *exp); Statement *syntaxCopy(); Statement *semantic(Scope *sc); + void toCBuffer(OutBuffer *buf); int fallOffEnd(); Statement *inlineScan(InlineScanState *iss); diff -uNr dmd-0.119/dmd/src/dmd/struct.c dmd-0.120/dmd/src/dmd/struct.c --- dmd-0.119/dmd/src/dmd/struct.c 2005-03-16 01:15:30.000000000 +0100 +++ dmd-0.120/dmd/src/dmd/struct.c 2005-04-01 16:16:00.000000000 +0200 @@ -1,5 +1,5 @@ -// Copyright (c) 1999-2004 by Digital Mars +// Copyright (c) 1999-2005 by Digital Mars // All Rights Reserved // written by Walter Bright // www.digitalmars.com @@ -15,6 +15,9 @@ #include "scope.h" #include "mtype.h" #include "declaration.h" +#include "module.h" +#include "id.h" +#include "statement.h" /********************************* AggregateDeclaration ****************************/ @@ -147,6 +150,8 @@ unsigned memalignsize; // size of member for alignment purposes unsigned xalign; // alignment boundaries + //printf("AggregateDeclaration::addField('%s')\n", v->toChars()); + // Check for forward referenced types which will fail the size() call Type *t = v->type->toBasetype(); if (t->ty == Tstruct /*&& isStructDeclaration()*/) @@ -167,8 +172,11 @@ sc->offset += memsize; if (sc->offset > structsize) structsize = sc->offset; + if (sc->structalign < memalignsize) + memalignsize = sc->structalign; if (alignsize < memalignsize) alignsize = memalignsize; + //printf("\talignsize = %d\n", alignsize); v->storage_class |= STCfield; //printf(" addField '%s' to '%s' at offset %d\n", v->toChars(), toChars(), v->offset); @@ -253,6 +261,63 @@ if (sizeok == 2) break; } + + /* The TypeInfo_Struct is expecting an opEquals and opCmp with + * a parameter that is a pointer to the struct. But if there + * isn't one, but is an opEquals or opCmp with a value, write + * another that is a shell around the value: + * int opCmp(struct *p) { return opCmp(*p); } + */ + + TypeFunction *tfeqptr; + { + Array *arguments = new Array; + Argument *arg = new Argument(In, handle, Id::p, NULL); + + arguments->push(arg); + tfeqptr = new TypeFunction(arguments, Type::tint32, 0, LINKd); + tfeqptr = (TypeFunction *)tfeqptr->semantic(0, sc); + } + + TypeFunction *tfeq; + { + Array *arguments = new Array; + Argument *arg = new Argument(In, type, NULL, NULL); + + arguments->push(arg); + tfeq = new TypeFunction(arguments, Type::tint32, 0, LINKd); + tfeq = (TypeFunction *)tfeq->semantic(0, sc); + } + + Identifier *id = Id::eq; + for (int i = 0; i < 2; i++) + { + FuncDeclaration *fdx = search_function(this, id); + if (fdx) + { FuncDeclaration *fd = fdx->overloadExactMatch(tfeqptr); + if (!fd) + { fd = fdx->overloadExactMatch(tfeq); + if (fd) + { // Create the thunk, fdptr + FuncDeclaration *fdptr = new FuncDeclaration(loc, loc, fdx->ident, STCundefined, tfeqptr); + Expression *e = new IdentifierExp(loc, Id::p); + e = new PtrExp(loc, e); + Array *args = new Array(); + args->push(e); + e = new IdentifierExp(loc, id); + e = new CallExp(loc, e, args); + fdptr->fbody = new ReturnStatement(loc, e); + members->push(fdptr); + fdptr->addMember(this); + fdptr->semantic(sc2); + } + } + } + + id = Id::cmp; + } + + sc2->pop(); if (sizeok == 2) @@ -276,9 +341,12 @@ alignsize = 1; } - sizeok = 1; + // Round struct size up to next alignsize boundary. + // This will ensure that arrays of structs will get their internals + // aligned properly. + structsize = (structsize + alignsize - 1) & ~(alignsize - 1); - AggregateDeclaration *sd; + sizeok = 1; //printf("-StructDeclaration::semantic(this=%p, '%s')\n", this, toChars()); @@ -313,7 +381,6 @@ aggNew = (NewDeclaration *)search(Id::classNew, 0); aggDelete = (DeleteDeclaration *)search(Id::classDelete, 0); - if (sc->func) { semantic2(sc); diff -uNr dmd-0.119/dmd/src/dmd/template.c dmd-0.120/dmd/src/dmd/template.c --- dmd-0.119/dmd/src/dmd/template.c 2005-03-17 19:41:26.000000000 +0100 +++ dmd-0.120/dmd/src/dmd/template.c 2005-04-04 17:11:18.000000000 +0200 @@ -16,8 +16,8 @@ #include "mem.h" #include "stringtable.h" -#include "template.h" #include "mtype.h" +#include "template.h" #include "init.h" #include "expression.h" #include "scope.h" @@ -268,7 +268,7 @@ goto Lnomatch; } #if 0 - printf("\targument [%d] is %s\n", i, oarg->toChars()); + printf("\targument [%d] is %s\n", i, oarg ? oarg->toChars() : "null"); TemplateTypeParameter *ttp = tp->isTemplateTypeParameter(); if (ttp) printf("\tparameter[%d] is %s : %s\n", i, tp->ident->toChars(), ttp->specType ? ttp->specType->toChars() : ""); @@ -276,7 +276,7 @@ m2 = tp->matchArg(paramscope, oarg, i, parameters, dedtypes, &sparam); if (m2 == MATCHnomatch) - { //printf("\tmatchArg() failed\n"); + { //printf("\tmatchArg() for parameter %i failed\n", i); goto Lnomatch; } @@ -289,12 +289,15 @@ goto Lnomatch; } - // Any parameter left without a type gets the type of its corresponding arg - for (int i = 0; i < dim; i++) + if (!flag) { - if (!dedtypes->data[i]) - { assert(i < ti->tiargs->dim); - dedtypes->data[i] = ti->tiargs->data[i]; + // Any parameter left without a type gets the type of its corresponding arg + for (int i = 0; i < dim; i++) + { + if (!dedtypes->data[i]) + { assert(i < ti->tiargs->dim); + dedtypes->data[i] = ti->tiargs->data[i]; + } } } @@ -385,12 +388,12 @@ if (td2->matchWithInstance(&ti, &dedtypes, 1)) { #if LOG_LEASTAS - printf(" is least as specialized\n"); + printf(" matches, so is least as specialized\n"); #endif return 1; } #if LOG_LEASTAS - printf(" is not as specialized\n"); + printf(" doesn't match, so is not as specialized\n"); #endif return 0; } @@ -843,11 +846,16 @@ // alias-parameter -TemplateAliasParameter::TemplateAliasParameter(Loc loc, Identifier *ident, Type *defaultAlias) +Dsymbol *TemplateAliasParameter::sdummy = NULL; + +TemplateAliasParameter::TemplateAliasParameter(Loc loc, Identifier *ident, Type *specAliasT, Type *defaultAlias) : TemplateParameter(loc, ident) { this->ident = ident; + this->specAliasT = specAliasT; this->defaultAlias = defaultAlias; + + this->specAlias = NULL; } TemplateAliasParameter *TemplateAliasParameter::isTemplateAliasParameter() @@ -857,7 +865,9 @@ TemplateParameter *TemplateAliasParameter::syntaxCopy() { - TemplateAliasParameter *tp = new TemplateAliasParameter(loc, ident, defaultAlias); + TemplateAliasParameter *tp = new TemplateAliasParameter(loc, ident, specAliasT, defaultAlias); + if (tp->specAliasT) + tp->specAliasT = specAliasT->syntaxCopy(); if (defaultAlias) tp->defaultAlias = defaultAlias->syntaxCopy(); return tp; @@ -870,6 +880,12 @@ if (!sc->insert(sparam)) error(loc, "parameter '%s' multiply defined", ident->toChars()); + if (specAliasT) + { + specAlias = specAliasT->toDsymbol(sc); + if (!specAlias) + error("%s is not a symbol", specAliasT->toChars()); + } #if 0 // Don't do semantic() until instantiation if (defaultAlias) defaultAlias = defaultAlias->semantic(loc, sc); @@ -882,6 +898,9 @@ if (tap) { + if (specAlias != tap->specAlias) + goto Lnomatch; + return 1; // match } @@ -917,6 +936,20 @@ if (!sa) goto Lnomatch; + if (specAlias) + { + if (!sa || sa == sdummy) + goto Lnomatch; + if (sa != specAlias) + goto Lnomatch; + } + else if (dedtypes->data[i]) + { // Must match already deduced symbol + Dsymbol *s = (Dsymbol *)dedtypes->data[i]; + + if (!sa || s != sa) + goto Lnomatch; + } dedtypes->data[i] = sa; *psparam = new AliasDeclaration(loc, ident, sa); @@ -942,6 +975,11 @@ { buf->writestring("alias "); buf->writestring(ident->toChars()); + if (specAliasT) + { + buf->writestring(" : "); + specAliasT->toCBuffer(buf, NULL); + } if (defaultAlias) { buf->writestring(" = "); @@ -951,28 +989,38 @@ void *TemplateAliasParameter::dummyArg() -{ - return NULL; // not sure what to put here +{ Dsymbol *s; + + s = specAlias; + if (!s) + { + if (!sdummy) + sdummy = new Dsymbol(); + s = sdummy; + } + return (void*)s; } Object *TemplateAliasParameter::defaultArg(Scope *sc) { - Type *t; + Dsymbol *s = NULL; - t = defaultAlias; - if (t) + if (defaultAlias) { - t = t->syntaxCopy(); - t = t->semantic(loc, sc); + s = defaultAlias->toDsymbol(sc); + if (!s) + error("%s is not a symbol", defaultAlias->toChars()); } - return t; + return s; } /* ======================== TemplateValueParameter ========================== */ // value-parameter +Expression *TemplateValueParameter::edummy = NULL; + TemplateValueParameter::TemplateValueParameter(Loc loc, Identifier *ident, Type *valType, Expression *specValue, Expression *defaultValue) : TemplateParameter(loc, ident) @@ -1070,7 +1118,7 @@ if (specValue) { - if (!ei) + if (!ei || ei == edummy) goto Lnomatch; Expression *e = specValue; @@ -1130,8 +1178,17 @@ void *TemplateValueParameter::dummyArg() -{ - return (void *)specValue; +{ Expression *e; + + e = specValue; + if (!e) + { + // Create a dummy value + if (!edummy) + edummy = new IntegerExp(0); + e = edummy; + } + return (void *)e; } @@ -1594,6 +1651,7 @@ // Disambiguate by picking the most specialized TemplateDeclaration int c1 = td->leastAsSpecialized(td_best); int c2 = td_best->leastAsSpecialized(td); + //printf("c1 = %d, c2 = %d\n", c1, c2); if (c1 && !c2) goto Ltd; @@ -1648,6 +1706,7 @@ { OutBuffer buf; char *id; + //printf("TemplateInstance::genIdent('%s')\n", tempdecl->ident->toChars()); buf.writestring(tempdecl->ident->toChars()); buf.writeByte('_'); for (int i = 0; i < tiargs->dim; i++) @@ -1688,8 +1747,13 @@ { error("cannot use local '%s' as template parameter", d->toChars()); } - char *p = sa->mangle(); - buf.printf("__%u_%s", strlen(p) + 1, p); + if (d && !d->type->deco) + error("forward reference of %s", d->toChars()); + else + { + char *p = sa->mangle(); + buf.printf("__%u_%s", strlen(p) + 1, p); + } } else assert(0); diff -uNr dmd-0.119/dmd/src/dmd/template.h dmd-0.120/dmd/src/dmd/template.h --- dmd-0.119/dmd/src/dmd/template.h 2004-07-30 15:01:40.000000000 +0200 +++ dmd-0.120/dmd/src/dmd/template.h 2005-04-04 17:00:58.000000000 +0200 @@ -123,6 +123,8 @@ Expression *specValue; Expression *defaultValue; + static Expression *edummy; + TemplateValueParameter(Loc loc, Identifier *ident, Type *valType, Expression *specValue, Expression *defaultValue); TemplateValueParameter *isTemplateValueParameter(); @@ -139,12 +141,17 @@ struct TemplateAliasParameter : TemplateParameter { /* Syntax: - * ident = defaultAlias + * ident : specAlias = defaultAlias */ + Type *specAliasT; + Dsymbol *specAlias; + Type *defaultAlias; - TemplateAliasParameter(Loc loc, Identifier *ident, Type *defaultAlias); + static Dsymbol *sdummy; + + TemplateAliasParameter(Loc loc, Identifier *ident, Type *specAliasT, Type *defaultAlias); TemplateAliasParameter *isTemplateAliasParameter(); TemplateParameter *syntaxCopy(); diff -uNr dmd-0.119/dmd/src/dmd/tocsym.c dmd-0.120/dmd/src/dmd/tocsym.c --- dmd-0.119/dmd/src/dmd/tocsym.c 2005-03-16 10:25:20.000000000 +0100 +++ dmd-0.120/dmd/src/dmd/tocsym.c 2005-04-01 16:14:58.000000000 +0200 @@ -22,6 +22,7 @@ #include "init.h" #include "attrib.h" #include "lexer.h" +#include "dsymbol.h" #include diff -uNr dmd-0.119/dmd/src/dmd/typinf.c dmd-0.120/dmd/src/dmd/typinf.c --- dmd-0.119/dmd/src/dmd/typinf.c 2005-02-12 00:45:56.000000000 +0100 +++ dmd-0.120/dmd/src/dmd/typinf.c 2005-03-26 00:30:20.000000000 +0100 @@ -1,6 +1,6 @@ -// Copyright (c) 1999-2004 by Digital Mars +// Copyright (c) 1999-2005 by Digital Mars // All Rights Reserved // written by Walter Bright // www.digitalmars.com @@ -38,6 +38,7 @@ #include "outbuf.h" #include "irstate.h" + /******************************************* * Get a canonicalized form of the TypeInfo for use with the internal * runtime library routines. Canonicalized in that static arrays are @@ -203,16 +204,29 @@ tftohash = (TypeFunction *)tftohash->semantic(0, &sc); } - TypeFunction *tfeq; + TypeFunction *tfeqptr; { Scope sc; Array *arguments = new Array; Argument *arg = new Argument(In, tc->pointerTo(), NULL, NULL); arguments->push(arg); + tfeqptr = new TypeFunction(arguments, Type::tint32, 0, LINKd); + tfeqptr = (TypeFunction *)tfeqptr->semantic(0, &sc); + } + +#if 0 + TypeFunction *tfeq; + { + Scope sc; + Array *arguments = new Array; + Argument *arg = new Argument(In, tc, NULL, NULL); + + arguments->push(arg); tfeq = new TypeFunction(arguments, Type::tint32, 0, LINKd); tfeq = (TypeFunction *)tfeq->semantic(0, &sc); } +#endif fdx = search_function(sd, Id::tohash); if (fdx) @@ -226,27 +240,20 @@ dtdword(pdt, 0); fdx = search_function(sd, Id::eq); - if (fdx) - { fd = fdx->overloadExactMatch(tfeq); - if (fd) - dtxoff(pdt, fd->toSymbol(), 0, TYnptr); - else - fdx->error("must be declared as extern (D) int %s(%s*)", fdx->toChars(), sd->toChars()); - } - else - dtdword(pdt, 0); - - fdx = search_function(sd, Id::cmp); - if (fdx) + for (int i = 0; i < 2; i++) { - fd = fdx->overloadExactMatch(tfeq); - if (fd) - dtxoff(pdt, fd->toSymbol(), 0, TYnptr); + if (fdx) + { fd = fdx->overloadExactMatch(tfeqptr); + if (fd) + dtxoff(pdt, fd->toSymbol(), 0, TYnptr); + else + fdx->error("must be declared as extern (D) int %s(%s*)", fdx->toChars(), sd->toChars()); + } else - fdx->error("must be declared as extern (D) int %s(%s*)", fdx->toChars(), sd->toChars()); + dtdword(pdt, 0); + + fdx = search_function(sd, Id::cmp); } - else - dtdword(pdt, 0); } void TypeInfoClassDeclaration::toDt(dt_t **pdt) diff -uNr dmd-0.119/dmd/src/dmd/version.c dmd-0.120/dmd/src/dmd/version.c --- dmd-0.119/dmd/src/dmd/version.c 2005-03-17 23:07:06.000000000 +0100 +++ dmd-0.120/dmd/src/dmd/version.c 2005-04-01 16:14:30.000000000 +0200 @@ -1,5 +1,5 @@ -// Copyright (c) 1999-2002 by Digital Mars +// Copyright (c) 1999-2005 by Digital Mars // All Rights Reserved // written by Walter Bright // www.digitalmars.com @@ -15,6 +15,7 @@ #include "dsymbol.h" #include "debcond.h" #include "version.h" +#include "module.h" /* ================================================== */ diff -uNr dmd-0.119/dmd/src/phobos/internal/dmain2.d dmd-0.120/dmd/src/phobos/internal/dmain2.d --- dmd-0.119/dmd/src/phobos/internal/dmain2.d 2005-03-18 09:29:40.000000000 +0100 +++ dmd-0.120/dmd/src/phobos/internal/dmain2.d 2005-04-06 12:26:42.000000000 +0200 @@ -70,6 +70,8 @@ args = am[0 .. argc]; result = main(args); + _moduleDtor(); + gc_term(); } catch (Object o) { @@ -78,8 +80,6 @@ exit(EXIT_FAILURE); } - _moduleDtor(); - gc_term(); version (linux) { free(am); diff -uNr dmd-0.119/dmd/src/phobos/internal/gc/gc.d dmd-0.120/dmd/src/phobos/internal/gc/gc.d --- dmd-0.119/dmd/src/phobos/internal/gc/gc.d 2005-03-18 09:29:42.000000000 +0100 +++ dmd-0.120/dmd/src/phobos/internal/gc/gc.d 2005-04-06 12:26:44.000000000 +0200 @@ -307,18 +307,24 @@ { ClassInfo c = **pc; - do + try { - if (c.destructor) + do { - fp_t fp = cast(fp_t)c.destructor; - (*fp)(cast(Object)p); // call destructor - } - c = c.base; - } while (c); - if ((cast(void**)p)[1]) // if monitor is not null - _d_monitorrelease(cast(Object)p); - *pc = null; // zero vptr + if (c.destructor) + { + fp_t fp = cast(fp_t)c.destructor; + (*fp)(cast(Object)p); // call destructor + } + c = c.base; + } while (c); + if ((cast(void**)p)[1]) // if monitor is not null + _d_monitorrelease(cast(Object)p); + } + finally + { + *pc = null; // zero vptr + } } } } @@ -450,6 +456,37 @@ return *cast(long*)px; } +extern (C) +long _d_arrayappendb(Array *px, bit[] y) +{ + + uint cap = _gc.capacity(px.data); + uint length = px.length; + uint newlength = length + y.length; + uint newsize = (newlength + 7) / 8; + if (newsize > cap) + { void* newdata; + + //newdata = _gc.malloc(newlength * size); + newdata = _gc.malloc(newCapacity(newsize, 1)); + memcpy(newdata, px.data, (length + 7) / 8); + px.data = cast(byte*)newdata; + } + px.length = newlength; + if ((length & 7) == 0) + // byte aligned, straightforward copy + memcpy(px.data + length / 8, y, (y.length + 7) / 8); + else + { bit* x = cast(bit*)px.data; + + for (size_t u = 0; u < y.length; u++) + { + x[length + u] = y[u]; + } + } + return *cast(long*)px; +} + uint newCapacity(uint newlength, uint size) { diff -uNr dmd-0.119/dmd/src/phobos/std/c/linux/linux.d dmd-0.120/dmd/src/phobos/std/c/linux/linux.d --- dmd-0.119/dmd/src/phobos/std/c/linux/linux.d 2005-03-18 09:29:40.000000000 +0100 +++ dmd-0.120/dmd/src/phobos/std/c/linux/linux.d 2005-04-06 12:26:44.000000000 +0200 @@ -9,6 +9,7 @@ import std.c.linux.linuxextern; alias int off_t; +alias uint mode_t; enum : int { @@ -109,11 +110,13 @@ int close(int); int lseek(int, int, int); int fstat(int, struct_stat*); + int lstat(char*, struct_stat*); int stat(char*, struct_stat*); int chdir(char*); int mkdir(char*, int); int rmdir(char*); char* getcwd(char*, int); + int chmod(char*, mode_t); } struct timeval @@ -257,8 +260,6 @@ private import std.intrinsic; - char* strerror(int errnum); - int select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* errorfds, timeval* timeout); int fcntl(int s, int f, ...); diff -uNr dmd-0.119/dmd/src/phobos/std/file.d dmd-0.120/dmd/src/phobos/std/file.d --- dmd-0.119/dmd/src/phobos/std/file.d 2005-03-18 09:29:36.000000000 +0100 +++ dmd-0.120/dmd/src/phobos/std/file.d 2005-04-06 12:26:40.000000000 +0200 @@ -795,7 +795,7 @@ int isfile(char[] name) { - return getAttributes(name) & S_IFREG; // regular file + return (getAttributes(name) & S_IFMT) == S_IFREG; // regular file } /**************************************************** @@ -804,7 +804,7 @@ int isdir(char[] name) { - return getAttributes(name) & S_IFDIR; + return (getAttributes(name) & S_IFMT) == S_IFDIR; } /**************************************************** @@ -887,7 +887,7 @@ dirent* fdata; h = opendir(toStringz(pathname)); - if (h) // if !h, should we throw exception? + if (h) { while((fdata = readdir(h)) != null) { @@ -902,6 +902,10 @@ } closedir(h); } + else + { + throw new FileException(pathname, getErrno()); + } } /*************************************************** diff -uNr dmd-0.119/dmd/src/phobos/std/openrj.d dmd-0.120/dmd/src/phobos/std/openrj.d --- dmd-0.119/dmd/src/phobos/std/openrj.d 2005-03-18 09:29:36.000000000 +0100 +++ dmd-0.120/dmd/src/phobos/std/openrj.d 2005-04-06 12:26:40.000000000 +0200 @@ -1,66 +1,1011 @@ - -// openrj.d -// placed into Public Domain +/* ///////////////////////////////////////////////////////////////////////////// + * File: std/openrj.d + * + * Purpose: Open-RJ/D mapping for the D standard library + * + * Created: 11th June 2004 + * Updated: 10th March 2005 + * + * Home: http://openrj.org/ + * + * Copyright 2004-2005 by Matthew Wilson and Synesis Software + * Written by Matthew Wilson + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, in both source and binary form, subject to the following + * restrictions: + * + * - The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * - Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * - This notice may not be removed or altered from any source + * distribution. + * + * ////////////////////////////////////////////////////////////////////////// */ + + +/* \file std/openrj.d Open-RJ/D mapping for the D standard library + * + */ + +/* ///////////////////////////////////////////////////////////////////////////// + * Module + */ module std.openrj; -import std.string; +/* ///////////////////////////////////////////////////////////////////////////// + * Imports + */ + +private import std.ctype; +version(MainTest) +{ + private import std.file; + private import std.perf; +} // version(MainTest) +private import std.string; + +/* ///////////////////////////////////////////////////////////////////////////// + * Version information + */ + +/// This'll be moved out to somewhere common soon + +private struct Version +{ + char[] name; + char[] description; + uint major; + uint minor; + uint revision; + uint edit; + ulong buildTime; +} + +public static Version VERSION = +{ + "std.openrj" + , "Record-JAR database reader" + , 1 + , 0 + , 7 + , 7 + , 0 +}; + +/* ///////////////////////////////////////////////////////////////////////////// + * Structs + */ + +/// This'll be moved out to somewhere common soon + +private struct EnumString +{ + int value; + char[] str; +}; + +private template enum_to_string(T) +{ + char[] enum_to_string(EnumString[] strings, T t) + { + // 'Optimised' search. + // + // Since many enums start at 0 and are contiguously ordered, it's quite + // likely that the value will equal the index. If it does, we can just + // return the string from that index. + int index = cast(int)(t); + + if( index >= 0 && + index < strings.length && + strings[index].value == index) + { + return strings[index].str; + } + + // Otherwise, just do a linear search + foreach(EnumString s; strings) + { + if(cast(int)(t) == s.value) + { + return s.str; + } + } + + return ""; + } +} + +/* ///////////////////////////////////////////////////////////////////////////// + * Enumerations + */ + +/** Flags that moderate the creation of Databases */ +public enum ORJ_FLAG +{ + ORDER_FIELDS = 0x0001 /*!< Arranges the fields in alphabetical order */ + , ELIDE_BLANK_RECORDS = 0x0002 /*!< Causes blank records to be ignored */ +} + +public char[] toString(ORJ_FLAG f) +{ + const EnumString strings[] = + [ + { ORJ_FLAG.ORDER_FIELDS, "Arranges the fields in alphabetical order" } + , { ORJ_FLAG.ELIDE_BLANK_RECORDS, "Causes blank records to be ignored" } + ]; + + return enum_to_string!(ORJ_FLAG)(strings, f); +} + +/** General error codes */ +public enum ORJRC +{ + SUCCESS = 0 /*!< Operation was successful */ + , CANNOT_OPEN_JAR_FILE /*!< The given file does not exist, or cannot be accessed */ + , NO_RECORDS /*!< The database file contained no records */ + , OUT_OF_MEMORY /*!< The API suffered memory exhaustion */ + , BAD_FILE_READ /*!< A read operation failed */ + , PARSE_ERROR /*!< Parsing of the database file failed due to a syntax error */ + , INVALID_INDEX /*!< An invalid index was specified */ + , UNEXPECTED /*!< An unexpected condition was encountered */ + , INVALID_CONTENT /*!< The database file contained invalid content */ +} + +public char[] toString(ORJRC f) +{ + const EnumString strings[] = + [ + { ORJRC.SUCCESS, "Operation was successful" } + , { ORJRC.CANNOT_OPEN_JAR_FILE, "The given file does not exist, or cannot be accessed" } + , { ORJRC.NO_RECORDS, "The database file contained no records" } + , { ORJRC.OUT_OF_MEMORY, "The API suffered memory exhaustion" } + , { ORJRC.BAD_FILE_READ, "A read operation failed" } + , { ORJRC.PARSE_ERROR, "Parsing of the database file failed due to a syntax error" } + , { ORJRC.INVALID_INDEX, "An invalid index was specified" } + , { ORJRC.UNEXPECTED, "An unexpected condition was encountered" } + , { ORJRC.INVALID_CONTENT, "The database file contained invalid content" } + ]; + + return enum_to_string!(ORJRC)(strings, f); +} + +/** Parsing error codes */ +public enum ORJ_PARSE_ERROR +{ + SUCCESS = 0 /*!< Parsing was successful */ + , RECORD_SEPARATOR_IN_CONTINUATION /*!< A record separator was encountered during a content line continuation */ + , UNFINISHED_LINE /*!< The last line in the database was not terminated by a line-feed */ + , UNFINISHED_FIELD /*!< The last field in the database file was not terminated by a record separator */ + , UNFINISHED_RECORD /*!< The last record in the database file was not terminated by a record separator */ +} + +public char[] toString(ORJ_PARSE_ERROR f) +{ + const EnumString strings[] = + [ + { ORJ_PARSE_ERROR.SUCCESS, "Parsing was successful" } + , { ORJ_PARSE_ERROR.RECORD_SEPARATOR_IN_CONTINUATION, "A record separator was encountered during a content line continuation" } + , { ORJ_PARSE_ERROR.UNFINISHED_LINE, "The last line in the database was not terminated by a line-feed" } + , { ORJ_PARSE_ERROR.UNFINISHED_FIELD, "The last field in the database file was not terminated by a record separator" } + , { ORJ_PARSE_ERROR.UNFINISHED_RECORD, "The last record in the database file was not terminated by a record separator" } + ]; + + return enum_to_string!(ORJ_PARSE_ERROR)(strings, f); +} + +/* ///////////////////////////////////////////////////////////////////////////// + * Classes + */ + +class OpenRJException + : public Exception +{ +/// \name Construction +/// @{ +protected: + this(char[] message) + { + super(message); + } +/// @} +} + +class DatabaseException + : public OpenRJException +{ +/// \name Construction +/// @{ +private: + this(char[] details, ORJRC rc) + { +//printf("DatabaseException(0: %.*s, %.*s)\n", details, std.openrj.toString(rc)); + + char[] message = std.string.format( "Database creation failed; error: %s, %s" + , cast(int)rc + , std.openrj.toString(rc)); + + m_rc = rc; + m_pe = ORJ_PARSE_ERROR.SUCCESS; + m_lineNum = -1; + + super(message); + } + + this(ORJRC rc, int lineNum) + { +//printf("DatabaseException(1: %.*s, %d)\n", std.openrj.toString(rc), lineNum); + + char[] message = std.string.format( "Database creation failed, at line %s; error: %s, %s" + , lineNum + , cast(int)rc + , std.openrj.toString(rc)); + + m_rc = rc; + m_pe = ORJ_PARSE_ERROR.SUCCESS; + m_lineNum = lineNum; + + super(message); + } + + this(ORJ_PARSE_ERROR pe, int lineNum) + { +//printf("DatabaseException(2: %.*s, %d)\n", std.openrj.toString(pe), lineNum); + + char[] message = std.string.format( "Parsing error in database, at line %s; parse error: %s, %s" + , lineNum + , cast(int)pe + , std.openrj.toString(pe)); + + m_rc = ORJRC.PARSE_ERROR; + m_pe = pe; + m_lineNum = lineNum; + + super(message); + } + + this(char[] details, ORJ_PARSE_ERROR pe, int lineNum) + { +//printf("DatabaseException(3: %.*s, %.*s, %d)\n", details, std.openrj.toString(rc), lineNum); + + char[] message = std.string.format( "Parsing error in database, at line %s; parse error: %s, %s; %s" + , lineNum + , cast(int)pe + , std.openrj.toString(pe) + , details); + + m_rc = ORJRC.PARSE_ERROR; + m_pe = pe; + m_lineNum = lineNum; + + super(message); + } +/// @} + +/// \name Attributes +/// @{ +public: + ORJRC rc() + { + return m_rc; + } + ORJ_PARSE_ERROR parseError() + { + return m_pe; + } + int lineNum() + { + return m_lineNum; + } +/// @} + +// Members +private: + int m_lineNum; + ORJRC m_rc; + ORJ_PARSE_ERROR m_pe; +} + +class InvalidKeyException + : public OpenRJException +{ +/// \name Construction +/// @{ +private: + this(char[] message) + { + super(message); + } +/// @} +} + +class InvalidTypeException + : public OpenRJException +{ +/// \name Construction +/// @{ +private: + this(char[] message) + { + super(message); + } +/// @} +} + +/* ///////////////////////////////////////////////////////////////////////////// + * Classes + */ + +/// Represents a field in the database +class Field +{ +/// \name Construction +/// @{ +private: + this(char[] name, char[] value/* , Record record */) + in + { + assert(null !== name); + assert(null !== value); + } + body + { + m_name = name; + m_value = value; + /* m_record = record; */ + } +/// @} + +/// \name Attributes +/// @{ +public: + final char[] name() + { + return m_name; + } + final char[] value() + { + return m_value; + } + Record record() + { + return m_record; + } +/// @} + +/// \name Comparison +/// @{ +/+ +public: + int opCmp(Object rhs) + { + Field f = cast(Field)(rhs); + + if(null === f) + { + throw new InvalidTypeException("Attempt to compare a Field with an instance of another type"); + } + + return opCmp(f); + } +public: + int opCmp(Field rhs) + { + int res; + + if(this === rhs) + { + res = 0; + } + else + { + res = std.string.cmp(m_name, rhs.m_name); + + if(0 == res) + { + res = std.string.cmp(m_value, rhs.m_value); + } + } -alias char[][] [char[]] [] openrj_t; + return res; + } ++/ +/// @} -class OpenrjException : Exception +// Members +private: + char[] m_name; + char[] m_value; + Record m_record; +} + +/// Represents a record in the database, consisting of a set of fields +class Record { - uint linnum; +/// \name Types +/// @{ +public: + alias object.size_t size_type; + alias object.size_t index_type; + alias object.ptrdiff_t difference_type; +/// @} + +/// \name Construction +/// @{ +private: + this(Field[] fields, uint flags, Database database) + { + m_fields = fields.dup; + + if(flags & ORJ_FLAG.ORDER_FIELDS) + { + m_fields = m_fields.sort; + } + + foreach(Field field; m_fields) + { + if(!(field.name in m_values)) + { + m_values[field.name] = field; + } + } - this(uint linnum, char[] msg) + m_database = database; + } +/// @} + +/// \name Attributes +/// @{ +public: + uint numFields() { - this.linnum = linnum; - super(std.string.format("OpenrjException line %s: %s", linnum, msg)); + return m_fields.length; } + + uint length() + { + return numFields(); + } + + Field[] fields() + { + return m_fields.dup; + } + + Field opIndex(index_type index) + in + { + assert(index < m_fields.length); + } + body + { + return m_fields[index]; + } + + char[] opIndex(char[] fieldName) + { + return getField(fieldName).value; + } + + Field getField(char[] fieldName) + in + { + assert(null !== fieldName); + } + body + { + Field field = findField(fieldName); + + if(null === field) + { + throw new InvalidKeyException("field not found"); + } + + return field; + } + + Field findField(char[] fieldName) + in + { + assert(null !== fieldName); + } + body + { + Field *pfield = (fieldName in m_values); + + return (null === pfield) ? null : *pfield; + } + + int hasField(char[] fieldName) + { + return null !== findField(fieldName); + } + + Database database() + { + return m_database; + } +/// @} + +/// \name Enumeration +/// @{ +public: + int opApply(int delegate(inout Field field) dg) + { + int result = 0; + + foreach(Field field; m_fields) + { + result = dg(field); + + if(0 != result) + { + break; + } + } + + return result; + } + + int opApply(int delegate(in char[] name, in char[] value) dg) + { + int result = 0; + + foreach(Field field; m_fields) + { + result = dg(field.name(), field.value()); + + if(0 != result) + { + break; + } + } + + return result; + } +/// @} + +// Members +private: + Field[] m_fields; + Field[char[]] m_values; + Database m_database; } -openrj_t parse(char[] db) +class Database { - openrj_t rj; - char[][] lines; - char[][] [char[]] record; +/// \name Types +/// @{ +public: + alias object.size_t size_type; + alias object.size_t index_type; + alias object.ptrdiff_t difference_type; +/// @} + +/// \name Construction +/// @{ +private: + void init_(char[][] lines, uint flags) + { + // Enumerate + int bContinuing = false; + Field[] fields; + char[] nextLine; + int lineNum = 1; + int nextLineNum = 1; + + foreach(char[] line; lines) + { + // Always strip trailing space + line = stripr(line); + + // Check that we don't start a continued line with a record separator + if( bContinuing && + line.length > 1 && + "%%" == line[0 .. 2]) + { + throw new DatabaseException(ORJ_PARSE_ERROR.RECORD_SEPARATOR_IN_CONTINUATION, lineNum); + } + + // Always strip leading whitespace + line = stripl(line); + + int bContinuationLine; + + if( line.length > 0 && + '\\' == line[line.length - 1]) + { + bContinuationLine = true; + bContinuing = true; + line = line[0 .. line.length - 1]; + } + + // Always add on to the previous line + nextLine = nextLine ~ line; + + line = null; + + if(!bContinuationLine) + { + if(0 == nextLine.length) + { + // Just ignore these lines + } + else if(1 == nextLine.length) + { + throw new DatabaseException(ORJ_PARSE_ERROR.UNFINISHED_FIELD, lineNum); + } + else + { + if("%%" == nextLine[0 .. 2]) + { + // Comment line - terminate the record +// printf("-- record --\n"); + + if( 0 != fields.length || + 0 == (ORJ_FLAG.ELIDE_BLANK_RECORDS & flags)) + { + Record record = new Record(fields, flags, this); + + foreach(Field field; fields) + { + field.m_record = record; + } + + m_records ~= record; + fields = null; + } + } + else + { + int colon = find(nextLine, ':'); + + if(-1 == colon) + { + throw new DatabaseException(ORJ_PARSE_ERROR.UNFINISHED_FIELD, lineNum); + } + +// printf("%.*s(%d): %.*s (%d)\n", file, nextLineNum, nextLine, colon); + + char[] name = nextLine[0 .. colon]; + char[] value = nextLine[colon + 1 .. nextLine.length]; + + name = stripr(name); + value = stripl(value); + +// printf("%.*s(%d): %.*s=%.*s\n", file, nextLineNum, name, value); + + Field field = new Field(name, value); + + fields ~= field; + m_fields ~= field; + } + } + + nextLine = ""; + nextLineNum = lineNum + 1; + bContinuing = false; + } + +/+ // This is currently commented out as it seems unlikely to be sensible to + // order the Fields globally. The reasoning is that if the Fields are used + // globally then it's more likely that their ordering in the database source + // is meaningful. If someone really needs an all-Fields array ordered, they + // can do it manually. + if(flags & ORJ_FLAG.ORDER_FIELDS) + { + m_fields = m_fields.sort; + } ++/ + + ++lineNum; + } + if(bContinuing) + { + throw new DatabaseException(ORJ_PARSE_ERROR.UNFINISHED_LINE, lineNum); + } + if(fields.length > 0) + { + throw new DatabaseException(ORJ_PARSE_ERROR.UNFINISHED_RECORD, lineNum); + } + if(0 == m_records.length) + { + throw new DatabaseException(ORJRC.NO_RECORDS, lineNum); + } - lines = std.string.splitlines(db); + m_flags = flags; + m_numLines = lines.length; + } +public: + this(char[] memory, uint flags) + { + char[][] lines = split(memory, "\n"); - for (uint linnum = 0; linnum < lines.length; linnum++) + init_(lines, flags); + } + + this(char[][] lines, uint flags) { - char[] line = lines[linnum]; + init_(lines, flags); + } +/// @} - // Splice lines ending with backslash - while (line.length && line[length - 1] == '\\') - { - if (++linnum == lines.length) - throw new OpenrjException(linnum, "no line after \\ line"); - line = line[0 .. length - 1] ~ lines[linnum]; - } +/// \name Attributes +/// @{ +public: + size_type numRecords() + { + return m_records.length; + } + size_type numFields() + { + return m_fields.length; + } + size_type numLines() + { + return m_numLines; + } +/// @} - if (line[0 .. 2] == "%%") - { - // Comment lines separate records - if (record) - rj ~= record; - record = null; - line = null; - continue; - } +/// \name Attributes +/// @{ +public: + uint flags() + { + return m_flags; + } - int colon = std.string.find(line, ':'); - if (colon == -1) - throw new OpenrjException(linnum, "'key : value' expected"); + Record[] records() + { + return m_records.dup; + } - char[] key = std.string.strip(line[0 .. colon]); - char[] value = std.string.strip(line[colon + 1 .. length]); + Field[] fields() + { + return m_fields.dup; + } - char[][] fields = record[key]; - fields ~= value; - record[key] = fields; + uint length() + { + return numRecords(); } - if (record) - rj ~= record; - return rj; + + Record opIndex(index_type index) + in + { + assert(index < m_records.length); + } + body + { + return m_records[index]; + } +/// @} + +/// \name Searching +/// @{ +public: + Record[] getRecordsContainingField(char[] fieldName) + { + Record[] records; + + foreach(Record record; m_records) + { + if(null !== record.findField(fieldName)) + { + records ~= record; + } + } + + return records; + } + + Record[] getRecordsContainingField(char[] fieldName, char[] fieldValue) + { + Record[] records; + uint flags = flags; + + foreach(Record record; m_records) + { + Field field = record.findField(fieldName); + + if(null !== field) + { + // Since there can be more than one field with the same name in + // the same record, we need to search all fields in this record + if(ORJ_FLAG.ORDER_FIELDS == (flags & ORJ_FLAG.ORDER_FIELDS)) + { + // We can do a sorted search + foreach(Field field; record) + { + int res = cmp(field.name, fieldName); + + if( 0 == res && + ( null === fieldValue || + field.value == fieldValue)) + { + records ~= record; + + break; + } + else if(res > 0) + { + break; + } + } + } + else + { + foreach(Field field; record) + { + if( field.name == fieldName && + ( null === fieldValue || + field.value == fieldValue)) + { + records ~= record; + + break; + } + } + } + } + } + + return records; + } +/// @} + +/// \name Enumeration +/// @{ +public: + int opApply(int delegate(inout Record record) dg) + { + int result = 0; + + foreach(Record record; m_records) + { + result = dg(record); + + if(0 != result) + { + break; + } + }; + + return result; + } + int opApply(int delegate(inout Field field) dg) + { + int result = 0; + + foreach(Field field; m_fields) + { + result = dg(field); + + if(0 != result) + { + break; + } + }; + + return result; + } +/// @} + +// Members +private: + uint m_flags; + size_type m_numLines; + Record[] m_records; + Field[] m_fields; } + +/* ////////////////////////////////////////////////////////////////////////// */ + +version(MainTest) +{ + + int main(char[][] args) + { + int flags = 0 + | ORJ_FLAG.ORDER_FIELDS + | ORJ_FLAG.ELIDE_BLANK_RECORDS + | 0; + + if(args.length < 2) + { + printf("Need to specify jar file\n"); + } + else + { + PerformanceCounter counter = new PerformanceCounter(); + + try + { + printf( "std.openrj test:\n\tmodule: \t%.*s\n\tdescription: \t%.*s\n\tversion: \t%d.%d.%d.%d\n" + , std.openrj.VERSION.name + , std.openrj.VERSION.description + , std.openrj.VERSION.major + , std.openrj.VERSION.minor + , std.openrj.VERSION.revision + , std.openrj.VERSION.edit); + + counter.start(); + + char[] file = args[1]; + char[] chars = cast(char[])std.file.read(file); + Database database = new Database(chars, flags); +// Database database = new Database(split(chars, "\n"), flags); + + counter.stop(); + + PerformanceCounter.interval_type loadTime = counter.microseconds(); + + counter.start(); + + int i = 0; + foreach(Record record; database.records) + { + foreach(Field field; record) + { + i += field.name.length + field.value.length; + } + } + + counter.stop(); + + PerformanceCounter.interval_type enumerateTime = counter.microseconds(); + + printf("Open-RJ/D test: 100%%-D!!\n"); + printf("Load time: %ld\n", loadTime); + printf("Enumerate time: %ld\n", enumerateTime); + + return 0; + + printf("Records (%u)\n", database.numRecords); + foreach(Record record; database) + { + printf(" Record\n"); + foreach(Field field; record.fields) + { + printf(" Field: %.*s=%.*s\n", field.name, field.value); + } + } + + printf("Fields (%u)\n", database.numFields); + foreach(Field field; database) + { + printf(" Field: %.*s=%.*s\n", field.name, field.value); + } + + Record[] records = database.getRecordsContainingField("Name"); + printf("Records containing 'Name' (%u)\n", records); + foreach(Record record; records) + { + printf(" Record\n"); + foreach(Field field; record.fields) + { + printf(" Field: %.*s=%.*s\n", field.name, field.value); + } + } + } + catch(Exception x) + { + printf("Exception: %.*s\n", x.toString()); + } + } + + return 0; + } + +} // version(MainTest) + +/* ////////////////////////////////////////////////////////////////////////// */ diff -uNr dmd-0.119/dmd/src/phobos/std/stream.d dmd-0.120/dmd/src/phobos/std/stream.d --- dmd-0.119/dmd/src/phobos/std/stream.d 2005-03-18 09:29:36.000000000 +0100 +++ dmd-0.120/dmd/src/phobos/std/stream.d 2005-04-06 12:26:40.000000000 +0200 @@ -1,7 +1,10 @@ /* - * Copyright (c) 2001, 2002 + * Copyright (c) 2001-2005 * Pavel "EvilOne" Minayev * with buffering and endian support added by Ben Hinkle + * with buffered readLine performance improvements by Dave Fladebo + * with opApply inspired by (and mostly copied from) Regan Heath + * with bug fixes and MemoryStream/SliceStream enhancements by Derick Eddington * * Permission to use, copy, modify, distribute and sell this software * and its documentation for any purpose is hereby granted without fee, @@ -29,106 +32,98 @@ // generic Stream exception, base class for all // other Stream exceptions -class StreamException: Exception -{ +class StreamException: Exception { this(char[] msg) { super(msg); } } alias StreamException StreamError; // for backwards compatibility // thrown when unable to read data from Stream -class ReadException: StreamException -{ +class ReadException: StreamException { this(char[] msg) { super(msg); } } alias ReadException ReadError; // for backwards compatibility // thrown when unable to write data to Stream -class WriteException: StreamException -{ +class WriteException: StreamException { this(char[] msg) { super(msg); } } alias WriteException WriteError; // for backwards compatibility // thrown when unable to move Stream pointer -class SeekException: StreamException -{ +class SeekException: StreamException { this(char[] msg) { super(msg); } } alias SeekException SeekError; // for backwards compatibility // seek whence... -enum SeekPos - { - Set, - Current, - End - } +enum SeekPos { + Set, + Current, + End +} import std.format; alias std.format.va_list va_list; private import std.c.stdio; alias std.c.stdio.va_list c_va_list; -private -{ +private { import std.system; // for Endian enumeration import std.intrinsic; // for bswap import std.utf; } -version (Windows) -{ - private import std.file; +version (Windows) { + private import std.file; } // Interface for readable streams -interface InputStream -{ +interface InputStream { // reads block of data of specified size, // throws ReadException on error - void readExact(void* buffer, uint size); + void readExact(void* buffer, size_t size); // reads block of data big enough to fill the given // array, returns actual number of bytes read - uint read(ubyte[] buffer); + size_t read(ubyte[] buffer); // read a single value of desired type, // throw ReadException on error - void read(out byte x); - void read(out ubyte x); - void read(out short x); + void read(out byte x); + void read(out ubyte x); + void read(out short x); void read(out ushort x); - void read(out int x); - void read(out uint x); - void read(out long x); - void read(out ulong x); - void read(out float x); + void read(out int x); + void read(out uint x); + void read(out long x); + void read(out ulong x); + void read(out float x); void read(out double x); - void read(out real x); - void read(out ifloat x); + void read(out real x); + void read(out ifloat x); void read(out idouble x); void read(out ireal x); - void read(out cfloat x); + void read(out cfloat x); void read(out cdouble x); void read(out creal x); - void read(out char x); - void read(out wchar x); - void read(out dchar x); - + void read(out char x); + void read(out wchar x); + void read(out dchar x); + // reads a string, written earlier by write() void read(out char[] s); - + // reads a Unicode string, written earlier by write() void read(out wchar[] s); - + // reads a line, terminated by either CR, LF, CR/LF, or EOF char[] readLine(); // reads a line, terminated by either CR, LF, CR/LF, or EOF // reusing the memory in result and reallocating if needed char[] readLine(char[] result); - + // reads a Unicode line, terminated by either CR, LF, CR/LF, // or EOF; pretty much the same as the above, working with // wchars rather than chars @@ -139,22 +134,28 @@ // wchars rather than chars wchar[] readLineW(wchar[] result); + // iterate through the stream line-by-line + int opApply(int delegate(inout char[] line) dg); + int opApply(int delegate(inout ulong n, inout char[] line) dg); + int opApply(int delegate(inout wchar[] line) dg); + int opApply(int delegate(inout ulong n, inout wchar[] line) dg); + // reads a string of given length, throws // ReadException on error - char[] readString(uint length); + char[] readString(size_t length); // reads a Unicode string of given length, throws // ReadException on error - wchar[] readStringW(uint length); - + wchar[] readStringW(size_t length); + // reads and returns next character from the stream, // handles characters pushed back by ungetc() char getc(); - + // reads and returns next Unicode character from the // stream, handles characters pushed back by ungetc() wchar getcw(); - + // pushes back character c into the stream; only has // effect on further calls to getc() and getcw() char ungetc(char c); @@ -167,46 +168,45 @@ int scanf(char[] format, ...); - uint available(); + size_t available(); } // Interface for writable streams -interface OutputStream -{ +interface OutputStream { // writes block of data of specified size, // throws WriteException on error - void writeExact(void* buffer, uint size); + void writeExact(void* buffer, size_t size); // writes the given array of bytes, returns // actual number of bytes written - uint write(ubyte[] buffer); - + size_t write(ubyte[] buffer); + // write a single value of desired type, // throw WriteException on error - void write(byte x); + void write(byte x); void write(ubyte x); void write(short x); - void write(ushort x); - void write(int x); + void write(ushort x); + void write(int x); void write(uint x); void write(long x); void write(ulong x); void write(float x); void write(double x); - void write(real x); + void write(real x); void write(ifloat x); void write(idouble x); void write(ireal x); void write(cfloat x); void write(cdouble x); void write(creal x); - void write(char x); + void write(char x); void write(wchar x); void write(dchar x); - + // writes a string, together with its length void write(char[] s); - + // writes a Unicode string, together with its length void write(wchar[] s); @@ -224,50 +224,47 @@ // writes data to stream using vprintf() syntax, // returns number of bytes written - uint vprintf(char[] format, c_va_list args); + size_t vprintf(char[] format, c_va_list args); // writes data to stream using printf() syntax, // returns number of bytes written - uint printf(char[] format, ...); + size_t printf(char[] format, ...); - // writes data to stream using writef() syntax, - void writef(...); + // writes data to stream using writef() syntax and returns self + Stream writef(...); - // writes data with trailing newline - void writefln(...); + // writes data with trailing newline and returns self + Stream writefln(...); } // base class for all streams; not really abstract, // but its instances will do nothing useful -class Stream : InputStream, OutputStream -{ +class Stream : InputStream, OutputStream { private import std.string, crc32, std.c.stdlib, std.c.stdio; // stream abilities bit readable = false; bit writeable = false; bit seekable = false; - private bit isopen = true; + protected bit isopen = true; this() {} // reads block of data of specified size, // returns actual number of bytes read - abstract uint readBlock(void* buffer, uint size); + abstract size_t readBlock(void* buffer, size_t size); // reads block of data of specified size, // throws ReadException on error - void readExact(void* buffer, uint size) - { - uint readsize = readBlock(buffer, size); + void readExact(void* buffer, size_t size) { + size_t readsize = readBlock(buffer, size); if (readsize != size) throw new ReadException("not enough data in stream"); } // reads block of data big enough to fill the given // array, returns actual number of bytes read - uint read(ubyte[] buffer) - { + size_t read(ubyte[] buffer) { return readBlock(buffer, buffer.length); } @@ -293,133 +290,166 @@ void read(out char x) { readExact(&x, x.sizeof); } void read(out wchar x) { readExact(&x, x.sizeof); } void read(out dchar x) { readExact(&x, x.sizeof); } - + // reads a string, written earlier by write() - void read(out char[] s) - { - int len; + void read(out char[] s) { + size_t len; read(len); s = readString(len); } - + // reads a Unicode string, written earlier by write() - void read(out wchar[] s) - { - int len; + void read(out wchar[] s) { + size_t len; read(len); s = readStringW(len); } - + // reads a line, terminated by either CR, LF, CR/LF, or EOF - char[] readLine() - { + char[] readLine() { return readLine(null); } // reads a line, terminated by either CR, LF, CR/LF, or EOF // reusing the memory in buffer if result will fit and otherwise // allocates a new string - char[] readLine(char[] result) - { - uint strlen = 0; - try - { - char ch = getc(); - while (readable) { - switch (ch) - { - case '\r': - { - ch = getc(); - if (ch != '\n') - ungetc(ch); - } - - case '\n': - result.length = strlen; - return result; - - default: - if (strlen < result.length) { - result[strlen] = ch; - } - else { - result ~= ch; - } - strlen++; - } + char[] readLine(char[] result) { + size_t strlen = 0; + try { + char ch = getc(); + while (readable) { + switch (ch) { + case '\r': { ch = getc(); + if (ch != '\n') + ungetc(ch); } + + case '\n': + result.length = strlen; + return result; + + default: + if (strlen < result.length) { + result[strlen] = ch; + } else { + result ~= ch; + } + strlen++; + } + ch = getc(); } - catch (ReadException e) - { - // either this is end of stream, which is okay, - // or something bad occured while reading - if (!eof()) - throw e; - } + } catch (ReadException e) { + // either this is end of stream, which is okay, + // or something bad occured while reading + if (!eof()) + throw e; + } result.length = strlen; return result; } - + // reads a Unicode line, terminated by either CR, LF, CR/LF, // or EOF; pretty much the same as the above, working with // wchars rather than chars - wchar[] readLineW() - { + wchar[] readLineW() { return readLineW(null); } // reads a Unicode line, terminated by either CR, LF, CR/LF, - // or EOF; + // or EOF; // fills supplied buffer if line fits and otherwise allocates a new string. - wchar[] readLineW(wchar[] result) - { - uint strlen = 0; - try - { - wchar c = getcw(); - while (readable) { - switch (c) - { - case '\r': - { - c = getcw(); - if (c != '\n') - ungetcw(c); - } - - case '\n': - result.length = strlen; - return result; - - default: - if (strlen < result.length) { - result[strlen] = c; - } - else { - result ~= c; - } - strlen++; - } + wchar[] readLineW(wchar[] result) { + size_t strlen = 0; + try { + wchar c = getcw(); + while (readable) { + switch (c) { + case '\r': { c = getcw(); + if (c != '\n') + ungetcw(c); } + + case '\n': + result.length = strlen; + return result; + + default: + if (strlen < result.length) { + result[strlen] = c; + } else { + result ~= c; + } + strlen++; + } + c = getcw(); } - catch (ReadException e) - { - // either this is end of stream, which is okay, - // or something bad occured while reading - if (!eof()) - throw e; - } + } catch (ReadException e) { + // either this is end of stream, which is okay, + // or something bad occured while reading + if (!eof()) + throw e; + } result.length = strlen; return result; } + // iterate through the stream line-by-line - due to Regan Heath + int opApply(int delegate(inout char[] line) dg) { + int res = 0; + char[128] buf; + while (!eof()) { + char[] line = readLine(buf); + res = dg(line); + if (res) break; + } + return res; + } + + // iterate through the stream line-by-line with line count and char[] + int opApply(int delegate(inout ulong n, inout char[] line) dg) { + int res = 0; + ulong n = 1; + char[128] buf; + while (!eof()) { + char[] line = readLine(buf); + res = dg(n,line); + if (res) break; + n++; + } + return res; + } + + // iterate through the stream line-by-line with wchar[] + int opApply(int delegate(inout wchar[] line) dg) { + int res = 0; + wchar[128] buf; + while (!eof()) { + wchar[] line = readLineW(buf); + res = dg(line); + if (res) break; + } + return res; + } + + // iterate through the stream line-by-line with line count and wchar[] + int opApply(int delegate(inout ulong n, inout wchar[] line) dg) { + int res = 0; + ulong n = 1; + wchar[128] buf; + while (!eof()) { + wchar[] line = readLineW(buf); + res = dg(n,line); + if (res) break; + n++; + } + return res; + } + // reads a string of given length, throws // ReadException on error - char[] readString(uint length) - { + char[] readString(size_t length) { char[] result = new char[length]; readExact(result, length); return result; @@ -427,422 +457,353 @@ // reads a Unicode string of given length, throws // ReadException on error - wchar[] readStringW(uint length) - { + wchar[] readStringW(size_t length) { wchar[] result = new wchar[length]; readExact(result, result.length * wchar.sizeof); return result; } - + // unget buffer private wchar[] unget; - + // reads and returns next character from the stream, // handles characters pushed back by ungetc() - char getc() - { + char getc() { char c; - if (unget.length > 1) - { - c = unget[unget.length - 1]; - unget.length = unget.length - 1; - } - else + if (unget.length > 1) { + c = unget[unget.length - 1]; + unget.length = unget.length - 1; + } else { read(c); + } return c; } - + // reads and returns next Unicode character from the // stream, handles characters pushed back by ungetc() - wchar getcw() - { + wchar getcw() { wchar c; - if (unget.length > 1) - { - c = unget[unget.length - 1]; - unget.length = unget.length - 1; - } - else + if (unget.length > 1) { + c = unget[unget.length - 1]; + unget.length = unget.length - 1; + } else { read(c); + } return c; } - + // pushes back character c into the stream; only has // effect on further calls to getc() and getcw() - char ungetc(char c) - { + char ungetc(char c) { // first byte is a dummy so that we never set length to 0 if (unget.length == 0) unget.length = 1; - unget ~= c; return c; } - + // pushes back Unicode character c into the stream; only // has effect on further calls to getc() and getcw() - wchar ungetcw(wchar c) - { + wchar ungetcw(wchar c) { // first byte is a dummy so that we never set length to 0 if (unget.length == 0) unget.length = 1; - unget ~= c; return c; } - - int vscanf(char[] fmt, c_va_list args) - { + + int vscanf(char[] fmt, c_va_list args) { void** arg = cast(void**) args; int count = 0, i = 0; - try - { - char c = getc(); - while (i < fmt.length) - { - if (fmt[i] == '%') // a field - { - i++; - bit suppress = false; - if (fmt[i] == '*') // suppress assignment - { - suppress = true; - i++; - } - // read field width - int width = 0; - while (isdigit(fmt[i])) - { - width = width * 10 + (fmt[i] - '0'); - i++; - } - if (width == 0) - width = -1; - // D string? - bit dstr = false; - if (fmt[i] == '.') - { - i++; - if (fmt[i] == '*') - { - dstr = true; - i++; - } - } - // read the modifier - char modifier = fmt[i]; - if (modifier == 'h' || modifier == 'l' || modifier == 'L') - i++; - else - modifier = 0; - // check the typechar and act accordingly - switch (fmt[i]) - { - case 'd': // decimal/hexadecimal/octal integer - case 'D': - case 'u': - case 'U': - case 'o': - case 'O': - case 'x': - case 'X': - case 'i': - case 'I': - { - while (iswhite(c)) - { - c = getc(); - count++; - } - bit neg = false; - if (c == '-') - { - neg = true; - c = getc(); - count++; - } - else if (c == '+') - { - c = getc(); - count++; - } - char ifmt = fmt[i] | 0x20; - if (ifmt == 'i') // undetermined base - { - if (c == '0') // octal or hex - { - c = getc(); - count++; - if (c == 'x' || c == 'X') // hex - { - ifmt = 'x'; - c = getc(); - count++; - } - else // octal - ifmt = 'o'; - } - else // decimal - ifmt = 'd'; - } - long n = 0; - switch (ifmt) - { - case 'd': // decimal - case 'u': - { - while (isdigit(c) && width) - { - n = n * 10 + (c - '0'); - width--; - c = getc(); - count++; - } - } break; - - case 'o': // octal - { - while (isoctdigit(c) && width) - { - n = n * 010 + (c - '0'); - width--; - c = getc(); - count++; - } - } break; - - case 'x': // hexadecimal - { - while (ishexdigit(c) && width) - { - n *= 0x10; - if (isdigit(c)) - n += c - '0'; - else - n += 0xA + (c | 0x20) - 'a'; - width--; - c = getc(); - count++; - } - } break; - } - if (neg) - n = -n; - // check the modifier and cast the pointer - // to appropriate type - switch (modifier) - { - case 'h': // short - { - *cast(short*)*arg = n; - } break; - - case 'L': // long - { - *cast(long*)*arg = n; - } break; - - default: // int - *cast(int*)*arg = n; - } - i++; - } break; - - case 'f': // float - case 'F': - case 'e': - case 'E': - case 'g': - case 'G': - { - while (iswhite(c)) - { - c = getc(); - count++; - } - bit neg = false; - if (c == '-') - { - neg = true; - c = getc(); - count++; - } - else if (c == '+') - { - c = getc(); - count++; - } - real n = 0; - while (isdigit(c) && width) - { - n = n * 10 + (c - '0'); - width--; - c = getc(); - count++; - } - if (width && c == '.') - { - width--; - c = getc(); - count++; - double frac = 1; - while (isdigit(c) && width) - { - n = n * 10 + (c - '0'); - frac *= 10; - width--; - c = getc(); - count++; - } - n /= frac; - } - if (width && (c == 'e' || c == 'E')) - { - width--; - c = getc(); - count++; - if (width) - { - bit expneg = false; - if (c == '-') - { - expneg = true; - width--; - c = getc(); - count++; - } - else if (c == '+') - { - width--; - c = getc(); - count++; - } - real exp = 0; - while (isdigit(c) && width) - { - exp = exp * 10 + (c - '0'); - width--; - c = getc(); - count++; - } - if (expneg) - { - while (exp--) - n /= 10; - } - else - { - while (exp--) - n *= 10; - } - } - } - if (neg) - n = -n; - // check the modifier and cast the pointer - // to appropriate type - switch (modifier) - { - case 'l': // double - { - *cast(double*)*arg = n; - } break; - - case 'L': // real - { - *cast(real*)*arg = n; - } break; - - default: // float - *cast(float*)*arg = n; - } - i++; - } break; - - case 's': // ANSI string - { - while (iswhite(c)) - { - c = getc(); - count++; - } - char[] s; - while (!iswhite(c)) - { - s ~= c; - c = getc(); - count++; - } - if (dstr) // D string (char[]) - *cast(char[]*)*arg = s; - else // C string (char*) - { - s ~= 0; - (cast(char*)*arg)[0 .. s.length] = s[]; - } - i++; - } break; - - case 'c': // character(s) - { - char* s = cast(char*)*arg; - if (width < 0) - width = 1; - else - while (iswhite(c)) - { - c = getc(); - count++; - } - while (width--) - { - *(s++) = c; - c = getc(); - count++; - } - i++; - } break; - - case 'n': // number of chars read so far - { - *cast(int*)*arg = count; - i++; - } break; - - default: // read character as is - goto nws; + try { + char c = getc(); + while (i < fmt.length) { + if (fmt[i] == '%') { // a field + i++; + bit suppress = false; + if (fmt[i] == '*') { // suppress assignment + suppress = true; + i++; + } + // read field width + int width = 0; + while (isdigit(fmt[i])) { + width = width * 10 + (fmt[i] - '0'); + i++; + } + if (width == 0) + width = -1; + // D string? + bit dstr = false; + if (fmt[i] == '.') { + i++; + if (fmt[i] == '*') { + dstr = true; + i++; + } + } + // read the modifier + char modifier = fmt[i]; + if (modifier == 'h' || modifier == 'l' || modifier == 'L') + i++; + else + modifier = 0; + // check the typechar and act accordingly + switch (fmt[i]) { + case 'd': // decimal/hexadecimal/octal integer + case 'D': + case 'u': + case 'U': + case 'o': + case 'O': + case 'x': + case 'X': + case 'i': + case 'I': + { + while (iswhite(c)) { + c = getc(); + count++; + } + bit neg = false; + if (c == '-') { + neg = true; + c = getc(); + count++; + } else if (c == '+') { + c = getc(); + count++; + } + char ifmt = fmt[i] | 0x20; + if (ifmt == 'i') { // undetermined base + if (c == '0') { // octal or hex + c = getc(); + count++; + if (c == 'x' || c == 'X') { // hex + ifmt = 'x'; + c = getc(); + count++; + } else { // octal + ifmt = 'o'; } - arg++; + } + else // decimal + ifmt = 'd'; + } + long n = 0; + switch (ifmt) { + case 'd': // decimal + case 'u': { + while (isdigit(c) && width) { + n = n * 10 + (c - '0'); + width--; + c = getc(); + count++; + } + } break; + + case 'o': { // octal + while (isoctdigit(c) && width) { + n = n * 010 + (c - '0'); + width--; + c = getc(); + count++; + } + } break; + + case 'x': { // hexadecimal + while (ishexdigit(c) && width) { + n *= 0x10; + if (isdigit(c)) + n += c - '0'; + else + n += 0xA + (c | 0x20) - 'a'; + width--; + c = getc(); + count++; + } + } break; + } + if (neg) + n = -n; + // check the modifier and cast the pointer + // to appropriate type + switch (modifier) { + case 'h': { // short + *cast(short*)*arg = n; + } break; + + case 'L': { // long + *cast(long*)*arg = n; + } break; + + default: // int + *cast(int*)*arg = n; } - else if (iswhite(fmt[i])) // skip whitespace - { - while (iswhite(c)) + i++; + } break; + + case 'f': // float + case 'F': + case 'e': + case 'E': + case 'g': + case 'G': + { + while (iswhite(c)) { + c = getc(); + count++; + } + bit neg = false; + if (c == '-') { + neg = true; + c = getc(); + count++; + } else if (c == '+') { + c = getc(); + count++; + } + real n = 0; + while (isdigit(c) && width) { + n = n * 10 + (c - '0'); + width--; + c = getc(); + count++; + } + if (width && c == '.') { + width--; + c = getc(); + count++; + double frac = 1; + while (isdigit(c) && width) { + n = n * 10 + (c - '0'); + frac *= 10; + width--; c = getc(); - i++; + count++; + } + n /= frac; } - else // read character as is - { - nws: - if (fmt[i] != c) - break; + if (width && (c == 'e' || c == 'E')) { + width--; c = getc(); - i++; + count++; + if (width) { + bit expneg = false; + if (c == '-') { + expneg = true; + width--; + c = getc(); + count++; + } else if (c == '+') { + width--; + c = getc(); + count++; + } + real exp = 0; + while (isdigit(c) && width) { + exp = exp * 10 + (c - '0'); + width--; + c = getc(); + count++; + } + if (expneg) { + while (exp--) + n /= 10; + } else { + while (exp--) + n *= 10; + } + } } - } - ungetc(c); - } - catch (ReadException e) - { - // either this is end of stream, which is okay, - // or something bad occured while reading - if (!eof()) - throw e; + if (neg) + n = -n; + // check the modifier and cast the pointer + // to appropriate type + switch (modifier) { + case 'l': { // double + *cast(double*)*arg = n; + } break; + + case 'L': { // real + *cast(real*)*arg = n; + } break; + + default: // float + *cast(float*)*arg = n; + } + i++; + } break; + + case 's': { // ANSI string + while (iswhite(c)) { + c = getc(); + count++; + } + char[] s; + while (!iswhite(c)) { + s ~= c; + c = getc(); + count++; + } + if (dstr) // D string (char[]) + *cast(char[]*)*arg = s; + else { // C string (char*) + s ~= 0; + (cast(char*)*arg)[0 .. s.length] = s[]; + } + i++; + } break; + + case 'c': { // character(s) + char* s = cast(char*)*arg; + if (width < 0) + width = 1; + else + while (iswhite(c)) { + c = getc(); + count++; + } + while (width--) { + *(s++) = c; + c = getc(); + count++; + } + i++; + } break; + + case 'n': { // number of chars read so far + *cast(int*)*arg = count; + i++; + } break; + + default: // read character as is + goto nws; + } + arg++; + } else if (iswhite(fmt[i])) { // skip whitespace + while (iswhite(c)) + c = getc(); + i++; + } else { // read character as is + nws: + if (fmt[i] != c) + break; + c = getc(); + i++; + } } + ungetc(c); + } catch (ReadException e) { + // either this is end of stream, which is okay, + // or something bad occured while reading + if (!eof()) + throw e; + } return count; } - - int scanf(char[] format, ...) - { + + int scanf(char[] format, ...) { c_va_list ap; ap = cast(c_va_list) &format; ap += format.sizeof; @@ -850,30 +811,25 @@ } // returns estimated number of bytes available for immediate reading - uint available() - { - return 0; - } + size_t available() { return 0; } // writes block of data of specified size, // returns actual number of bytes written - abstract uint writeBlock(void* buffer, uint size); + abstract size_t writeBlock(void* buffer, size_t size); // writes block of data of specified size, // throws WriteException on error - void writeExact(void* buffer, uint size) - { + void writeExact(void* buffer, size_t size) { if (writeBlock(buffer, size) != size) throw new WriteException("unable to write to stream"); } // writes the given array of bytes, returns // actual number of bytes written - uint write(ubyte[] buffer) - { + size_t write(ubyte[] buffer) { return writeBlock(buffer, buffer.length); } - + // write a single value of desired type, // throw WriteException on error void write(byte x) { writeExact(&x, x.sizeof); } @@ -896,24 +852,21 @@ void write(char x) { writeExact(&x, x.sizeof); } void write(wchar x) { writeExact(&x, x.sizeof); } void write(dchar x) { writeExact(&x, x.sizeof); } - + // writes a string, together with its length - void write(char[] s) - { + void write(char[] s) { write(s.length); writeString(s); } - + // writes a Unicode string, together with its length - void write(wchar[] s) - { + void write(wchar[] s) { write(s.length); writeStringW(s); } // writes a line, throws WriteException on error - void writeLine(char[] s) - { + void writeLine(char[] s) { writeString(s); version (Win32) writeString("\r\n"); @@ -924,8 +877,7 @@ } // writes a UNICODE line, throws WriteException on error - void writeLineW(wchar[] s) - { + void writeLineW(wchar[] s) { writeStringW(s); version (Win32) writeStringW("\r\n"); @@ -936,68 +888,58 @@ } // writes a string, throws WriteException on error - void writeString(char[] s) - { + void writeString(char[] s) { writeExact(s, s.length); } // writes a UNICODE string, throws WriteException on error - void writeStringW(wchar[] s) - { + void writeStringW(wchar[] s) { writeExact(s, s.length * wchar.sizeof); } // writes data to stream using vprintf() syntax, // returns number of bytes written - uint vprintf(char[] format, c_va_list args) - { + size_t vprintf(char[] format, c_va_list args) { // shamelessly stolen from OutBuffer, // by Walter's permission char[1024] buffer; char* p = buffer; char* f = toStringz(format); - uint psize = buffer.length; - int count; - while (true) - { - version (Win32) - { - count = _vsnprintf(p, psize, f, args); - if (count != -1) - break; - psize *= 2; - p = cast(char*) alloca(psize); - } - else version (linux) - { - count = vsnprintf(p, psize, f, args); - if (count == -1) - psize *= 2; - else if (count >= psize) - psize = count + 1; - else - break; - p = cast(char*) alloca(psize); - } + size_t psize = buffer.length; + size_t count; + while (true) { + version (Win32) { + count = _vsnprintf(p, psize, f, args); + if (count != -1) + break; + psize *= 2; + p = cast(char*) alloca(psize); + } else version (linux) { + count = vsnprintf(p, psize, f, args); + if (count == -1) + psize *= 2; + else if (count >= psize) + psize = count + 1; else + break; + p = cast(char*) alloca(psize); + } else throw new Exception("unsupported platform"); - } + } writeString(p[0 .. count]); - return count; + return count; } // writes data to stream using printf() syntax, // returns number of bytes written - uint printf(char[] format, ...) - { + size_t printf(char[] format, ...) { c_va_list ap; ap = cast(c_va_list) &format; ap += format.sizeof; return vprintf(format, ap); } - private void doFormatCallback(dchar c) - { + private void doFormatCallback(dchar c) { char[4] buf; char[] b; b = std.utf.toUTF8(buf, c); @@ -1005,38 +947,39 @@ } // writes data to stream using writef() syntax, - void writef(...) - { + Stream writef(...) { doFormat(&doFormatCallback,_arguments,_argptr); + return this; } // writes data with trailing newline - void writefln(...) - { + Stream writefln(...) { doFormat(&doFormatCallback,_arguments,_argptr); writeLine(""); + return this; } // copies all data from given stream into this one, // may throw ReadException or WriteException on failure - void copyFrom(Stream s) - { - uint pos = position(); + void copyFrom(Stream s) { + ulong pos = s.position(); s.position(0); copyFrom(s, s.size()); s.position(pos); } - + // copies specified number of bytes from given stream into // this one, may throw ReadException or WriteException on failure - void copyFrom(Stream s, uint count) - { - ubyte[] buf; - buf.length = s.size(); - s.readExact(buf, buf.length); - writeExact(buf, buf.length); + void copyFrom(Stream s, ulong count) { + ubyte[128] buf; + while (count > 0) { + size_t n = count 1) unget.length = 1; // keep at least 1 so that data ptr stays } // close the stream somehow; the default just flushes the buffer - void close() - { + void close() { if (isopen) flush(); - isopen = false; + isopen = readable = writeable = seekable = false; } - // creates a string in memory containing copy of stream data - override char[] toString() - { - if (!isopen) + // creates a string in memory containing copy of stream data + override char[] toString() { + if (!readable || !seekable) return super.toString(); - uint pos = position(); + ulong pos = position(); char[] result; result.length = size(); position(0); @@ -1098,37 +1037,49 @@ position(pos); return result; } - + // calculates CRC-32 of data in stream - override uint toHash() - { - if (!isopen) + override uint toHash() { + if (!readable) return super.toHash(); ulong pos = position(); uint crc = init_crc32 (); position(0); - for (long i = 0; i < size(); i++) - { - ubyte c; - read(c); - crc = update_crc32(c, crc); - } + for (ulong i = 0; i < size(); i++) { + ubyte c; + read(c); + crc = update_crc32(c, crc); + } position(pos); return crc; } + // helper for checking that the stream is readable + final protected void assertReadable() { + if (!readable) + throw new ReadException("Stream is not readable"); + } + // helper for checking that the stream is writeable + final protected void assertWriteable() { + if (!writeable) + throw new WriteException("Stream is not writeable"); + } + // helper for checking that the stream is seekable + final protected void assertSeekable() { + if (!seekable) + throw new SeekException("Stream is not seekable"); + } } // A stream that wraps a source stream in a buffer -class BufferedStream : Stream -{ +class BufferedStream : Stream { Stream s; // source stream ubyte[] buffer; // buffer, if any uint bufferCurPos; // current position in buffer uint bufferLen; // amount of data in buffer bit bufferDirty = false; uint bufferSourcePos; // position in buffer of source stream position - ulong streamPos; // absolute position in source stream + ulong streamPos; // absolute position in source stream /* Example of relationship between fields: * @@ -1140,8 +1091,7 @@ * */ - invariant - { + invariant { assert(bufferSourcePos <= bufferLen); assert(bufferCurPos <= bufferLen); assert(bufferLen <= buffer.length); @@ -1149,8 +1099,7 @@ const uint DefaultBufferSize = 8192; - this(Stream source, uint bufferSize = DefaultBufferSize) - { + this(Stream source, uint bufferSize = DefaultBufferSize) { super(); if (bufferSize) buffer = new ubyte[bufferSize]; @@ -1158,8 +1107,7 @@ updateAttribs(); } - void updateAttribs() - { + void updateAttribs() { if (s !== null) { readable = s.readable; writeable = s.writeable; @@ -1175,8 +1123,7 @@ } // close source and stream - override void close() - { + override void close() { if (isopen) { super.close(); s.close(); @@ -1186,46 +1133,46 @@ // reads block of data of specified size using any buffered data // returns actual number of bytes read - override uint readBlock(void* result, uint size) - { + override size_t readBlock(void* result, size_t size) { + assertReadable(); + ubyte* buf = cast(ubyte*)result; - uint readsize = 0; - - if (bufferCurPos + size <= bufferLen) - { // buffer has all the data so copy it - buf[0 .. size] = buffer[bufferCurPos .. bufferCurPos+size]; - bufferCurPos += size; - readsize = size; - goto ExitRead; - } + size_t readsize = 0; + + if (bufferCurPos + size <= bufferLen) { + // buffer has all the data so copy it + buf[0 .. size] = buffer[bufferCurPos .. bufferCurPos+size]; + bufferCurPos += size; + readsize = size; + goto ExitRead; + } readsize = bufferLen - bufferCurPos; - if (readsize > 0) - { // buffer has some data so copy what is left - buf[0 .. readsize] = buffer[bufferCurPos .. bufferLen]; - buf += readsize; - bufferCurPos += readsize; - size -= readsize; - } + if (readsize > 0) { + // buffer has some data so copy what is left + buf[0 .. readsize] = buffer[bufferCurPos .. bufferLen]; + buf += readsize; + bufferCurPos += readsize; + size -= readsize; + } flush(); - if (size >= buffer.length) - { // buffer can't hold the data so fill output buffer directly - uint siz = s.readBlock(buf, size); - readsize += siz; - streamPos += siz; - } - else - { // read a new block into buffer - bufferLen = s.readBlock(buffer, buffer.length); - if (bufferLen < size) size = bufferLen; - buf[0 .. size] = buffer[0 .. size]; - bufferSourcePos = bufferLen; - streamPos += bufferLen; - bufferCurPos = size; - readsize += size; - } + if (size >= buffer.length) { + // buffer can't hold the data so fill output buffer directly + size_t siz = s.readBlock(buf, size); + readsize += siz; + streamPos += siz; + } else { + // read a new block into buffer + bufferLen = s.readBlock(buffer, buffer.length); + if (bufferLen < size) size = bufferLen; + buf[0 .. size] = buffer[0 .. size]; + bufferSourcePos = bufferLen; + streamPos += bufferLen; + bufferCurPos = size; + readsize += size; + } ExitRead: return readsize; @@ -1233,46 +1180,47 @@ // write block of data of specified size // returns actual number of bytes written - override uint writeBlock(void* result, uint size) - { + override size_t writeBlock(void* result, size_t size) { + assertWriteable(); + ubyte* buf = cast(ubyte*)result; - uint writesize = 0; + size_t writesize = 0; - if (bufferLen == 0) - { // buffer is empty so fill it if possible - if ((size < buffer.length) && (readable)) - { // read in data if the buffer is currently empty - bufferLen = s.readBlock(buffer,buffer.length); - bufferSourcePos = bufferLen; - streamPos += bufferLen; - } - else if (size >= buffer.length) - { // buffer can't hold the data so write it directly and exit - writesize = s.writeBlock(buf,size); - streamPos += writesize; - goto ExitWrite; - } + if (bufferLen == 0) { + // buffer is empty so fill it if possible + if ((size < buffer.length) && (readable)) { + // read in data if the buffer is currently empty + bufferLen = s.readBlock(buffer,buffer.length); + bufferSourcePos = bufferLen; + streamPos += bufferLen; + + } else if (size >= buffer.length) { + // buffer can't hold the data so write it directly and exit + writesize = s.writeBlock(buf,size); + streamPos += writesize; + goto ExitWrite; } + } - if (bufferCurPos + size <= buffer.length) - { // buffer has space for all the data so copy it and exit - buffer[bufferCurPos .. bufferCurPos+size] = buf[0 .. size]; - bufferCurPos += size; - bufferLen = bufferCurPos > bufferLen ? bufferCurPos : bufferLen; - writesize = size; - bufferDirty = true; - goto ExitWrite; - } + if (bufferCurPos + size <= buffer.length) { + // buffer has space for all the data so copy it and exit + buffer[bufferCurPos .. bufferCurPos+size] = buf[0 .. size]; + bufferCurPos += size; + bufferLen = bufferCurPos > bufferLen ? bufferCurPos : bufferLen; + writesize = size; + bufferDirty = true; + goto ExitWrite; + } writesize = buffer.length - bufferCurPos; - if (writesize > 0) - { // buffer can take some data - buffer[bufferCurPos .. buffer.length] = buf[0 .. writesize]; - bufferCurPos = bufferLen = buffer.length; - buf += writesize; - size -= writesize; - bufferDirty = true; - } + if (writesize > 0) { + // buffer can take some data + buffer[bufferCurPos .. buffer.length] = buf[0 .. writesize]; + bufferCurPos = bufferLen = buffer.length; + buf += writesize; + size -= writesize; + bufferDirty = true; + } assert(bufferCurPos == buffer.length); assert(bufferLen == buffer.length); @@ -1285,25 +1233,17 @@ return writesize; } - override ulong seek(long offset, SeekPos whence) - in - { - assert(seekable); - assert(s.seekable); - } - body - { + override ulong seek(long offset, SeekPos whence) { + assertSeekable(); + if ((whence != SeekPos.Current) || (offset + bufferCurPos < 0) || - (offset + bufferCurPos >= bufferLen)) - { - flush(); - streamPos = s.seek(offset,whence); - } - else - { - bufferCurPos += offset; - } + (offset + bufferCurPos >= bufferLen)) { + flush(); + streamPos = s.seek(offset,whence); + } else { + bufferCurPos += offset; + } return streamPos-bufferSourcePos+bufferCurPos; } @@ -1313,10 +1253,10 @@ template TreadLine(T) { override T[] readLine(T[] inBuffer) { - uint lineSize = 0; + size_t lineSize = 0; bool haveCR = false; T c = '\0'; - uint idx = 0; + size_t idx = 0; ubyte* pc = cast(ubyte*)&c; L0: @@ -1349,7 +1289,7 @@ } } flush(); - uint res = s.readBlock(buffer,buffer.length); + size_t res = s.readBlock(buffer,buffer.length); if(!res) break L0; // EOF bufferSourcePos = bufferLen = res; streamPos += res; @@ -1359,8 +1299,7 @@ } } // template TreadLine(T) - override char[] readLine(char[] inBuffer) - { + override char[] readLine(char[] inBuffer) { if (unget.length > 1) return super.readLine(inBuffer); else @@ -1368,8 +1307,7 @@ } alias Stream.readLine readLine; - override wchar[] readLineW(wchar[] inBuffer) - { + override wchar[] readLineW(wchar[] inBuffer) { if (unget.length > 1) return super.readLineW(inBuffer); else @@ -1378,58 +1316,48 @@ alias Stream.readLineW readLineW; override void flush() - out - { + out { assert(bufferCurPos == 0); assert(bufferSourcePos == 0); assert(bufferLen == 0); } - body - { + body { super.flush(); - if (writeable && bufferDirty) - { - if (bufferSourcePos != 0) - { - // move actual file pointer to front of buffer - streamPos = s.seek(-bufferSourcePos, SeekPos.Current); - } - // write buffer out - bufferSourcePos = s.writeBlock(buffer,bufferLen); - if (bufferSourcePos != bufferLen) - { - throw new WriteException("Unable to write to stream"); - } + if (writeable && bufferDirty) { + if (bufferSourcePos != 0) { + // move actual file pointer to front of buffer + streamPos = s.seek(-bufferSourcePos, SeekPos.Current); + } + // write buffer out + bufferSourcePos = s.writeBlock(buffer,bufferLen); + if (bufferSourcePos != bufferLen) { + throw new WriteException("Unable to write to stream"); } + } long diff = bufferCurPos-bufferSourcePos; - if (diff != 0) - { - // move actual file pointer to current position - streamPos = s.seek(diff, SeekPos.Current); - } + if (diff != 0) { + // move actual file pointer to current position + streamPos = s.seek(diff, SeekPos.Current); + } // reset buffer data to be empty bufferSourcePos = bufferCurPos = bufferLen = 0; bufferDirty = false; } // returns true if end of stream is reached, false otherwise - override bit eof() - { - if ((buffer.length == 0) || !readable) - { - return super.eof(); - } - if (bufferCurPos == bufferLen) - { - if ((bufferLen != buffer.length) && - (bufferLen != 0)) - { - return true; - } + override bit eof() { + if ((buffer.length == 0) || !readable) { + return super.eof(); + } + if (bufferCurPos == bufferLen) { + if ((bufferLen != buffer.length) && + (bufferLen != 0)) { + return true; } + } else return false; - uint res = s.readBlock(buffer,buffer.length); + size_t res = s.readBlock(buffer,buffer.length); bufferSourcePos = bufferLen = res; streamPos += res; bufferCurPos = 0; @@ -1437,15 +1365,13 @@ } // returns size of stream - ulong size() - { + ulong size() { flush(); return s.size(); } // returns estimated number of bytes available for immediate reading - uint available() - { + size_t available() { return bufferLen - bufferCurPos; } @@ -1453,275 +1379,213 @@ // generic File error, base class for all // other File exceptions -class StreamFileException: StreamException -{ +class StreamFileException: StreamException { this(char[] msg) { super(msg); } } // thrown when unable to open file -class OpenException: StreamFileException -{ +class OpenException: StreamFileException { this(char[] msg) { super(msg); } } // access modes; may be or'ed -enum FileMode - { - In = 1, - Out = 2, - OutNew = 6, // includes FileMode.Out - Append = 10 // includes FileMode.Out - } +enum FileMode { + In = 1, + Out = 2, + OutNew = 6, // includes FileMode.Out + Append = 10 // includes FileMode.Out +} -version (Win32) -{ +version (Win32) { private import std.c.windows.windows; - // BVH: should be part of windows.d extern (Windows) void FlushFileBuffers(HANDLE hFile); } -version (linux) -{ +version (linux) { private import std.c.linux.linux; alias int HANDLE; } // just a file on disk without buffering -class File: Stream -{ +class File: Stream { - version (Win32) - { + version (Win32) { private HANDLE hFile; } - version (linux) - { + version (linux) { private HANDLE hFile = -1; } - this() - { + this() { super(); - version (Win32) - { - hFile = null; - } - version (linux) - { - hFile = -1; - } + version (Win32) { + hFile = null; + } + version (linux) { + hFile = -1; + } isopen = false; } - + // opens existing handle; use with care! - this(HANDLE hFile, FileMode mode) - { + this(HANDLE hFile, FileMode mode) { super(); this.hFile = hFile; readable = cast(bit)(mode & FileMode.In); writeable = cast(bit)(mode & FileMode.Out); } - + // opens file in requested mode this(char[] filename, FileMode mode = FileMode.In) { this(); open(filename, mode); } - - + + // opens file in requested mode - void open(char[] filename, FileMode mode = FileMode.In) - { + void open(char[] filename, FileMode mode = FileMode.In) { close(); int access, share, createMode; parseMode(mode, access, share, createMode); seekable = true; readable = cast(bit)(mode & FileMode.In); writeable = cast(bit)(mode & FileMode.Out); - version (Win32) - { - if (std.file.useWfuncs) - { - hFile = CreateFileW(std.utf.toUTF16z(filename), access, share, - null, createMode, 0, null); - } - else - { - hFile = CreateFileA(std.file.toMBSz(filename), access, share, - null, createMode, 0, null); - } - isopen = hFile != INVALID_HANDLE_VALUE; - } - version (linux) - { - hFile = std.c.linux.linux.open(toStringz(filename), access | createMode, share); - isopen = hFile != -1; + version (Win32) { + if (std.file.useWfuncs) { + hFile = CreateFileW(std.utf.toUTF16z(filename), access, share, + null, createMode, 0, null); + } else { + hFile = CreateFileA(std.file.toMBSz(filename), access, share, + null, createMode, 0, null); } + isopen = hFile != INVALID_HANDLE_VALUE; + } + version (linux) { + hFile = std.c.linux.linux.open(toStringz(filename), access | createMode, share); + isopen = hFile != -1; + } if (!isopen) - throw new OpenException("file '" ~ filename ~ "' not found"); - else if ((mode & FileMode.Append) == FileMode.Append) + throw new OpenException("Cannot open or create file '" ~ filename ~ "'"); + else if ((mode & FileMode.Append) == FileMode.Append) seekEnd(0); } - private void parseMode(int mode, - out int access, + private void parseMode(int mode, + out int access, out int share, - out int createMode) - { - version (Win32) - { - if (mode & FileMode.In) - { - access |= GENERIC_READ; - share |= FILE_SHARE_READ; - createMode = OPEN_EXISTING; - } - if (mode & FileMode.Out) - { - access |= GENERIC_WRITE; - createMode = OPEN_ALWAYS; // will create if not present - } - if ((mode & FileMode.OutNew) == FileMode.OutNew) - { - createMode = CREATE_ALWAYS; // resets file - } + out int createMode) { + version (Win32) { + if (mode & FileMode.In) { + access |= GENERIC_READ; + share |= FILE_SHARE_READ; + createMode = OPEN_EXISTING; + } + if (mode & FileMode.Out) { + access |= GENERIC_WRITE; + createMode = OPEN_ALWAYS; // will create if not present } - version (linux) - { - if (mode & FileMode.In) - { - access = O_RDONLY; - share = 0660; - } - if (mode & FileMode.Out) - { - createMode = O_CREAT; // will create if not present - access = O_WRONLY; - share = 0660; - } - if (access == (O_WRONLY | O_RDONLY)) - { - access = O_RDWR; - } - if ((mode & FileMode.OutNew) == FileMode.OutNew) - { - access |= O_TRUNC; // resets file - } + if ((mode & FileMode.OutNew) == FileMode.OutNew) { + createMode = CREATE_ALWAYS; // resets file + } + } + version (linux) { + if (mode & FileMode.In) { + access = O_RDONLY; + share = 0660; + } + if (mode & FileMode.Out) { + createMode = O_CREAT; // will create if not present + access = O_WRONLY; + share = 0660; } + if (access == (O_WRONLY | O_RDONLY)) { + access = O_RDWR; + } + if ((mode & FileMode.OutNew) == FileMode.OutNew) { + access |= O_TRUNC; // resets file + } + } } // creates file for writing - void create(char[] filename) - { - create(filename, FileMode.OutNew); + void create(char[] filename) { + create(filename, FileMode.OutNew); } // creates file in requested mode - void create(char[] filename, FileMode mode) - { + void create(char[] filename, FileMode mode) { close(); open(filename, mode | FileMode.OutNew); } - override void flush() - { + override void flush() { super.flush(); - version (Win32) - { + version (Win32) { + if (isopen && this !== .stdout) { FlushFileBuffers(hFile); } + } } // closes file, if it is open; otherwise, does nothing - override void close() - { - if (isopen && hFile) - { - version (Win32) - { - CloseHandle(hFile); - hFile = null; - } - version (linux) - { - std.c.linux.linux.close(hFile); - hFile = -1; - } - readable = writeable = seekable = false; - isopen = false; + override void close() { + if (isopen) { + super.close(); + if (hFile) { + version (Win32) { + CloseHandle(hFile); + hFile = null; + } else version (linux) { + std.c.linux.linux.close(hFile); + hFile = -1; + } } + } } // destructor, closes file if still opened ~this() { close(); } - version (Win32) - { + version (Win32) { // returns size of stream - ulong size() - { - uint sizehi; - uint sizelow = GetFileSize(hFile,&sizehi); - return (sizehi << 32)+sizelow; - } + ulong size() { + uint sizehi; + uint sizelow = GetFileSize(hFile,&sizehi); + return (cast(ulong)sizehi << 32) + sizelow; + } } - override uint readBlock(void* buffer, uint size) - // since in-blocks are not inherited, redefine them - in - { - assert(readable); - } - body - { - version (Win32) - { - ReadFile(hFile, buffer, size, &size, null); - } - version (linux) - { - size = std.c.linux.linux.read(hFile, buffer, size); - if (size == -1) - size = 0; - } + override size_t readBlock(void* buffer, size_t size) { + assertReadable(); + version (Win32) { + ReadFile(hFile, buffer, size, &size, null); + } else version (linux) { + size = std.c.linux.linux.read(hFile, buffer, size); + if (size == -1) + size = 0; + } return size; } - override uint writeBlock(void* buffer, uint size) - // since in-blocks are not inherited, redefine them - in - { - assert(writeable); - } - body - { - version (Win32) - { - WriteFile(hFile, buffer, size, &size, null); - } - version (linux) - { - size = std.c.linux.linux.write(hFile, buffer, size); - } + override size_t writeBlock(void* buffer, size_t size) { + assertWriteable(); + version (Win32) { + WriteFile(hFile, buffer, size, &size, null); + } else version (linux) { + size = std.c.linux.linux.write(hFile, buffer, size); + if (size == -1) + size = 0; + } return size; } - - override ulong seek(long offset, SeekPos rel) - // since in-blocks are not inherited, redefine them - in - { - assert(seekable); - } - body - { - version (Win32) - { - uint result = SetFilePointer(hFile, offset, null, rel); - if (result == 0xFFFFFFFF) - throw new SeekException("unable to move file pointer"); - } - version (linux) - { - ulong result = lseek(hFile, offset, rel); - if (result == 0xFFFFFFFF) - throw new SeekException("unable to move file pointer"); - } + + override ulong seek(long offset, SeekPos rel) { + assertSeekable(); + version (Win32) { + uint result = SetFilePointer(hFile, offset, null, rel); + if (result == 0xFFFFFFFF) + throw new SeekException("unable to move file pointer"); + } else version (linux) { + ulong result = lseek(hFile, offset, rel); + if (result == 0xFFFFFFFF) + throw new SeekException("unable to move file pointer"); + } return result; } @@ -1730,8 +1594,7 @@ HANDLE handle() { return hFile; } // run a few tests - unittest - { + unittest { File file = new File; int i = 666; file.create("stream.$$$"); @@ -1775,63 +1638,73 @@ // we must be at the end of file assert(file.eof()); file.close(); + file.open("stream.$$$",FileMode.OutNew | FileMode.In); + file.writeLine("Testing stream.d:"); + file.writeLine("Another line"); + file.writeLine(""); + file.writeLine("That was blank"); + file.position = 0; + char[][] lines; + foreach(char[] line; file) { + lines ~= line.dup; + } + assert( lines.length == 4 ); + assert( lines[0] == "Testing stream.d:"); + assert( lines[1] == "Another line"); + assert( lines[2] == ""); + assert( lines[3] == "That was blank"); + file.position = 0; + lines = new char[][4]; + foreach(ulong n, char[] line; file) { + lines[n-1] = line.dup; + } + assert( lines[0] == "Testing stream.d:"); + assert( lines[1] == "Another line"); + assert( lines[2] == ""); + assert( lines[3] == "That was blank"); + file.close(); remove("stream.$$$"); } } // a buffered file on disk -class BufferedFile: BufferedStream -{ +class BufferedFile: BufferedStream { - // opens file for reading - this() - { - super(new File()); - } + // opens file for reading + this() { super(new File()); } // opens file in requested mode and buffer size - this(char[] filename, FileMode mode = FileMode.In, - uint bufferSize = DefaultBufferSize) - { + this(char[] filename, FileMode mode = FileMode.In, + uint bufferSize = DefaultBufferSize) { super(new File(filename,mode),bufferSize); } // opens file for reading with requested buffer size - this(File file, uint bufferSize = DefaultBufferSize) - { + this(File file, uint bufferSize = DefaultBufferSize) { super(file,bufferSize); } // opens existing handle; use with care! - this(HANDLE hFile, FileMode mode, uint buffersize) - { + this(HANDLE hFile, FileMode mode, uint buffersize) { super(new File(hFile,mode),buffersize); } // opens file in requested mode - void open(char[] filename, FileMode mode = FileMode.In) - in - { - assert(!(s is null)); - } - body - { + void open(char[] filename, FileMode mode = FileMode.In) { File sf = cast(File)s; sf.open(filename,mode); updateAttribs(); } // creates file in requested mode - void create(char[] filename, FileMode mode = FileMode.Out) - { + void create(char[] filename, FileMode mode = FileMode.Out) { File sf = cast(File)s; sf.create(filename,mode); updateAttribs(); } // run a few tests same as File - unittest - { + unittest { BufferedFile file = new BufferedFile; int i = 666; file.create("stream.$$$"); @@ -1879,27 +1752,28 @@ enum BOM { UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE } private const int NBOMS = 5; -Endian[NBOMS] BOMEndian = [std.system.endian, - Endian.LittleEndian, Endian.BigEndian, - Endian.LittleEndian, Endian.BigEndian]; - -ubyte[][NBOMS] ByteOrderMarks; -ubyte[3] BOM_UTF8_data = [0xEF, 0xBB, 0xBF]; -ubyte[2] BOM_UTF16LE_data = [0xFF, 0xFE]; -ubyte[2] BOM_UTF16BE_data = [0xFE, 0xFF]; -ubyte[4] BOM_UTF32LE_data = [0xFF, 0xFE, 0x00, 0x00]; -ubyte[4] BOM_UTF32BE_data = [0x00, 0x00, 0xFE, 0xFF]; +Endian[NBOMS] BOMEndian = +[ std.system.endian, + Endian.LittleEndian, Endian.BigEndian, + Endian.LittleEndian, Endian.BigEndian + ]; + +ubyte[][NBOMS] ByteOrderMarks = +[ [0xEF, 0xBB, 0xBF], + [0xFF, 0xFE], + [0xFE, 0xFF], + [0xFF, 0xFE, 0x00, 0x00], + [0x00, 0x00, 0xFE, 0xFF] + ]; // A stream that wraps a source stream with endian support -class EndianStream : Stream -{ +class EndianStream : Stream { Stream s; // source stream Endian endian; // endianness of the source stream // Construct an Endian stream with specified endianness, defaulting // to the native endiannes. - this(Stream source, Endian end = std.system.endian) - { + this(Stream source, Endian end = std.system.endian) { super(); s = source; endian = end; @@ -1914,112 +1788,93 @@ * the ungetc buffer or ungetcw buffer. Pass ungetCharSize == 2 * to use ungetcw instead of ungetc. */ - int readBOM(int ungetCharSize = 1) - { + int readBOM(int ungetCharSize = 1) { ubyte[4] BOM_buffer; int n = 0; // the number of read bytes int result = -1; // the last match or -1 - for (int i=0; i < NBOMS; ++i) - { - int j; - ubyte[] bom = ByteOrderMarks[i]; - for (j=0; j < bom.length; ++j) - { - if (n <= j) // have to read more - { - if (eof()) - break; - readExact(&BOM_buffer[n++],1); - } - if (BOM_buffer[j] != bom[j]) - break; - } - if (j == bom.length) // found a match - result = i; + for (int i=0; i < NBOMS; ++i) { + int j; + ubyte[] bom = ByteOrderMarks[i]; + for (j=0; j < bom.length; ++j) { + if (n <= j) { // have to read more + if (eof()) + break; + readExact(&BOM_buffer[n++],1); + } + if (BOM_buffer[j] != bom[j]) + break; } + if (j == bom.length) // found a match + result = i; + } int m = 0; - if (result != -1) - { + if (result != -1) { endian = BOMEndian[result]; // set stream endianness m = ByteOrderMarks[result].length; } - if ((ungetCharSize == 1 && result == -1) || (result == BOM.UTF8)) - { - while (n-- > m) - ungetc(BOM_buffer[n]); - } - else // should eventually support unget for dchar as well - { - if (n & 1) // make sure we have an even number of bytes - readExact(&BOM_buffer[n++],1); - while (n > m) - { - n -= 2; - wchar cw = *(cast(wchar*)&BOM_buffer[n]); - fixBO(&cw,2); - ungetcw(cw); - } + if ((ungetCharSize == 1 && result == -1) || (result == BOM.UTF8)) { + while (n-- > m) + ungetc(BOM_buffer[n]); + } else { // should eventually support unget for dchar as well + if (n & 1) // make sure we have an even number of bytes + readExact(&BOM_buffer[n++],1); + while (n > m) { + n -= 2; + wchar cw = *(cast(wchar*)&BOM_buffer[n]); + fixBO(&cw,2); + ungetcw(cw); } + } return result; } // Correct the byte order of buffer to match native endianness. // size must be even - final void fixBO(void* buffer, uint size) - { - if (endian != std.system.endian) - { - ubyte* startb = cast(ubyte*)buffer; - uint* start = cast(uint*)buffer; - switch (size) - { - case 0: break; - case 2: - { - ubyte x = *startb; - *startb = *(startb+1); - *(startb+1) = x; - break; - } - case 4: - { - *start = bswap(*start); - break; - } - default: - { - uint* end = cast(uint*)(buffer + size - uint.sizeof); - while (start < end) - { - uint x = bswap(*start); - *start = bswap(*end); - *end = x; - ++start; - --end; - } - startb = cast(ubyte*)start; - ubyte* endb = cast(ubyte*)end; - int len = uint.sizeof - (startb - endb); - if (len > 0) - fixBO(startb,len); - } - } + final void fixBO(void* buffer, uint size) { + if (endian != std.system.endian) { + ubyte* startb = cast(ubyte*)buffer; + uint* start = cast(uint*)buffer; + switch (size) { + case 0: break; + case 2: { + ubyte x = *startb; + *startb = *(startb+1); + *(startb+1) = x; + break; + } + case 4: { + *start = bswap(*start); + break; + } + default: { + uint* end = cast(uint*)(buffer + size - uint.sizeof); + while (start < end) { + uint x = bswap(*start); + *start = bswap(*end); + *end = x; + ++start; + --end; + } + startb = cast(ubyte*)start; + ubyte* endb = cast(ubyte*)end; + int len = uint.sizeof - (startb - endb); + if (len > 0) + fixBO(startb,len); + } } + } } // Correct the byte order of buffer in blocks repeatedly // size must be even - final void fixBlockBO(void* buffer, uint size, uint repeat) - { - while (repeat--) - { - fixBO(buffer,size); - buffer += size; - } + final void fixBlockBO(void* buffer, uint size, size_t repeat) { + while (repeat--) { + fixBO(buffer,size); + buffer += size; + } } - uint readBlock(void* buffer, uint size) - { + size_t readBlock(void* buffer, size_t size) { return s.readBlock(buffer,size); } @@ -2041,23 +1896,20 @@ void read(out wchar x) { readExact(&x, x.sizeof); fixBO(&x,x.sizeof); } void read(out dchar x) { readExact(&x, x.sizeof); fixBO(&x,x.sizeof); } - wchar[] readStringW(uint length) - { + wchar[] readStringW(size_t length) { wchar[] result = new wchar[length]; readExact(result, result.length * wchar.sizeof); fixBlockBO(&result,2,length); return result; } - + // Write the specified BOM to the source stream - void writeBOM(BOM b) - { + void writeBOM(BOM b) { ubyte[] bom = ByteOrderMarks[b]; writeBlock(bom,bom.length); } - uint writeBlock(void* buffer, uint size) - { + size_t writeBlock(void* buffer, size_t size) { return s.writeBlock(buffer,size); } void write(short x) { fixBO(&x,x.sizeof); writeExact(&x, x.sizeof); } @@ -2078,33 +1930,33 @@ void write(wchar x) { fixBO(&x,x.sizeof); writeExact(&x, x.sizeof); } void write(dchar x) { fixBO(&x,x.sizeof); writeExact(&x, x.sizeof); } - void writeStringW(wchar[] str) - { - foreach(wchar cw;str) - { - fixBO(&cw,2); - s.writeExact(&cw, 2); - } + void writeStringW(wchar[] str) { + foreach(wchar cw;str) { + fixBO(&cw,2); + s.writeExact(&cw, 2); + } } // close stream - override void close() - { + override void close() { if (isopen) { + super.close(); s.close(); - isopen = false; } } - override ulong seek(long offset, SeekPos whence) - { - return s.seek(offset,whence); + override ulong seek(long offset, SeekPos whence) { + return s.seek(offset,whence); + } + + override size_t available () { + return s.available(); } override void flush() { super.flush(); s.flush(); } override bit eof() { return s.eof(); } override ulong size() { return s.size(); } - + unittest { MemoryStream m; m = new MemoryStream (); @@ -2192,23 +2044,27 @@ // Parameterized stream class that wraps an array-like type. // The Buffer type must support .length, opIndex and opSlice -class TArrayStream(Buffer): Stream -{ +class TArrayStream(Buffer): Stream { Buffer buf; // current data - uint len; // current data length - uint cur; // current file position + size_t len; // current data length + size_t cur; // current file position // use this buffer, non-copying. - this(Buffer buf) - { + this(Buffer buf) { super (); this.buf = buf; this.len = buf.length; readable = writeable = seekable = true; } - - override uint readBlock(void* buffer, uint size) - { + + // ensure subclasses don't violate this + invariant { + assert(len <= buf.length); + assert(cur <= len); + } + + override size_t readBlock(void* buffer, size_t size) { + assertReadable(); ubyte* cbuf = cast(ubyte*) buffer; if (len - cur < size) size = len - cur; @@ -2217,10 +2073,12 @@ cur += size; return size; } - - override uint writeBlock(void* buffer, uint size) - { + + override size_t writeBlock(void* buffer, size_t size) { + assertWriteable(); ubyte* cbuf = cast(ubyte*) buffer; + if (cur + size > buf.length) + size = buf.length - cur; ubyte[] ubuf = cast(ubyte[])buf[cur .. cur + size]; ubuf[] = cbuf[0 .. size]; cur += size; @@ -2229,16 +2087,15 @@ return size; } - override ulong seek(long offset, SeekPos rel) - { + override ulong seek(long offset, SeekPos rel) { + assertSeekable(); long scur; // signed to saturate to 0 properly - switch (rel) - { - case SeekPos.Set: scur = offset; break; - case SeekPos.Current: scur = cur + offset; break; - case SeekPos.End: scur = len + offset; break; - } + switch (rel) { + case SeekPos.Set: scur = offset; break; + case SeekPos.Current: scur = cur + offset; break; + case SeekPos.End: scur = len + offset; break; + } if (scur < 0) cur = 0; @@ -2250,46 +2107,50 @@ return cur; } + override size_t available () { return len - cur; } + // returns pointer to stream data ubyte[] data() { return cast(ubyte[])buf [0 .. len]; } - override char[] toString() - { + override char[] toString() { return cast(char[]) data (); } - } + /* Test the TArrayStream */ -unittest -{ +unittest { char[100] buf; TArrayStream!(char[]) m; m = new TArrayStream!(char[]) (buf); + assert (m.isOpen); m.writeString ("Hello, world"); assert (m.position () == 12); + assert (m.available == 88); assert (m.seekSet (0) == 0); + assert (m.available == 100); assert (m.seekCur (4) == 4); + assert (m.available == 96); assert (m.seekEnd (-8) == 92); + assert (m.available == 8); assert (m.size () == 100); assert (m.seekSet (4) == 4); assert (m.readString (4) == "o, w"); m.writeString ("ie"); assert (buf[0..12] == "Hello, wield"); + assert (m.position == 10); + assert (m.available == 90); + assert (m.size () == 100); } // virtual stream residing in memory -class MemoryStream: TArrayStream!(ubyte[]) -{ +class MemoryStream: TArrayStream!(ubyte[]) { // clear to an empty buffer. this() { this(cast(ubyte[]) null); } // use this buffer, non-copying. - this(ubyte[] buf) - { - super (buf); - } + this(ubyte[] buf) { super (buf); } // use this buffer, non-copying. this(byte[] buf) { this(cast(ubyte[]) buf); } @@ -2298,29 +2159,30 @@ this(char[] buf) { this(cast(ubyte[]) buf); } // ensure the stream can hold this many bytes. - void reserve(uint count) - { + void reserve(size_t count) { if (cur + count > buf.length) buf.length = (cur + count) * 2; } - override uint writeBlock(void* buffer, uint size) - { + override size_t writeBlock(void* buffer, size_t size) { reserve(size); return super.writeBlock(buffer,size); } - + /* Test the whole class. */ - unittest - { + unittest { MemoryStream m; m = new MemoryStream (); + assert (m.isOpen); m.writeString ("Hello, world"); assert (m.position () == 12); assert (m.seekSet (0) == 0); + assert (m.available == 12); assert (m.seekCur (4) == 4); + assert (m.available == 8); assert (m.seekEnd (-8) == 4); + assert (m.available == 8); assert (m.size () == 12); assert (m.readString (4) == "o, w"); m.writeString ("ie"); @@ -2328,40 +2190,54 @@ m.seekEnd (0); m.writeString ("Foo"); assert (m.position () == 15); + assert (m.available == 0); m.writeString ("Foo foo foo foo foo foo foo"); assert (m.position () == 42); - m.seekSet(0); + m.position = 0; + assert (m.available == 42); m.writef("%d %d %s",100,345,"hello"); char[] str = m.toString; assert (str[0..13] == "100 345 hello"); + assert (m.available == 29); + assert (m.position == 13); + + MemoryStream m2; + m.position = 3; + m2 = new MemoryStream (); + m2.writeString("before"); + m2.copyFrom(m,10); + str = m2.toString; + assert (str[0..16] == "before 345 hello"); + m2.position = 3; + m2.copyFrom(m); + char[] str2 = m.toString; + str = m2.toString; + assert (str == ("bef" ~ str2)); } } import std.mmfile; +// TODO: why check isopen and silently proceed? // stream wrapping memory-mapped files -class MmFileStream : TArrayStream!(MmFile) -{ +class MmFileStream : TArrayStream!(MmFile) { // constructor to wrap file - this(MmFile file) - { + this(MmFile file) { super (file); MmFile.Mode mode = file.mode; writeable = mode > MmFile.Mode.Read; } - override uint readBlock(void* buffer, uint size) - { + override size_t readBlock(void* buffer, size_t size) { if (isopen) return super.readBlock(buffer,size); else return 0; } - override uint writeBlock(void* buffer, uint size) - { + override size_t writeBlock(void* buffer, size_t size) { if (isopen) return super.writeBlock(buffer,size); else @@ -2369,24 +2245,21 @@ } // flush stream - override void flush() - { + override void flush() { if (isopen) buf.flush(); } // close stream - override void close() - { + override void close() { if (isopen) { + super.close(); delete buf; - isopen = false; } } } -unittest -{ +unittest { MmFile mf = new MmFile("testing.txt",MmFile.Mode.ReadWriteNew,100,null); MmFileStream m; @@ -2401,7 +2274,7 @@ assert (m.readString (4) == "o, w"); m.writeString ("ie"); assert ((cast(char[]) m.data())[0 .. 12] == "Hello, wield"); - m.seekSet (12); + m.position = 12; m.writeString ("Foo"); assert (m.position () == 15); m.writeString ("Foo foo foo foo foo foo foo"); @@ -2418,9 +2291,9 @@ // slices off a portion of another stream, making seeking // relative to the boundaries of the slice. -class SliceStream : Stream -{ +class SliceStream : Stream { Stream base; // stream to base this off of. + ulong pos; // our position relative to low ulong low; // low stream offset. ulong high; // high stream offset. bit bounded; // upper-bounded by high. @@ -2428,13 +2301,11 @@ // set the base stream and the low offset but leave the high unbounded. this (Stream base, ulong low) - in - { + in { assert (base !== null); assert (low <= base.size ()); } - body - { + body { super (); this.base = base; this.low = low; @@ -2443,18 +2314,17 @@ readable = base.readable; writeable = base.writeable; seekable = base.seekable; + isopen = base.isOpen(); } // set the base stream, the low offset, and the high offset. this (Stream base, ulong low, ulong high) - in - { + in { assert (base !== null); assert (low <= high); assert (high <= base.size ()); } - body - { + body { super (); this.base = base; this.low = low; @@ -2463,188 +2333,201 @@ readable = base.readable; writeable = base.writeable; seekable = base.seekable; + isopen = base.isOpen(); } - override void close () - { - try - { - if (base !== null && nestClose) - base.close (); - } - finally - base = null; + invariant { + if (bounded) + assert (pos <= high - low); + else + assert (pos <= base.size - low); } - override uint readBlock (void *buffer, uint size) - in - { - assert (readable); + override bool isOpen () { + if (isopen) + return base.isOpen(); + else + return false; } - body - { - if (bounded) - { - ulong pos = base.position (); - - if (pos > high) - return 0; - if (size > high - pos) - size = high - pos; - } - return base.readBlock (buffer, size); + override void flush() { + if (isopen) { + super.flush(); + base.flush(); + } } - override uint writeBlock (void *buffer, uint size) - in - { - assert (writeable); + override void close () { + if (isopen) { + super.close(); + if (nestClose) + base.close(); + } } - body - { - if (bounded) - { - ulong pos = base.position (); - if (pos > high) - return 0; - if (size > high - pos) - size = high - pos; - } + override size_t readBlock (void *buffer, size_t size) { + assertReadable(); + if (bounded) { + if (size > high - low + pos) + size = high - low + pos; + } - return base.writeBlock (buffer, size); + ulong bp = base.position; + if (seekable) + base.position = low + pos; + size_t ret = base.readBlock(buffer, size); + if (seekable) { + pos = base.position - low; + base.position = bp; + } + return ret; } - override ulong seek(long offset, SeekPos rel) - in - { - assert (seekable); + override size_t writeBlock (void *buffer, size_t size) { + assertWriteable(); + if (bounded) { + if (size > high - low + pos) + size = high - low + pos; + } + + ulong bp = base.position; + if (seekable) + base.position = low + pos; + size_t ret = base.writeBlock(buffer, size); + if (seekable) { + pos = base.position - low; + base.position = bp; + } + return ret; } - body - { - long output; - switch (rel) - { - case SeekPos.Set: - output = low + offset; - break; + override ulong seek(long offset, SeekPos rel) { + assertSeekable(); + long spos; - case SeekPos.Current: - output = base.position () + offset; + switch (rel) { + case SeekPos.Set: { + spos = offset; break; - - case SeekPos.End: + } + case SeekPos.Current: { + spos = pos + offset; + break; + } + case SeekPos.End: { if (bounded) - output = high + offset; + spos = high - low + offset; else - { - output = base.seek (offset, SeekPos.End); - assert (output >= low); - return output - low; - } + spos = base.size - low + offset; + break; } + } + + if (spos < 0) + pos = 0; + else if (bounded && spos > high - low) + pos = high - low; + else if (!bounded && spos > base.size - low) + pos = base.size - low; + else + pos = spos; - if (output < low) - output = low; - else if (bounded && output > high) - output = high; - - output = base.seek (output, SeekPos.Set); - assert (output >= low); - return output - low; + return pos; + } + + override size_t available () { + return size - pos; } /* Test the whole class. */ - unittest - { + unittest { MemoryStream m; SliceStream s; m = new MemoryStream ((cast(char[])"Hello, world").dup); s = new SliceStream (m, 4, 8); assert (s.size () == 4); + assert (m.position () == 0); + assert (s.position () == 0); + assert (m.available == 12); + assert (s.available == 4); + assert (s.writeBlock (cast(char *) "Vroom", 5) == 4); + assert (m.position () == 0); assert (s.position () == 4); + assert (m.available == 12); + assert (s.available == 0); assert (s.seekEnd (-2) == 2); + assert (s.available == 2); assert (s.seekEnd (2) == 4); + assert (s.available == 0); + assert (m.position () == 0); + assert (m.available == 12); + + m.seekEnd(0); + m.writeString("\nBlaho"); + assert (m.position == 18); + assert (m.available == 0); + assert (s.position == 4); + assert (s.available == 0); + s = new SliceStream (m, 4); - assert (s.size () == 8); - assert (s.toString () == "Vrooorld"); + assert (s.size () == 14); + assert (s.available == 14); + assert (s.toString () == "Vrooorld\nBlaho"); s.seekEnd (0); + assert (s.available == 0); + s.writeString (", etcetera."); - assert (s.position () == 19); + assert (s.position () == 25); assert (s.seekSet (0) == 0); - assert (m.position () == 4); + assert (s.size () == 25); + assert (s.available == 25); + assert (m.position () == 18); + assert (m.size () == 29); + assert (m.toString() == "HellVrooorld\nBlaho, etcetera."); } } // helper functions -private bit iswhite(char c) -{ +private bit iswhite(char c) { return c == ' ' || c == '\t' || c == '\r' || c == '\n'; } -private bit isdigit(char c) -{ +private bit isdigit(char c) { return c >= '0' && c <= '9'; } -private bit isoctdigit(char c) -{ +private bit isoctdigit(char c) { return c >= '0' && c <= '7'; } -private bit ishexdigit(char c) -{ +private bit ishexdigit(char c) { return isdigit(c) || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'); } // standard IO devices File stdin, stdout, stderr; -version (Win32) -{ +version (Win32) { // API imports - private extern(Windows) - { - private import std.c.windows.windows; - HANDLE GetStdHandle(DWORD); - } - - static this() - { - // init ByteOrderMarks - ByteOrderMarks[BOM.UTF8] = BOM_UTF8_data; - ByteOrderMarks[BOM.UTF16LE] = BOM_UTF16LE_data; - ByteOrderMarks[BOM.UTF16BE] = BOM_UTF16BE_data; - ByteOrderMarks[BOM.UTF32LE] = BOM_UTF32LE_data; - ByteOrderMarks[BOM.UTF32BE] = BOM_UTF32BE_data; - - // open standard I/O devices - stdin = new File(GetStdHandle(cast(uint)-10), FileMode.In); - stdout = new File(GetStdHandle(cast(uint)-11), FileMode.Out); - stderr = new File(GetStdHandle(cast(uint)-12), FileMode.Out); - } -} - -version (linux) -{ - static this() - { - // init ByteOrderMarks - ByteOrderMarks[BOM.UTF8] = BOM_UTF8_data; - ByteOrderMarks[BOM.UTF16LE] = BOM_UTF16LE_data; - ByteOrderMarks[BOM.UTF16BE] = BOM_UTF16BE_data; - ByteOrderMarks[BOM.UTF32LE] = BOM_UTF32LE_data; - ByteOrderMarks[BOM.UTF32BE] = BOM_UTF32BE_data; - - // open standard I/O devices - stdin = new File(0, FileMode.In); - stdout = new File(1, FileMode.Out); - stderr = new File(2, FileMode.Out); - } + private extern(Windows) { + private import std.c.windows.windows; + HANDLE GetStdHandle(DWORD); + } + + static this() { + // open standard I/O devices + stdin = new File(GetStdHandle(cast(uint)-10), FileMode.In); + stdout = new File(GetStdHandle(cast(uint)-11), FileMode.Out); + stderr = new File(GetStdHandle(cast(uint)-12), FileMode.Out); + } +} else version (linux) { + static this() { + // open standard I/O devices + stdin = new File(0, FileMode.In); + stdout = new File(1, FileMode.Out); + stderr = new File(2, FileMode.Out); + } } - diff -uNr dmd-0.119/dmd/src/phobos/std/string.d dmd-0.120/dmd/src/phobos/std/string.d --- dmd-0.119/dmd/src/phobos/std/string.d 2005-03-18 09:29:36.000000000 +0100 +++ dmd-0.120/dmd/src/phobos/std/string.d 2005-04-06 12:26:40.000000000 +0200 @@ -48,6 +48,8 @@ void *memcpy(void *, void *, uint); void *memmove(void *, void *, uint); void *memset(void *, uint, uint); + char* strerror(int); + real strtold(char*, char**); int wcslen(wchar *); int wcscmp(wchar *, wchar *); @@ -92,10 +94,16 @@ return std.c.stdlib.atoi(toStringz(s)); } +/************************************* + * Convert string to float + */ + real atof(char[] s) -{ - // BUG: should implement atold() - return std.c.stdlib.atof(toStringz(s)); +{ char* endptr; + real result; + + result = strtold(toStringz(s), &endptr); + return result; } /********************************** diff -uNr dmd-0.119/dmd/src/phobos/std/typeinfo/ti_Ag.d dmd-0.120/dmd/src/phobos/std/typeinfo/ti_Ag.d --- dmd-0.119/dmd/src/phobos/std/typeinfo/ti_Ag.d 2005-03-18 09:29:38.000000000 +0100 +++ dmd-0.120/dmd/src/phobos/std/typeinfo/ti_Ag.d 2005-04-06 12:26:42.000000000 +0200 @@ -5,6 +5,8 @@ class TypeInfo_Ag : TypeInfo { + char[] toString() { return "byte[]"; } + uint getHash(void *p) { byte[] s = *cast(byte[]*)p; uint len = s.length; diff -uNr dmd-0.119/dmd/src/phobos/std/typeinfo/ti_double.d dmd-0.120/dmd/src/phobos/std/typeinfo/ti_double.d --- dmd-0.119/dmd/src/phobos/std/typeinfo/ti_double.d 2005-03-18 09:29:38.000000000 +0100 +++ dmd-0.120/dmd/src/phobos/std/typeinfo/ti_double.d 2005-04-06 12:26:40.000000000 +0200 @@ -29,7 +29,7 @@ } return 1; } - return (d1 < d2) ? -1 : 1; + return (d1 == d2) ? 0 : ((d1 < d2) ? -1 : 1); } int equals(void *p1, void *p2) diff -uNr dmd-0.119/dmd/src/phobos/std/typeinfo/ti_float.d dmd-0.120/dmd/src/phobos/std/typeinfo/ti_float.d --- dmd-0.119/dmd/src/phobos/std/typeinfo/ti_float.d 2005-03-18 09:29:38.000000000 +0100 +++ dmd-0.120/dmd/src/phobos/std/typeinfo/ti_float.d 2005-04-06 12:26:40.000000000 +0200 @@ -29,7 +29,7 @@ } return 1; } - return (d1 < d2) ? -1 : 1; + return (d1 == d2) ? 0 : ((d1 < d2) ? -1 : 1); } int equals(void *p1, void *p2) diff -uNr dmd-0.119/dmd/src/phobos/std/typeinfo/ti_real.d dmd-0.120/dmd/src/phobos/std/typeinfo/ti_real.d --- dmd-0.119/dmd/src/phobos/std/typeinfo/ti_real.d 2005-03-18 09:29:38.000000000 +0100 +++ dmd-0.120/dmd/src/phobos/std/typeinfo/ti_real.d 2005-04-06 12:26:42.000000000 +0200 @@ -29,7 +29,7 @@ } return 1; } - return (d1 < d2) ? -1 : 1; + return (d1 == d2) ? 0 : ((d1 < d2) ? -1 : 1); } int equals(void *p1, void *p2)