diff -uNr dmd-0.131/dmd/src/dmd/aggregate.h dmd-0.132/dmd/src/dmd/aggregate.h --- dmd-0.131/dmd/src/dmd/aggregate.h 2005-07-19 11:26:06.000000000 +0200 +++ dmd-0.132/dmd/src/dmd/aggregate.h 2005-09-19 02:26:56.000000000 +0200 @@ -65,6 +65,9 @@ void addField(Scope *sc, VarDeclaration *v); int isDeprecated(); // is aggregate deprecated? + void emitComment(Scope *sc); + void toDocBuffer(OutBuffer *buf); + // For access checking virtual PROT getAccess(Dsymbol *smember); // determine access to smember int isFriendOf(AggregateDeclaration *cd); @@ -189,6 +192,7 @@ virtual int vtblOffset(); char *kind(); char *mangle(); + void toDocBuffer(OutBuffer *buf); PROT getAccess(Dsymbol *smember); // determine access to smember diff -uNr dmd-0.131/dmd/src/dmd/attrib.c dmd-0.132/dmd/src/dmd/attrib.c --- dmd-0.131/dmd/src/dmd/attrib.c 2005-07-23 10:21:40.000000000 +0200 +++ dmd-0.132/dmd/src/dmd/attrib.c 2005-09-19 14:44:34.000000000 +0200 @@ -124,6 +124,49 @@ } } +void AttribDeclaration::addComment(unsigned char *comment) +{ + if (comment) + { + unsigned i; + Array *d = include(NULL, NULL); + + if (d) + { + for (i = 0; i < d->dim; i++) + { Dsymbol *s; + + s = (Dsymbol *)d->data[i]; + //printf("AttribDeclaration::addComment %s\n", s->toChars()); + s->addComment(comment); + } + } + } +} + +void AttribDeclaration::emitComment(Scope *sc) +{ + /* If generating doc comment, skip this because if we're inside + * a template, then include(NULL, NULL) will fail. + */ +// if (sc->docbuf) +// return; + + unsigned i; + Array *d = include(NULL, NULL); + + if (d) + { + for (i = 0; i < d->dim; i++) + { Dsymbol *s; + + s = (Dsymbol *)d->data[i]; + //printf("AttribDeclaration::emitComment %s\n", s->toChars()); + s->emitComment(sc); + } + } +} + void AttribDeclaration::toObjFile() { unsigned i; @@ -168,7 +211,8 @@ } Dsymbol *AttribDeclaration::oneMember() -{ Dsymbol *s; +{ + Dsymbol *s; Array *d = include(NULL, NULL); if (d && d->dim == 1) @@ -706,6 +750,11 @@ } +Dsymbol *ConditionalDeclaration::oneMember() +{ + return NULL; +} + // Decide if 'then' or 'else' code should be included Array *ConditionalDeclaration::include(Scope *sc, ScopeDsymbol *sd) @@ -715,6 +764,35 @@ } +void ConditionalDeclaration::addComment(unsigned char *comment) +{ + /* Because addComment is called by the parser, if we called + * include() it would define a version before it was used. + * But it's no problem to drill down to both decl and elsedecl, + * so that's the workaround. + */ + + if (comment) + { + Array *d = decl; + + for (int j = 0; j < 2; j++) + { + if (d) + { + for (unsigned i = 0; i < d->dim; i++) + { Dsymbol *s; + + s = (Dsymbol *)d->data[i]; + printf("ConditionalDeclaration::addComment %s\n", s->toChars()); + s->addComment(comment); + } + } + d = elsedecl; + } + } +} + void ConditionalDeclaration::toCBuffer(OutBuffer *buf) { condition->toCBuffer(buf); diff -uNr dmd-0.131/dmd/src/dmd/attrib.h dmd-0.132/dmd/src/dmd/attrib.h --- dmd-0.131/dmd/src/dmd/attrib.h 2005-07-23 10:20:38.000000000 +0200 +++ dmd-0.132/dmd/src/dmd/attrib.h 2005-09-19 14:44:10.000000000 +0200 @@ -36,6 +36,8 @@ void semantic2(Scope *sc); void semantic3(Scope *sc); void inlineScan(); + void addComment(unsigned char *comment); + void emitComment(Scope *sc); char *kind(); Dsymbol *oneMember(); void checkCtorConstInit(); @@ -118,7 +120,9 @@ ConditionalDeclaration(Condition *condition, Array *decl, Array *elsedecl); Dsymbol *syntaxCopy(Dsymbol *s); + Dsymbol *oneMember(); Array *include(Scope *sc, ScopeDsymbol *s); + void addComment(unsigned char *comment); void toCBuffer(OutBuffer *buf); }; diff -uNr dmd-0.131/dmd/src/dmd/cond.c dmd-0.132/dmd/src/dmd/cond.c --- dmd-0.131/dmd/src/dmd/cond.c 2005-06-16 13:03:40.000000000 +0200 +++ dmd-0.132/dmd/src/dmd/cond.c 2005-09-19 14:39:42.000000000 +0200 @@ -178,7 +178,8 @@ else if (findCondition(global.params.versionids, ident)) inc = 1; else - { if (!mod->versionidsNot) + { + if (!mod->versionidsNot) mod->versionidsNot = new Array(); mod->versionidsNot->push(ident->toChars()); } @@ -276,6 +277,7 @@ { if (!sc) { +*(char*)0=0; error(loc, "iftype conditional cannot be at global scope"); inc = 2; return 0; diff -uNr dmd-0.131/dmd/src/dmd/declaration.h dmd-0.132/dmd/src/dmd/declaration.h --- dmd-0.131/dmd/src/dmd/declaration.h 2005-07-23 10:16:08.000000000 +0200 +++ dmd-0.132/dmd/src/dmd/declaration.h 2005-09-18 23:14:24.000000000 +0200 @@ -79,6 +79,9 @@ char *kind(); unsigned size(Loc loc); + void emitComment(Scope *sc); + void toDocBuffer(OutBuffer *buf); + char *mangle(); int isStatic() { return storage_class & STCstatic; } virtual int isStaticConstructor(); @@ -123,6 +126,8 @@ Type *getType(); void toCBuffer(OutBuffer *buf); + void toDocBuffer(OutBuffer *buf); + void toObjFile(); // compile to .obj file void toDebug(); int cvMember(unsigned char *p); @@ -146,6 +151,8 @@ Dsymbol *toAlias(); void toCBuffer(OutBuffer *buf); + void toDocBuffer(OutBuffer *buf); + AliasDeclaration *isAliasDeclaration() { return this; } }; @@ -202,6 +209,8 @@ Dsymbol *syntaxCopy(Dsymbol *); void semantic(Scope *sc); + void emitComment(Scope *sc); + Symbol *toSymbol(); }; @@ -213,6 +222,8 @@ Dsymbol *syntaxCopy(Dsymbol *); void semantic(Scope *sc); + void emitComment(Scope *sc); + Symbol *toSymbol(); }; @@ -224,6 +235,8 @@ Dsymbol *syntaxCopy(Dsymbol *); void semantic(Scope *sc); + void emitComment(Scope *sc); + Symbol *toSymbol(); void toObjFile(); // compile to .obj file virtual void toDt(dt_t **pdt); @@ -422,6 +435,7 @@ int isVirtual(); int addPreInvariant(); int addPostInvariant(); + void toDocBuffer(OutBuffer *buf); CtorDeclaration *isCtorDeclaration() { return this; } }; @@ -434,6 +448,7 @@ int addPreInvariant(); int addPostInvariant(); int overloadInsert(Dsymbol *s); + void emitComment(Scope *sc); DtorDeclaration *isDtorDeclaration() { return this; } }; @@ -448,6 +463,7 @@ int isVirtual(); int addPreInvariant(); int addPostInvariant(); + void emitComment(Scope *sc); StaticCtorDeclaration *isStaticCtorDeclaration() { return this; } }; @@ -462,6 +478,7 @@ int isVirtual(); int addPreInvariant(); int addPostInvariant(); + void emitComment(Scope *sc); StaticDtorDeclaration *isStaticDtorDeclaration() { return this; } }; @@ -474,6 +491,7 @@ int isVirtual(); int addPreInvariant(); int addPostInvariant(); + void emitComment(Scope *sc); InvariantDeclaration *isInvariantDeclaration() { return this; } }; diff -uNr dmd-0.131/dmd/src/dmd/doc.c dmd-0.132/dmd/src/dmd/doc.c --- dmd-0.131/dmd/src/dmd/doc.c 1970-01-01 01:00:00.000000000 +0100 +++ dmd-0.132/dmd/src/dmd/doc.c 2005-09-19 17:45:24.000000000 +0200 @@ -0,0 +1,1331 @@ + +// Copyright (c) 1999-2005 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +#include +#include +#include +#include + +#if _WIN32 +#include "..\root\mem.h" +#elif linux +#include "../root/mem.h" +#else +#error "fix this" +#endif + +#include "root.h" + +#include "mars.h" +#include "dsymbol.h" +#include "macro.h" +#include "template.h" +#include "doc.h" + +struct Section +{ + unsigned char *name; + unsigned namelen; + + unsigned char *body; + unsigned bodylen; + + int nooutput; + + virtual void write(Scope *sc, Dsymbol *s, OutBuffer *buf); +}; + +struct ParamSection : Section +{ + void write(Scope *sc, Dsymbol *s, OutBuffer *buf); +}; + +struct DocComment +{ + Array sections; // Section*[] + + Section *summary; + Section *boilerplate; + Section *copyright; + Section *macros; + + DocComment(); + + static DocComment *parse(Scope *sc, Dsymbol *s, unsigned char *comment); + + void parseSections(unsigned char *comment); + void writeSections(Scope *sc, Dsymbol *s, OutBuffer *buf); + void doMacros(Macro **pmacrotable); +}; + + +int cmp(char *stringz, void *s, size_t slen); +int icmp(char *stringz, void *s, size_t slen); +int isDitto(unsigned char *comment); +unsigned char *skipwhitespace(unsigned char *p); +unsigned skiptoident(OutBuffer *buf, unsigned i); +unsigned skippastident(OutBuffer *buf, unsigned i); +void highlightText(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset); +void highlightCode(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset); +Argument *isFunctionParameter(Dsymbol *s, unsigned char *p, unsigned len); + +static char dtbigbig_s[] = "
"; +static char dtbigbig_e[] = "
\n"; + +static unsigned char default_boilerplate[] = "\ +\n\ +\n\ +\n\ +$(TITLE)\n\ +\n\ +\n\ +

$(TITLE)

