1: 
   2: // Compiler implementation of the D programming language
   3: // Copyright (c) 1999-2011 by Digital Mars
   4: // All Rights Reserved
   5: // written by Walter Bright
   6: // http://www.digitalmars.com
   7: // License for redistribution is by either the Artistic License
   8: // in artistic.txt, or the GNU General Public License in gnu.txt.
   9: // See the included readme.txt for details.
  10: 
  11: // This implements the Ddoc capability.
  12: 
  13: #include <stdio.h>
  14: #include <string.h>
  15: #include <time.h>
  16: #include <ctype.h>
  17: static char __file__[] = __FILE__;      /* for tassert.h                */
  18: #include        "tassert.h"
  19: 
  20: #include "rmem.h"
  21: #include "root.h"
  22: 
  23: #include "mars.h"
  24: #include "dsymbol.h"
  25: #include "macro.h"
  26: #include "template.h"
  27: #include "lexer.h"
  28: #include "aggregate.h"
  29: #include "declaration.h"
  30: #include "enum.h"
  31: #include "id.h"
  32: #include "module.h"
  33: #include "scope.h"
  34: #include "hdrgen.h"
  35: #include "doc.h"
  36: #include "mtype.h"
  37: #include "utf.h"
  38: 
  39: struct Escape
  40: {
  41:     const char *strings[256];
  42: 
  43:     static const char *escapeChar(unsigned c);
  44: };
  45: 
  46: struct Section
  47: {
  48:     unsigned char *name;
  49:     unsigned namelen;
  50: 
  51:     unsigned char *body;
  52:     unsigned bodylen;
  53: 
  54:     int nooutput;
  55: 
  56:     virtual void write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf);
  57: };
  58: 
  59: struct ParamSection : Section
  60: {
  61:     void write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf);
  62: };
  63: 
  64: struct MacroSection : Section
  65: {
  66:     void write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf);
  67: };
  68: 
  69: typedef ArrayBase<Section> Sections;
  70: 
  71: struct DocComment
  72: {
  73:     Sections sections;             // Section*[]
  74: 
  75:     Section *summary;
  76:     Section *copyright;
  77:     Section *macros;
  78:     Macro **pmacrotable;
  79:     Escape **pescapetable;
  80: 
  81:     DocComment();
  82: 
  83:     static DocComment *parse(Scope *sc, Dsymbol *s, unsigned char *comment);
  84:     static void parseMacros(Escape **pescapetable, Macro **pmacrotable, unsigned char *m, unsigned mlen);
  85:     static void parseEscapes(Escape **pescapetable, unsigned char *textstart, unsigned textlen);
  86: 
  87:     void parseSections(unsigned char *comment);
  88:     void writeSections(Scope *sc, Dsymbol *s, OutBuffer *buf);
  89: };
  90: 
  91: 
  92: int cmp(const char *stringz, void *s, size_t slen);
  93: int icmp(const char *stringz, void *s, size_t slen);
  94: int isDitto(unsigned char *comment);
  95: unsigned char *skipwhitespace(unsigned char *p);
  96: unsigned skiptoident(OutBuffer *buf, size_t i);
  97: unsigned skippastident(OutBuffer *buf, size_t i);
  98: unsigned skippastURL(OutBuffer *buf, size_t i);
  99: void highlightText(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset);
 100: void highlightCode(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset);
 101: void highlightCode2(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset);
 102: Parameter *isFunctionParameter(Dsymbol *s, unsigned char *p, unsigned len);
 103: 
 104: int isIdStart(unsigned char *p);
 105: int isIdTail(unsigned char *p);
 106: int utfStride(unsigned char *p);
 107: 
 108: static unsigned char ddoc_default[] = "\
 109: DDOC =  <html><head>\n\
 110:         <META http-equiv=\"content-type\" content=\"text/html; charset=utf-8\">\n\
 111:         <title>$(TITLE)</title>\n\
 112:         </head><body>\n\
 113:         <h1>$(TITLE)</h1>\n\
 114:         $(BODY)\n\
 115:         <hr>$(SMALL Page generated by $(LINK2 http://www.digitalmars.com/d/2.0/ddoc.html, Ddoc). $(COPYRIGHT))\n\
 116:         </body></html>\n\
 117: \n\
 118: B =     <b>$0</b>\n\
 119: I =     <i>$0</i>\n\
 120: U =     <u>$0</u>\n\
 121: P =     <p>$0</p>\n\
 122: DL =    <dl>$0</dl>\n\
 123: DT =    <dt>$0</dt>\n\
 124: DD =    <dd>$0</dd>\n\
 125: TABLE = <table>$0</table>\n\
 126: TR =    <tr>$0</tr>\n\
 127: TH =    <th>$0</th>\n\
 128: TD =    <td>$0</td>\n\
 129: OL =    <ol>$0</ol>\n\
 130: UL =    <ul>$0</ul>\n\
 131: LI =    <li>$0</li>\n\
 132: BIG =   <big>$0</big>\n\
 133: SMALL = <small>$0</small>\n\
 134: BR =    <br>\n\
 135: LINK =  <a href=\"$0\">$0</a>\n\
 136: LINK2 = <a href=\"$1\">$+</a>\n\
 137: LPAREN= (\n\
 138: RPAREN= )\n\
 139: DOLLAR= $\n\
 140: \n\
 141: RED =   <font color=red>$0</font>\n\
 142: BLUE =  <font color=blue>$0</font>\n\
 143: GREEN = <font color=green>$0</font>\n\
 144: YELLOW =<font color=yellow>$0</font>\n\
 145: BLACK = <font color=black>$0</font>\n\
 146: WHITE = <font color=white>$0</font>\n\
 147: \n\
 148: D_CODE = <pre class=\"d_code\">$0</pre>\n\
 149: D_COMMENT = $(GREEN $0)\n\
 150: D_STRING  = $(RED $0)\n\
 151: D_KEYWORD = $(BLUE $0)\n\
 152: D_PSYMBOL = $(U $0)\n\
 153: D_PARAM   = $(I $0)\n\
 154: \n\
 155: DDOC_COMMENT   = <!-- $0 -->\n\
 156: DDOC_DECL      = $(DT $(BIG $0))\n\
 157: DDOC_DECL_DD   = $(DD $0)\n\
 158: DDOC_DITTO     = $(BR)$0\n\
 159: DDOC_SECTIONS  = $0\n\
 160: DDOC_SUMMARY   = $0$(BR)$(BR)\n\
 161: DDOC_DESCRIPTION = $0$(BR)$(BR)\n\
 162: DDOC_AUTHORS   = $(B Authors:)$(BR)\n$0$(BR)$(BR)\n\
 163: DDOC_BUGS      = $(RED BUGS:)$(BR)\n$0$(BR)$(BR)\n\
 164: DDOC_COPYRIGHT = $(B Copyright:)$(BR)\n$0$(BR)$(BR)\n\
 165: DDOC_DATE      = $(B Date:)$(BR)\n$0$(BR)$(BR)\n\
 166: DDOC_DEPRECATED = $(RED Deprecated:)$(BR)\n$0$(BR)$(BR)\n\
 167: DDOC_EXAMPLES  = $(B Examples:)$(BR)\n$0$(BR)$(BR)\n\
 168: DDOC_HISTORY   = $(B History:)$(BR)\n$0$(BR)$(BR)\n\
 169: DDOC_LICENSE   = $(B License:)$(BR)\n$0$(BR)$(BR)\n\
 170: DDOC_RETURNS   = $(B Returns:)$(BR)\n$0$(BR)$(BR)\n\
 171: DDOC_SEE_ALSO  = $(B See Also:)$(BR)\n$0$(BR)$(BR)\n\
 172: DDOC_STANDARDS = $(B Standards:)$(BR)\n$0$(BR)$(BR)\n\
 173: DDOC_THROWS    = $(B Throws:)$(BR)\n$0$(BR)$(BR)\n\
 174: DDOC_VERSION   = $(B Version:)$(BR)\n$0$(BR)$(BR)\n\
 175: DDOC_SECTION_H = $(B $0)$(BR)\n\
 176: DDOC_SECTION   = $0$(BR)$(BR)\n\
 177: DDOC_MEMBERS   = $(DL $0)\n\
 178: DDOC_MODULE_MEMBERS = $(DDOC_MEMBERS $0)\n\
 179: DDOC_CLASS_MEMBERS  = $(DDOC_MEMBERS $0)\n\
 180: DDOC_STRUCT_MEMBERS = $(DDOC_MEMBERS $0)\n\
 181: DDOC_ENUM_MEMBERS   = $(DDOC_MEMBERS $0)\n\
 182: DDOC_TEMPLATE_MEMBERS = $(DDOC_MEMBERS $0)\n\
 183: DDOC_PARAMS    = $(B Params:)$(BR)\n$(TABLE $0)$(BR)\n\
 184: DDOC_PARAM_ROW = $(TR $0)\n\
 185: DDOC_PARAM_ID  = $(TD $0)\n\
 186: DDOC_PARAM_DESC = $(TD $0)\n\
 187: DDOC_BLANKLINE  = $(BR)$(BR)\n\
 188: \n\
 189: DDOC_PSYMBOL    = $(U $0)\n\
 190: DDOC_KEYWORD    = $(B $0)\n\
 191: DDOC_PARAM      = $(I $0)\n\
 192: \n\
 193: ESCAPES = /</&lt;/\n\
 194:           />/&gt;/\n\
 195:           /&/&amp;/\n\
 196: ";
 197: 
 198: static char ddoc_decl_s[] = "$(DDOC_DECL ";
 199: static char ddoc_decl_e[] = ")\n";
 200: 
 201: static char ddoc_decl_dd_s[] = "$(DDOC_DECL_DD ";
 202: static char ddoc_decl_dd_e[] = ")\n";
 203: 
 204: 
 205: /****************************************************
 206:  */
 207: 
 208: void Module::gendocfile()
 209: {
 210:     static OutBuffer mbuf;
 211:     static int mbuf_done;
 212: 
 213:     OutBuffer buf;
 214: 
 215:     //printf("Module::gendocfile()\n");
 216: 
 217:     if (!mbuf_done)             // if not already read the ddoc files
 218:     {   mbuf_done = 1;
 219: 
 220:         // Use our internal default
 221:         mbuf.write(ddoc_default, sizeof(ddoc_default) - 1);
 222: 
 223:         // Override with DDOCFILE specified in the sc.ini file
 224:         char *p = getenv("DDOCFILE");
warning C4996: 'getenv': This function or variable may be unsafe. Consider using _dupenv_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details. c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\stdlib.h(433) : see declaration of 'getenv'
225: if (p) 226: global.params.ddocfiles->shift(p); 227: 228: // Override with the ddoc macro files from the command line 229: for (int i = 0; i < global.params.ddocfiles->dim; i++)
warning C4018: '<' : signed/unsigned mismatch
230: { 231: FileName f(global.params.ddocfiles->tdata()[i], 0); 232: File file(&f); 233: file.readv(); 234: // BUG: convert file contents to UTF-8 before use 235: 236: //printf("file: '%.*s'\n", file.len, file.buffer); 237: mbuf.write(file.buffer, file.len); 238: } 239: } 240: DocComment::parseMacros(&escapetable, &macrotable, mbuf.data, mbuf.offset); 241: 242: Scope *sc = Scope::createGlobal(this); // create root scope 243: sc->docbuf = &buf; 244: 245: DocComment *dc = DocComment::parse(sc, this, comment); 246: dc->pmacrotable = &macrotable; 247: dc->pescapetable = &escapetable; 248: 249: // Generate predefined macros 250: 251: // Set the title to be the name of the module 252: { const char *p = toPrettyChars(); 253: Macro::define(&macrotable, (unsigned char *)"TITLE", 5, (unsigned char *)p, strlen(p)); 254: } 255: 256: time_t t; 257: time(&t); 258: char *p = ctime(&t);
warning C4996: 'ctime': This function or variable may be unsafe. Consider using ctime_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details. c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\time.inl(86) : see declaration of 'ctime'
259: p = mem.strdup(p); 260: Macro::define(&macrotable, (unsigned char *)"DATETIME", 8, (unsigned char *)p, strlen(p)); 261: Macro::define(&macrotable, (unsigned char *)"YEAR", 4, (unsigned char *)p + 20, 4); 262: 263: char *docfilename = docfile->toChars(); 264: Macro::define(&macrotable, (unsigned char *)"DOCFILENAME", 11, (unsigned char *)docfilename, strlen(docfilename)); 265: 266: if (dc->copyright) 267: { 268: dc->copyright->nooutput = 1; 269: Macro::define(&macrotable, (unsigned char *)"COPYRIGHT", 9, dc->copyright->body, dc->copyright->bodylen); 270: } 271: 272: buf.printf("$(DDOC_COMMENT Generated by Ddoc from %s)\n", srcfile->toChars()); 273: if (isDocFile) 274: { 275: size_t commentlen = strlen((char *)comment); 276: if (dc->macros) 277: { 278: commentlen = dc->macros->name - comment; 279: dc->macros->write(dc, sc, this, sc->docbuf); 280: } 281: sc->docbuf->write(comment, commentlen); 282: highlightText(NULL, this, sc->docbuf, 0); 283: } 284: else 285: { 286: dc->writeSections(sc, this, sc->docbuf); 287: emitMemberComments(sc); 288: } 289: 290: //printf("BODY= '%.*s'\n", buf.offset, buf.data); 291: Macro::define(&macrotable, (unsigned char *)"BODY", 4, buf.data, buf.offset); 292: 293: OutBuffer buf2; 294: buf2.writestring("$(DDOC)\n"); 295: unsigned end = buf2.offset; 296: macrotable->expand(&buf2, 0, &end, NULL, 0); 297: 298: #if 1 299: /* Remove all the escape sequences from buf2, 300: * and make CR-LF the newline. 301: */ 302: { 303: buf.setsize(0); 304: buf.reserve(buf2.offset); 305: unsigned char *p = buf2.data;
warning C6246: Local declaration of 'p' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '258' of 'c:\projects\extern\d\dmd\src\doc.c': Lines: 258
306: for (unsigned j = 0; j < buf2.offset; j++) 307: { 308: unsigned char c = p[j]; 309: if (c == 0xFF && j + 1 < buf2.offset) 310: { 311: j++; 312: continue; 313: } 314: if (c == '\n') 315: buf.writeByte('\r'); 316: else if (c == '\r') 317: { 318: buf.writestring("\r\n"); 319: if (j + 1 < buf2.offset && p[j + 1] == '\n') 320: { 321: j++; 322: } 323: continue; 324: } 325: buf.writeByte(c); 326: } 327: } 328: 329: // Transfer image to file 330: assert(docfile); 331: docfile->setbuffer(buf.data, buf.offset); 332: docfile->ref = 1; 333: char *pt = FileName::path(docfile->toChars()); 334: if (*pt) 335: FileName::ensurePathExists(pt); 336: mem.free(pt); 337: docfile->writev(); 338: #else 339: /* Remove all the escape sequences from buf2 340: */ 341: { unsigned i = 0; 342: unsigned char *p = buf2.data; 343: for (unsigned j = 0; j < buf2.offset; j++) 344: { 345: if (p[j] == 0xFF && j + 1 < buf2.offset) 346: { 347: j++; 348: continue; 349: } 350: p[i] = p[j]; 351: i++; 352: } 353: buf2.setsize(i); 354: } 355: 356: // Transfer image to file 357: docfile->setbuffer(buf2.data, buf2.offset); 358: docfile->ref = 1; 359: char *pt = FileName::path(docfile->toChars()); 360: if (*pt) 361: FileName::ensurePathExists(pt); 362: mem.free(pt); 363: docfile->writev(); 364: #endif 365: } 366: 367: /**************************************************** 368: * Having unmatched parentheses can hose the output of Ddoc, 369: * as the macros depend on properly nested parentheses. 370: * This function replaces all ( with $(LPAREN) and ) with $(RPAREN) 371: * to preserve text literally. This also means macros in the 372: * text won't be expanded. 373: */ 374: void escapeDdocString(OutBuffer *buf, unsigned start) 375: { 376: for (unsigned u = start; u < buf->offset; u++) 377: { 378: unsigned char c = buf->data[u]; 379: switch(c) 380: { 381: case '$': 382: buf->remove(u, 1); 383: buf->insert(u, "$(DOLLAR)", 9); 384: u += 8; 385: break; 386: 387: case '(': 388: buf->remove(u, 1); //remove the ( 389: buf->insert(u, "$(LPAREN)", 9); //insert this instead 390: u += 8; //skip over newly inserted macro 391: break; 392: 393: case ')': 394: buf->remove(u, 1); //remove the ) 395: buf->insert(u, "$(RPAREN)", 9); //insert this instead 396: u += 8; //skip over newly inserted macro 397: break; 398: } 399: } 400: } 401: 402: /**************************************************** 403: * Having unmatched parentheses can hose the output of Ddoc, 404: * as the macros depend on properly nested parentheses. 405: 406: * Fix by replacing unmatched ( with $(LPAREN) and unmatched ) with $(RPAREN). 407: */ 408: void escapeStrayParenthesis(OutBuffer *buf, unsigned start, Loc loc) 409: { 410: unsigned par_open = 0; 411: 412: for (unsigned u = start; u < buf->offset; u++) 413: { 414: unsigned char c = buf->data[u]; 415: switch(c) 416: { 417: case '(': 418: par_open++; 419: break; 420: 421: case ')': 422: if (par_open == 0) 423: { 424: //stray ')' 425: if (global.params.warnings) 426: warning(loc, "Ddoc: Stray ')'. This may cause incorrect Ddoc output." 427: " Use $(RPAREN) instead for unpaired right parentheses."); 428: buf->remove(u, 1); //remove the ) 429: buf->insert(u, "$(RPAREN)", 9); //insert this instead 430: u += 8; //skip over newly inserted macro 431: } 432: else 433: par_open--; 434: break; 435: #if 0 436: // For this to work, loc must be set to the beginning of the passed 437: // text which is currently not possible 438: // (loc is set to the Loc of the Dsymbol) 439: case '\n': 440: loc.linnum++; 441: break; 442: #endif 443: } 444: } 445: 446: if (par_open) // if any unmatched lparens 447: { par_open = 0; 448: for (unsigned u = buf->offset; u > start;) 449: { u--; 450: unsigned char c = buf->data[u]; 451: switch(c) 452: { 453: case ')': 454: par_open++; 455: break; 456: 457: case '(': 458: if (par_open == 0) 459: { 460: //stray '(' 461: if (global.params.warnings) 462: warning(loc, "Ddoc: Stray '('. This may cause incorrect Ddoc output." 463: " Use $(LPAREN) instead for unpaired left parentheses."); 464: buf->remove(u, 1); //remove the ( 465: buf->insert(u, "$(LPAREN)", 9); //insert this instead 466: } 467: else 468: par_open--; 469: break; 470: } 471: } 472: } 473: } 474: 475: /******************************* emitComment **********************************/ 476: 477: /* 478: * Emit doc comment to documentation file 479: */ 480: 481: void Dsymbol::emitDitto(Scope *sc) 482: { 483: //printf("Dsymbol::emitDitto() %s %s\n", kind(), toChars()); 484: OutBuffer *buf = sc->docbuf; 485: unsigned o; 486: OutBuffer b; 487: 488: b.writestring("$(DDOC_DITTO "); 489: o = b.offset; 490: toDocBuffer(&b); 491: //printf("b: '%.*s'\n", b.offset, b.data); 492: /* If 'this' is a function template, then highlightCode() was 493: * already run by FuncDeclaration::toDocbuffer(). 494: */ 495: TemplateDeclaration *td; 496: if (parent && 497: (td = parent->isTemplateDeclaration()) != NULL && 498: td->onemember == this) 499: { 500: } 501: else 502: highlightCode(sc, this, &b, o); 503: b.writeByte(')'); 504: buf->spread(sc->lastoffset, b.offset); 505: memcpy(buf->data + sc->lastoffset, b.data, b.offset); 506: sc->lastoffset += b.offset; 507: } 508: 509: void ScopeDsymbol::emitMemberComments(Scope *sc) 510: { 511: //printf("ScopeDsymbol::emitMemberComments() %s\n", toChars()); 512: OutBuffer *buf = sc->docbuf; 513: 514: if (members) 515: { const char *m = "$(DDOC_MEMBERS \n"; 516: 517: if (isModule()) 518: m = "$(DDOC_MODULE_MEMBERS \n"; 519: else if (isClassDeclaration()) 520: m = "$(DDOC_CLASS_MEMBERS \n"; 521: else if (isStructDeclaration()) 522: m = "$(DDOC_STRUCT_MEMBERS \n"; 523: else if (isEnumDeclaration()) 524: m = "$(DDOC_ENUM_MEMBERS \n"; 525: else if (isTemplateDeclaration()) 526: m = "$(DDOC_TEMPLATE_MEMBERS \n"; 527: 528: unsigned offset1 = buf->offset; // save starting offset 529: buf->writestring(m); 530: unsigned offset2 = buf->offset; // to see if we write anything 531: sc = sc->push(this); 532: for (int i = 0; i < members->dim; i++)
warning C4018: '<' : signed/unsigned mismatch
533: { 534: Dsymbol *s = members->tdata()[i]; 535: //printf("\ts = '%s'\n", s->toChars()); 536: s->emitComment(sc); 537: } 538: sc->pop(); 539: if (buf->offset == offset2) 540: { 541: /* Didn't write out any members, so back out last write 542: */ 543: buf->offset = offset1; 544: } 545: else 546: buf->writestring(")\n"); 547: } 548: } 549: 550: void emitProtection(OutBuffer *buf, PROT prot) 551: { 552: const char *p; 553: 554: switch (prot) 555: { 556: case PROTpackage: p = "package"; break; 557: case PROTprotected: p = "protected"; break; 558: case PROTexport: p = "export"; break; 559: default: p = NULL; break; 560: } 561: if (p) 562: buf->printf("%s ", p); 563: } 564: 565: void Dsymbol::emitComment(Scope *sc) { } 566: void InvariantDeclaration::emitComment(Scope *sc) { } 567: #if DMDV2 568: void PostBlitDeclaration::emitComment(Scope *sc) { } 569: #endif 570: void DtorDeclaration::emitComment(Scope *sc) { } 571: void StaticCtorDeclaration::emitComment(Scope *sc) { } 572: void StaticDtorDeclaration::emitComment(Scope *sc) { } 573: void ClassInfoDeclaration::emitComment(Scope *sc) { } 574: void ModuleInfoDeclaration::emitComment(Scope *sc) { } 575: void TypeInfoDeclaration::emitComment(Scope *sc) { } 576: 577: 578: void Declaration::emitComment(Scope *sc) 579: { 580: //printf("Declaration::emitComment(%p '%s'), comment = '%s'\n", this, toChars(), comment); 581: //printf("type = %p\n", type); 582: 583: if (protection == PROTprivate || !ident || 584: (!type && !isCtorDeclaration() && !isAliasDeclaration())) 585: return; 586: if (!comment) 587: return; 588: 589: OutBuffer *buf = sc->docbuf; 590: DocComment *dc = DocComment::parse(sc, this, comment); 591: unsigned o; 592: 593: if (!dc) 594: { 595: emitDitto(sc); 596: return; 597: } 598: dc->pmacrotable = &sc->module->macrotable; 599: 600: buf->writestring(ddoc_decl_s); 601: o = buf->offset; 602: toDocBuffer(buf); 603: highlightCode(sc, this, buf, o); 604: sc->lastoffset = buf->offset; 605: buf->writestring(ddoc_decl_e); 606: 607: buf->writestring(ddoc_decl_dd_s); 608: dc->writeSections(sc, this, buf); 609: buf->writestring(ddoc_decl_dd_e); 610: } 611: 612: void AggregateDeclaration::emitComment(Scope *sc) 613: { 614: //printf("AggregateDeclaration::emitComment() '%s'\n", toChars()); 615: if (prot() == PROTprivate) 616: return; 617: if (!comment) 618: return; 619: 620: OutBuffer *buf = sc->docbuf; 621: DocComment *dc = DocComment::parse(sc, this, comment); 622: 623: if (!dc) 624: { 625: emitDitto(sc); 626: return; 627: } 628: dc->pmacrotable = &sc->module->macrotable; 629: 630: buf->writestring(ddoc_decl_s); 631: toDocBuffer(buf); 632: sc->lastoffset = buf->offset; 633: buf->writestring(ddoc_decl_e); 634: 635: buf->writestring(ddoc_decl_dd_s); 636: dc->writeSections(sc, this, buf); 637: emitMemberComments(sc); 638: buf->writestring(ddoc_decl_dd_e); 639: } 640: 641: void TemplateDeclaration::emitComment(Scope *sc) 642: { 643: //printf("TemplateDeclaration::emitComment() '%s', kind = %s\n", toChars(), kind()); 644: if (prot() == PROTprivate) 645: return; 646: 647: unsigned char *com = comment; 648: int hasmembers = 1; 649: 650: Dsymbol *ss = this; 651: 652: if (onemember) 653: { 654: ss = onemember->isAggregateDeclaration(); 655: if (!ss) 656: { 657: ss = onemember->isFuncDeclaration(); 658: if (ss) 659: { hasmembers = 0; 660: if (com != ss->comment) 661: com = Lexer::combineComments(com, ss->comment); 662: } 663: else 664: ss = this; 665: } 666: } 667: 668: if (!com) 669: return; 670: 671: OutBuffer *buf = sc->docbuf; 672: DocComment *dc = DocComment::parse(sc, this, com); 673: unsigned o; 674: 675: if (!dc) 676: { 677: ss->emitDitto(sc); 678: return; 679: } 680: dc->pmacrotable = &sc->module->macrotable; 681: 682: buf->writestring(ddoc_decl_s); 683: o = buf->offset; 684: ss->toDocBuffer(buf); 685: if (ss == this) 686: highlightCode(sc, this, buf, o); 687: sc->lastoffset = buf->offset; 688: buf->writestring(ddoc_decl_e); 689: 690: buf->writestring(ddoc_decl_dd_s); 691: dc->writeSections(sc, this, buf); 692: if (hasmembers) 693: ((ScopeDsymbol *)ss)->emitMemberComments(sc); 694: buf->writestring(ddoc_decl_dd_e); 695: } 696: 697: void EnumDeclaration::emitComment(Scope *sc) 698: { 699: if (prot() == PROTprivate) 700: return; 701: // if (!comment) 702: { if (isAnonymous() && members) 703: { 704: for (int i = 0; i < members->dim; i++)
warning C4018: '<' : signed/unsigned mismatch
705: { 706: Dsymbol *s = members->tdata()[i]; 707: s->emitComment(sc); 708: } 709: return; 710: } 711: } 712: if (!comment) 713: return; 714: if (isAnonymous()) 715: return; 716: 717: OutBuffer *buf = sc->docbuf; 718: DocComment *dc = DocComment::parse(sc, this, comment); 719: 720: if (!dc) 721: { 722: emitDitto(sc); 723: return; 724: } 725: dc->pmacrotable = &sc->module->macrotable; 726: 727: buf->writestring(ddoc_decl_s); 728: toDocBuffer(buf); 729: sc->lastoffset = buf->offset; 730: buf->writestring(ddoc_decl_e); 731: 732: buf->writestring(ddoc_decl_dd_s); 733: dc->writeSections(sc, this, buf); 734: emitMemberComments(sc); 735: buf->writestring(ddoc_decl_dd_e); 736: } 737: 738: void EnumMember::emitComment(Scope *sc) 739: { 740: //printf("EnumMember::emitComment(%p '%s'), comment = '%s'\n", this, toChars(), comment); 741: if (prot() == PROTprivate) 742: return; 743: if (!comment) 744: return; 745: 746: OutBuffer *buf = sc->docbuf; 747: DocComment *dc = DocComment::parse(sc, this, comment); 748: unsigned o; 749: 750: if (!dc) 751: { 752: emitDitto(sc); 753: return; 754: } 755: dc->pmacrotable = &sc->module->macrotable; 756: 757: buf->writestring(ddoc_decl_s); 758: o = buf->offset; 759: toDocBuffer(buf); 760: highlightCode(sc, this, buf, o); 761: sc->lastoffset = buf->offset; 762: buf->writestring(ddoc_decl_e); 763: 764: buf->writestring(ddoc_decl_dd_s); 765: dc->writeSections(sc, this, buf); 766: buf->writestring(ddoc_decl_dd_e); 767: } 768: 769: /******************************* toDocBuffer **********************************/ 770: 771: void Dsymbol::toDocBuffer(OutBuffer *buf) 772: { 773: //printf("Dsymbol::toDocbuffer() %s\n", toChars()); 774: HdrGenState hgs; 775: 776: hgs.ddoc = 1; 777: toCBuffer(buf, &hgs); 778: } 779: 780: void prefix(OutBuffer *buf, Dsymbol *s) 781: { 782: if (s->isDeprecated()) 783: buf->writestring("deprecated "); 784: Declaration *d = s->isDeclaration(); 785: if (d) 786: { 787: emitProtection(buf, d->protection); 788: if (d->isAbstract()) 789: buf->writestring("abstract "); 790: if (d->isStatic()) 791: buf->writestring("static "); 792: if (d->isConst()) 793: buf->writestring("const "); 794: #if DMDV2 795: if (d->isImmutable()) 796: buf->writestring("immutable "); 797: #endif 798: if (d->isFinal()) 799: buf->writestring("final "); 800: if (d->isSynchronized()) 801: buf->writestring("synchronized "); 802: } 803: } 804: 805: void declarationToDocBuffer(Declaration *decl, OutBuffer *buf, TemplateDeclaration *td) 806: { 807: //printf("declarationToDocBuffer() %s, originalType = %s, td = %s\n", decl->toChars(), decl->originalType ? decl->originalType->toChars() : "--", td ? td->toChars() : "--"); 808: if (decl->ident) 809: { 810: prefix(buf, decl); 811: 812: if (decl->type) 813: { HdrGenState hgs; 814: hgs.ddoc = 1; 815: Type *origType = decl->originalType ? decl->originalType : decl->type; 816: if (origType->ty == Tfunction) 817: { 818: TypeFunction *attrType = (TypeFunction*)(decl->ident == Id::ctor ? origType : decl->type); 819: ((TypeFunction*)origType)->toCBufferWithAttributes(buf, decl->ident, &hgs, attrType, td); 820: } 821: else 822: origType->toCBuffer(buf, decl->ident, &hgs); 823: } 824: else 825: buf->writestring(decl->ident->toChars()); 826: buf->writestring(";\n"); 827: } 828: } 829: 830: void Declaration::toDocBuffer(OutBuffer *buf) 831: { 832: declarationToDocBuffer(this, buf, NULL); 833: } 834: 835: void AliasDeclaration::toDocBuffer(OutBuffer *buf) 836: { 837: //printf("AliasDeclaration::toDocbuffer() %s\n", toChars()); 838: if (ident) 839: { 840: if (isDeprecated()) 841: buf->writestring("deprecated "); 842: 843: emitProtection(buf, protection); 844: buf->writestring("alias "); 845: buf->writestring(toChars()); 846: buf->writestring(";\n"); 847: } 848: } 849: 850: 851: void TypedefDeclaration::toDocBuffer(OutBuffer *buf) 852: { 853: if (ident) 854: { 855: if (isDeprecated()) 856: buf->writestring("deprecated "); 857: 858: emitProtection(buf, protection); 859: buf->writestring("typedef "); 860: buf->writestring(toChars()); 861: buf->writestring(";\n"); 862: } 863: } 864: 865: 866: void FuncDeclaration::toDocBuffer(OutBuffer *buf) 867: { 868: //printf("FuncDeclaration::toDocbuffer() %s\n", toChars()); 869: if (ident) 870: { 871: TemplateDeclaration *td; 872: 873: if (parent && 874: (td = parent->isTemplateDeclaration()) != NULL && 875: td->onemember == this) 876: { /* It's a function template 877: */ 878: unsigned o = buf->offset; 879: 880: declarationToDocBuffer(this, buf, td); 881: 882: highlightCode(NULL, this, buf, o); 883: } 884: else 885: { 886: Declaration::toDocBuffer(buf); 887: } 888: } 889: } 890: 891: #if DMDV1 892: void CtorDeclaration::toDocBuffer(OutBuffer *buf) 893: { 894: HdrGenState hgs; 895: 896: buf->writestring("this"); 897: Parameter::argsToCBuffer(buf, &hgs, arguments, varargs); 898: buf->writestring(";\n"); 899: } 900: #endif 901: 902: void AggregateDeclaration::toDocBuffer(OutBuffer *buf) 903: { 904: if (ident) 905: { 906: #if 0 907: emitProtection(buf, protection); 908: #endif 909: buf->printf("%s $(DDOC_PSYMBOL %s)", kind(), toChars()); 910: buf->writestring(";\n"); 911: } 912: } 913: 914: void StructDeclaration::toDocBuffer(OutBuffer *buf) 915: { 916: //printf("StructDeclaration::toDocbuffer() %s\n", toChars()); 917: if (ident) 918: { 919: #if 0 920: emitProtection(buf, protection); 921: #endif 922: TemplateDeclaration *td; 923: 924: if (parent && 925: (td = parent->isTemplateDeclaration()) != NULL && 926: td->onemember == this) 927: { unsigned o = buf->offset; 928: td->toDocBuffer(buf); 929: highlightCode(NULL, this, buf, o); 930: } 931: else 932: { 933: buf->printf("%s $(DDOC_PSYMBOL %s)", kind(), toChars()); 934: } 935: buf->writestring(";\n"); 936: } 937: } 938: 939: void ClassDeclaration::toDocBuffer(OutBuffer *buf) 940: { 941: //printf("ClassDeclaration::toDocbuffer() %s\n", toChars()); 942: if (ident) 943: { 944: #if 0 945: emitProtection(buf, protection); 946: #endif 947: TemplateDeclaration *td; 948: 949: if (parent && 950: (td = parent->isTemplateDeclaration()) != NULL && 951: td->onemember == this) 952: { unsigned o = buf->offset; 953: td->toDocBuffer(buf); 954: highlightCode(NULL, this, buf, o); 955: } 956: else 957: { 958: if (isAbstract()) 959: buf->writestring("abstract "); 960: buf->printf("%s $(DDOC_PSYMBOL %s)", kind(), toChars()); 961: } 962: int any = 0; 963: for (int i = 0; i < baseclasses->dim; i++)
warning C4018: '<' : signed/unsigned mismatch
964: { BaseClass *bc = baseclasses->tdata()[i]; 965: 966: if (bc->protection == PROTprivate) 967: continue; 968: if (bc->base && bc->base->ident == Id::Object) 969: continue; 970: 971: if (any) 972: buf->writestring(", "); 973: else 974: { buf->writestring(": "); 975: any = 1; 976: } 977: emitProtection(buf, bc->protection); 978: if (bc->base) 979: { 980: buf->writestring(bc->base->toPrettyChars()); 981: } 982: else 983: { 984: HdrGenState hgs; 985: bc->type->toCBuffer(buf, NULL, &hgs); 986: } 987: } 988: buf->writestring(";\n"); 989: } 990: } 991: 992: 993: void EnumDeclaration::toDocBuffer(OutBuffer *buf) 994: { 995: if (ident) 996: { 997: buf->printf("%s $(DDOC_PSYMBOL %s)", kind(), toChars()); 998: buf->writestring(";\n"); 999: } 1000: } 1001: 1002: void EnumMember::toDocBuffer(OutBuffer *buf) 1003: { 1004: if (ident) 1005: { 1006: buf->writestring(toChars()); 1007: } 1008: } 1009: 1010: 1011: /********************************* DocComment *********************************/ 1012: 1013: DocComment::DocComment() 1014: { 1015: memset(this, 0, sizeof(DocComment)); 1016: } 1017: 1018: DocComment *DocComment::parse(Scope *sc, Dsymbol *s, unsigned char *comment) 1019: { unsigned idlen;
warning C4101: 'idlen' : unreferenced local variable
1020: 1021: //printf("parse(%s): '%s'\n", s->toChars(), comment); 1022: if (sc->lastdc && isDitto(comment)) 1023: return NULL; 1024: 1025: DocComment *dc = new DocComment(); 1026: if (!comment) 1027: return dc; 1028: 1029: dc->parseSections(comment); 1030: 1031: for (int i = 0; i < dc->sections.dim; i++)
warning C4018: '<' : signed/unsigned mismatch
1032: { Section *s = dc->sections.tdata()[i];
warning C6246: Local declaration of 's' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '1018' of 'c:\projects\extern\d\dmd\src\doc.c': Lines: 1018
1033: 1034: if (icmp("copyright", s->name, s->namelen) == 0) 1035: { 1036: dc->copyright = s; 1037: } 1038: if (icmp("macros", s->name, s->namelen) == 0) 1039: { 1040: dc->macros = s; 1041: } 1042: } 1043: 1044: sc->lastdc = dc; 1045: return dc; 1046: } 1047: 1048: /***************************************** 1049: * Parse next paragraph out of *pcomment. 1050: * Update *pcomment to point past paragraph. 1051: * Returns NULL if no more paragraphs. 1052: * If paragraph ends in 'identifier:', 1053: * then (*pcomment)[0 .. idlen] is the identifier. 1054: */ 1055: 1056: void DocComment::parseSections(unsigned char *comment) 1057: { unsigned char *p; 1058: unsigned char *pstart; 1059: unsigned char *pend; 1060: unsigned char *idstart; 1061: unsigned idlen; 1062: 1063: unsigned char *name = NULL; 1064: unsigned namelen = 0; 1065: 1066: //printf("parseSections('%s')\n", comment); 1067: p = comment; 1068: while (*p) 1069: { 1070: p = skipwhitespace(p); 1071: pstart = p; 1072: pend = p; 1073: 1074: /* Find end of section, which is ended by one of: 1075: * 'identifier:' (but not inside a code section) 1076: * '\0' 1077: */ 1078: idlen = 0; 1079: int inCode = 0; 1080: while (1) 1081: { 1082: // Check for start/end of a code section 1083: if (*p == '-') 1084: { 1085: int numdash = 0; 1086: while (*p == '-') 1087: { 1088: ++numdash; 1089: p++; 1090: } 1091: // BUG: handle UTF PS and LS too 1092: if (!*p || *p == '\r' || *p == '\n' && numdash >= 3) 1093: inCode ^= 1; 1094: pend = p; 1095: } 1096: 1097: if (!inCode && isIdStart(p)) 1098: { 1099: unsigned char *q = p + utfStride(p); 1100: while (isIdTail(q)) 1101: q += utfStride(q); 1102: if (*q == ':') // identifier: ends it 1103: { idlen = q - p; 1104: idstart = p; 1105: for (pend = p; pend > pstart; pend--) 1106: { if (pend[-1] == '\n') 1107: break; 1108: } 1109: p = q + 1; 1110: break; 1111: } 1112: } 1113: while (1) 1114: { 1115: if (!*p) 1116: goto L1; 1117: if (*p == '\n') 1118: { p++; 1119: if (*p == '\n' && !summary && !namelen) 1120: { 1121: pend = p; 1122: p++; 1123: goto L1; 1124: } 1125: break; 1126: } 1127: p++; 1128: pend = p; 1129: } 1130: p = skipwhitespace(p); 1131: } 1132: L1: 1133: 1134: if (namelen || pstart < pend) 1135: { 1136: Section *s; 1137: if (icmp("Params", name, namelen) == 0) 1138: s = new ParamSection(); 1139: else if (icmp("Macros", name, namelen) == 0) 1140: s = new MacroSection(); 1141: else 1142: s = new Section(); 1143: s->name = name; 1144: s->namelen = namelen; 1145: s->body = pstart; 1146: s->bodylen = pend - pstart; 1147: s->nooutput = 0; 1148: 1149: //printf("Section: '%.*s' = '%.*s'\n", s->namelen, s->name, s->bodylen, s->body); 1150: 1151: sections.push(s); 1152: 1153: if (!summary && !namelen) 1154: summary = s; 1155: } 1156: 1157: if (idlen) 1158: { name = idstart; 1159: namelen = idlen; 1160: } 1161: else 1162: { name = NULL; 1163: namelen = 0; 1164: if (!*p) 1165: break; 1166: } 1167: } 1168: } 1169: 1170: void DocComment::writeSections(Scope *sc, Dsymbol *s, OutBuffer *buf) 1171: { 1172: //printf("DocComment::writeSections()\n"); 1173: if (sections.dim) 1174: { 1175: buf->writestring("$(DDOC_SECTIONS \n"); 1176: for (int i = 0; i < sections.dim; i++)
warning C4018: '<' : signed/unsigned mismatch
1177: { Section *sec = sections.tdata()[i]; 1178: 1179: if (sec->nooutput) 1180: continue; 1181: //printf("Section: '%.*s' = '%.*s'\n", sec->namelen, sec->name, sec->bodylen, sec->body); 1182: if (sec->namelen || i) 1183: sec->write(this, sc, s, buf); 1184: else 1185: { 1186: buf->writestring("$(DDOC_SUMMARY "); 1187: unsigned o = buf->offset; 1188: buf->write(sec->body, sec->bodylen); 1189: escapeStrayParenthesis(buf, o, s->loc); 1190: highlightText(sc, s, buf, o); 1191: buf->writestring(")\n"); 1192: } 1193: } 1194: buf->writestring(")\n"); 1195: } 1196: else 1197: { 1198: buf->writestring("$(DDOC_BLANKLINE)\n"); 1199: } 1200: } 1201: 1202: /*************************************************** 1203: */ 1204: 1205: void Section::write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf) 1206: { 1207: if (namelen) 1208: { 1209: static const char *table[] = 1210: { "AUTHORS", "BUGS", "COPYRIGHT", "DATE", 1211: "DEPRECATED", "EXAMPLES", "HISTORY", "LICENSE", 1212: "RETURNS", "SEE_ALSO", "STANDARDS", "THROWS", 1213: "VERSION" }; 1214: 1215: for (int i = 0; i < sizeof(table) / sizeof(table[0]); i++) 1216: { 1217: if (icmp(table[i], name, namelen) == 0) 1218: { 1219: buf->printf("$(DDOC_%s ", table[i]); 1220: goto L1; 1221: } 1222: } 1223: 1224: buf->writestring("$(DDOC_SECTION "); 1225: // Replace _ characters with spaces 1226: buf->writestring("$(DDOC_SECTION_H "); 1227: unsigned o = buf->offset; 1228: for (unsigned u = 0; u < namelen; u++) 1229: { unsigned char c = name[u]; 1230: buf->writeByte((c == '_') ? ' ' : c); 1231: } 1232: escapeStrayParenthesis(buf, o, s->loc); 1233: buf->writestring(":)\n"); 1234: } 1235: else 1236: { 1237: buf->writestring("$(DDOC_DESCRIPTION "); 1238: } 1239: L1: 1240: unsigned o = buf->offset; 1241: buf->write(body, bodylen); 1242: escapeStrayParenthesis(buf, o, s->loc); 1243: highlightText(sc, s, buf, o); 1244: buf->writestring(")\n"); 1245: } 1246: 1247: /*************************************************** 1248: */ 1249: 1250: void ParamSection::write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf) 1251: { 1252: unsigned char *p = body; 1253: unsigned len = bodylen; 1254: unsigned char *pend = p + len; 1255: 1256: unsigned char *tempstart; 1257: unsigned templen; 1258: 1259: unsigned char *namestart; 1260: unsigned namelen = 0; // !=0 if line continuation 1261: 1262: unsigned char *textstart; 1263: unsigned textlen; 1264: 1265: unsigned o; 1266: Parameter *arg; 1267: 1268: buf->writestring("$(DDOC_PARAMS \n"); 1269: while (p < pend) 1270: { 1271: // Skip to start of macro 1272: while (1) 1273: { 1274: switch (*p) 1275: { 1276: case ' ': 1277: case '\t': 1278: p++; 1279: continue; 1280: 1281: case '\n': 1282: p++; 1283: goto Lcont; 1284: 1285: default: 1286: if (isIdStart(p)) 1287: break; 1288: if (namelen) 1289: goto Ltext; // continuation of prev macro 1290: goto Lskipline; 1291: } 1292: break; 1293: } 1294: tempstart = p; 1295: 1296: while (isIdTail(p)) 1297: p += utfStride(p); 1298: templen = p - tempstart; 1299: 1300: while (*p == ' ' || *p == '\t') 1301: p++; 1302: 1303: if (*p != '=') 1304: { if (namelen) 1305: goto Ltext; // continuation of prev macro 1306: goto Lskipline; 1307: } 1308: p++; 1309: 1310: if (namelen) 1311: { // Output existing param 1312: 1313: L1: 1314: //printf("param '%.*s' = '%.*s'\n", namelen, namestart, textlen, textstart); 1315: HdrGenState hgs; 1316: buf->writestring("$(DDOC_PARAM_ROW "); 1317: buf->writestring("$(DDOC_PARAM_ID "); 1318: o = buf->offset; 1319: arg = isFunctionParameter(s, namestart, namelen); 1320: if (arg && arg->type && arg->ident) 1321: arg->type->toCBuffer(buf, arg->ident, &hgs); 1322: else 1323: buf->write(namestart, namelen); 1324: escapeStrayParenthesis(buf, o, s->loc); 1325: highlightCode(sc, s, buf, o); 1326: buf->writestring(")\n"); 1327: 1328: buf->writestring("$(DDOC_PARAM_DESC "); 1329: o = buf->offset; 1330: buf->write(textstart, textlen); 1331: escapeStrayParenthesis(buf, o, s->loc); 1332: highlightText(sc, s, buf, o); 1333: buf->writestring(")"); 1334: buf->writestring(")\n"); 1335: namelen = 0; 1336: if (p >= pend) 1337: break; 1338: } 1339: 1340: namestart = tempstart; 1341: namelen = templen; 1342: 1343: while (*p == ' ' || *p == '\t') 1344: p++; 1345: textstart = p; 1346: 1347: Ltext: 1348: while (*p != '\n') 1349: p++; 1350: textlen = p - textstart; 1351: p++; 1352: 1353: Lcont: 1354: continue; 1355: 1356: Lskipline: 1357: // Ignore this line 1358: while (*p++ != '\n') 1359: ; 1360: } 1361: if (namelen) 1362: goto L1; // write out last one 1363: buf->writestring(")\n"); 1364: } 1365: 1366: /*************************************************** 1367: */ 1368: 1369: void MacroSection::write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf) 1370: { 1371: //printf("MacroSection::write()\n"); 1372: DocComment::parseMacros(dc->pescapetable, dc->pmacrotable, body, bodylen); 1373: } 1374: 1375: /************************************************ 1376: * Parse macros out of Macros: section. 1377: * Macros are of the form: 1378: * name1 = value1 1379: * 1380: * name2 = value2 1381: */ 1382: 1383: void DocComment::parseMacros(Escape **pescapetable, Macro **pmacrotable, unsigned char *m, unsigned mlen) 1384: { 1385: unsigned char *p = m; 1386: unsigned len = mlen; 1387: unsigned char *pend = p + len; 1388: 1389: unsigned char *tempstart; 1390: unsigned templen; 1391: 1392: unsigned char *namestart; 1393: unsigned namelen = 0; // !=0 if line continuation 1394: 1395: unsigned char *textstart; 1396: unsigned textlen; 1397: 1398: while (p < pend) 1399: { 1400: // Skip to start of macro 1401: while (1) 1402: { 1403: if (p >= pend) 1404: goto Ldone; 1405: switch (*p) 1406: { 1407: case ' ': 1408: case '\t': 1409: p++; 1410: continue; 1411: 1412: case '\n': 1413: p++; 1414: goto Lcont; 1415: 1416: default: 1417: if (isIdStart(p)) 1418: break; 1419: if (namelen) 1420: goto Ltext; // continuation of prev macro 1421: goto Lskipline; 1422: } 1423: break; 1424: } 1425: tempstart = p; 1426: 1427: while (1) 1428: { 1429: if (p >= pend) 1430: goto Ldone; 1431: if (!isIdTail(p)) 1432: break; 1433: p += utfStride(p); 1434: } 1435: templen = p - tempstart; 1436: 1437: while (1) 1438: { 1439: if (p >= pend) 1440: goto Ldone; 1441: if (!(*p == ' ' || *p == '\t')) 1442: break; 1443: p++; 1444: } 1445: 1446: if (*p != '=') 1447: { if (namelen) 1448: goto Ltext; // continuation of prev macro 1449: goto Lskipline; 1450: } 1451: p++; 1452: if (p >= pend) 1453: goto Ldone; 1454: 1455: if (namelen) 1456: { // Output existing macro 1457: L1: 1458: //printf("macro '%.*s' = '%.*s'\n", namelen, namestart, textlen, textstart); 1459: if (icmp("ESCAPES", namestart, namelen) == 0) 1460: parseEscapes(pescapetable, textstart, textlen); 1461: else 1462: Macro::define(pmacrotable, namestart, namelen, textstart, textlen); 1463: namelen = 0; 1464: if (p >= pend) 1465: break; 1466: } 1467: 1468: namestart = tempstart; 1469: namelen = templen; 1470: 1471: while (p < pend && (*p == ' ' || *p == '\t')) 1472: p++; 1473: textstart = p; 1474: 1475: Ltext: 1476: while (p < pend && *p != '\n') 1477: p++; 1478: textlen = p - textstart; 1479: 1480: // Remove trailing \r if there is one 1481: if (p > m && p[-1] == '\r') 1482: textlen--; 1483: 1484: p++; 1485: //printf("p = %p, pend = %p\n", p, pend); 1486: 1487: Lcont: 1488: continue; 1489: 1490: Lskipline: 1491: // Ignore this line 1492: while (p < pend && *p++ != '\n') 1493: ; 1494: } 1495: Ldone: 1496: if (namelen) 1497: goto L1; // write out last one 1498: } 1499: 1500: /************************************** 1501: * Parse escapes of the form: 1502: * /c/string/ 1503: * where c is a single character. 1504: * Multiple escapes can be separated 1505: * by whitespace and/or commas. 1506: */ 1507: 1508: void DocComment::parseEscapes(Escape **pescapetable, unsigned char *textstart, unsigned textlen) 1509: { Escape *escapetable = *pescapetable; 1510: 1511: if (!escapetable) 1512: { escapetable = new Escape; 1513: *pescapetable = escapetable; 1514: } 1515: unsigned char *p = textstart; 1516: unsigned char *pend = p + textlen; 1517: 1518: while (1) 1519: { 1520: while (1) 1521: { 1522: if (p + 4 >= pend) 1523: return; 1524: if (!(*p == ' ' || *p == '\t' || *p == '\n' || *p == ',')) 1525: break; 1526: p++; 1527: } 1528: if (p[0] != '/' || p[2] != '/') 1529: return; 1530: unsigned char c = p[1]; 1531: p += 3; 1532: unsigned char *start = p; 1533: while (1) 1534: { 1535: if (p >= pend) 1536: return; 1537: if (*p == '/') 1538: break; 1539: p++; 1540: } 1541: size_t len = p - start; 1542: char *s = (char *)memcpy(mem.malloc(len + 1), start, len); 1543: s[len] = 0; 1544: escapetable->strings[c] = s; 1545: //printf("%c = '%s'\n", c, s); 1546: p++; 1547: } 1548: } 1549: 1550: 1551: /****************************************** 1552: * Compare 0-terminated string with length terminated string. 1553: * Return < 0, ==0, > 0 1554: */ 1555: 1556: int cmp(const char *stringz, void *s, size_t slen) 1557: { 1558: size_t len1 = strlen(stringz); 1559: 1560: if (len1 != slen) 1561: return len1 - slen; 1562: return memcmp(stringz, s, slen); 1563: } 1564: 1565: int icmp(const char *stringz, void *s, size_t slen) 1566: { 1567: size_t len1 = strlen(stringz); 1568: 1569: if (len1 != slen) 1570: return len1 - slen; 1571: return memicmp(stringz, (char *)s, slen);
warning C4996: 'memicmp': The POSIX name for this item is deprecated. Instead, use the ISO C++ conformant name: _memicmp. See online help for details. c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\string.h(93) : see declaration of 'memicmp'
1572: } 1573: 1574: /***************************************** 1575: * Return !=0 if comment consists entirely of "ditto". 1576: */ 1577: 1578: int isDitto(unsigned char *comment) 1579: { 1580: if (comment) 1581: { 1582: unsigned char *p = skipwhitespace(comment); 1583: 1584: if (memicmp((char *)p, "ditto", 5) == 0 && *skipwhitespace(p + 5) == 0)
warning C4996: 'memicmp': The POSIX name for this item is deprecated. Instead, use the ISO C++ conformant name: _memicmp. See online help for details. c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\string.h(93) : see declaration of 'memicmp'
1585: return 1; 1586: } 1587: return 0; 1588: } 1589: 1590: /********************************************** 1591: * Skip white space. 1592: */ 1593: 1594: unsigned char *skipwhitespace(unsigned char *p) 1595: { 1596: for (; 1; p++) 1597: { switch (*p) 1598: { 1599: case ' ': 1600: case '\t': 1601: case '\n': 1602: continue; 1603: } 1604: break; 1605: } 1606: return p; 1607: } 1608: 1609: 1610: /************************************************ 1611: * Scan forward to one of: 1612: * start of identifier 1613: * beginning of next line 1614: * end of buf 1615: */ 1616: 1617: unsigned skiptoident(OutBuffer *buf, size_t i) 1618: { 1619: while (i < buf->offset) 1620: { dchar_t c; 1621: 1622: size_t oi = i; 1623: if (utf_decodeChar((unsigned char *)buf->data, buf->offset, &i, &c)) 1624: /* Ignore UTF errors, but still consume input 1625: */ 1626: break; 1627: if (c >= 0x80) 1628: { 1629: if (!isUniAlpha(c)) 1630: continue; 1631: } 1632: else if (!(isalpha(c) || c == '_' || c == '\n')) 1633: continue; 1634: i = oi; 1635: break; 1636: } 1637: return i; 1638: } 1639: 1640: /************************************************ 1641: * Scan forward past end of identifier. 1642: */ 1643: 1644: unsigned skippastident(OutBuffer *buf, size_t i) 1645: { 1646: while (i < buf->offset) 1647: { dchar_t c; 1648: 1649: size_t oi = i; 1650: if (utf_decodeChar((unsigned char *)buf->data, buf->offset, &i, &c)) 1651: /* Ignore UTF errors, but still consume input 1652: */ 1653: break; 1654: if (c >= 0x80) 1655: { 1656: if (isUniAlpha(c)) 1657: continue; 1658: } 1659: else if (isalnum(c) || c == '_') 1660: continue; 1661: i = oi; 1662: break; 1663: } 1664: return i; 1665: } 1666: 1667: 1668: /************************************************ 1669: * Scan forward past URL starting at i. 1670: * We don't want to highlight parts of a URL. 1671: * Returns: 1672: * i if not a URL 1673: * index just past it if it is a URL 1674: */ 1675: 1676: unsigned skippastURL(OutBuffer *buf, size_t i) 1677: { unsigned length = buf->offset - i; 1678: unsigned char *p = &buf->data[i]; 1679: unsigned j; 1680: unsigned sawdot = 0; 1681: 1682: if (length > 7 && memicmp((char *)p, "http://", 7) == 0)
warning C4996: 'memicmp': The POSIX name for this item is deprecated. Instead, use the ISO C++ conformant name: _memicmp. See online help for details. c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\string.h(93) : see declaration of 'memicmp'
1683: { 1684: j = 7; 1685: } 1686: else if (length > 8 && memicmp((char *)p, "https://", 8) == 0)
warning C4996: 'memicmp': The POSIX name for this item is deprecated. Instead, use the ISO C++ conformant name: _memicmp. See online help for details. c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\string.h(93) : see declaration of 'memicmp'
1687: { 1688: j = 8; 1689: } 1690: else 1691: goto Lno; 1692: 1693: for (; j < length; j++) 1694: { unsigned char c = p[j]; 1695: if (isalnum(c)) 1696: continue; 1697: if (c == '-' || c == '_' || c == '?' || 1698: c == '=' || c == '%' || c == '&' || 1699: c == '/' || c == '+' || c == '#' || 1700: c == '~') 1701: continue; 1702: if (c == '.') 1703: { 1704: sawdot = 1; 1705: continue; 1706: } 1707: break; 1708: } 1709: if (sawdot) 1710: return i + j; 1711: 1712: Lno: 1713: return i; 1714: } 1715: 1716: 1717: /**************************************************** 1718: */ 1719: 1720: int isKeyword(unsigned char *p, unsigned len) 1721: { 1722: static const char *table[] = { "true", "false", "null" }; 1723: 1724: for (int i = 0; i < sizeof(table) / sizeof(table[0]); i++) 1725: { 1726: if (cmp(table[i], p, len) == 0) 1727: return 1; 1728: } 1729: return 0; 1730: } 1731: 1732: /**************************************************** 1733: */ 1734: 1735: Parameter *isFunctionParameter(Dsymbol *s, unsigned char *p, unsigned len) 1736: { 1737: FuncDeclaration *f = s->isFuncDeclaration(); 1738: 1739: /* f->type may be NULL for template members. 1740: */ 1741: if (f && f->type) 1742: { 1743: TypeFunction *tf; 1744: if (f->originalType) 1745: { 1746: tf = (TypeFunction *)f->originalType; 1747: } 1748: else 1749: tf = (TypeFunction *)f->type; 1750: 1751: if (tf->parameters) 1752: { 1753: for (size_t k = 0; k < tf->parameters->dim; k++) 1754: { Parameter *arg = tf->parameters->tdata()[k]; 1755: 1756: if (arg->ident && cmp(arg->ident->toChars(), p, len) == 0) 1757: { 1758: return arg; 1759: } 1760: } 1761: } 1762: } 1763: return NULL; 1764: } 1765: 1766: /************************************************** 1767: * Highlight text section. 1768: */ 1769: 1770: void highlightText(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset) 1771: { 1772: //printf("highlightText()\n"); 1773: const char *sid = s->ident->toChars(); 1774: FuncDeclaration *f = s->isFuncDeclaration(); 1775: unsigned char *p; 1776: const char *se; 1777: 1778: int leadingBlank = 1; 1779: int inCode = 0; 1780: int inComment = 0; // in <!-- ... --> comment 1781: unsigned iCodeStart; // start of code section 1782: 1783: unsigned iLineStart = offset; 1784: 1785: for (unsigned i = offset; i < buf->offset; i++) 1786: { unsigned char c = buf->data[i]; 1787: 1788: Lcont: 1789: switch (c) 1790: { 1791: case ' ': 1792: case '\t': 1793: break; 1794: 1795: case '\n': 1796: if (sc && !inCode && i == iLineStart && i + 1 < buf->offset) // if "\n\n" 1797: { 1798: static char blankline[] = "$(DDOC_BLANKLINE)\n"; 1799: 1800: i = buf->insert(i, blankline, sizeof(blankline) - 1); 1801: } 1802: leadingBlank = 1; 1803: iLineStart = i + 1; 1804: break; 1805: 1806: case '<': 1807: leadingBlank = 0; 1808: if (inCode) 1809: break; 1810: p = &buf->data[i]; 1811: 1812: // Skip over comments 1813: if (p[1] == '!' && p[2] == '-' && p[3] == '-') 1814: { unsigned j = i + 4; 1815: p += 4; 1816: while (1) 1817: { 1818: if (j == buf->offset) 1819: goto L1; 1820: if (p[0] == '-' && p[1] == '-' && p[2] == '>') 1821: { 1822: i = j + 2; // place on closing '>' 1823: break; 1824: } 1825: j++; 1826: p++; 1827: } 1828: break; 1829: } 1830: 1831: // Skip over HTML tag 1832: if (isalpha(p[1]) || (p[1] == '/' && isalpha(p[2]))) 1833: { unsigned j = i + 2; 1834: p += 2; 1835: while (1) 1836: { 1837: if (j == buf->offset) 1838: goto L1; 1839: if (p[0] == '>') 1840: { 1841: i = j; // place on closing '>' 1842: break; 1843: } 1844: j++; 1845: p++; 1846: } 1847: break; 1848: } 1849: 1850: L1: 1851: // Replace '<' with '&lt;' character entity 1852: se = Escape::escapeChar('<'); 1853: if (se) 1854: { size_t len = strlen(se); 1855: buf->remove(i, 1); 1856: i = buf->insert(i, se, len); 1857: i--; // point to ';' 1858: } 1859: break; 1860: 1861: case '>': 1862: leadingBlank = 0; 1863: if (inCode) 1864: break; 1865: // Replace '>' with '&gt;' character entity 1866: se = Escape::escapeChar('>'); 1867: if (se) 1868: { size_t len = strlen(se); 1869: buf->remove(i, 1); 1870: i = buf->insert(i, se, len); 1871: i--; // point to ';' 1872: } 1873: break; 1874: 1875: case '&': 1876: leadingBlank = 0; 1877: if (inCode) 1878: break; 1879: p = &buf->data[i]; 1880: if (p[1] == '#' || isalpha(p[1])) 1881: break; // already a character entity 1882: // Replace '&' with '&amp;' character entity 1883: se = Escape::escapeChar('&'); 1884: if (se) 1885: { size_t len = strlen(se); 1886: buf->remove(i, 1); 1887: i = buf->insert(i, se, len); 1888: i--; // point to ';' 1889: } 1890: break; 1891: 1892: case '-': 1893: /* A line beginning with --- delimits a code section. 1894: * inCode tells us if it is start or end of a code section. 1895: */ 1896: if (leadingBlank) 1897: { int istart = i; 1898: int eollen = 0; 1899: 1900: leadingBlank = 0; 1901: while (1) 1902: { 1903: ++i; 1904: if (i >= buf->offset) 1905: break; 1906: c = buf->data[i]; 1907: if (c == '\n') 1908: { eollen = 1; 1909: break; 1910: } 1911: if (c == '\r') 1912: { 1913: eollen = 1; 1914: if (i + 1 >= buf->offset) 1915: break; 1916: if (buf->data[i + 1] == '\n') 1917: { eollen = 2; 1918: break; 1919: } 1920: } 1921: // BUG: handle UTF PS and LS too 1922: if (c != '-') 1923: goto Lcont; 1924: } 1925: if (i - istart < 3) 1926: goto Lcont; 1927: 1928: // We have the start/end of a code section 1929: 1930: // Remove the entire --- line, including blanks and \n 1931: buf->remove(iLineStart, i - iLineStart + eollen); 1932: i = iLineStart; 1933: 1934: if (inCode && (i <= iCodeStart)) 1935: { // Empty code section, just remove it completely. 1936: inCode = 0; 1937: break; 1938: } 1939: 1940: if (inCode) 1941: { 1942: inCode = 0; 1943: // The code section is from iCodeStart to i 1944: OutBuffer codebuf; 1945: 1946: codebuf.write(buf->data + iCodeStart, i - iCodeStart); 1947: codebuf.writeByte(0); 1948: highlightCode2(sc, s, &codebuf, 0); 1949: buf->remove(iCodeStart, i - iCodeStart); 1950: i = buf->insert(iCodeStart, codebuf.data, codebuf.offset); 1951: i = buf->insert(i, ")\n", 2); 1952: i--; 1953: } 1954: else 1955: { static char pre[] = "$(D_CODE \n"; 1956: 1957: inCode = 1; 1958: i = buf->insert(i, pre, sizeof(pre) - 1); 1959: iCodeStart = i; 1960: i--; // place i on > 1961: leadingBlank = true; 1962: } 1963: } 1964: break; 1965: 1966: default: 1967: leadingBlank = 0; 1968: if (sc && !inCode && isIdStart(&buf->data[i])) 1969: { unsigned j; 1970: 1971: j = skippastident(buf, i); 1972: if (j > i) 1973: { 1974: unsigned k = skippastURL(buf, i); 1975: if (k > i) 1976: { i = k - 1; 1977: break; 1978: } 1979: 1980: if (buf->data[i] == '_') // leading '_' means no highlight 1981: { 1982: buf->remove(i, 1); 1983: i = j - 1; 1984: } 1985: else 1986: { 1987: if (cmp(sid, buf->data + i, j - i) == 0) 1988: { 1989: i = buf->bracket(i, "$(DDOC_PSYMBOL ", j, ")") - 1; 1990: break; 1991: } 1992: else if (isKeyword(buf->data + i, j - i)) 1993: { 1994: i = buf->bracket(i, "$(DDOC_KEYWORD ", j, ")") - 1; 1995: break; 1996: } 1997: else 1998: { 1999: if (f && isFunctionParameter(f, buf->data + i, j - i)) 2000: { 2001: //printf("highlighting arg '%s', i = %d, j = %d\n", arg->ident->toChars(), i, j); 2002: i = buf->bracket(i, "$(DDOC_PARAM ", j, ")") - 1; 2003: break; 2004: } 2005: } 2006: i = j - 1; 2007: } 2008: } 2009: } 2010: break; 2011: } 2012: } 2013: Ldone:
warning C4102: 'Ldone' : unreferenced label
2014: if (inCode) 2015: s->error("unmatched --- in DDoc comment"); 2016: ; 2017: } 2018: 2019: /************************************************** 2020: * Highlight code for DDOC section. 2021: */ 2022: 2023: void highlightCode(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset) 2024: { 2025: char *sid = s->ident->toChars(); 2026: FuncDeclaration *f = s->isFuncDeclaration(); 2027: 2028: //printf("highlightCode(s = '%s', kind = %s)\n", sid, s->kind()); 2029: for (unsigned i = offset; i < buf->offset; i++) 2030: { unsigned char c = buf->data[i]; 2031: const char *se; 2032: 2033: se = Escape::escapeChar(c); 2034: if (se) 2035: { 2036: size_t len = strlen(se); 2037: buf->remove(i, 1); 2038: i = buf->insert(i, se, len); 2039: i--; // point to ';' 2040: } 2041: else if (isIdStart(&buf->data[i])) 2042: { unsigned j; 2043: 2044: j = skippastident(buf, i); 2045: if (j > i) 2046: { 2047: if (cmp(sid, buf->data + i, j - i) == 0) 2048: { 2049: i = buf->bracket(i, "$(DDOC_PSYMBOL ", j, ")") - 1; 2050: continue; 2051: } 2052: else if (f) 2053: { 2054: if (isFunctionParameter(f, buf->data + i, j - i)) 2055: { 2056: //printf("highlighting arg '%s', i = %d, j = %d\n", arg->ident->toChars(), i, j); 2057: i = buf->bracket(i, "$(DDOC_PARAM ", j, ")") - 1; 2058: continue; 2059: } 2060: } 2061: i = j - 1; 2062: } 2063: } 2064: } 2065: } 2066: 2067: /**************************************** 2068: */ 2069: 2070: void highlightCode3(OutBuffer *buf, unsigned char *p, unsigned char *pend) 2071: { 2072: for (; p < pend; p++) 2073: { const char *s = Escape::escapeChar(*p); 2074: if (s) 2075: buf->writestring(s); 2076: else 2077: buf->writeByte(*p); 2078: } 2079: } 2080: 2081: /************************************************** 2082: * Highlight code for CODE section. 2083: */ 2084: 2085: 2086: void highlightCode2(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset) 2087: { 2088: char *sid = s->ident->toChars(); 2089: FuncDeclaration *f = s->isFuncDeclaration(); 2090: unsigned errorsave = global.errors; 2091: Lexer lex(NULL, buf->data, 0, buf->offset - 1, 0, 1); 2092: Token tok; 2093: OutBuffer res; 2094: unsigned char *lastp = buf->data; 2095: const char *highlight; 2096: 2097: //printf("highlightCode2('%.*s')\n", buf->offset - 1, buf->data); 2098: res.reserve(buf->offset); 2099: while (1) 2100: { 2101: lex.scan(&tok); 2102: highlightCode3(&res, lastp, tok.ptr); 2103: highlight = NULL; 2104: switch (tok.value) 2105: { 2106: case TOKidentifier: 2107: if (!sc) 2108: break; 2109: if (cmp(sid, tok.ptr, lex.p - tok.ptr) == 0) 2110: { 2111: highlight = "$(D_PSYMBOL "; 2112: break; 2113: } 2114: else if (f) 2115: { 2116: if (isFunctionParameter(f, tok.ptr, lex.p - tok.ptr)) 2117: { 2118: //printf("highlighting arg '%s', i = %d, j = %d\n", arg->ident->toChars(), i, j); 2119: highlight = "$(D_PARAM "; 2120: break; 2121: } 2122: } 2123: break; 2124: 2125: case TOKcomment: 2126: highlight = "$(D_COMMENT "; 2127: break; 2128: 2129: case TOKstring: 2130: highlight = "$(D_STRING "; 2131: break; 2132: 2133: default: 2134: if (tok.isKeyword()) 2135: highlight = "$(D_KEYWORD "; 2136: break; 2137: } 2138: if (highlight) 2139: res.writestring(highlight); 2140: highlightCode3(&res, tok.ptr, lex.p); 2141: if (highlight) 2142: res.writeByte(')'); 2143: if (tok.value == TOKeof) 2144: break; 2145: lastp = lex.p; 2146: } 2147: buf->setsize(offset); 2148: buf->write(&res); 2149: global.errors = errorsave; 2150: } 2151: 2152: /*************************************** 2153: * Find character string to replace c with. 2154: */ 2155: 2156: const char *Escape::escapeChar(unsigned c) 2157: { const char *s; 2158: 2159: switch (c) 2160: { 2161: case '<': 2162: s = "&lt;"; 2163: break; 2164: case '>': 2165: s = "&gt;"; 2166: break; 2167: case '&': 2168: s = "&amp;"; 2169: break; 2170: default: 2171: s = NULL; 2172: break; 2173: } 2174: return s; 2175: } 2176: 2177: /**************************************** 2178: * Determine if p points to the start of an identifier. 2179: */ 2180: 2181: int isIdStart(unsigned char *p) 2182: { 2183: unsigned c = *p; 2184: if (isalpha(c) || c == '_') 2185: return 1; 2186: if (c >= 0x80) 2187: { size_t i = 0; 2188: if (utf_decodeChar(p, 4, &i, &c)) 2189: return 0; // ignore errors 2190: if (isUniAlpha(c)) 2191: return 1; 2192: } 2193: return 0; 2194: } 2195: 2196: /**************************************** 2197: * Determine if p points to the rest of an identifier. 2198: */ 2199: 2200: int isIdTail(unsigned char *p) 2201: { 2202: unsigned c = *p; 2203: if (isalnum(c) || c == '_') 2204: return 1; 2205: if (c >= 0x80) 2206: { size_t i = 0; 2207: if (utf_decodeChar(p, 4, &i, &c)) 2208: return 0; // ignore errors 2209: if (isUniAlpha(c)) 2210: return 1; 2211: } 2212: return 0; 2213: } 2214: 2215: /***************************************** 2216: * Return number of bytes in UTF character. 2217: */ 2218: 2219: int utfStride(unsigned char *p) 2220: { 2221: unsigned c = *p; 2222: if (c < 0x80) 2223: return 1; 2224: size_t i = 0; 2225: utf_decodeChar(p, 4, &i, &c); // ignore errors, but still consume input 2226: return i; 2227: } 2228: