comparison dmd/doc.c @ 1:c53b6e3fe49a trunk

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