\n\ +
\n\ +$(BODY)\n\ +
\n\ +
\n\ +Last modified: $(DATETIME)
\n\ +$(COPYRIGHT)
\n\ +\n\ +"; + +/**************************************************** + */ + +void Module::gendocfile() +{ + OutBuffer buf; + + //printf("Module::gendocfile()\n"); + + Scope *sc = Scope::createGlobal(this); // create root scope + sc->docbuf = &buf; + + DocComment *dc = DocComment::parse(sc, this, comment); + + if (dc->copyright) + { + dc->copyright->nooutput = 1; + Macro::define(¯otable, (unsigned char *)"COPYRIGHT", 9, dc->copyright->body, dc->copyright->bodylen); + } + + if (dc->macros) + dc->doMacros(¯otable); + + buf.printf("\n", srcfile->toChars()); + + dc->writeSections(sc, this, sc->docbuf); + + buf.writestring("
\n"); + for (int i = 0; i < members->dim; i++) + { + Dsymbol *s; + + s = (Dsymbol *)members->data[i]; + s->emitComment(sc); + } + buf.writestring("
\n"); + + // Generate predefined macros + + // Set the title to be the name of the module + { char *p = toPrettyChars(); + Macro::define(¯otable, (unsigned char *)"TITLE", 5, (unsigned char *)p, strlen(p)); + } + + Macro::define(¯otable, (unsigned char *)"BODY", 4, buf.data, buf.offset); + + time_t t; + time(&t); + char *p = ctime(&t); + p = mem.strdup(p); + Macro::define(¯otable, (unsigned char *)"DATETIME", 8, (unsigned char *)p, strlen(p)); + Macro::define(¯otable, (unsigned char *)"YEAR", 4, (unsigned char *)p + 20, 4); + + + OutBuffer buf2; + if (dc->boilerplate) + buf2.write(dc->boilerplate->body, dc->boilerplate->bodylen); + else + buf2.write(default_boilerplate, sizeof(default_boilerplate) - 1); + unsigned end = buf2.offset; + macrotable->expand(&buf2, 0, &end); + + // Transfer image to file + docfile->setbuffer(buf2.data, buf2.offset); + docfile->ref = 1; + docfile->writev(); +} + +/******************************* emitComment **********************************/ + +/* + * Emit doc comment to documentation file + */ + +void Dsymbol::emitDitto(Scope *sc) +{ + OutBuffer *buf = sc->docbuf; + unsigned o; + OutBuffer b; + + b.writestring("
"); + o = b.offset; + toDocBuffer(&b); + highlightCode(sc, this, &b, o); + buf->spread(sc->lastoffset, b.offset); + memcpy(buf->data + sc->lastoffset, b.data, b.offset); + sc->lastoffset += b.offset; +} + +void ScopeDsymbol::emitMemberComments(Scope *sc) +{ + OutBuffer *buf = sc->docbuf; + + if (members) + { + buf->writestring("
\n"); + sc = sc->push(this); + for (int i = 0; i < members->dim; i++) + { + Dsymbol *s = (Dsymbol *)members->data[i]; + s->emitComment(sc); + } + sc->pop(); + buf->writestring("
\n"); + } +} + +void emitProtection(OutBuffer *buf, PROT prot) +{ + char *p; + + switch (prot) + { + case PROTpackage: p = "package"; break; + case PROTprotected: p = "protected"; break; + case PROTexport: p = "export"; break; + default: p = NULL; break; + } + if (p) + buf->printf("%s ", p); +} + +void Dsymbol::emitComment(Scope *sc) { } +void InvariantDeclaration::emitComment(Scope *sc) { } +void DtorDeclaration::emitComment(Scope *sc) { } +void StaticCtorDeclaration::emitComment(Scope *sc) { } +void StaticDtorDeclaration::emitComment(Scope *sc) { } +void ClassInfoDeclaration::emitComment(Scope *sc) { } +void ModuleInfoDeclaration::emitComment(Scope *sc) { } +void TypeInfoDeclaration::emitComment(Scope *sc) { } + + +void Declaration::emitComment(Scope *sc) +{ + //printf("Declaration::emitComment(%p '%s'), comment = '%s'\n", this, toChars(), comment); + + if (protection == PROTprivate || !ident || + (!type && !isCtorDeclaration())) + return; + if (!comment) + return; + + OutBuffer *buf = sc->docbuf; + DocComment *dc = DocComment::parse(sc, this, comment); + unsigned o; + + if (!dc) + { + emitDitto(sc); + return; + } + + buf->writestring(dtbigbig_s); + o = buf->offset; + toDocBuffer(buf); + highlightCode(sc, this, buf, o); + sc->lastoffset = buf->offset; + buf->writestring(dtbigbig_e); + + buf->printf("
\n"); + dc->writeSections(sc, this, buf); + buf->printf("
\n"); +} + +void AggregateDeclaration::emitComment(Scope *sc) +{ + //printf("AggregateDeclaration::emitComment() '%s'\n", toChars()); +#if 0 + if (protection == PROTprivate) + return; +#endif + if (!comment) + return; + + OutBuffer *buf = sc->docbuf; + DocComment *dc = DocComment::parse(sc, this, comment); + + if (!dc) + { + emitDitto(sc); + return; + } + + buf->writestring(dtbigbig_s); + toDocBuffer(buf); + sc->lastoffset = buf->offset; + buf->writestring(dtbigbig_e); + + buf->printf("
\n"); + + dc->writeSections(sc, this, buf); + emitMemberComments(sc); + + buf->printf("
\n"); + + buf->printf("
\n"); +} + +void TemplateDeclaration::emitComment(Scope *sc) +{ + //printf("TemplateDeclaration::emitComment() '%s'\n", toChars()); +#if 0 + if (protection == PROTprivate) + return; +#endif + if (!comment) + return; + + OutBuffer *buf = sc->docbuf; + DocComment *dc = DocComment::parse(sc, this, comment); + + if (!dc) + { + emitDitto(sc); + return; + } + + ScopeDsymbol *ss = this; + + if (onemember) + ss = onemember->isAggregateDeclaration(); + + buf->writestring(dtbigbig_s); + ss->toDocBuffer(buf); + sc->lastoffset = buf->offset; + buf->writestring(dtbigbig_e); + + buf->printf("
\n"); + + dc->writeSections(sc, this, buf); + ss->emitMemberComments(sc); + + buf->printf("
\n"); + + buf->printf("
\n"); +} + +void EnumDeclaration::emitComment(Scope *sc) +{ +#if 0 + if (protection == PROTprivate) + return; +#endif + if (!comment) + return; + + OutBuffer *buf = sc->docbuf; + DocComment *dc = DocComment::parse(sc, this, comment); + + if (!dc) + { + emitDitto(sc); + return; + } + + buf->writestring(dtbigbig_s); + toDocBuffer(buf); + sc->lastoffset = buf->offset; + buf->writestring(dtbigbig_e); + + buf->printf("
\n"); + + dc->writeSections(sc, this, buf); + emitMemberComments(sc); + + buf->printf("
\n"); + +} + +void EnumMember::emitComment(Scope *sc) +{ + //printf("EnumMember::emitComment(%p '%s'), comment = '%s'\n", this, toChars(), comment); + if (!comment) + return; + + OutBuffer *buf = sc->docbuf; + DocComment *dc = DocComment::parse(sc, this, comment); + unsigned o; + + if (!dc) + { + emitDitto(sc); + return; + } + + buf->writestring(dtbigbig_s); + o = buf->offset; + toDocBuffer(buf); + highlightCode(sc, this, buf, o); + sc->lastoffset = buf->offset; + buf->writestring(dtbigbig_e); + + buf->printf("
\n"); + dc->writeSections(sc, this, buf); + buf->printf("
\n"); +} + +/******************************* toDocBuffer **********************************/ + +void Dsymbol::toDocBuffer(OutBuffer *buf) +{ + toCBuffer(buf); +} + +void Declaration::toDocBuffer(OutBuffer *buf) +{ + if (ident) + { + if (isDeprecated()) + buf->writestring("deprecated "); + + emitProtection(buf, protection); + if (isStatic()) + buf->writestring("static "); + if (isConst()) + buf->writestring("const "); + if (isFinal()) + buf->writestring("final "); + if (isSynchronized()) + buf->writestring("synchronized "); + if (type) + type->toCBuffer(buf, ident); + buf->writestring(";\n"); + } +} + + +void AliasDeclaration::toDocBuffer(OutBuffer *buf) +{ + if (ident) + { + if (isDeprecated()) + buf->writestring("deprecated "); + + emitProtection(buf, protection); + buf->writestring("alias "); + buf->writestring(toChars()); + buf->writestring(";\n"); + } +} + + +void TypedefDeclaration::toDocBuffer(OutBuffer *buf) +{ + if (ident) + { + if (isDeprecated()) + buf->writestring("deprecated "); + + emitProtection(buf, protection); + buf->writestring("typedef "); + buf->writestring(toChars()); + buf->writestring(";\n"); + } +} + + +void CtorDeclaration::toDocBuffer(OutBuffer *buf) +{ + TypeFunction *tf = (TypeFunction *)type; + + buf->writestring("this"); + if (!tf) + { // Need to create one + tf = new TypeFunction(arguments, Type::tvoid, varargs, LINKd); + } + tf->argsToCBuffer(buf); + buf->writestring(";\n"); +} + + +void AggregateDeclaration::toDocBuffer(OutBuffer *buf) +{ + if (ident) + { +#if 0 + emitProtection(buf, protection); +#endif + buf->printf("%s %s", kind(), toChars()); + buf->writestring(";\n"); + } +} + +void ClassDeclaration::toDocBuffer(OutBuffer *buf) +{ + if (ident) + { +#if 0 + emitProtection(buf, protection); +#endif + TemplateDeclaration *td; + + if (parent && + (td = parent->isTemplateDeclaration()) != NULL && + td->onemember == this) + { unsigned o = buf->offset; + td->toDocBuffer(buf); + highlightCode(NULL, this, buf, o); + } + else + buf->printf("%s %s", kind(), toChars()); + int any = 0; + for (int i = 0; i < baseclasses.dim; i++) + { BaseClass *bc = (BaseClass *)baseclasses.data[i]; + + if (bc->protection == PROTprivate) + continue; + if (bc->base && bc->base->ident == Id::Object) + continue; + + if (any) + buf->writestring(", "); + else + { buf->writestring(": "); + any = 1; + } + emitProtection(buf, bc->protection); + if (bc->base) + { + buf->writestring(bc->base->toPrettyChars()); + } + else + { + bc->type->toCBuffer(buf, NULL); + } + } + buf->writestring(";\n"); + } +} + + +void EnumDeclaration::toDocBuffer(OutBuffer *buf) +{ + if (ident) + { + buf->printf("%s %s", kind(), toChars()); + buf->writestring(";\n"); + } +} + +void EnumMember::toDocBuffer(OutBuffer *buf) +{ + if (ident) + { + buf->writestring(toChars()); + } +} + + +/********************************* DocComment *********************************/ + +DocComment::DocComment() +{ + memset(this, 0, sizeof(DocComment)); +} + +DocComment *DocComment::parse(Scope *sc, Dsymbol *s, unsigned char *comment) +{ unsigned idlen; + + if (sc->lastdc && isDitto(comment)) + return NULL; + + DocComment *dc = new DocComment(); + if (!comment) + return dc; + + dc->parseSections(comment); + + for (int i = 0; i < dc->sections.dim; i++) + { Section *s = (Section *)dc->sections.data[i]; + + if (icmp("boilerplate", s->name, s->namelen) == 0) + { + dc->boilerplate = s; + s->nooutput = 1; + } + + if (icmp("copyright", s->name, s->namelen) == 0) + { + dc->copyright = s; + } + + if (icmp("macros", s->name, s->namelen) == 0) + { + dc->macros = s; + s->nooutput = 1; + } + } + + sc->lastdc = dc; + return dc; +} + +/***************************************** + * Parse next paragraph out of *pcomment. + * Update *pcomment to point past paragraph. + * Returns NULL if no more paragraphs. + * If paragraph ends in 'identifier:', + * then (*pcomment)[0 .. idlen] is the identifier. + */ + +void DocComment::parseSections(unsigned char *comment) +{ unsigned char *p; + unsigned char *pstart; + unsigned char *pend; + unsigned char *q; + unsigned char *idstart; + unsigned idlen; + + unsigned char *name = NULL; + unsigned namelen = 0; + + p = comment; + while (*p) + { + p = skipwhitespace(p); + pstart = p; + + /* Find end of section, which is ended by one of: + * 'identifier:' + * '\0' + */ + idlen = 0; + while (1) + { + if (isalpha(*p) || *p == '_') + { + q = p + 1; + while (isalnum(*q) || *q == '_') + q++; + if (*q == ':') // identifier: ends it + { idlen = q - p; + idstart = p; + for (pend = p; pend > pstart; pend--) + { if (pend[-1] == '\n') + break; + } + p = q + 1; + break; + } + } + while (1) + { + if (!*p) + { pend = p; + goto L1; + } + if (*p == '\n') + { p++; + if (*p == '\n' && !summary && !namelen) + { + pend = p; + p++; + goto L1; + } + break; + } + p++; + } + p = skipwhitespace(p); + } + L1: + + Section *s; + if (icmp("Params", name, namelen) == 0) + s = new ParamSection(); + else + s = new Section(); + s->name = name; + s->namelen = namelen; + s->body = pstart; + s->bodylen = pend - pstart; + s->nooutput = 0; + + //printf("Section: '%.*s' = '%.*s'\n", s->namelen, s->name, s->bodylen, s->body); + + sections.push(s); + + if (!summary && !namelen) + summary = s; + + if (idlen) + { name = idstart; + namelen = idlen; + } + else + { name = NULL; + namelen = 0; + if (!*p) + break; + } + } +} + +void DocComment::writeSections(Scope *sc, Dsymbol *s, OutBuffer *buf) +{ + if (sections.dim) + { + for (int i = 0; i < sections.dim; i++) + { Section *sec = (Section *)sections.data[i]; + + if (sec->nooutput) + continue; + if (sec->namelen) + { + buf->printf("

%.*s:

", sec->namelen, sec->name); + } + sec->write(sc, s, buf); + } + } + else + buf->writestring("

\n"); +} + +/*************************************************** + */ + +void Section::write(Scope *sc, Dsymbol *s, OutBuffer *buf) +{ + buf->writestring("

"); + unsigned o = buf->offset; + buf->write(body, bodylen); + highlightText(sc, s, buf, o); + buf->writestring("

\n"); +} + +/*************************************************** + */ + +void ParamSection::write(Scope *sc, Dsymbol *s, OutBuffer *buf) +{ + unsigned char *p = body; + unsigned len = bodylen; + unsigned char *pend = p + len; + + unsigned char *tempstart; + unsigned templen; + + unsigned char *namestart; + unsigned namelen = 0; // !=0 if line continuation + + unsigned char *textstart; + unsigned textlen; + + unsigned o; + Argument *arg; + + buf->writestring("

\n"); + while (p < pend) + { + // Skip to start of macro + for (; 1; p++) + { + switch (*p) + { + case ' ': + case '\t': + continue; + + case '\n': + p++; + goto Lcont; + + default: + if (!(isalpha(*p) || *p == '_')) + { + if (namelen) + goto Ltext; // continuation of prev macro + goto Lskipline; + } + break; + } + break; + } + tempstart = p; + + while (isalnum(*p) || *p == '_') + p++; + templen = p - tempstart; + + while (*p == ' ' || *p == '\t') + p++; + + if (*p != '=') + { if (namelen) + goto Ltext; // continuation of prev macro + goto Lskipline; + } + p++; + + namestart = tempstart; + namelen = templen; + + while (*p == ' ' || *p == '\t') + p++; + textstart = p; + + Ltext: + while (*p != '\n') + p++; + textlen = p - textstart; + + //printf("param '%.*s' = '%.*s'\n", namelen, namestart, textlen, textstart); + + buf->writestring("\n"); + + buf->writestring("\n"); + + p++; + + Lcont: + continue; + + Lskipline: + // Ignore this line + while (*p++ != '\n') + ; + } + buf->writestring("
"); + o = buf->offset; + arg = isFunctionParameter(s, namestart, namelen); + if (arg && arg->type && arg->ident) + arg->type->toCBuffer(buf, arg->ident); + else + buf->write(namestart, namelen); + highlightCode(sc, s, buf, o); + buf->writestring(""); + o = buf->offset; + buf->write(textstart, textlen); + highlightText(sc, s, buf, o); + buf->writestring("

\n"); +} + +/************************************************ + * Parse macros out of Macros: section. + * Macros are of the form: + * name1 = value1 + * + * name2 = value2 + */ + +void DocComment::doMacros(Macro **pmacrotable) +{ + unsigned char *p = macros->body; + unsigned len = macros->bodylen; + unsigned char *pend = p + len; + + unsigned char *tempstart; + unsigned templen; + + unsigned char *namestart; + unsigned namelen = 0; // !=0 if line continuation + + unsigned char *textstart; + unsigned textlen; + + while (p < pend) + { + // Skip to start of macro + for (; 1; p++) + { + switch (*p) + { + case ' ': + case '\t': + continue; + + case '\n': + p++; + goto Lcont; + + default: + if (!(isalpha(*p) || *p == '_')) + { + if (namelen) + goto Ltext; // continuation of prev macro + goto Lskipline; + } + break; + } + break; + } + tempstart = p; + + while (isalnum(*p) || *p == '_') + p++; + templen = p - tempstart; + + while (*p == ' ' || *p == '\t') + p++; + + if (*p != '=') + { if (namelen) + goto Ltext; // continuation of prev macro + goto Lskipline; + } + p++; + + namestart = tempstart; + namelen = templen; + + while (*p == ' ' || *p == '\t') + p++; + textstart = p; + + Ltext: + while (*p != '\n') + p++; + textlen = p - textstart; + + //printf("macro '%.*s' = '%.*s'\n", namelen, namestart, textlen, textstart); + Macro::define(pmacrotable, namestart, namelen, textstart, textlen); + + p++; + //printf("p = %p, pend = %p\n", p, pend); + + Lcont: + continue; + + Lskipline: + // Ignore this line + while (*p++ != '\n') + ; + } +} + +/****************************************** + * Compare 0-terminated string with length terminated string. + * Return < 0, ==0, > 0 + */ + +int cmp(char *stringz, void *s, size_t slen) +{ + size_t len1 = strlen(stringz); + + if (len1 != slen) + return len1 - slen; + return memcmp(stringz, s, slen); +} + +int icmp(char *stringz, void *s, size_t slen) +{ + size_t len1 = strlen(stringz); + + if (len1 != slen) + return len1 - slen; + return memicmp(stringz, (char *)s, slen); +} + +/***************************************** + * Return !=0 if comment consists entirely of "ditto". + */ + +int isDitto(unsigned char *comment) +{ + if (comment) + { + unsigned char *p = skipwhitespace(comment); + + if (memicmp((char *)p, "ditto", 5) == 0 && *skipwhitespace(p + 5) == 0) + return 1; + } + return 0; +} + +/********************************************** + * Skip white space. + */ + +unsigned char *skipwhitespace(unsigned char *p) +{ + for (; 1; p++) + { switch (*p) + { + case ' ': + case '\t': + case '\n': + continue; + } + break; + } + return p; +} + + +/************************************************ + * Scan forward to one of: + * start of identifier + * beginning of next line + * end of buf + */ + +unsigned skiptoident(OutBuffer *buf, unsigned i) +{ + for (; i < buf->offset; i++) + { + // BUG: handle unicode alpha's + unsigned char c = buf->data[i]; + if (isalpha(c) || c == '_') + break; + if (c == '\n') + break; + } + return i; +} + +/************************************************ + * Scan forward past end of identifier. + */ + +unsigned skippastident(OutBuffer *buf, unsigned i) +{ + for (; i < buf->offset; i++) + { + // BUG: handle unicode alpha's + unsigned char c = buf->data[i]; + if (!(isalnum(c) || c == '_')) + break; + } + return i; +} + + +/**************************************************** + */ + +int isKeyword(unsigned char *p, unsigned len) +{ + static char *table[] = { "true", "false", "null" }; + + for (int i = 0; i < sizeof(table) / sizeof(table[0]); i++) + { + if (cmp(table[i], p, len) == 0) + return 1; + } + return 0; +} + +/**************************************************** + */ + +Argument *isFunctionParameter(Dsymbol *s, unsigned char *p, unsigned len) +{ + FuncDeclaration *f = s->isFuncDeclaration(); + + /* f->type may be NULL for template members. + */ + if (f && f->type) + { + TypeFunction *tf = (TypeFunction *)f->type; + + if (tf->arguments) + { + for (int k = 0; k < tf->arguments->dim; k++) + { Argument *arg = (Argument *)tf->arguments->data[k]; + + if (arg->ident && cmp(arg->ident->toChars(), p, len) == 0) + { + return arg; + } + } + } + } + return NULL; +} + +/************************************************** + * Highlight text section. + */ + +void highlightText(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset) +{ + //printf("highlightText()\n"); + char *sid = s->ident->toChars(); + FuncDeclaration *f = s->isFuncDeclaration(); + unsigned char *p; + + int leadingBlank = 1; + int inCode = 0; + int inComment = 0; // in comment + unsigned iCodeStart; // start of code section + unsigned iLineStart = offset; + + for (unsigned i = offset; i < buf->offset; i++) + { unsigned char c = buf->data[i]; + + Lcont: + switch (c) + { + case ' ': + case '\t': + break; + + case '\n': + if (i == iLineStart) // if "\n\n" + { buf->insert(i, "

\n

", 8); + i += 8; // point at last '>' + } + leadingBlank = 1; + iLineStart = i + 1; + break; + + case '<': + leadingBlank = 0; + if (inCode) + break; + p = &buf->data[i]; + + // Skip over comments + if (p[1] == '!' && p[2] == '-' && p[3] == '-') + { unsigned j = i + 4; + p += 4; + while (1) + { + if (j == buf->offset) + goto L1; + if (p[0] == '-' && p[1] == '-' && p[2] == '>') + { + i = j + 2; // place on closing '>' + break; + } + j++; + p++; + } + break; + } + + // Skip over HTML tag + if (isalpha(p[1]) || (p[1] == '/' && isalpha(p[2]))) + { unsigned j = i + 2; + p += 2; + while (1) + { + if (j == buf->offset) + goto L1; + if (p[0] == '>') + { + i = j; // place on closing '>' + break; + } + j++; + p++; + } + break; + } + + L1: + // Replace '<' with < character entity + buf->remove(i, 1); + buf->insert(i, "<", 4); + i += 3; // point to ';' + break; + + case '>': + leadingBlank = 0; + if (inCode) + break; + buf->remove(i, 1); + buf->insert(i, ">", 4); + i += 3; // point to ';' + break; + + case '&': + leadingBlank = 0; + if (inCode) + break; + p = &buf->data[i]; + if (p[1] == '#' || isalpha(p[1])) + break; // already a character entity + buf->remove(i, 1); + buf->insert(i, "&", 5); + i += 4; // point to ';' + break; + + case '-': + /* A line beginning with --- delimits a code section. + * inCode tells us if it is start or end of a code section. + */ + if (leadingBlank) + { int istart = i; + + leadingBlank = 0; + while (1) + { + ++i; + assert(i < buf->offset); + c = buf->data[i]; + if (c != '-') + break; + } + if (c != '\n' || i - istart < 3) + goto Lcont; + + // We have the start/end of a code section + + // Remove the entire --- line, including blanks and \n + buf->remove(iLineStart, i - iLineStart + 1); // remove '-----\n' + i = iLineStart; + + if (inCode) + { + inCode = 0; + // The code section is from iCodeStart to i + OutBuffer codebuf; + + codebuf.write(buf->data + iCodeStart, i - iCodeStart); + highlightCode(sc, s, &codebuf, 0); + buf->remove(iCodeStart, i - iCodeStart); + buf->insert(iCodeStart, codebuf.data, codebuf.offset); + i = iCodeStart + codebuf.offset; + buf->insert(i, "\n", 7); + i += 5; // place i on > + } + else + { static char pre[] = "

\n";
+
+			inCode = 1;
+			buf->insert(i, pre, sizeof(pre) - 1);
+			i += sizeof(pre) - 2;		// place i on >
+			iCodeStart = i + 2;
+		    }
+		}
+		break;
+
+	    default:
+		leadingBlank = 0;
+		if (!inCode && (isalpha(c) || c == '_'))
+		{   unsigned j;
+
+		    j = skippastident(buf, i);
+		    if (j > i)
+		    {
+			if (buf->data[i] == '_')	// leading '_' means no highlight
+			{
+			    buf->remove(i, 1);
+			    i = j - 1;
+			}
+			else
+			{
+			    if (cmp(sid, buf->data + i, j - i) == 0 ||
+				isKeyword(buf->data + i, j - i))
+			    {
+				buf->insert(i, "", 3);
+				buf->insert(j + 3, "", 4);
+				i = j + 7 - 1;
+				break;
+			    }
+			    else
+			    {
+				if (f && isFunctionParameter(f, buf->data + i, j - i))
+				{
+				    //printf("highlighting arg '%s', i = %d, j = %d\n", arg->ident->toChars(), i, j);
+				    buf->insert(i, "", 3);
+				    buf->insert(j + 3, "", 4);
+				    i = j + 7 - 1;
+				    break;
+				}
+			    }
+			    i = j - 1;
+			}
+		    }
+		}
+		break;
+	}
+    }
+  Ldone:
+    ;
+}
+
+/**************************************************
+ * Highlight code.
+ */
+
+void highlightCode(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset)
+{
+    char *sid = s->ident->toChars();
+    FuncDeclaration *f = s->isFuncDeclaration();
+
+    for (unsigned i = offset; i < buf->offset; i++)
+    {	unsigned char c = buf->data[i];
+
+	switch (c)
+	{
+	    case '<':			// replace '<' with '<'
+		buf->remove(i, 1);
+		buf->insert(i, "<", 4);
+		i += 3;		// point to ';'
+		break;
+
+	    case '>':
+		buf->remove(i, 1);
+		buf->insert(i, ">", 4);
+		i += 3;		// point to ';'
+		break;
+
+	    case '&':
+		buf->remove(i, 1);
+		buf->insert(i, "&", 5);
+		i += 4;		// point to ';'
+		break;
+
+	    default:
+		if (isalpha(c) || c == '_')
+		{   unsigned j;
+
+		    j = skippastident(buf, i);
+		    if (j > i)
+		    {
+			if (cmp(sid, buf->data + i, j - i) == 0)
+			{
+			    buf->insert(i, "", 3);
+			    buf->insert(j + 3, "", 4);
+			    i = j + 7 - 1;
+			    break;
+			}
+			else if (f)
+			{
+			    if (isFunctionParameter(f, buf->data + i, j - i))
+			    {
+				//printf("highlighting arg '%s', i = %d, j = %d\n", arg->ident->toChars(), i, j);
+				buf->insert(i, "", 3);
+				buf->insert(j + 3, "", 4);
+				i = j + 7 - 1;
+				break;
+			    }
+			}
+			i = j - 1;
+		    }
+		}
+		break;
+	}
+    }
+}
+
diff -uNr dmd-0.131/dmd/src/dmd/doc.h dmd-0.132/dmd/src/dmd/doc.h
--- dmd-0.131/dmd/src/dmd/doc.h	1970-01-01 01:00:00.000000000 +0100
+++ dmd-0.132/dmd/src/dmd/doc.h	2005-09-17 00:37:06.000000000 +0200
@@ -0,0 +1,18 @@
+
+// Copyright (c) 1999-2005 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#ifndef DMD_DOC_H
+#define DMD_DOC_H
+
+#ifdef __DMC__
+#pragma once
+#endif /* __DMC__ */
+
+
+#endif
diff -uNr dmd-0.131/dmd/src/dmd/dsymbol.c dmd-0.132/dmd/src/dmd/dsymbol.c
--- dmd-0.131/dmd/src/dmd/dsymbol.c	2005-06-12 01:51:00.000000000 +0200
+++ dmd-0.132/dmd/src/dmd/dsymbol.c	2005-09-15 01:19:54.000000000 +0200
@@ -36,6 +36,7 @@
     this->csym = NULL;
     this->isym = NULL;
     this->loc = 0;
+    this->comment = NULL;
 }
 
 Dsymbol::Dsymbol(Identifier *ident)
@@ -47,6 +48,7 @@
     this->csym = NULL;
     this->isym = NULL;
     this->loc = 0;
+    this->comment = NULL;
 }
 
 int Dsymbol::equals(Object *o)
@@ -415,6 +417,22 @@
     return b;
 }
 
+
+/****************************************
+ * Add documentation comment to Dsymbol.
+ * Ignore NULL comments.
+ */
+
+void Dsymbol::addComment(unsigned char *comment)
+{
+    //if (comment)
+	//printf("adding comment '%s' to symbol %p '%s'\n", comment, this, toChars());
+
+    if (!this->comment)
+	this->comment = comment;
+}
+
+
 /********************************* ScopeDsymbol ****************************/
 
 ScopeDsymbol::ScopeDsymbol()
diff -uNr dmd-0.131/dmd/src/dmd/dsymbol.h dmd-0.132/dmd/src/dmd/dsymbol.h
--- dmd-0.131/dmd/src/dmd/dsymbol.h	2005-07-23 10:15:42.000000000 +0200
+++ dmd-0.132/dmd/src/dmd/dsymbol.h	2005-09-19 11:18:42.000000000 +0200
@@ -81,6 +81,7 @@
     Dsymbol *parent;
     Symbol *csym;		// symbol for code generator
     Symbol *isym;		// import version of csym
+    unsigned char *comment;	// documentation comment for this Dsymbol
     Loc loc;			// where defined
 
     Dsymbol();
@@ -111,6 +112,7 @@
     virtual Dsymbol *search(Identifier *ident, int flags);
     virtual int overloadInsert(Dsymbol *s);
     virtual void toCBuffer(OutBuffer *buf);
+    virtual void toDocBuffer(OutBuffer *buf);
     virtual unsigned size(Loc loc);
     virtual int isforwardRef();
     virtual void defineRef(Dsymbol *s);
@@ -130,6 +132,10 @@
     virtual void addLocalClass(Array *) { }
     virtual void checkCtorConstInit() { }
 
+    virtual void addComment(unsigned char *comment);
+    virtual void emitComment(Scope *sc);
+    void emitDitto(Scope *sc);
+
     // Backend
 
     virtual Symbol *toSymbol();			// to backend symbol
@@ -196,6 +202,8 @@
     Dsymbol *nameCollision(Dsymbol *s);
     char *kind();
 
+    void emitMemberComments(Scope *sc);
+
     ScopeDsymbol *isScopeDsymbol() { return this; }
 };
 
diff -uNr dmd-0.131/dmd/src/dmd/enum.h dmd-0.132/dmd/src/dmd/enum.h
--- dmd-0.131/dmd/src/dmd/enum.h	2005-05-09 15:51:16.000000000 +0200
+++ dmd-0.132/dmd/src/dmd/enum.h	2005-09-18 22:55:10.000000000 +0200
@@ -37,6 +37,9 @@
     Type *getType();
     char *kind();
 
+    void emitComment(Scope *sc);
+    void toDocBuffer(OutBuffer *buf);
+
     EnumDeclaration *isEnumDeclaration() { return this; }
 
     void toObjFile();			// compile to .obj file
@@ -54,6 +57,9 @@
     void toCBuffer(OutBuffer *buf);
     char *kind();
 
+    void emitComment(Scope *sc);
+    void toDocBuffer(OutBuffer *buf);
+
     EnumMember *isEnumMember() { return this; }
 };
 
diff -uNr dmd-0.131/dmd/src/dmd/lexer.c dmd-0.132/dmd/src/dmd/lexer.c
--- dmd-0.131/dmd/src/dmd/lexer.c	2005-07-19 09:47:48.000000000 +0200
+++ dmd-0.132/dmd/src/dmd/lexer.c	2005-09-15 17:06:58.000000000 +0200
@@ -79,7 +79,7 @@
 }
 
 
-/******************************************************/
+/************************* Token **********************************************/
 
 char *Token::tochars[TOKMAX];
 
@@ -187,13 +187,13 @@
     return p;
 }
 
-/******************************************************/
+/*************************** Lexer ********************************************/
 
 Token *Lexer::freelist = NULL;
 StringTable Lexer::stringtable;
 OutBuffer Lexer::stringbuffer;
 
-Lexer::Lexer(Module *mod, unsigned char *base, unsigned length)
+Lexer::Lexer(Module *mod, unsigned char *base, unsigned length, int doDocComment)
     : loc(mod, 1)
 {
     //printf("Lexer::Lexer(%p,%d)\n",base,length);
@@ -203,6 +203,8 @@
     this->end  = base + length;
     p = base;
     this->mod = mod;
+    this->doDocComment = doDocComment;
+    this->anyToken = 0;
     //initKeywords();
 }
 
@@ -307,6 +309,11 @@
 
 void Lexer::scan(Token *t)
 {
+    unsigned lastLine = loc.linnum;
+    unsigned linnum;
+
+    t->blockComment = NULL;
+    t->lineComment = NULL;
     while (1)
     {
 	t->ptr = p;
@@ -441,6 +448,7 @@
 		}
 		t->ident = id;
 		t->value = (enum TOK) id->value;
+		anyToken = 1;
 		if (*t->ptr == '_')	// if special identifier token
 		{
 		    static char date[11+1];
@@ -506,6 +514,7 @@
 
 		    case '*':
 			p++;
+			linnum = loc.linnum;
 			while (1)
 			{
 			    while (1)
@@ -548,9 +557,14 @@
 			    if (p[-2] == '*' && p - 3 != t->ptr)
 				break;
 			}
+			if (doDocComment && t->ptr[2] == '*' && p - 4 != t->ptr)
+			{   // if /** but not /**/
+			    getDocComment(t, lastLine == linnum);
+			}
 			continue;
 
-		    case '/':
+		    case '/':		// do // style comments
+			linnum = loc.linnum;
 			while (1)
 			{   unsigned char c = *++p;
 			    switch (c)
@@ -565,6 +579,8 @@
 
 				case 0:
 				case 0x1A:
+				    if (doDocComment && t->ptr[2] == '/')
+					getDocComment(t, lastLine == linnum);
 				    p = end;
 				    t->value = TOKeof;
 				    return;
@@ -579,6 +595,10 @@
 			    }
 			    break;
 			}
+
+			if (doDocComment && t->ptr[2] == '/')
+			    getDocComment(t, lastLine == linnum);
+
 			p++;
 			loc.linnum++;
 			continue;
@@ -586,6 +606,7 @@
 		    case '+':
 		    {	int nest;
 
+			linnum = loc.linnum;
 			p++;
 			nest = 1;
 			while (1)
@@ -640,6 +661,10 @@
 			    }
 			    break;
 			}
+			if (doDocComment && t->ptr[2] == '+' && p - 4 != t->ptr)
+			{   // if /++ but not /++/
+			    getDocComment(t, lastLine == linnum);
+			}
 			continue;
 		    }
 		}
@@ -2065,6 +2090,134 @@
     return u;
 }
 
+
+/***************************************************
+ * Parse doc comment embedded between t->ptr and p.
+ * Remove trailing blanks and tabs from lines.
+ * Replace all newlines with \n.
+ * Remove leading comment character from each line.
+ * Decide if it's a lineComment or a blockComment.
+ * Append to previous one for this token.
+ */
+
+void Lexer::getDocComment(Token *t, unsigned lineComment)
+{
+    OutBuffer buf;
+    unsigned char ct = t->ptr[2];
+    unsigned char *q = t->ptr + 3;	// start of comment text
+    int linestart = 0;
+
+    unsigned char *qend = p;
+    if (ct == '*' || ct == '+')
+	qend -= 2;
+
+    /* Scan over initial row of ****'s or ++++'s or ////'s
+     */
+    for (; q < qend; q++)
+    {
+	if (*q != ct)
+	    break;
+    }
+
+    for (; q < qend; q++)
+    {
+	unsigned char c = *q;
+
+	switch (c)
+	{
+	    case '*':
+	    case '+':
+		if (linestart && c == ct)
+		{   linestart = 0;
+		    /* Trim preceding whitespace up to preceding \n
+		     */
+		    while (buf.offset && (buf.data[buf.offset - 1] == ' ' || buf.data[buf.offset - 1] == '\t'))
+			buf.offset--;
+		    continue;
+		}
+		break;
+
+	    case ' ':
+	    case '\t':
+		break;
+
+	    case '\r':
+		if (q[1] == '\n')
+		    continue;		// skip the \r
+		goto Lnewline;
+
+	    default:
+		if (c == 226)
+		{
+		    // If LS or PS
+		    if (q[1] == 128 &&
+			(q[2] == 168 || q[2] == 169))
+		    {
+			q += 2;
+			goto Lnewline;
+		    }
+		}
+		linestart = 0;
+		break;
+
+	    Lnewline:
+		c = '\n';		// replace all newlines with \n
+	    case '\n':
+		linestart = 1;
+
+		/* Trim trailing whitespace
+		 */
+		while (buf.offset && (buf.data[buf.offset - 1] == ' ' || buf.data[buf.offset - 1] == '\t'))
+		    buf.offset--;
+
+		break;
+	}
+	buf.writeByte(c);
+    }
+
+    // Always end with a newline
+    if (!buf.offset || buf.data[buf.offset - 1] != '\n')
+	buf.writeByte('\n');
+
+    buf.writeByte(0);
+
+    // It's a line comment if the start of the doc comment comes
+    // after other non-whitespace on the same line.
+    unsigned char** dc = (lineComment && anyToken)
+			 ? &t->lineComment
+			 : &t->blockComment;
+
+    // Combine with previous doc comment, if any
+    if (*dc)
+	*dc = combineComments(*dc, (unsigned char *)buf.data);
+    else
+	*dc = (unsigned char *)buf.extractData();
+}
+
+/********************************************
+ * Combine two document comments into one.
+ */
+
+unsigned char *Lexer::combineComments(unsigned char *c1, unsigned char *c2)
+{
+    unsigned char *c = c2;
+
+    if (c1)
+    {	c = c1;
+	if (c2)
+	{   size_t len1 = strlen((char *)c1);
+	    size_t len2 = strlen((char *)c2);
+
+	    c = (unsigned char *)mem.malloc(len1 + 1 + len2 + 1);
+	    memcpy(c, c1, len1);
+	    c[len1] = '\n';
+	    memcpy(c + len1 + 1, c2, len2);
+	    c[len1 + 1 + len2] = 0;
+	}
+    }
+    return c;
+}
+
 /********************************************
  * Create an identifier in the string table.
  */
diff -uNr dmd-0.131/dmd/src/dmd/lexer.h dmd-0.132/dmd/src/dmd/lexer.h
--- dmd-0.131/dmd/src/dmd/lexer.h	2005-07-18 10:27:38.000000000 +0200
+++ dmd-0.132/dmd/src/dmd/lexer.h	2005-09-13 02:50:00.000000000 +0200
@@ -185,6 +185,8 @@
     Token *next;
     unsigned char *ptr;		// pointer to first character of this token within buffer
     enum TOK value;
+    unsigned char *blockComment; // doc comment string prior to this token
+    unsigned char *lineComment;	 // doc comment for previous token
     union
     {
 	// Integers
@@ -225,8 +227,10 @@
     unsigned char *p;		// current character
     Token token;
     Module *mod;
+    int doDocComment;		// collect doc comment information
+    int anyToken;		// !=0 means seen at least one token
 
-    Lexer(Module *mod, unsigned char *base, unsigned length);
+    Lexer(Module *mod, unsigned char *base, unsigned length, int doDocComment);
 
     static void initKeywords();
     static Identifier *idPool(const char *s);
@@ -247,6 +251,9 @@
     void error(Loc loc, const char *format, ...);
     void pragma();
     unsigned decodeUTF();
+    void getDocComment(Token *t, unsigned lineComment);
+
+    static unsigned char *combineComments(unsigned char *c1, unsigned char *c2);
 };
 
 #endif /* DMD_LEXER_H */
diff -uNr dmd-0.131/dmd/src/dmd/mars.c dmd-0.132/dmd/src/dmd/mars.c
--- dmd-0.131/dmd/src/dmd/mars.c	2005-09-08 19:11:24.000000000 +0200
+++ dmd-0.132/dmd/src/dmd/mars.c	2005-09-13 03:26:32.000000000 +0200
@@ -38,6 +38,7 @@
 {
     mars_ext = "d";
     sym_ext  = "d";
+    doc_ext  = "html";
 
 #if _WIN32
     obj_ext  = "obj";
@@ -49,7 +50,7 @@
 
     copyright = "Copyright (c) 1999-2005 by Digital Mars";
     written = "written by Walter Bright";
-    version = "v0.131";
+    version = "v0.132";
     global.structalign = 8;
 
     memset(¶ms, 0, sizeof(Param));
@@ -129,6 +130,9 @@
 \n\
   files.d        D source files\n\
   -c             do not link\n\
+  -D             generate documentation\n\
+  -Dddocdir      write documentation file to docdir directory\n\
+  -Dffilename    write documentation file to filename\n\
   -d             allow deprecated features\n\
   -debug         compile in debug code\n\
   -debug=level   compile in debug code <= level\n\
@@ -272,6 +276,28 @@
 			goto Lerror;
 		}
 	    }
+	    else if (p[1] == 'D')
+	    {	global.params.doDocComments = 1;
+		switch (p[2])
+		{
+		    case 'd':
+			if (!p[3])
+			    goto Lnoarg;
+			global.params.docdir = p + 3;
+			break;
+		    case 'f':
+			if (!p[3])
+			    goto Lnoarg;
+			global.params.docname = p + 3;
+			break;
+
+		    case 0:
+			break;
+
+		    default:
+			goto Lerror;
+		}
+	    }
 	    else if (strcmp(p + 1, "inline") == 0)
 		global.params.useInline = 1;
 	    else if (strcmp(p + 1, "quiet") == 0)
@@ -515,7 +541,7 @@
 	}
 
 	id = new Identifier(name, 0);
-	m = new Module((char *) files.data[i], id);
+	m = new Module((char *) files.data[i], id, global.params.doDocComments);
 	modules.push(m);
 
 	global.params.objfiles->push(m->objfile->name->str);
@@ -588,9 +614,14 @@
 	if (global.params.verbose)
 	    printf("code      %s\n", m->toChars());
 	m->genobjfile();
-//	m->gensymfile();
 	if (global.errors)
 	    m->deleteObjFile();
+	else
+	{
+	    //m->gensymfile();
+	    if (global.params.doDocComments)
+		m->gendocfile();
+	}
     }
 
     backend_term();
diff -uNr dmd-0.131/dmd/src/dmd/mars.h dmd-0.132/dmd/src/dmd/mars.h
--- dmd-0.131/dmd/src/dmd/mars.h	2005-05-25 21:40:40.000000000 +0200
+++ dmd-0.132/dmd/src/dmd/mars.h	2005-09-11 02:11:08.000000000 +0200
@@ -47,6 +47,10 @@
     char *objdir;	// .obj file output directory
     char *objname;	// .obj file output name
 
+    char doDocComments;	// process embedded documentation comments
+    char *docdir;	// write documentation file to docdir directory
+    char *docname;	// write documentation file to docname
+
     unsigned debuglevel;	// debug level
     Array *debugids;		// debug identifiers
 
@@ -77,6 +81,7 @@
     char *mars_ext;
     char *sym_ext;
     char *obj_ext;
+    char *doc_ext;
     char *copyright;
     char *written;
     Array *path;	// Array of char*'s which form the import lookup path
diff -uNr dmd-0.131/dmd/src/dmd/module.c dmd-0.132/dmd/src/dmd/module.c
--- dmd-0.131/dmd/src/dmd/module.c	2005-06-16 12:50:46.000000000 +0200
+++ dmd-0.132/dmd/src/dmd/module.c	2005-09-14 19:40:42.000000000 +0200
@@ -34,7 +34,7 @@
     modules = new DsymbolTable();
 }
 
-Module::Module(char *filename, Identifier *ident)
+Module::Module(char *filename, Identifier *ident, int doDocComment)
 	: Package(ident)
 {
     FileName *srcfilename;
@@ -42,6 +42,7 @@
     FileName *hfilename;
     FileName *objfilename;
     FileName *symfilename;
+    FileName *docfilename;
 
 //    printf("Module::Module(filename = '%s', ident = '%s')\n", filename, ident->toChars());
     this->arg = filename;
@@ -65,6 +66,7 @@
     sfilename = NULL;
     importedFrom = this;
     srcfile = NULL;
+    docfile = NULL;
 
     debuglevel = 0;
     debugids = NULL;
@@ -73,6 +75,8 @@
     versionids = NULL;
     versionidsNot = NULL;
 
+    macrotable = NULL;
+
     srcfilename = FileName::defaultExt(filename, global.mars_ext);
     if (!srcfilename->equalsExt(global.mars_ext))
     {
@@ -98,6 +102,30 @@
     else
 	objfilename = FileName::forceExt(argobj, global.obj_ext);
 
+    if (doDocComment)
+    {
+	char *argdoc;
+	if (global.params.docname)
+	    argdoc = global.params.docname;
+	else if (global.params.preservePaths)
+	    argdoc = filename;
+	else
+	    argdoc = FileName::name(filename);
+	if (!FileName::absolute(argdoc))
+	    argdoc = FileName::combine(global.params.docdir, argdoc);
+	if (global.params.docname)
+	    docfilename = new FileName(argdoc, 0);
+	else
+	    docfilename = FileName::forceExt(argdoc, global.doc_ext);
+
+	if (docfilename->equals(srcfilename))
+	{   error("Source file and documentation file have same name '%s'", srcfilename->toChars());
+	    fatal();
+	}
+
+	docfile = new File(docfilename);
+    }
+
     symfilename = FileName::forceExt(filename, global.sym_ext);
 
     srcfile = new File(srcfilename);
@@ -108,6 +136,8 @@
 void Module::deleteObjFile()
 {
     objfile->remove();
+    if (docfile)
+	docfile->remove();
 }
 
 Module::~Module()
@@ -150,7 +180,7 @@
 	filename = (char *)buf.extractData();
     }
 
-    m = new Module(filename, ident);
+    m = new Module(filename, ident, 0);
     m->loc = loc;
 
     // Find the sym file
@@ -390,7 +420,7 @@
 	buf = dbuf->data;
 	buflen = dbuf->offset;
     }
-    Parser p(this, buf, buflen);
+    Parser p(this, buf, buflen, docfile != NULL);
     members = p.parseModule();
     md = p.md;
 
@@ -559,6 +589,9 @@
     }
 }
 
+/****************************************************
+ */
+
 void Module::gensymfile()
 {
     OutBuffer buf;
diff -uNr dmd-0.131/dmd/src/dmd/module.h dmd-0.132/dmd/src/dmd/module.h
--- dmd-0.131/dmd/src/dmd/module.h	2005-06-16 12:50:46.000000000 +0200
+++ dmd-0.132/dmd/src/dmd/module.h	2005-09-14 19:35:16.000000000 +0200
@@ -20,6 +20,7 @@
 struct ModuleInfoDeclaration;
 struct ClassDeclaration;
 struct ModuleDeclaration;
+struct Macro;
 
 // Back end
 struct elem;
@@ -50,6 +51,7 @@
     File *srcfile;	// input source file
     File *objfile;	// output .obj file
     File *symfile;	// output symbol file
+    File *docfile;	// output documentation file
     unsigned errors;	// if any errors in file
     int isHtml;		// if it is an HTML file
     int needmoduleinfo;
@@ -78,8 +80,9 @@
     Array *versionids;		// version identifiers
     Array *versionidsNot;	// forward referenced version identifiers
 
+    Macro *macrotable;		// document comment macros
 
-    Module(char *arg, Identifier *ident);
+    Module(char *arg, Identifier *ident, int doDocComment);
     ~Module();
 
     static Module *load(Loc loc, Array *packages, Identifier *ident);
@@ -93,6 +96,7 @@
     void inlineScan();	// scan for functions to inline
     void genobjfile();
     void gensymfile();
+    void gendocfile();
     int needModuleInfo();
     Dsymbol *search(Identifier *ident, int flags);
     void deleteObjFile();
diff -uNr dmd-0.131/dmd/src/dmd/mtype.c dmd-0.132/dmd/src/dmd/mtype.c
--- dmd-0.131/dmd/src/dmd/mtype.c	2005-07-19 10:44:06.000000000 +0200
+++ dmd-0.132/dmd/src/dmd/mtype.c	2005-09-13 16:03:12.000000000 +0200
@@ -315,7 +315,6 @@
 
 void Type::toCBuffer2(OutBuffer *buf, Identifier *ident)
 {
-//    buf->prependbyte(' ');
     buf->prependstring(toChars());
     if (ident)
     {	buf->writeByte(' ');
diff -uNr dmd-0.131/dmd/src/dmd/parse.c dmd-0.132/dmd/src/dmd/parse.c
--- dmd-0.131/dmd/src/dmd/parse.c	2005-07-18 10:32:46.000000000 +0200
+++ dmd-0.132/dmd/src/dmd/parse.c	2005-09-18 01:21:42.000000000 +0200
@@ -70,8 +70,8 @@
 };
 
 
-Parser::Parser(Module *module, unsigned char *base, unsigned length)
-    : Lexer(module, base, length)
+Parser::Parser(Module *module, unsigned char *base, unsigned length, int doDocComment)
+    : Lexer(module, base, length, doDocComment)
 {
     //printf("Parser::Parser()\n");
     md = NULL;
@@ -88,6 +88,8 @@
     // ModuleDeclation leads off
     if (token.value == TOKmodule)
     {
+	unsigned char *comment = token.blockComment;
+
 	nextToken();
 	if (token.value != TOKidentifier)
 	{   error("Identifier expected following module");
@@ -117,6 +119,7 @@
 	    if (token.value != TOKsemicolon)
 		error("';' expected following module declaration instead of %s", token.toChars());
 	    nextToken();
+	    addComment(mod, comment);
 	}
     }
 
@@ -142,11 +145,13 @@
     enum PROT prot;
     unsigned stc;
     Condition *condition;
+    unsigned char *comment;
 
     //printf("Parser::parseDeclDefs()\n");
     decldefs = new Array();
     do
     {
+	comment = token.blockComment;
 	switch (token.value)
 	{
 	    case TOKenum:
@@ -470,7 +475,9 @@
 		continue;
 	}
 	if (s)
-	    decldefs->push(s);
+	{   decldefs->push(s);
+	    addComment(s, comment);
+	}
     } while (!once);
     return decldefs;
 }
@@ -961,6 +968,7 @@
 	//printf("enum definition\n");
 	e->members = new Array();
 	nextToken();
+	unsigned char *comment = token.blockComment;
 	while (token.value != TOKrcurly)
 	{
 	    if (token.value == TOKidentifier)
@@ -982,6 +990,7 @@
 		    ;
 		else
 		    check(TOKcomma);
+		addComment(em, comment);
 	    }
 	    else
 	    {	error("enum member expected");
@@ -1933,6 +1942,7 @@
     Identifier *ident;
     Array *a;
     enum TOK tok;
+    unsigned char *comment = token.blockComment;
 
     //printf("parseDeclaration()\n");
     switch (token.value)
@@ -1979,6 +1989,7 @@
 	s = (AggregateDeclaration *)parseAggregate();
 	s->storage_class |= storage_class;
 	a->push(s);
+	addComment(s, comment);
 	return a;
     }
 
@@ -2023,10 +2034,12 @@
 	    switch (token.value)
 	    {   case TOKsemicolon:
 		    nextToken();
+		    addComment(v, comment);
 		    break;
 
 		case TOKcomma:
 		    nextToken();
+		    addComment(v, comment);
 		    continue;
 
 		default:
@@ -2039,7 +2052,9 @@
 
 	    f = new FuncDeclaration(loc, 0, ident, storage_class, t);
 	    a->push(f);
+	    addComment(f, comment);
 	    parseContracts(f);
+	    addComment(f, NULL);
 	}
 	else
 	{   VarDeclaration *v;
@@ -2057,10 +2072,12 @@
 	    switch (token.value)
 	    {   case TOKsemicolon:
 		    nextToken();
+		    addComment(v, comment);
 		    break;
 
 		case TOKcomma:
 		    nextToken();
+		    addComment(v, comment);
 		    continue;
 
 		default:
@@ -4588,5 +4605,14 @@
     return e;
 }
 
+/**********************************************
+ */
+
+void Parser::addComment(Dsymbol *s, unsigned char *blockComment)
+{
+    s->addComment(combineComments(blockComment, token.lineComment));
+}
+
+
 /********************************* ***************************/
 
diff -uNr dmd-0.131/dmd/src/dmd/parse.h dmd-0.132/dmd/src/dmd/parse.h
--- dmd-0.131/dmd/src/dmd/parse.h	2005-06-06 12:14:52.000000000 +0200
+++ dmd-0.132/dmd/src/dmd/parse.h	2005-09-12 21:42:32.000000000 +0200
@@ -47,7 +47,7 @@
     Loc endloc;			// set to location of last right curly
     int inBrackets;		// inside [] of array index or slice
 
-    Parser(Module *module, unsigned char *base, unsigned length);
+    Parser(Module *module, unsigned char *base, unsigned length, int doDocComment);
 
     Array *parseModule();
     Array *parseDeclDefs(int once);
@@ -112,6 +112,8 @@
     Array *parseArguments();
 
     Expression *parseNewExp();
+
+    void addComment(Dsymbol *s, unsigned char *blockComment);
 };
 
 #endif /* DMD_PARSE_H */
diff -uNr dmd-0.131/dmd/src/dmd/root.c dmd-0.132/dmd/src/dmd/root.c
--- dmd-0.131/dmd/src/dmd/root.c	2004-10-28 20:08:14.000000000 +0200
+++ dmd-0.132/dmd/src/dmd/root.c	2005-09-13 19:44:52.000000000 +0200
@@ -1646,6 +1646,18 @@
     this->offset += nbytes;
 }
 
+void OutBuffer::insert(unsigned offset, const void *p, unsigned nbytes)
+{
+    spread(offset, nbytes);
+    memmove(data + offset, p, nbytes);
+}
+
+void OutBuffer::remove(unsigned offset, unsigned nbytes)
+{
+    memmove(data + offset, data + offset + nbytes, this->offset - (offset + nbytes));
+    this->offset -= nbytes;
+}
+
 char *OutBuffer::toChars()
 {
     writeByte(0);
diff -uNr dmd-0.131/dmd/src/dmd/root.h dmd-0.132/dmd/src/dmd/root.h
--- dmd-0.131/dmd/src/dmd/root.h	2004-03-27 00:11:52.000000000 +0100
+++ dmd-0.132/dmd/src/dmd/root.h	2005-09-13 19:28:14.000000000 +0200
@@ -285,6 +285,8 @@
 #endif
     void bracket(char left, char right);
     void spread(unsigned offset, unsigned nbytes);
+    void insert(unsigned offset, const void *data, unsigned nbytes);
+    void remove(unsigned offset, unsigned nbytes);
     char *toChars();
     char *extractString();
 };
diff -uNr dmd-0.131/dmd/src/dmd/scope.c dmd-0.132/dmd/src/dmd/scope.c
--- dmd-0.131/dmd/src/dmd/scope.c	2005-05-26 17:18:50.000000000 +0200
+++ dmd-0.132/dmd/src/dmd/scope.c	2005-09-13 15:14:00.000000000 +0200
@@ -65,6 +65,9 @@
     this->callSuper = 0;
     this->flags = 0;
     this->anonAgg = NULL;
+    this->lastdc = NULL;
+    this->lastoffset = 0;
+    this->docbuf = NULL;
 }
 
 Scope::Scope(Scope *enclosing)
@@ -93,6 +96,9 @@
     this->callSuper = enclosing->callSuper;
     this->flags = 0;
     this->anonAgg = NULL;
+    this->lastdc = NULL;
+    this->lastoffset = 0;
+    this->docbuf = enclosing->docbuf;
     assert(this != enclosing);
 }
 
diff -uNr dmd-0.131/dmd/src/dmd/scope.h dmd-0.132/dmd/src/dmd/scope.h
--- dmd-0.131/dmd/src/dmd/scope.h	2005-07-19 15:21:02.000000000 +0200
+++ dmd-0.132/dmd/src/dmd/scope.h	2005-09-13 15:13:42.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
@@ -28,6 +28,7 @@
 struct AggregateDeclaration;
 struct AnonymousAggregateDeclaration;
 struct FuncDeclaration;
+struct DocComment;
 enum LINK;
 enum PROT;
 
@@ -73,6 +74,10 @@
 
     AnonymousAggregateDeclaration *anonAgg;	// for temporary analysis
 
+    DocComment *lastdc;		// documentation comment for last symbol at this scope
+    unsigned lastoffset;	// offset in docbuf of where to insert next dec
+    OutBuffer *docbuf;		// buffer for documentation output
+
     static Scope *freelist;
     static void *operator new(size_t sz);
     static Scope *createGlobal(Module *module);
diff -uNr dmd-0.131/dmd/src/dmd/template.c dmd-0.132/dmd/src/dmd/template.c
--- dmd-0.131/dmd/src/dmd/template.c	2005-07-08 11:49:00.000000000 +0200
+++ dmd-0.132/dmd/src/dmd/template.c	2005-09-19 13:44:44.000000000 +0200
@@ -85,6 +85,7 @@
     this->members = decldefs;
     this->overnext = NULL;
     this->scope = NULL;
+    this->onemember = NULL;
 }
 
 Dsymbol *TemplateDeclaration::syntaxCopy(Dsymbol *)
@@ -155,6 +156,17 @@
 
     paramscope->pop();
 
+    if (members && members->dim)
+    {
+	Dsymbol *s = (Dsymbol *)members->data[0];
+	s = s->oneMember();
+	if (s && s->ident && s->ident->equals(ident))
+	{
+	    onemember = s;
+	    s->parent = this;
+	}
+    }
+
     /* BUG: should check:
      *	o no virtual functions or non-static data members of classes
      */
@@ -162,7 +174,9 @@
 
 char *TemplateDeclaration::kind()
 {
-    return "template";
+    return (onemember && onemember->isAggregateDeclaration())
+		? onemember->kind()
+		: (char *)"template";
 }
 
 /**********************************
@@ -402,7 +416,8 @@
 {
     int i;
 
-    buf->writestring("template ");
+    buf->writestring(kind());
+    buf->writeByte(' ');
     buf->writestring(ident->toChars());
     buf->writeByte('(');
     for (i = 0; i < parameters->dim; i++)
@@ -424,7 +439,7 @@
     toCBuffer(&buf);
     s = buf.toChars();
     buf.data = NULL;
-    return s + 9;	// kludge to skip over 'template '
+    return s + strlen(kind()) + 1;	// kludge to skip over 'template '
 }
 
 /* ======================== Type ============================================ */
diff -uNr dmd-0.131/dmd/src/dmd/template.h dmd-0.132/dmd/src/dmd/template.h
--- dmd-0.131/dmd/src/dmd/template.h	2005-04-04 17:00:58.000000000 +0200
+++ dmd-0.132/dmd/src/dmd/template.h	2005-09-19 11:29:18.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
@@ -37,6 +37,7 @@
 
     TemplateDeclaration *overnext;	// next overloaded TemplateDeclaration
     Scope *scope;
+    Dsymbol *onemember;		// if !=NULL then one member of this template
 
     TemplateDeclaration(Loc loc, Identifier *id, Array *parameters, Array *decldefs);
     Dsymbol *syntaxCopy(Dsymbol *);
@@ -46,6 +47,9 @@
     char *kind();
     char *toChars();
 
+    void emitComment(Scope *sc);
+//    void toDocBuffer(OutBuffer *buf);
+
     MATCH matchWithInstance(TemplateInstance *ti, Array *atypes, int flag);
     int leastAsSpecialized(TemplateDeclaration *td2);
 
diff -uNr dmd-0.131/dmd/src/phobos/std/math.d dmd-0.132/dmd/src/phobos/std/math.d
--- dmd-0.131/dmd/src/phobos/std/math.d	2005-09-09 01:57:32.000000000 +0200
+++ dmd-0.132/dmd/src/phobos/std/math.d	2005-09-19 17:54:38.000000000 +0200
@@ -1,8 +1,20 @@
 // math.d
+
+/**
+ * Boilerplate:
+ *	$(std_boilerplate.html)
+ * Macros:
+ *	WIKI = StdMath
+ */
+
 /*
- *  Copyright (C) 2001-2005 by Digital Mars, www.digitalmars.com
- *  Written by Walter Bright
- *
+ * Author:
+ *	Walter Bright
+ * Copyright:
+ *	Copyright (c) 2001-2005 by Digital Mars,
+ *	All Rights Reserved,
+ *	www.digitalmars.com
+ * License:
  *  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.
@@ -11,16 +23,22 @@
  *  including commercial applications, and to alter it and redistribute it
  *  freely, subject to the following restrictions:
  *
- *  o  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.
- *  o  Altered source versions must be plainly marked as such, and must not
- *     be misrepresented as being the original software.
- *  o  This notice may not be removed or altered from any source
- *     distribution.
+ *  
    + *
  • 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. + *
  • + *
*/ + module std.math; //debug=math; // uncomment to turn on debugging printf's @@ -28,21 +46,169 @@ private import std.c.stdio; private import std.c.math; -/* Intrinsics */ +const real E = 2.7182818284590452354L; /** e */ +const real LOG2T = 0x1.a934f0979a3715fcp+1; /** log210 */ // 3.32193 fldl2t +const real LOG2E = 0x1.71547652b82fe178p+0; /** log2e */ // 1.4427 fldl2e +const real LOG2 = 0x1.34413509f79fef32p-2; /** log102 */ // 0.30103 fldlg2 +const real LOG10E = 0.43429448190325182765; /** log10e */ +const real LN2 = 0x1.62e42fefa39ef358p-1; /** ln 2 */ // 0.693147 fldln2 +const real LN10 = 2.30258509299404568402; /** ln 10 */ +const real PI = 0x1.921fb54442d1846ap+1; /** π */ // 3.14159 fldpi +const real PI_2 = 1.57079632679489661923; /** π / 2 */ +const real PI_4 = 0.78539816339744830962; /** π / 4 */ +const real M_1_PI = 0.31830988618379067154; /** 1 / π */ +const real M_2_PI = 0.63661977236758134308; /** 2 / π */ +const real M_2_SQRTPI = 1.12837916709551257390; /** 2 / √π */ +const real SQRT2 = 1.41421356237309504880; /** √2 */ +const real SQRT1_2 = 0.70710678118654752440; /** √½ */ + +/* + Octal versions: + PI/64800 0.00001 45530 36176 77347 02143 15351 61441 26767 + PI/180 0.01073 72152 11224 72344 25603 54276 63351 22056 + PI/8 0.31103 75524 21026 43021 51423 06305 05600 67016 + SQRT(1/PI) 0.44067 27240 41233 33210 65616 51051 77327 77303 + 2/PI 0.50574 60333 44710 40522 47741 16537 21752 32335 + PI/4 0.62207 73250 42055 06043 23046 14612 13401 56034 + SQRT(2/PI) 0.63041 05147 52066 24106 41762 63612 00272 56161 + + PI 3.11037 55242 10264 30215 14230 63050 56006 70163 + LOG2 0.23210 11520 47674 77674 61076 11263 26013 37111 + */ + + +/*********************************** + * Returns cosine of x. x is in radians. + * + * + * + *
Special Values
x cos(x) invalid? + *
NAN NAN yes + *
±∞ NAN yes + *
+ */ + +real cos(real x); /* intrinsic */ + +/*********************************** + * Returns sine of x. x is in radians. + * + * + * + *
Special Values
x sin(x) invalid? + *
NAN NAN yes + *
±0.0 ±0.0 no + *
±∞ NAN yes + *
+ */ + +real sin(real x); /* intrinsic */ + + +/**************************************************************************** + * Returns tangent of x. x is in radians. + * + * + * + *
Special Values
x tan(x) invalid? + *
NAN NAN yes + *
±0.0 ±0.0 no + *
±∞ NAN yes + *
+ */ + +real tan(real x) +{ + asm + { + fld x[EBP] ; // load theta + fxam ; // test for oddball values + fstsw AX ; + sahf ; + jc trigerr ; // x is NAN, infinity, or empty + // 387's can handle denormals +SC18: fptan ; + fstp ST(0) ; // dump X, which is always 1 + fstsw AX ; + sahf ; + jnp Lret ; // C2 = 1 (x is out of range) + + // Do argument reduction to bring x into range + fldpi ; + fxch ; +SC17: fprem1 ; + fstsw AX ; + sahf ; + jp SC17 ; + fstp ST(1) ; // remove pi from stack + jmp SC18 ; + +trigerr: + fstp ST(0) ; // dump theta + } + return real.nan; + +Lret: + ; +} + +unittest +{ + static real vals[][2] = // angle,tan + [ + [ 0, 0], + [ .5, .5463024898], + [ 1, 1.557407725], + [ 1.5, 14.10141995], + [ 2, -2.185039863], + [ 2.5,-.7470222972], + [ 3, -.1425465431], + [ 3.5, .3745856402], + [ 4, 1.157821282], + [ 4.5, 4.637332055], + [ 5, -3.380515006], + [ 5.5,-.9955840522], + [ 6, -.2910061914], + [ 6.5, .2202772003], + [ 10, .6483608275], + + // special angles + [ PI_4, 1], + //[ PI_2, real.infinity], + [ 3*PI_4, -1], + [ PI, 0], + [ 5*PI_4, 1], + //[ 3*PI_2, -real.infinity], + [ 7*PI_4, -1], + [ 2*PI, 0], + + // overflow + [ real.infinity, real.nan], + [ real.nan, real.nan], + [ 1e+100, real.nan], + ]; + int i; + + for (i = 0; i < vals.length; i++) + { + real x = vals[i][0]; + real r = vals[i][1]; + real t = tan(x); + + //printf("tan(%Lg) = %Lg, should be %Lg\n", x, t, r); + assert(mfeq(r, t, .0000001)); + + x = -x; + r = -r; + t = tan(x); + //printf("tan(%Lg) = %Lg, should be %Lg\n", x, t, r); + assert(mfeq(r, t, .0000001)); + } +} -real cos(real); -real sin(real); -real fabs(real); -real rint(real); -long rndtol(real); -real ldexp(real, int); - -float sqrt(float); -double sqrt(double); -real sqrt(real); -//creal sqrt(creal); real acos(real x) { return std.c.math.acosl(x); } + real asin(real x) { return std.c.math.asinl(x); } real atan(real x) { return std.c.math.atanl(x); } real atan2(real x, real y) { return std.c.math.atan2l(x,y); } @@ -54,53 +220,173 @@ //real asinh(real x) { return std.c.math.asinhl(x); } //real atanh(real x) { return std.c.math.atanhl(x); } +real fabs(real x); /* intrinsic */ +real rint(real x); /* intrinsic */ +long rndtol(real x); /* intrinsic */ + +/******************************************* + * Compute n * 2exp + * References: frexp + */ + +real ldexp(real n, int exp); /* intrinsic */ + +/*************************************** + * Compute square root of x. + * + * + * + * + * + * + * + *
Special Values
x sqrt(x) invalid? + *
-0.0 -0.0 no + *
<0.0 NAN yes + *
+∞ +∞ no + *
+ */ + +float sqrt(float x); /* intrinsic */ +double sqrt(double x); /* intrinsic */ /// ditto +real sqrt(real x); /* intrinsic */ /// ditto + +creal sqrt(creal z) +{ + creal c; + real x,y,w,r; + + if (z == 0) + { + c = 0; + } + else + { real z_re = z.re; + real z_im = z.im; + + x = fabs(z_re); + y = fabs(z_im); + if (x >= y) + { + r = y / x; + w = sqrt(x) * sqrt(0.5 * (1 + sqrt(1 + r * r))); + } + else + { + r = x / y; + w = sqrt(y) * sqrt(0.5 * (r + sqrt(1 + r * r))); + } + + if (z_re >= 0) + { + c = w + (z_im / (w + w)) * 1.0i; + } + else + { + if (z_im < 0) + w = -w; + c = z_im / (w + w) + w * 1.0i; + } + } + return c; +} + +/*************************** + * Cube root. + */ + +real cbrt(real x) { return std.c.math.cbrtl(x); } + real exp(real x) { return std.c.math.expl(x); } real exp2(real x) { return std.c.math.exp2l(x); } + +/****************************************** + * Calculates the value of the natural logarithm base (e) + * raised to the power of x, minus 1. + * + * For very small x, expm1(x) is more accurate + * than exp(x)-1. + * + * + * + *
Special Values
x ex-1 + *
±0.0 ±0.0 + *
+∞ +∞ + *
-∞ -1.0 + *
+ */ + real expm1(real x) { return std.c.math.expm1l(x); } + int ilogb(real x) { return std.c.math.ilogbl(x); } + +/************************************** + * Calculate the natural logarithm of x. + * + * + * + * + * + * + * + *
Special Values
x log(x) divide by 0? invalid? + *
±0.0 -∞ yes no + *
< 0.0 NAN no yes + *
+∞ +∞ no no + *
+ */ + real log(real x) { return std.c.math.logl(x); } + +/************************************** + * Calculate the base-10 logarithm of x. + * + * + * + * + * + * + * + *
Special Values
x log10(x) divide by 0? invalid? + *
±0.0 -∞ yes no + *
< 0.0 NAN no yes + *
+∞ +∞ no no + *
+ */ + real log10(real x) { return std.c.math.log10l(x); } + +/****************************************** + * Calculates the natural logarithm of 1 + x. + * + * For very small x, log1p(x) will be more accurate than + * log(1 + x). + * + * + * + * + * + * + * + * + *
Special Values
x log1p(x) divide by 0? invalid? + *
±0.0 ±0.0 no no + *
-1.0 -∞ yes no + *
<-1.0 NAN no yes + *
+∞ -∞ no no + *
+ */ + real log1p(real x) { return std.c.math.log1pl(x); } + real log2(real x) { return std.c.math.log2l(x); } real logb(real x) { return std.c.math.logbl(x); } real modf(real x, inout real y) { return std.c.math.modfl(x,&y); } -real cbrt(real x) { return std.c.math.cbrtl(x); } real erf(real x) { return std.c.math.erfl(x); } real erfc(real x) { return std.c.math.erfcl(x); } real ceil(real x) { return std.c.math.ceill(x); } real floor(real x) { return std.c.math.floorl(x); } -const real PI = 0x1.921fb54442d1846ap+1; // 3.14159 fldpi -const real LOG2T = 0x1.a934f0979a3715fcp+1; // 3.32193 fldl2t -const real LOG2E = 0x1.71547652b82fe178p+0; // 1.4427 fldl2e -const real LOG2 = 0x1.34413509f79fef32p-2; // 0.30103 fldlg2 -const real LN2 = 0x1.62e42fefa39ef358p-1; // 0.693147 fldln2 -const real E = 2.7182818284590452354L; -const real LOG10E = 0.43429448190325182765; -const real LN10 = 2.30258509299404568402; -const real PI_2 = 1.57079632679489661923; -const real PI_4 = 0.78539816339744830962; -const real M_1_PI = 0.31830988618379067154; -const real M_2_PI = 0.63661977236758134308; -const real M_2_SQRTPI = 1.12837916709551257390; -const real SQRT2 = 1.41421356237309504880; -const real SQRT1_2 = 0.70710678118654752440; - -/* - Octal versions: - PI/64800 0.00001 45530 36176 77347 02143 15351 61441 26767 - PI/180 0.01073 72152 11224 72344 25603 54276 63351 22056 - PI/8 0.31103 75524 21026 43021 51423 06305 05600 67016 - SQRT(1/PI) 0.44067 27240 41233 33210 65616 51051 77327 77303 - 2/PI 0.50574 60333 44710 40522 47741 16537 21752 32335 - PI/4 0.62207 73250 42055 06043 23046 14612 13401 56034 - SQRT(2/PI) 0.63041 05147 52066 24106 41762 63612 00272 56161 - - PI 3.11037 55242 10264 30215 14230 63050 56006 70163 - LOG2 0.23210 11520 47674 77674 61076 11263 26013 37111 - */ - - /********************************* * Is number a nan? */ @@ -145,7 +431,9 @@ /********************************* * Is number normalized? - * Need one for each format because subnormal floats might + */ + +/* Need one for each format because subnormal floats might * be converted to normal reals. */ @@ -159,6 +447,8 @@ return e && e != 0x7F800000; } +/// ditto + int isnormal(double d) { uint *p = cast(uint *)&d; @@ -168,6 +458,8 @@ return e && e != 0x7FF00000; } +/// ditto + int isnormal(real e) { ushort* pe = cast(ushort *)&e; @@ -190,7 +482,9 @@ /********************************* * Is number subnormal? (Also called "denormal".) * Subnormals have a 0 exponent and a 0 most significant mantissa bit. - * Need one for each format because subnormal floats might + */ + +/* Need one for each format because subnormal floats might * be converted to normal reals. */ @@ -210,6 +504,8 @@ assert(f != 0); } +/// ditto + int issubnormal(double d) { uint *p = cast(uint *)&d; @@ -225,6 +521,8 @@ assert(f != 0); } +/// ditto + int issubnormal(real e) { ushort* pe = cast(ushort *)&e; @@ -322,129 +620,57 @@ assert(isnan(e) && signbit(e)); } -/**************************************************************************** - * Tangent. - */ - -real tan(real x) -{ - asm - { - fld x[EBP] ; // load theta - fxam ; // test for oddball values - fstsw AX ; - sahf ; - jc trigerr ; // x is NAN, infinity, or empty - // 387's can handle denormals -SC18: fptan ; - fstp ST(0) ; // dump X, which is always 1 - fstsw AX ; - sahf ; - jnp Lret ; // C2 = 1 (x is out of range) - - // Do argument reduction to bring x into range - fldpi ; - fxch ; -SC17: fprem1 ; - fstsw AX ; - sahf ; - jp SC17 ; - fstp ST(1) ; // remove pi from stack - jmp SC18 ; - -trigerr: - fstp ST(0) ; // dump theta - } - return real.nan; - -Lret: - ; -} - -unittest -{ - static real vals[][2] = // angle,tan - [ - [ 0, 0], - [ .5, .5463024898], - [ 1, 1.557407725], - [ 1.5, 14.10141995], - [ 2, -2.185039863], - [ 2.5,-.7470222972], - [ 3, -.1425465431], - [ 3.5, .3745856402], - [ 4, 1.157821282], - [ 4.5, 4.637332055], - [ 5, -3.380515006], - [ 5.5,-.9955840522], - [ 6, -.2910061914], - [ 6.5, .2202772003], - [ 10, .6483608275], - - // special angles - [ PI_4, 1], - //[ PI_2, real.infinity], - [ 3*PI_4, -1], - [ PI, 0], - [ 5*PI_4, 1], - //[ 3*PI_2, -real.infinity], - [ 7*PI_4, -1], - [ 2*PI, 0], - - // overflow - [ real.infinity, real.nan], - [ real.nan, real.nan], - [ 1e+100, real.nan], - ]; - int i; - - for (i = 0; i < vals.length; i++) - { - real x = vals[i][0]; - real r = vals[i][1]; - real t = tan(x); - - //printf("tan(%Lg) = %Lg, should be %Lg\n", x, t, r); - assert(mfeq(r, t, .0000001)); - - x = -x; - r = -r; - t = tan(x); - //printf("tan(%Lg) = %Lg, should be %Lg\n", x, t, r); - assert(mfeq(r, t, .0000001)); - } -} - - -/**************************************************************************** - * hypotenuese. - * This is based on code from: - * Cephes Math Library Release 2.1: January, 1989 - * Copyright 1984, 1987, 1989 by Stephen L. Moshier - * Direct inquiries to 30 Frost Street, Cambridge, MA 02140 +/*********************************************************************** + * Calculates the length of the + * hypotenuse of a right-angled triangle with sides of length x and y. + * The hypotenuse is the value of the square root of + * the sums of the squares of x and y: + * + * sqrt(x² + y²) + * + * Note that hypot(x, y), hypot(y, x) and + * hypot(x, -y) are equivalent. + * + * + * + * + * + * + * + *
Special Values
x y hypot(x, y) invalid? + *
x ±0.0 |x| no + *
±∞ y +∞ no + *
±∞ NAN +∞ no + *
*/ -real hypot(real zre, real zim) +real hypot(real x, real y) { + /* + * This is based on code from: + * Cephes Math Library Release 2.1: January, 1989 + * Copyright 1984, 1987, 1989 by Stephen L. Moshier + * Direct inquiries to 30 Frost Street, Cambridge, MA 02140 + */ const int PRECL = 32; const int MAXEXPL = real.max_exp; //16384; const int MINEXPL = real.min_exp; //-16384; - real x, y, b, re, im; + real xx, yy, b, re, im; int ex, ey, e; // Note, hypot(INFINITY,NAN) = INFINITY. - if (isinf(zre) || isinf(zim)) + if (isinf(x) || isinf(y)) return real.infinity; - if (isnan(zre)) - return zre; - if (isnan(zim)) - return zim; + if (isnan(x)) + return x; + if (isnan(y)) + return y; - re = fabs(zre); - im = fabs(zim); + re = fabs(x); + im = fabs(y); if (re == 0.0) return im; @@ -452,8 +678,8 @@ return re; // Get the exponents of the numbers - x = frexp(re, ex); - y = frexp(im, ey); + xx = frexp(re, ex); + yy = frexp(im, ey); // Check if one number is tiny compared to the other e = ex - ey; @@ -466,14 +692,14 @@ e = (ex + ey) >> 1; // Rescale so mean is about 1 - x = ldexp(re, -e); - y = ldexp(im, -e); + xx = ldexp(re, -e); + yy = ldexp(im, -e); // Hypotenuse of the right triangle - b = sqrt(x * x + y * y); + b = sqrt(xx * xx + yy * yy); // Compute the exponent of the answer. - y = frexp(b, ey); + yy = frexp(b, ey); ey = e + ey; // Check it for overflow and underflow. @@ -520,55 +746,65 @@ } /********************************************************************* + * Separate floating point value into significand and exponent. + * * Returns: - * x such that value=x*2**n, .5 <= |x| < 1.0 - * x has same sign as value. - * *eptr = n + *
Calculate and return x and exp such that + * value =x*2exp and + * .5 <= |x| < 1.0
+ * x has same sign as value. * - * Special cases: - * value x *eptr - * +-0.0 +-0.0 0 - * +-inf +-inf int.max/int.min - * +-NaN +-NaN int.min - * +-NaNs +-NaN int.min + * + * + * + * + * + * + * + *
Special values
value returns exp + *
±0.0 ±0.0 0 + *
+∞ +∞ int.max + *
-∞ -∞ int.min + *
±NAN ±NAN int.min + *
*/ -real frexp(real value, out int eptr) +real frexp(real value, out int exp) { ushort* vu = cast(ushort*)&value; long* vl = cast(long*)&value; - uint exp; + uint ex; // If exponent is non-zero - exp = vu[4] & 0x7FFF; - if (exp) + ex = vu[4] & 0x7FFF; + if (ex) { - if (exp == 0x7FFF) + if (ex == 0x7FFF) { // infinity or NaN if (*vl & 0x7FFFFFFFFFFFFFFF) // if NaN { *vl |= 0xC000000000000000; // convert NANS to NANQ - eptr = int.min; + exp = int.min; } else if (vu[4] & 0x8000) { // negative infinity - eptr = int.min; + exp = int.min; } else { // positive infinity - eptr = int.max; + exp = int.max; } } else { - eptr = exp - 0x3FFE; + exp = ex - 0x3FFE; vu[4] = (0x8000 & vu[4]) | 0x3FFE; } } else if (!*vl) { // value is +-0.0 - eptr = 0; + exp = 0; } else { // denormal @@ -579,7 +815,7 @@ i--; *vl <<= 1; } while (*vl > 0); - eptr = i; + exp = i; vu[4] = (0x8000 & vu[4]) | 0x3FFE; } return value; @@ -588,7 +824,7 @@ unittest { - static real vals[][3] = // x,frexp,eptr + static real vals[][3] = // x,frexp,exp [ [0.0, 0.0, 0], [-0.0, -0.0, 0], @@ -663,6 +899,8 @@ return p; } +/// ditto + real pow(real x, int n) { if (n < 0) @@ -777,49 +1015,6 @@ assert(pow(x,8) == (x * x) * (x * x) * (x * x) * (x * x)); } -/***************************************** - */ - -creal sqrt(creal z) -{ - creal c; - real x,y,w,r; - - if (z == 0) - { - c = 0; - } - else - { real z_re = z.re; - real z_im = z.im; - - x = fabs(z_re); - y = fabs(z_im); - if (x >= y) - { - r = y / x; - w = sqrt(x) * sqrt(0.5 * (1 + sqrt(1 + r * r))); - } - else - { - r = x / y; - w = sqrt(y) * sqrt(0.5 * (r + sqrt(1 + r * r))); - } - - if (z_re >= 0) - { - c = w + (z_im / (w + w)) * 1.0i; - } - else - { - if (z_im < 0) - w = -w; - c = z_im / (w + w) + w * 1.0i; - } - } - return c; -} - /**************************************** * Simple function to compare two floating point values * to a specified precision. @@ -846,33 +1041,46 @@ /************************************** - int feqrel(real x, real y) - To what precision is x equal to y? - Public Domain. Author: Don Clugston, 18 Aug 2005. - - Returns the number of mantissa bits which are equal in x and y. - eg, 0x1.F8p+60 and 0x1.F1p+60 are equal to 5 bits of precision. - If x == y, then feqrel(x, y) == real.mant_dig. - - If x and y differ by a factor of two or more, or if one or both - is a nan, the return value is 0. -*/ + * To what precision is x equal to y? + * + * Returns: the number of mantissa bits which are equal in x and y. + * eg, 0x1.F8p+60 and 0x1.F1p+60 are equal to 5 bits of precision. + * + * + * + * + * + * + * + * + * + *
Special values
x y feqrel(x, y) + *
x x real.mant_dig + *
x >= 2*x 0 + *
x <= x/2 0 + *
NAN any 0 + *
any NAN 0 + *
+ */ -int feqrel(real a, real b) +int feqrel(real x, real y) { - if (a == b) + /* Public Domain. Author: Don Clugston, 18 Aug 2005. + */ + + if (x == y) return real.mant_dig; // ensure diff!=0, cope with INF. - real diff = fabs(a-b); + real diff = fabs(x - y); - ushort *pa = cast(ushort *)(&a); - ushort *pb = cast(ushort *)(&b); + ushort *pa = cast(ushort *)(&x); + ushort *pb = cast(ushort *)(&y); ushort *pd = cast(ushort *)(&diff); - // The difference in abs(exponent) between a or b and abs(a-b) - // is equal to the number of mantissa bits of a which are - // equal to b. If negative, a and b have different exponents. - // If positive, a and b are equal to 'bitsdiff' bits. + // The difference in abs(exponent) between x or y and abs(x-y) + // is equal to the number of mantissa bits of x which are + // equal to y. If negative, x and y have different exponents. + // If positive, x and y are equal to 'bitsdiff' bits. // AND with 0x7FFF to form the absolute value. // To avoid out-by-1 errors, we subtract 1 so it rounds down // if the exponents were different. This means 'bitsdiff' is diff -uNr dmd-0.131/dmd/src/phobos/std/outbuffer.d dmd-0.132/dmd/src/phobos/std/outbuffer.d --- dmd-0.131/dmd/src/phobos/std/outbuffer.d 2005-09-09 01:57:34.000000000 +0200 +++ dmd-0.132/dmd/src/phobos/std/outbuffer.d 2005-09-19 17:54:38.000000000 +0200 @@ -1,16 +1,18 @@ // outbuffer.d + +/** + * Boilerplate: + * $(std_boilerplate.html) + * Macros: + * WIKI = StdOutbuffer + * Copyright: + * Copyright (c) 2001-2005 by Digital Mars + * All Rights Reserved + * www.digitalmars.com + */ + + // Written by Walter Bright -// Copyright (c) 2001 Digital Mars -// All Rights Reserved -// www.digitalmars.com - -// OutBuffer provides a way to build up an array of bytes out -// of raw data. It is useful for things like preparing an -// array of bytes to write out to a file. -// OutBuffer's byte order is the format native to the computer. -// To control the byte order (endianness), use a class derived -// from OutBuffer. -// To convert an array of bytes back into raw data, use InBuffer. module std.outbuffer; @@ -22,6 +24,15 @@ import std.c.stdarg; } +/********************************************* + * OutBuffer provides a way to build up an array of bytes out + * of raw data. It is useful for things like preparing an + * array of bytes to write out to a file. + * OutBuffer's byte order is the format native to the computer. + * To control the byte order (endianness), use a class derived + * from OutBuffer. + */ + class OutBuffer { ubyte data[]; @@ -44,6 +55,15 @@ ubyte[] toBytes() { return data[0 .. offset]; } + /*********************************** + * Preallocate nbytes more to the size of the internal buffer. + * + * This is a + * speed optimization, a good guess at the maximum size of the resulting + * buffer will improve performance by eliminating reallocations and copying. + */ + + void reserve(uint nbytes) in { @@ -62,6 +82,10 @@ } } + /************************************* + * Append data to the internal buffer. + */ + void write(ubyte[] bytes) { reserve(bytes.length); @@ -69,81 +93,85 @@ offset += bytes.length; } - void write(ubyte b) + void write(ubyte b) /// ditto { reserve(ubyte.sizeof); this.data[offset] = b; offset += ubyte.sizeof; } - void write(byte b) { write(cast(ubyte)b); } - void write(char c) { write(cast(ubyte)c); } + void write(byte b) { write(cast(ubyte)b); } /// ditto + void write(char c) { write(cast(ubyte)c); } /// ditto - void write(ushort w) + void write(ushort w) /// ditto { reserve(ushort.sizeof); *cast(ushort *)&data[offset] = w; offset += ushort.sizeof; } - void write(short s) { write(cast(ushort)s); } + void write(short s) { write(cast(ushort)s); } /// ditto - void write(wchar c) + void write(wchar c) /// ditto { reserve(wchar.sizeof); *cast(wchar *)&data[offset] = c; offset += wchar.sizeof; } - void write(uint w) + void write(uint w) /// ditto { reserve(uint.sizeof); *cast(uint *)&data[offset] = w; offset += uint.sizeof; } - void write(int i) { write(cast(uint)i); } + void write(int i) { write(cast(uint)i); } /// ditto - void write(ulong l) + void write(ulong l) /// ditto { reserve(ulong.sizeof); *cast(ulong *)&data[offset] = l; offset += ulong.sizeof; } - void write(long l) { write(cast(ulong)l); } + void write(long l) { write(cast(ulong)l); } /// ditto - void write(float f) + void write(float f) /// ditto { reserve(float.sizeof); *cast(float *)&data[offset] = f; offset += float.sizeof; } - void write(double f) + void write(double f) /// ditto { reserve(double.sizeof); *cast(double *)&data[offset] = f; offset += double.sizeof; } - void write(real f) + void write(real f) /// ditto { reserve(real.sizeof); *cast(real *)&data[offset] = f; offset += real.sizeof; } - void write(char[] s) + void write(char[] s) /// ditto { write(cast(ubyte[])s); } - void write(OutBuffer buf) + void write(OutBuffer buf) /// ditto { write(buf.toBytes()); } + /**************************************** + * Append nbytes of 0 to the internal buffer. + */ + void fill0(uint nbytes) { reserve(nbytes); @@ -194,6 +222,10 @@ } } + /************************************** + * Convert internal buffer to array of chars. + */ + char[] toString() { //printf("OutBuffer.toString()\n"); @@ -201,7 +233,7 @@ } /***************************************** - * vprintf() into buffer. + * Append output of C's vprintf() to internal buffer. */ void vprintf(char[] format, va_list args) @@ -253,7 +285,7 @@ } /***************************************** - * printf() into buffer. + * Append output of C's printf() to internal buffer. */ void printf(char[] format, ...) @@ -265,6 +297,8 @@ } /***************************************** + * At offset index into buffer, create nbytes of space by shifting upwards + * all data past index. */ void spread(uint index, uint nbytes) diff -uNr dmd-0.131/dmd/src/phobos/std/path.d dmd-0.132/dmd/src/phobos/std/path.d --- dmd-0.131/dmd/src/phobos/std/path.d 2005-09-09 01:57:32.000000000 +0200 +++ dmd-0.132/dmd/src/phobos/std/path.d 2005-09-19 17:54:38.000000000 +0200 @@ -1,7 +1,14 @@ -// Copyright (c) 2001-2003 by Digital Mars -// All Rights Reserved -// www.digitalmars.com +/** + * Boilerplate: + * $(std_boilerplate.html) + * Macros: + * WIKI = StdPath + * Copyright: + * Copyright (c) 2001-2005 by Digital Mars + * All Rights Reserved + * www.digitalmars.com + */ // File name parsing @@ -13,21 +20,22 @@ version(Win32) { - const char[1] sep = "\\"; - const char[1] altsep = "/"; - const char[1] pathsep = ";"; - const char[2] linesep = "\r\n"; - const char[1] curdir = "."; - const char[2] pardir = ".."; + + const char[1] sep = "\\"; /// String used to separate directory names in a path. + const char[1] altsep = "/"; /// Alternate version of sep[], used in Windows. + const char[1] pathsep = ";"; /// Path separator string. + const char[2] linesep = "\r\n"; /// String used to separate lines. + const char[1] curdir = "."; /// String representing the current directory. + const char[2] pardir = ".."; /// String representing the parent directory. } version(linux) { - const char[1] sep = "/"; - const char[0] altsep; - const char[1] pathsep = ":"; - const char[1] linesep = "\n"; - const char[1] curdir = "."; - const char[2] pardir = ".."; + const char[1] sep = "/"; /// String used to separate directory names in a path. + const char[0] altsep; /// Alternate version of sep[], used in Windows. + const char[1] pathsep = ":"; /// Path separator string. + const char[1] linesep = "\n"; /// String used to separate lines. + const char[1] curdir = "."; /// String representing the current directory. + const char[2] pardir = ".."; /// String representing the parent directory. } /************************** @@ -219,54 +227,55 @@ } /**************************** - * Put a default extension on fullname if it doesn't already - * have an extension. + * If filename doesn't already have an extension, + * append the extension ext and return the result. */ -char[] defaultExt(char[] fullname, char[] ext) +char[] defaultExt(char[] filename, char[] ext) { char[] existing; - existing = getExt(fullname); + existing = getExt(filename); if (existing.length == 0) { - // Check for fullname ending in '.' - if (fullname.length && fullname[fullname.length - 1] == '.') - fullname ~= ext; + // Check for filename ending in '.' + if (filename.length && filename[filename.length - 1] == '.') + filename ~= ext; else - fullname = fullname ~ "." ~ ext; + filename = filename ~ "." ~ ext; } - return fullname; + return filename; } /**************************** - * Strip the old extension off and add the new one. + * Strip any existing extension off of filename and add the new extension ext. + * Return the result. */ -char[] addExt(char[] fullname, char[] ext) +char[] addExt(char[] filename, char[] ext) { char[] existing; - existing = getExt(fullname); + existing = getExt(filename); if (existing.length == 0) { - // Check for fullname ending in '.' - if (fullname.length && fullname[fullname.length - 1] == '.') - fullname ~= ext; + // Check for filename ending in '.' + if (filename.length && filename[filename.length - 1] == '.') + filename ~= ext; else - fullname = fullname ~ "." ~ ext; + filename = filename ~ "." ~ ext; } else { - fullname = fullname[0 .. fullname.length - existing.length] ~ ext; + filename = filename[0 .. filename.length - existing.length] ~ ext; } - return fullname; + return filename; } /************************************* - * Determine if absolute path name. + * Return !=0 if path is absolute (i.e. it starts from the root directory). */ int isabs(char[] path) @@ -277,7 +286,7 @@ } /************************************* - * Join two path components. + * Join two path components p1 and p2 and return the result. */ char[] join(char[] p1, char[] p2) @@ -422,7 +431,7 @@ /********************************* - * Match file name characters. + * Match file name characters c1 and c2. * Case sensitivity depends on the operating system. */ @@ -447,20 +456,22 @@ } /************************************ - * Match filename strings with pattern[], using the following wildcards: - * * match 0 or more characters - * ? match any character - * [chars] match any character that appears between the [] - * [!chars] match any character that does not appear between the [! ] + * Match filename with pattern, using the following wildcards: + * + * + *
* match 0 or more characters + *
? match any character + *
[chars] match any character that appears between the [] + *
[!chars] match any character that does not appear between the [! ] + *
* * Matching is case sensitive on a file system that is case sensitive. * * Returns: - * true match - * false no match + * !=0 for match */ -int fnmatch(char[] name, char[] pattern) +int fnmatch(char[] filename, char[] pattern) in { // Verify that pattern[] is valid @@ -505,23 +516,23 @@ case '*': if (pi + 1 == pattern.length) goto match; - for (j = ni; j < name.length; j++) + for (j = ni; j < filename.length; j++) { - if (fnmatch(name[j .. name.length], pattern[pi + 1 .. pattern.length])) + if (fnmatch(filename[j .. filename.length], pattern[pi + 1 .. pattern.length])) goto match; } goto nomatch; case '?': - if (ni == name.length) + if (ni == filename.length) goto nomatch; ni++; break; case '[': - if (ni == name.length) + if (ni == filename.length) goto nomatch; - nc = name[ni]; + nc = filename[ni]; ni++; not = 0; pi++; @@ -544,16 +555,16 @@ break; default: - if (ni == name.length) + if (ni == filename.length) goto nomatch; - nc = name[ni]; + nc = filename[ni]; if (!fncharmatch(pc, nc)) goto nomatch; ni++; break; } } - if (ni < name.length) + if (ni < filename.length) goto nomatch; match: diff -uNr dmd-0.131/dmd/src/phobos/std/stream.d dmd-0.132/dmd/src/phobos/std/stream.d --- dmd-0.131/dmd/src/phobos/std/stream.d 2005-09-09 01:57:34.000000000 +0200 +++ dmd-0.132/dmd/src/phobos/std/stream.d 2005-09-19 17:54:38.000000000 +0200 @@ -1,3 +1,10 @@ +/** + * Boilerplate: + * $(std_boilerplate.html) + * Macros: + * WIKI = StdStream + */ + /* * Copyright (c) 2001-2005 * Pavel "EvilOne" Minayev @@ -31,24 +38,27 @@ * TArrayStream a stream wrapping an array-like buffer */ -// generic Stream exception, base class for all -// other Stream exceptions +/// A base class for stream exceptions. class StreamException: Exception { + /// Construct a StreamException with given error message. this(char[] msg) { super(msg); } } -// thrown when unable to read data from Stream +/// Thrown when unable to read data from Stream. class ReadException: StreamException { + /// Construct a ReadException with given error message. this(char[] msg) { super(msg); } } -// thrown when unable to write data to Stream +/// Thrown when unable to write data to Stream. class WriteException: StreamException { + /// Construct a WriteException with given error message. this(char[] msg) { super(msg); } } -// thrown when unable to move Stream pointer +/// Thrown when unable to move Stream pointer. class SeekException: StreamException { + /// Construct a SeekException with given error message. this(char[] msg) { super(msg); } } @@ -70,198 +80,326 @@ private import std.file; } -// Interface for readable streams +/// InputStream is the interface for readable streams. + interface InputStream { - // reads block of data of specified size, - // throws ReadException on error + + /*** + * Read exactly size bytes into the buffer. + * + * Throws a ReadException if it is not correct. + */ void readExact(void* buffer, size_t size); - // reads block of data big enough to fill the given - // array, returns actual number of bytes read + /*** + * Read a block of data big enough to fill the given array buffer. + * + * Returns: the actual number of bytes read. Unfilled bytes are not modified. + */ size_t read(ubyte[] buffer); - // read a single value of desired type, - // throw ReadException on error + /*** + * Read a basic type or counted string. + * + * Throw a ReadException if it could not be read. + * Outside of byte, ubyte, and char, the format is + * implementation-specific and should not be used except as opposite actions + * to write. + */ 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 double 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 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 ubyte x); /// ditto + void read(out short x); /// ditto + void read(out ushort x); /// ditto + void read(out int x); /// ditto + void read(out uint x); /// ditto + void read(out long x); /// ditto + void read(out ulong x); /// ditto + void read(out float x); /// ditto + void read(out double x); /// ditto + void read(out real x); /// ditto + void read(out ifloat x); /// ditto + void read(out idouble x); /// ditto + void read(out ireal x); /// ditto + void read(out cfloat x); /// ditto + void read(out cdouble x); /// ditto + void read(out creal x); /// ditto + void read(out char x); /// ditto + void read(out wchar x); /// ditto + void read(out dchar x); /// ditto // reads a string, written earlier by write() - void read(out char[] s); + void read(out char[] s); /// ditto // reads a Unicode string, written earlier by write() - void read(out wchar[] s); + void read(out wchar[] s); /// ditto - // reads a line, terminated by either CR, LF, CR/LF, or EOF + /*** + * Read a line that is terminated with some combination of carriage return and + * line feed or end-of-file. + * + * The terminators are not included. The wchar version + * is identical. The optional buffer parameter is filled (reallocating + * it if necessary) and a slice of the result is returned. + */ 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 - wchar[] readLineW(); - - // 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[] result); + char[] readLine(char[] result); /// ditto + wchar[] readLineW(); /// ditto + wchar[] readLineW(wchar[] result); /// ditto + + /*** + * Overload foreach statements to read the stream line by line and call the + * supplied delegate with each line or with each line with line number. + * + * The string passed in line may be reused between calls to the delegate. + * Line numbering starts at 1. + * Breaking out of the foreach will leave the stream + * position at the beginning of the next line to be read. + * For example, to echo a file line-by-line with line numbers run: + * ------------------------------------ + * Stream file = new BufferedFile("sample.txt"); + * foreach(ulong n, char[] line; file) { + * stdout.writefln("line %d: %s",n,line); + * } + * file.close(); + * ------------------------------------ + */ // 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); + int opApply(int delegate(inout ulong n, inout char[] line) dg); /// ditto + int opApply(int delegate(inout wchar[] line) dg); /// ditto + int opApply(int delegate(inout ulong n, inout wchar[] line) dg); /// ditto - // reads a string of given length, throws - // ReadException on error + /// Read a string of the given length, + /// throwing ReadException if there was a problem. char[] readString(size_t length); - // reads a Unicode string of given length, throws - // ReadException on error + /*** + * Read a string of the given length, throwing ReadException if there was a + * problem. + * + * The file format is implementation-specific and should not be used + * except as opposite actions to write. + */ + wchar[] readStringW(size_t length); - // reads and returns next character from the stream, - // handles characters pushed back by ungetc() - // return char.init on EOF - char getc(); - // reads and returns next Unicode character from the - // stream, handles characters pushed back by ungetc() - // return wchar.init on EOF - wchar getcw(); + /*** + * Read and return the next character in the stream. + * + * This is the only method that will handle ungetc properly. + * getcw's format is implementation-specific. + * If EOF is reached then getc returns char.init and getcw returns wchar.init. + */ - // pushes back character c into the stream; only has - // effect on further calls to getc() and getcw() - char ungetc(char c); + char getc(); + wchar getcw(); /// ditto - // pushes back Unicode character c into the stream; only - // has effect on further calls to getc() and getcw() - wchar ungetcw(wchar c); + /*** + * Push a character back onto the stream. + * + * They will be returned in first-in last-out order from getc/getcw. + * Only has effect on further calls to getc() and getcw(). + */ + char ungetc(char c); + wchar ungetcw(wchar c); /// ditto + /*** + * Scan a string from the input using a similar form to C's scanf + * and std.format. + * + * An argument of type char[] is interpreted as a format string. + * All other arguments must be pointer types. + * If a format string is not present a default will be supplied computed from + * the base type of the pointer type. An argument of type char[]* is filled + * (possibly with appending characters) and a slice of the result is assigned + * back into the argument. For example the following readf statements + * are equivalent: + * -------------------------- + * int x; + * double y; + * char[] s; + * file.readf(&x, " hello ", &y, &s); + * file.readf("%d hello %f %s", &x, &y, &s); + * file.readf("%d hello %f", &x, &y, "%s", &s); + * -------------------------- + */ int vreadf(TypeInfo[] arguments, void* args); + int readf(...); /// ditto - int readf(...); - + /// Retrieve the number of bytes available for immediate reading. size_t available(); + + /*** + * Return whether the current file position is the same as the end of the + * file. + * + * This does not require actually reading past the end, as with stdio. For + * non-seekable streams this might only return true after attempting to read + * past the end. + */ + bool eof(); - bool isOpen(); + + bool isOpen(); /// Return true if the stream is currently open. } -// Interface for writable streams +/// Interface for writable streams. interface OutputStream { - // writes block of data of specified size, - // throws WriteException on error + + /*** + * Write exactly size bytes from buffer, or throw a WriteException if that + * could not be done. + */ void writeExact(void* buffer, size_t size); - // writes the given array of bytes, returns - // actual number of bytes written + /*** + * Write as much of the buffer as possible, + * returning the number of bytes written. + */ size_t write(ubyte[] buffer); - // write a single value of desired type, - // throw WriteException on error + /*** + * Write a basic type. + * + * Outside of byte, ubyte, and char, the format is implementation-specific + * and should only be used in conjunction with read. + * Throw WriteException on error. + */ void write(byte x); - void write(ubyte x); - void write(short 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(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(wchar x); - void write(dchar x); + void write(ubyte x); /// ditto + void write(short x); /// ditto + void write(ushort x); /// ditto + void write(int x); /// ditto + void write(uint x); /// ditto + void write(long x); /// ditto + void write(ulong x); /// ditto + void write(float x); /// ditto + void write(double x); /// ditto + void write(real x); /// ditto + void write(ifloat x); /// ditto + void write(idouble x); /// ditto + void write(ireal x); /// ditto + void write(cfloat x); /// ditto + void write(cdouble x); /// ditto + void write(creal x); /// ditto + void write(char x); /// ditto + void write(wchar x); /// ditto + void write(dchar x); /// ditto - // writes a string, together with its length + /*** + * Writes a string, together with its length. + * + * The format is implementation-specific + * and should only be used in conjunction with read. + * Throw WriteException on error. + */ void write(char[] s); + void write(wchar[] s); /// ditto - // writes a Unicode string, together with its length - void write(wchar[] s); - - // writes a line, throws WriteException on error + /*** + * Write a line of text, + * appending the line with an operating-system-specific line ending. + * + * Throws WriteException on error. + */ void writeLine(char[] s); - // writes a Unicode line, throws WriteException on error + /*** + * Write a line of text, + * appending the line with an operating-system-specific line ending. + * + * The format is implementation-specific. + * Throws WriteException on error. + */ void writeLineW(wchar[] s); - // writes a string, throws WriteException on error + /*** + * Write a string of text. + * + * Throws WriteException if it could not be fully written. + */ void writeString(char[] s); - // writes a Unicode string, throws WriteException on error + /*** + * Write a string of text. + * + * The format is implementation-specific. + * Throws WriteException if it could not be fully written. + */ void writeStringW(wchar[] s); - // writes data to stream using vprintf() syntax, - // returns number of bytes written + /*** + * Print a formatted string into the stream using printf-style syntax, + * returning the number of bytes written. + */ size_t vprintf(char[] format, va_list args); + size_t printf(char[] format, ...); /// ditto - // writes data to stream using printf() syntax, - // returns number of bytes written - size_t printf(char[] format, ...); - - // writes data to stream using writef() syntax and returns self + /*** + * Print a formatted string into the stream using writef-style syntax. + * References: std.format. + * Returns: self to chain with other stream commands like flush. + */ OutputStream writef(...); + OutputStream writefln(...); /// ditto + OutputStream writefx(TypeInfo[] arguments, void* argptr, int newline = false); /// ditto - // writes data with trailing newline and returns self - OutputStream writefln(...); + void flush(); /// Flush pending output if appropriate. + void close(); /// Close the stream, flushing output if appropriate. + bool isOpen(); /// Return true if the stream is currently open. +} - // writes data with optional trailing newline and returns self - OutputStream writefx(TypeInfo[] arguments, void* argptr, int newline = false); - void flush(); - void close(); - bool isOpen(); -} +/*** + * Stream is the base abstract class from which the other stream classes derive. + * + * Stream's byte order is the format native to the computer. + * + * Reading: + * These methods require that the readable flag be set. + * Problems with reading result in a ReadException being thrown. + * Stream implements the InputStream interface in addition to the + * readBlock method. + * + * Writing: + * These methods require that the writeable flag be set. Problems with writing + * result in a WriteException being thrown. Stream implements the OutputStream + * interface in addition to the following methods: + * writeBlock + * copyFrom + * copyFrom + * + * Seeking: + * These methods require that the seekable flag be set. + * Problems with seeking result in a SeekException being thrown. + * seek, seekSet, seekCur, seekEnd, position, size, toString, toHash + */ -// base class for all streams; not really abstract, -// but its instances will do nothing useful +// not really abstract, but its instances will do nothing useful 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; - protected bit isopen = true; - - // flag that last readBlock resulted in eof - protected bit readEOF = false; - - // flag that last getc got \r - protected bit prevCr = false; + bit readable = false; /// Indicates whether this stream can be read from. + bit writeable = false; /// Indicates whether this stream can be written to. + bit seekable = false; /// Indicates whether this stream can be seeked within. + protected bit isopen = true; /// Indicates whether this stream is open. + + protected bit readEOF = false; /// Indicates whether this stream is at eof + /// after the last read attempt. + + protected bit prevCr = false; /// For a non-seekable stream indicates that + /// the last readLine or readLineW ended on a + /// '\r' character. this() {} - // reads block of data of specified size, - // returns actual number of bytes read - // returning 0 indicates end-of-file + /*** + * Read up to size bytes into the buffer and return the number of bytes + * actually read. A return value of 0 indicates end-of-file. + */ abstract size_t readBlock(void* buffer, size_t size); // reads block of data of specified size, @@ -879,8 +1017,10 @@ // returns estimated number of bytes available for immediate reading size_t available() { return 0; } - // writes block of data of specified size, - // returns actual number of bytes written + /*** + * Write up to size bytes from buffer in the stream, returning the actual + * number of bytes that were written. + */ abstract size_t writeBlock(void* buffer, size_t size); // writes block of data of specified size, @@ -1037,8 +1177,11 @@ return this; } - // copies all data from given stream into this one, - // may throw ReadException or WriteException on failure + /*** + * Copies all data from s into this stream. + * This may throw ReadException or WriteException on failure. + * This restores the file position of s so that it is unchanged. + */ void copyFrom(Stream s) { if (seekable) { ulong pos = s.position(); @@ -1054,8 +1197,11 @@ } } - // copies specified number of bytes from given stream into - // this one, may throw ReadException or WriteException on failure + /*** + * Copy a specified number of bytes from the given stream into this one. + * This may throw ReadException or WriteException on failure. + * Unlike the previous form, this doesn't restore the file position of s. + */ void copyFrom(Stream s, ulong count) { ubyte[128] buf; while (count > 0) { @@ -1066,26 +1212,37 @@ } } - // moves pointer to given position, relative to beginning of stream, - // end of stream, or current position, returns new position + /*** + * Change the current position of the stream. whence is either SeekPos.Set, in + which case the offset is an absolute index from the beginning of the stream, + SeekPos.Current, in which case the offset is a delta from the current + position, or SeekPos.End, in which case the offset is a delta from the end of + the stream (negative or zero offsets only make sense in that case). This + returns the new file position. + */ abstract ulong seek(long offset, SeekPos whence); - // seek from the beginning of the stream. + /*** + * Aliases for their normal seek counterparts. + */ ulong seekSet(long offset) { return seek (offset, SeekPos.Set); } + ulong seekCur(long offset) { return seek (offset, SeekPos.Current); } /// ditto + ulong seekEnd(long offset) { return seek (offset, SeekPos.End); } /// ditto - // seek from the current point in the stream. - ulong seekCur(long offset) { return seek (offset, SeekPos.Current); } - - // seek from the end of the stream. - ulong seekEnd(long offset) { return seek (offset, SeekPos.End); } - - // sets position + /*** + * Sets file position. Equivalent to calling seek(pos, SeekPos.Set). + */ void position(ulong pos) { seek(pos, SeekPos.Set); } - // returns current position + /*** + * Returns current file position. Equivalent to seek(0, SeekPos.Current). + */ ulong position() { return seek(0, SeekPos.Current); } - // returns size of stream + /*** + * Retrieve the size of the stream in bytes. + * The stream must be seekable or a SeekException is thrown. + */ ulong size() { assertSeekable(); ulong pos = position(), result = seek(0, SeekPos.End); @@ -1120,7 +1277,11 @@ readEOF = prevCr = isopen = readable = writeable = seekable = false; } - // creates a string in memory containing copy of stream data + /*** + * Read the entire stream and return it as a string. + * If the stream is not seekable the contents from the current position to eof + * is read and returned. + */ override char[] toString() { if (!readable) return super.toString(); @@ -1151,7 +1312,10 @@ return result[0 .. pos]; } - // calculates CRC-32 of data in stream + /*** + * Get a hash of the stream by reading each byte and using it in a CRC-32 + * checksum. + */ override uint toHash() { if (!readable || !seekable) return super.toHash(); @@ -1185,26 +1349,57 @@ } } -// Base class for streams that wrap a backing source stream +/*** + * A base class for streams that wrap a source stream with additional + * functionality. + * + * The method implementations forward read/write/seek calls to the + * source stream. A FilterStream can change the position of the source stream + * arbitrarily and may not keep the source stream state in sync with the + * FilterStream, even upon flushing and closing the FilterStream. It is + * recommended to not make any assumptions about the state of the source position + * and read/write state after a FilterStream has acted upon it. Specifc subclasses + * of FilterStream should document how they modify the source stream and if any + * invariants hold true between the source and filter. + */ class FilterStream : Stream { private Stream s; // source stream - bit nestClose = true; // close the source when this stream closes - // Construct a FilterStream around source + /// Property indicating when this stream closes to close the source stream as + /// well. + /// Defaults to true. + bit nestClose = true; + + /// Construct a FilterStream for the given source. this(Stream source) { s = source; resetSource(); } // source getter/setter + + /*** + * Get the current source stream. + */ final Stream source(){return s;} + + /*** + * Set the current source stream. + * + * Setting the source stream closes this stream before attaching the new + * source. Attaching an open stream reopens this stream and resets the stream + * state. + */ void source(Stream s) { close(); this.s = s; resetSource(); } - // set this streams state for a new or changed source + /*** + * Indicates the source stream changed state and that this stream should reset + * any readable, writeable, seekable, isopen and buffering flags. + */ void resetSource() { if (s !is null) { readable = s.readable; @@ -1249,7 +1444,15 @@ override void flush() { super.flush(); s.flush(); } } -// A stream that wraps a source stream in a buffer +/*** + * This subclass is for buffering a source stream. + * + * A buffered stream must be + * closed explicitly to ensure the final buffer content is written to the source + * stream. The source stream position is changed according to the block size so + * reading or writing to the BufferedStream may not change the source stream + * position by the same amount. + */ class BufferedStream : FilterStream { ubyte[] buffer; // buffer, if any uint bufferCurPos; // current position in buffer @@ -1276,6 +1479,10 @@ const uint DefaultBufferSize = 8192; + /*** + * Create a buffered stream for the stream source with the buffer size + * bufferSize. + */ this(Stream source, uint bufferSize = DefaultBufferSize) { super(source); if (bufferSize) @@ -1534,14 +1741,15 @@ } } -// generic File error, base class for all -// other File exceptions +/// An exception for File errors. class StreamFileException: StreamException { + /// Construct a StreamFileException with given error message. this(char[] msg) { super(msg); } } -// thrown when unable to open file +/// An exception for errors during File.open. class OpenException: StreamFileException { + /// Construct an OpenFileException with given error message. this(char[] msg) { super(msg); } } @@ -1565,7 +1773,7 @@ alias int HANDLE; } -// just a file on disk without buffering +/// This subclass is for unbuffered file system streams. class File: Stream { version (Win32) { @@ -1600,11 +1808,26 @@ } } - // opens file in requested mode + /*** + * Create the stream with no open file, an open file in read mode, or an open + * file with explicit file mode. + * mode, if given, is a combination of FileMode.In + * (indicating a file that can be read) and FileMode.Out (indicating a file + * that can be written). + * Opening a file for reading that doesn't exist will error. + * Opening a file for writing that doesn't exist will create the file. + * The FileMode.OutNew mode will open the file for writing and reset the + * length to zero. + * The FileMode.Append mode will open the file for writing and move the + * file position to the end of the file. + */ this(char[] filename, FileMode mode = FileMode.In) { this(); open(filename, mode); } - // opens file in requested mode + /*** + * Open a file for the stream, in an identical manner to the constructors. + * If an error occurs an OpenException is thrown. + */ void open(char[] filename, FileMode mode = FileMode.In) { close(); int access, share, createMode; @@ -1669,18 +1892,18 @@ } } - // creates file for writing + /// Create a file for writing. void create(char[] filename) { create(filename, FileMode.OutNew); } - // creates file in requested mode + /// ditto void create(char[] filename, FileMode mode) { close(); open(filename, mode | FileMode.OutNew); } - // closes file, if it is open; otherwise, does nothing + /// Close the current file if it is open; otherwise it does nothing. override void close() { if (isopen) { super.close(); @@ -1751,6 +1974,11 @@ return result; } + /*** + * For a seekable file returns the difference of the size and position and + * otherwise returns 0. + */ + override size_t available() { if (seekable) { ulong lavail = size - position; @@ -1839,7 +2067,13 @@ } } -// a buffered file on disk +/*** + * This subclass is for buffered file system streams. + * + * It is a convenience class for wrapping a File in a BufferedStream. + * A buffered stream must be closed explicitly to ensure the final buffer + * content is written to the file. + */ class BufferedFile: BufferedStream { // opens file for reading @@ -1926,7 +2160,14 @@ } -enum BOM { UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE } +/// UTF byte-order-mark signatures +enum BOM { + UTF8, /// UTF-8 + UTF16LE, /// UTF-16 Little Endian + UTF16BE, /// UTF-16 Big Endian + UTF32LE, /// UTF-32 Little Endian + UTF32BE, /// UTF-32 Big Endian +} private const int NBOMS = 5; Endian[NBOMS] BOMEndian = @@ -1943,21 +2184,43 @@ [0x00, 0x00, 0xFE, 0xFF] ]; -// A stream that wraps a source stream with endian support + +/*** + * This subclass wraps a stream with big-endian or little-endian byte order + * swapping. + * + * UTF Byte-Order-Mark (BOM) signatures can be read and deduced or + * written. + * Note that an EndianStream should not be used as the source of another + * FilterStream since a FilterStream call the source with byte-oriented + * read/write requests and the EndianStream will not perform any byte swapping. + * The EndianStream reads and writes binary data (non-getc functions) in a + * one-to-one + * manner with the source stream so the source stream's position and state will be + * kept in sync with the EndianStream if only non-getc functions are called. + */ class EndianStream : FilterStream { - Endian endian; // endianness of the source stream - // Construct an Endian stream with specified endianness, defaulting - // to the native endiannes. + Endian endian; /// Endianness property of the source stream. + + /*** + * Create the endian stream for the source stream source with endianness end. + * The default endianness is the native byte order. + * The Endian type is defined + * in the std.system module. + */ this(Stream source, Endian end = std.system.endian) { super(source); endian = end; } - /* Return -1 if no BOM and otherwise read the BOM and return it. - * If there is no BOM then the bytes read are pushed back onto - * the ungetc buffer or ungetcw buffer. Pass ungetCharSize == 2 - * to use ungetcw instead of ungetc. + /*** + * Return -1 if no BOM and otherwise read the BOM and return it. + * + * If there is no BOM or if bytes beyond the BOM are read then the bytes read + * are pushed back onto the ungetc buffer or ungetcw buffer. + * Pass ungetCharSize == 2 to use + * ungetcw instead of ungetc when no BOM is present. */ int readBOM(int ungetCharSize = 1) { ubyte[4] BOM_buffer; @@ -1999,8 +2262,10 @@ return result; } - // Correct the byte order of buffer to match native endianness. - // size must be even + /*** + * 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; @@ -2036,8 +2301,11 @@ } } - // Correct the byte order of buffer in blocks repeatedly - // size must be even + /*** + * Correct the byte order of the given buffer in blocks of the given size and + * repeated the given number of times. + * size must be even. + */ final void fixBlockBO(void* buffer, uint size, size_t repeat) { while (repeat--) { fixBO(buffer,size); @@ -2091,7 +2359,7 @@ return result; } - // Write the specified BOM to the source stream + /// Write the specified BOM b to the source stream. void writeBOM(BOM b) { ubyte[] bom = ByteOrderMarks[b]; writeBlock(bom,bom.length); @@ -2210,14 +2478,20 @@ } } -// Parameterized stream class that wraps an array-like type. -// The Buffer type must support .length, opIndex and opSlice +/*** + * Parameterized subclass that wraps an array-like buffer with a stream + * interface. + * + * The type Buffer must support the length property, opIndex and opSlice. + * Compile in release mode when directly instantiating a TArrayStream to avoid + * link errors. + */ class TArrayStream(Buffer): Stream { Buffer buf; // current data ulong len; // current data length ulong cur; // current file position - // use this buffer, non-copying. + /// Create the stream for the the buffer buf. Non-copying. this(Buffer buf) { super (); this.buf = buf; @@ -2278,7 +2552,7 @@ override size_t available () { return len - cur; } - // returns pointer to stream data + /// Get the current memory data in total. ubyte[] data() { if (len > size_t.max) throw new StreamException("Stream too big"); @@ -2317,22 +2591,22 @@ assert (m.size () == 100); } -// virtual stream residing in memory +/// This subclass reads and constructs an array of bytes in memory. class MemoryStream: TArrayStream!(ubyte[]) { + /// Create the output buffer and setup for reading, writing, and seeking. // clear to an empty buffer. this() { this(cast(ubyte[]) null); } - // use this buffer, non-copying. + /*** + * Create the output buffer and setup for reading, writing, and seeking. + * Load it with specific input data. + */ this(ubyte[] buf) { super (buf); } + this(byte[] buf) { this(cast(ubyte[]) buf); } /// ditto + this(char[] buf) { this(cast(ubyte[]) buf); } /// ditto - // use this buffer, non-copying. - this(byte[] buf) { this(cast(ubyte[]) buf); } - - // use this buffer, non-copying. - this(char[] buf) { this(cast(ubyte[]) buf); } - - // ensure the stream can hold this many bytes. + /// Ensure the stream can hold count bytes. void reserve(size_t count) { if (cur + count > buf.length) buf.length = (cur + count) * 2; @@ -2390,9 +2664,14 @@ } import std.mmfile; -// stream wrapping memory-mapped files + +/*** + * This subclass wraps a memory-mapped file with the stream API. + * See std.mmfile module. + */ class MmFileStream : TArrayStream!(MmFile) { + /// Create stream wrapper for file. this(MmFile file) { super (file); MmFile.Mode mode = file.mode; @@ -2445,8 +2724,16 @@ std.file.remove("testing.txt"); } -// slices off a portion of another stream, making seeking -// relative to the boundaries of the slice. + +/*** + * This subclass slices off a portion of another stream, making seeking relative + * to the boundaries of the slice. + * + * It could be used to section a large file into a + * set of smaller files, such as with tar archives. Reading and writing a + * SliceStream does not modify the position of the source stream if it is + * seekable. + */ class SliceStream : FilterStream { private { ulong pos; // our position relative to low @@ -2455,7 +2742,13 @@ bit bounded; // upper-bounded by high. } - // set the s stream and the low offset but leave the high unbounded. + /*** + * Indicate both the source stream to use for reading from and the low part of + * the slice. + * + * The high part of the slice is dependent upon the end of the source + * stream, so that if you write beyond the end it resizes the stream normally. + */ this (Stream s, ulong low) in { assert (low <= s.size ()); @@ -2467,7 +2760,12 @@ this.bounded = false; } - // set the source stream, the low offset, and the high offset. + /*** + * Indicate the high index as well. + * + * Attempting to read or write past the high + * index results in the end being clipped off. + */ this (Stream s, ulong low, ulong high) in { assert (low <= high); diff -uNr dmd-0.131/dmd/src/phobos/std_boilerplate.html dmd-0.132/dmd/src/phobos/std_boilerplate.html --- dmd-0.131/dmd/src/phobos/std_boilerplate.html 1970-01-01 01:00:00.000000000 +0100 +++ dmd-0.132/dmd/src/phobos/std_boilerplate.html 2005-09-19 17:54:38.000000000 +0200 @@ -0,0 +1,137 @@ + + + + + + + +Digital Mars - The D Programming Language - $(TITLE) + + + + +www.digitalmars.com + +Home +| Search +| D +| Comments + +
+Last update $(DATETIME) +
+ + + +
+
+
+ + + + + +
+
+
D
+
Language
+
Phobos
+
Comparisons


+ +object
+
+ +std
std.base64
std.boxer
std.compiler
std.conv
std.ctype
std.date
std.file
std.format
std.gc
std.intrinsic
std.math
std.md5
std.mmfile
std.openrj
std.outbuffer
std.path
std.process
std.random
std.recls
std.regexp
std.socket
std.socketstream
std.stdint
std.stdio
std.cstream
std.stream
std.string
std.system
std.thread
std.uri
std.utf
std.zip
std.zlib
+
+std.windows
+
+std.linux
+
+std.c
std.c.stdio
+
+std.c.windows
+
+std.c.linux
+
+
+
+ + +

$(TITLE)

+ +
+$(BODY) +
+ + +
+

Feedback and Comments

+ + Add feedback and comments regarding this + page. + +
+Copyright © 1999-$(YEAR) by Digital Mars, All Rights Reserved

+ + + + + + + + + + + diff -uNr dmd-0.131/dmd/src/phobos/win32.mak dmd-0.132/dmd/src/phobos/win32.mak --- dmd-0.131/dmd/src/phobos/win32.mak 2005-09-09 01:57:32.000000000 +0200 +++ dmd-0.132/dmd/src/phobos/win32.mak 2005-09-19 17:54:38.000000000 +0200 @@ -20,10 +20,14 @@ DFLAGS=-O -release #DFLAGS=-unittest -g -CC=sc +CC=dmc + DMD=\dmd\bin\dmd #DMD=..\dmd +DOC=..\..\html\d\phobos +#DOC=..\doc\phobos + .c.obj: $(CC) -c $(CFLAGS) $* @@ -79,6 +83,8 @@ ti_Acfloat.obj ti_Acdouble.obj ti_Acreal.obj \ ti_dchar.obj ti_Adchar.obj ti_bit.obj ti_Abit.obj ti_void.obj +DOCS= $(DOC)\std_path.html $(DOC)\std_math.html $(DOC)\std_outbuffer.html \ + $(DOC)\std_stream.html SRC= errno.c object.d unittest.d crc32.d gcstats.d @@ -348,6 +354,8 @@ lib -c -p32 phobos.lib $(OBJS) minit.obj internal\gc\dmgc.lib \ etc\c\recls\recls.lib etc\c\zlib\zlib.lib +html : $(DOCS) + ###################################################### internal\gc\dmgc.lib: @@ -470,8 +478,8 @@ loader.obj : std\loader.d $(DMD) -c $(DFLAGS) std\loader.d -math.obj : std\math.d - $(DMD) -c $(DFLAGS) std\math.d +math.obj $(DOC)\std_math.html : std\math.d + $(DMD) -c $(DFLAGS) -Df$(DOC)\std_math.html std\math.d math2.obj : std\math2.d $(DMD) -c $(DFLAGS) std\math2.d @@ -491,14 +499,14 @@ openrj.obj : std\openrj.d $(DMD) -c $(DFLAGS) std\openrj.d -outbuffer.obj : std\outbuffer.d - $(DMD) -c $(DFLAGS) std\outbuffer.d +outbuffer.obj $(DOC)\std_outbuffer.html : std\outbuffer.d + $(DMD) -c $(DFLAGS) -Df$(DOC)\std_outbuffer.html std\outbuffer.d outofmemory.obj : std\outofmemory.d $(DMD) -c $(DFLAGS) std\outofmemory.d -path.obj : std\path.d - $(DMD) -c $(DFLAGS) std\path.d +path.obj $(DOC)\std_path.html : std\path.d + $(DMD) -c $(DFLAGS) -Df$(DOC)\std_path.html std\path.d perf.obj : std\perf.d $(DMD) -c $(DFLAGS) std\perf.d @@ -524,8 +532,8 @@ stdio.obj : std\stdio.d $(DMD) -c $(DFLAGS) std\stdio.d -stream.obj : std\stream.d - $(DMD) -c $(DFLAGS) -d std\stream.d +stream.obj $(DOC)\std_stream.html : std\stream.d + $(DMD) -c $(DFLAGS) -Df$(DOC)\std_stream.html -d std\stream.d string.obj : std\string.d $(DMD) -c $(DFLAGS) std\string.d @@ -728,11 +736,11 @@ ###################################################### -zip : win32.mak linux.mak phoboslicense.txt $(SRC) \ +zip : win32.mak linux.mak phoboslicense.txt std_boilerplate.html $(SRC) \ $(SRC_STD) $(SRC_STD_C) $(SRC_TI) $(SRC_INT) $(SRC_STD_WIN) \ $(SRC_STDLINUX) $(SRC_ETC) $(SRC_ETC_C) $(SRC_ZLIB) $(SRC_GC) del phobos.zip - zip32 -u phobos win32.mak linux.mak + zip32 -u phobos win32.mak linux.mak std_boilerplate.html zip32 -u phobos $(SRC) zip32 -u phobos $(SRC_TI) zip32 -u phobos $(SRC_INT) @@ -750,10 +758,11 @@ clean: del $(OBJS) + del $(DOCS) install: $(CP) phobos.lib gcstub.obj \dmd\lib - $(CP) win32.mak linux.mak phoboslicense.txt minit.obj \dmd\src\phobos + $(CP) win32.mak linux.mak phoboslicense.txt minit.obj std_boilerplate.html \dmd\src\phobos $(CP) $(SRC) \dmd\src\phobos $(CP) $(SRC_STD) \dmd\src\phobos\std $(CP) $(SRC_STD_C) \dmd\src\phobos\std\c