HTMLRewrite.cpp revision a745e8c52839d9c8dd0fd8d5276b4eab182ec7f2
16a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek//== HTMLRewrite.cpp - Translate source code into prettified HTML --*- C++ -*-//
26a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek//
36a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek//                     The LLVM Compiler Infrastructure
46a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek//
56a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek// This file is distributed under the University of Illinois Open Source
66a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek// License. See LICENSE.TXT for details.
76a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek//
86a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek//===----------------------------------------------------------------------===//
96a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek//
106a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek//  This file defines the HTMLRewriter clas, which is used to translate the
116a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek//  text of a source file into prettified HTML.
126a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek//
136a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek//===----------------------------------------------------------------------===//
146a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek
156a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek#include "clang/Rewrite/Rewriter.h"
166a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek#include "clang/Rewrite/HTMLRewrite.h"
173245a0a1c7a4fd74fca845b2edba275bb126d773Chris Lattner#include "clang/Lex/Preprocessor.h"
186a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek#include "clang/Basic/SourceManager.h"
1957df3b950061c73d13d3116f747e79d7955a216aChris Lattner#include "llvm/ADT/SmallString.h"
206a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek#include "llvm/Support/MemoryBuffer.h"
216a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek#include <sstream>
226a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenekusing namespace clang;
236a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek
24fa5be3617294f0e3c341f0ecb6b2076478b1b5acTed Kremenekvoid html::EscapeText(Rewriter& R, unsigned FileID,
25fa5be3617294f0e3c341f0ecb6b2076478b1b5acTed Kremenek                      bool EscapeSpaces, bool ReplaceTabs) {
266a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek
276a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek  const llvm::MemoryBuffer *Buf = R.getSourceMgr().getBuffer(FileID);
286a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek  const char* C = Buf->getBufferStart();
296a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek  const char* FileEnd = Buf->getBufferEnd();
306a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek
316a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek  assert (C <= FileEnd);
326a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek
33735271479ac57c27f744806859efd5b001dea248Chris Lattner  RewriteBuffer &RB = R.getEditBuffer(FileID);
34735271479ac57c27f744806859efd5b001dea248Chris Lattner
356a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek  for (unsigned FilePos = 0; C != FileEnd ; ++C, ++FilePos) {
3649cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek
376a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek    switch (*C) {
38735271479ac57c27f744806859efd5b001dea248Chris Lattner    default: break;
39735271479ac57c27f744806859efd5b001dea248Chris Lattner
40735271479ac57c27f744806859efd5b001dea248Chris Lattner    case ' ':
41735271479ac57c27f744806859efd5b001dea248Chris Lattner      if (EscapeSpaces)
42735271479ac57c27f744806859efd5b001dea248Chris Lattner        RB.ReplaceText(FilePos, 1, "&nbsp;", 6);
43735271479ac57c27f744806859efd5b001dea248Chris Lattner      break;
446a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek
45735271479ac57c27f744806859efd5b001dea248Chris Lattner    case '\t':
46735271479ac57c27f744806859efd5b001dea248Chris Lattner      if (!ReplaceTabs)
4749cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek        break;
48735271479ac57c27f744806859efd5b001dea248Chris Lattner      if (EscapeSpaces)
49735271479ac57c27f744806859efd5b001dea248Chris Lattner        RB.ReplaceText(FilePos, 1, "&nbsp;&nbsp;&nbsp;&nbsp;", 6*4);
50735271479ac57c27f744806859efd5b001dea248Chris Lattner      else
51735271479ac57c27f744806859efd5b001dea248Chris Lattner        RB.ReplaceText(FilePos, 1, "    ", 4);
52735271479ac57c27f744806859efd5b001dea248Chris Lattner      break;
53735271479ac57c27f744806859efd5b001dea248Chris Lattner
54735271479ac57c27f744806859efd5b001dea248Chris Lattner    case '<':
55735271479ac57c27f744806859efd5b001dea248Chris Lattner      RB.ReplaceText(FilePos, 1, "&lt;", 4);
56735271479ac57c27f744806859efd5b001dea248Chris Lattner      break;
57735271479ac57c27f744806859efd5b001dea248Chris Lattner
58735271479ac57c27f744806859efd5b001dea248Chris Lattner    case '>':
59735271479ac57c27f744806859efd5b001dea248Chris Lattner      RB.ReplaceText(FilePos, 1, "&gt;", 4);
60735271479ac57c27f744806859efd5b001dea248Chris Lattner      break;
61735271479ac57c27f744806859efd5b001dea248Chris Lattner
62735271479ac57c27f744806859efd5b001dea248Chris Lattner    case '&':
63735271479ac57c27f744806859efd5b001dea248Chris Lattner      RB.ReplaceText(FilePos, 1, "&amp;", 5);
64735271479ac57c27f744806859efd5b001dea248Chris Lattner      break;
656a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek    }
666a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek  }
676a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek}
686a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek
69fa5be3617294f0e3c341f0ecb6b2076478b1b5acTed Kremenekstd::string html::EscapeText(const std::string& s, bool EscapeSpaces,
70fa5be3617294f0e3c341f0ecb6b2076478b1b5acTed Kremenek                             bool ReplaceTabs) {
71053ef593fa9d2b890645a914eee203231fb34458Ted Kremenek
72053ef593fa9d2b890645a914eee203231fb34458Ted Kremenek  unsigned len = s.size();
73053ef593fa9d2b890645a914eee203231fb34458Ted Kremenek  std::ostringstream os;
74053ef593fa9d2b890645a914eee203231fb34458Ted Kremenek
75053ef593fa9d2b890645a914eee203231fb34458Ted Kremenek  for (unsigned i = 0 ; i < len; ++i) {
76053ef593fa9d2b890645a914eee203231fb34458Ted Kremenek
77053ef593fa9d2b890645a914eee203231fb34458Ted Kremenek    char c = s[i];
78053ef593fa9d2b890645a914eee203231fb34458Ted Kremenek    switch (c) {
798570f0b0fde7ca812f8d37f52305f3df4dd2ce01Chris Lattner    default:
808570f0b0fde7ca812f8d37f52305f3df4dd2ce01Chris Lattner      os << c; break;
818570f0b0fde7ca812f8d37f52305f3df4dd2ce01Chris Lattner
828570f0b0fde7ca812f8d37f52305f3df4dd2ce01Chris Lattner    case ' ':
838570f0b0fde7ca812f8d37f52305f3df4dd2ce01Chris Lattner      if (EscapeSpaces) os << "&nbsp;";
848570f0b0fde7ca812f8d37f52305f3df4dd2ce01Chris Lattner      else os << ' ';
858570f0b0fde7ca812f8d37f52305f3df4dd2ce01Chris Lattner      break;
868570f0b0fde7ca812f8d37f52305f3df4dd2ce01Chris Lattner
878570f0b0fde7ca812f8d37f52305f3df4dd2ce01Chris Lattner      case '\t':
888570f0b0fde7ca812f8d37f52305f3df4dd2ce01Chris Lattner        if (ReplaceTabs)
898570f0b0fde7ca812f8d37f52305f3df4dd2ce01Chris Lattner          for (unsigned i = 0; i < 4; ++i)
908570f0b0fde7ca812f8d37f52305f3df4dd2ce01Chris Lattner            os << "&nbsp;";
918570f0b0fde7ca812f8d37f52305f3df4dd2ce01Chris Lattner        else
928570f0b0fde7ca812f8d37f52305f3df4dd2ce01Chris Lattner          os << c;
938570f0b0fde7ca812f8d37f52305f3df4dd2ce01Chris Lattner
94053ef593fa9d2b890645a914eee203231fb34458Ted Kremenek        break;
958570f0b0fde7ca812f8d37f52305f3df4dd2ce01Chris Lattner
968570f0b0fde7ca812f8d37f52305f3df4dd2ce01Chris Lattner      case '<': os << "&lt;"; break;
978570f0b0fde7ca812f8d37f52305f3df4dd2ce01Chris Lattner      case '>': os << "&gt;"; break;
988570f0b0fde7ca812f8d37f52305f3df4dd2ce01Chris Lattner      case '&': os << "&amp;"; break;
99053ef593fa9d2b890645a914eee203231fb34458Ted Kremenek    }
100053ef593fa9d2b890645a914eee203231fb34458Ted Kremenek  }
101053ef593fa9d2b890645a914eee203231fb34458Ted Kremenek
102053ef593fa9d2b890645a914eee203231fb34458Ted Kremenek  return os.str();
103053ef593fa9d2b890645a914eee203231fb34458Ted Kremenek}
104053ef593fa9d2b890645a914eee203231fb34458Ted Kremenek
1058570f0b0fde7ca812f8d37f52305f3df4dd2ce01Chris Lattnerstatic void AddLineNumber(RewriteBuffer &RB, unsigned LineNo,
1068570f0b0fde7ca812f8d37f52305f3df4dd2ce01Chris Lattner                          unsigned B, unsigned E) {
10757df3b950061c73d13d3116f747e79d7955a216aChris Lattner  llvm::SmallString<100> Str;
10857df3b950061c73d13d3116f747e79d7955a216aChris Lattner  Str += "<tr><td class=\"num\" id=\"LN";
10957df3b950061c73d13d3116f747e79d7955a216aChris Lattner  Str.append_uint(LineNo);
11057df3b950061c73d13d3116f747e79d7955a216aChris Lattner  Str += "\">";
11157df3b950061c73d13d3116f747e79d7955a216aChris Lattner  Str.append_uint(LineNo);
11257df3b950061c73d13d3116f747e79d7955a216aChris Lattner  Str += "</td><td class=\"line\">";
11357df3b950061c73d13d3116f747e79d7955a216aChris Lattner
11449cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek  if (B == E) { // Handle empty lines.
11557df3b950061c73d13d3116f747e79d7955a216aChris Lattner    Str += " </td></tr>";
1168570f0b0fde7ca812f8d37f52305f3df4dd2ce01Chris Lattner    RB.InsertTextBefore(B, &Str[0], Str.size());
11757df3b950061c73d13d3116f747e79d7955a216aChris Lattner  } else {
1188570f0b0fde7ca812f8d37f52305f3df4dd2ce01Chris Lattner    RB.InsertTextBefore(B, &Str[0], Str.size());
1198570f0b0fde7ca812f8d37f52305f3df4dd2ce01Chris Lattner    RB.InsertTextBefore(E, "</td></tr>", strlen("</td></tr>"));
12049cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek  }
121b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek}
122b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek
123b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenekvoid html::AddLineNumbers(Rewriter& R, unsigned FileID) {
124b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek
125b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek  const llvm::MemoryBuffer *Buf = R.getSourceMgr().getBuffer(FileID);
126b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek  const char* FileBeg = Buf->getBufferStart();
127b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek  const char* FileEnd = Buf->getBufferEnd();
128b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek  const char* C = FileBeg;
1298570f0b0fde7ca812f8d37f52305f3df4dd2ce01Chris Lattner  RewriteBuffer &RB = R.getEditBuffer(FileID);
130b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek
131b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek  assert (C <= FileEnd);
132b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek
133b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek  unsigned LineNo = 0;
134b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek  unsigned FilePos = 0;
135b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek
136b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek  while (C != FileEnd) {
137b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek
138b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek    ++LineNo;
139b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek    unsigned LineStartPos = FilePos;
140b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek    unsigned LineEndPos = FileEnd - FileBeg;
141b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek
142b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek    assert (FilePos <= LineEndPos);
143b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek    assert (C < FileEnd);
144b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek
145b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek    // Scan until the newline (or end-of-file).
146b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek
14749cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek    while (C != FileEnd) {
14849cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek      char c = *C;
14949cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek      ++C;
15049cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek
15149cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek      if (c == '\n') {
15249cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek        LineEndPos = FilePos++;
153b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek        break;
154b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek      }
15549cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek
15649cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek      ++FilePos;
15749cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek    }
158b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek
1598570f0b0fde7ca812f8d37f52305f3df4dd2ce01Chris Lattner    AddLineNumber(RB, LineNo, LineStartPos, LineEndPos);
160d6c1360c2bf234c73572a865f119d0518aca8154Ted Kremenek  }
161d6c1360c2bf234c73572a865f119d0518aca8154Ted Kremenek
1628570f0b0fde7ca812f8d37f52305f3df4dd2ce01Chris Lattner  // Add one big table tag that surrounds all of the code.
1638570f0b0fde7ca812f8d37f52305f3df4dd2ce01Chris Lattner  RB.InsertTextBefore(0, "<table class=\"code\">\n",
1648570f0b0fde7ca812f8d37f52305f3df4dd2ce01Chris Lattner                      strlen("<table class=\"code\">\n"));
165d6c1360c2bf234c73572a865f119d0518aca8154Ted Kremenek
1668570f0b0fde7ca812f8d37f52305f3df4dd2ce01Chris Lattner  RB.InsertTextAfter(FileEnd - FileBeg, "</table>", strlen("</table>"));
167b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek}
168ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek
169ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenekvoid html::AddHeaderFooterInternalBuiltinCSS(Rewriter& R, unsigned FileID) {
170ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek
171ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek  const llvm::MemoryBuffer *Buf = R.getSourceMgr().getBuffer(FileID);
172ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek  const char* FileStart = Buf->getBufferStart();
173ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek  const char* FileEnd = Buf->getBufferEnd();
174ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek
175ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek  SourceLocation StartLoc = SourceLocation::getFileLoc(FileID, 0);
176ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek  SourceLocation EndLoc = SourceLocation::getFileLoc(FileID, FileEnd-FileStart);
177ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek
178ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek  // Generate header
17970bcba6030a76edf46c4f941ad9a5297a1f98c47Ted Kremenek  R.InsertCStrBefore(StartLoc,
18070bcba6030a76edf46c4f941ad9a5297a1f98c47Ted Kremenek      "<html>\n<head>\n"
18170bcba6030a76edf46c4f941ad9a5297a1f98c47Ted Kremenek      "<style type=\"text/css\">\n"
18270bcba6030a76edf46c4f941ad9a5297a1f98c47Ted Kremenek      " body { color:#000000; background-color:#ffffff }\n"
18370bcba6030a76edf46c4f941ad9a5297a1f98c47Ted Kremenek      " body { font-family:Helvetica, sans-serif; font-size:10pt }\n"
1844b0f81323b518429203051bbcd4864bbf4b000a9Ted Kremenek      " h1 { font-size:14pt }\n"
18570bcba6030a76edf46c4f941ad9a5297a1f98c47Ted Kremenek      " .code { border-spacing:0px; width:100%; }\n"
18670bcba6030a76edf46c4f941ad9a5297a1f98c47Ted Kremenek      " .code { font-family: \"Andale Mono\", monospace; font-size:10pt }\n"
18770bcba6030a76edf46c4f941ad9a5297a1f98c47Ted Kremenek      " .code { line-height: 1.2em }\n"
188c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner      " .comment { color: #A0A0A0 }\n"
189c4586c234edd8df0477a895aebcbc3eb220aed6bChris Lattner      " .keyword { color: #FF00FF }\n"
19074ea3e5c57c087c046223096a97ea4e365f85eb6Chris Lattner      " .directive { color: #FFFF00 }\n"
191c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner      " .macro { color: #FF0000; background-color:#FFC0C0 }\n"
19270bcba6030a76edf46c4f941ad9a5297a1f98c47Ted Kremenek      " .num { width:2.5em; padding-right:2ex; background-color:#eeeeee }\n"
19370bcba6030a76edf46c4f941ad9a5297a1f98c47Ted Kremenek      " .num { text-align:right; font-size: smaller }\n"
19470bcba6030a76edf46c4f941ad9a5297a1f98c47Ted Kremenek      " .num { color:#444444 }\n"
19570bcba6030a76edf46c4f941ad9a5297a1f98c47Ted Kremenek      " .line { padding-left: 1ex; border-left: 3px solid #ccc }\n"
19670bcba6030a76edf46c4f941ad9a5297a1f98c47Ted Kremenek      " .line { white-space: pre }\n"
19770bcba6030a76edf46c4f941ad9a5297a1f98c47Ted Kremenek      " .msg { background-color:#fff8b4; color:#000000 }\n"
19870bcba6030a76edf46c4f941ad9a5297a1f98c47Ted Kremenek      " .msg { -webkit-box-shadow:1px 1px 7px #000 }\n"
19970bcba6030a76edf46c4f941ad9a5297a1f98c47Ted Kremenek      " .msg { -webkit-border-radius:5px }\n"
20070bcba6030a76edf46c4f941ad9a5297a1f98c47Ted Kremenek      " .msg { font-family:Helvetica, sans-serif; font-size: smaller }\n"
20170bcba6030a76edf46c4f941ad9a5297a1f98c47Ted Kremenek      " .msg { font-weight: bold }\n"
20270bcba6030a76edf46c4f941ad9a5297a1f98c47Ted Kremenek      " .msg { float:left }\n"
20370bcba6030a76edf46c4f941ad9a5297a1f98c47Ted Kremenek      " .msg { padding:0.5em 1ex 0.5em 1ex }\n"
20470bcba6030a76edf46c4f941ad9a5297a1f98c47Ted Kremenek      " .msg { margin-top:10px; margin-bottom:10px }\n"
20570bcba6030a76edf46c4f941ad9a5297a1f98c47Ted Kremenek      " .mrange { background-color:#dfddf3 }\n"
20670bcba6030a76edf46c4f941ad9a5297a1f98c47Ted Kremenek      " .mrange { border-bottom:1px solid #6F9DBE }\n"
20770bcba6030a76edf46c4f941ad9a5297a1f98c47Ted Kremenek      " .PathIndex { font-weight: bold }\n"
2084b0f81323b518429203051bbcd4864bbf4b000a9Ted Kremenek      " table.simpletable {\n"
2094b0f81323b518429203051bbcd4864bbf4b000a9Ted Kremenek      "   padding: 5px;\n"
2104b0f81323b518429203051bbcd4864bbf4b000a9Ted Kremenek      "   font-size:12pt;\n"
2114b0f81323b518429203051bbcd4864bbf4b000a9Ted Kremenek      "   margin:20px;\n"
2124b0f81323b518429203051bbcd4864bbf4b000a9Ted Kremenek      "   border-collapse: collapse; border-spacing: 0px;\n"
2134b0f81323b518429203051bbcd4864bbf4b000a9Ted Kremenek      " }\n"
2144b0f81323b518429203051bbcd4864bbf4b000a9Ted Kremenek      " td.rowname {\n"
2154b0f81323b518429203051bbcd4864bbf4b000a9Ted Kremenek      "   text-align:right; font-weight:bold; color:#444444;\n"
2164b0f81323b518429203051bbcd4864bbf4b000a9Ted Kremenek      "   padding-right:2ex; }\n"
21770bcba6030a76edf46c4f941ad9a5297a1f98c47Ted Kremenek      "</style>\n</head>\n<body>");
21870bcba6030a76edf46c4f941ad9a5297a1f98c47Ted Kremenek
219ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek  // Generate footer
220ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek
22170bcba6030a76edf46c4f941ad9a5297a1f98c47Ted Kremenek  R.InsertCStrAfter(EndLoc, "</body></html>\n");
222ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek}
2233245a0a1c7a4fd74fca845b2edba275bb126d773Chris Lattner
2243245a0a1c7a4fd74fca845b2edba275bb126d773Chris Lattner/// SyntaxHighlight - Relex the specified FileID and annotate the HTML with
2253245a0a1c7a4fd74fca845b2edba275bb126d773Chris Lattner/// information about keywords, macro expansions etc.  This uses the macro
2263245a0a1c7a4fd74fca845b2edba275bb126d773Chris Lattner/// table state from the end of the file, so it won't be perfectly perfect,
2273245a0a1c7a4fd74fca845b2edba275bb126d773Chris Lattner/// but it will be reasonably close.
2283245a0a1c7a4fd74fca845b2edba275bb126d773Chris Lattnervoid html::SyntaxHighlight(Rewriter &R, unsigned FileID, Preprocessor &PP) {
2293245a0a1c7a4fd74fca845b2edba275bb126d773Chris Lattner  RewriteBuffer &RB = R.getEditBuffer(FileID);
2303245a0a1c7a4fd74fca845b2edba275bb126d773Chris Lattner
231a745e8c52839d9c8dd0fd8d5276b4eab182ec7f2Chris Lattner  const SourceManager &SourceMgr = PP.getSourceManager();
232a745e8c52839d9c8dd0fd8d5276b4eab182ec7f2Chris Lattner  std::pair<const char*, const char*> File = SourceMgr.getBufferData(FileID);
233a745e8c52839d9c8dd0fd8d5276b4eab182ec7f2Chris Lattner  const char *BufferStart = File.first;
234a745e8c52839d9c8dd0fd8d5276b4eab182ec7f2Chris Lattner
235a745e8c52839d9c8dd0fd8d5276b4eab182ec7f2Chris Lattner  Lexer L(SourceLocation::getFileLoc(FileID, 0), PP.getLangOptions(),
236a745e8c52839d9c8dd0fd8d5276b4eab182ec7f2Chris Lattner          File.first, File.second);
237a745e8c52839d9c8dd0fd8d5276b4eab182ec7f2Chris Lattner
2383245a0a1c7a4fd74fca845b2edba275bb126d773Chris Lattner  // Inform the preprocessor that we want to retain comments as tokens, so we
2393245a0a1c7a4fd74fca845b2edba275bb126d773Chris Lattner  // can highlight them.
240a745e8c52839d9c8dd0fd8d5276b4eab182ec7f2Chris Lattner  //PP.SetCommentRetentionState(true, false);
2413245a0a1c7a4fd74fca845b2edba275bb126d773Chris Lattner
242c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner  // Lex all the tokens in raw mode, to avoid entering #includes or expanding
243c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner  // macros.
2443245a0a1c7a4fd74fca845b2edba275bb126d773Chris Lattner  Token Tok;
245a745e8c52839d9c8dd0fd8d5276b4eab182ec7f2Chris Lattner  L.LexRawToken(Tok);
24674ea3e5c57c087c046223096a97ea4e365f85eb6Chris Lattner
24774ea3e5c57c087c046223096a97ea4e365f85eb6Chris Lattner  while (Tok.isNot(tok::eof)) {
24874ea3e5c57c087c046223096a97ea4e365f85eb6Chris Lattner    // Since we are lexing unexpanded tokens, all tokens are from the main
24974ea3e5c57c087c046223096a97ea4e365f85eb6Chris Lattner    // FileID.
25074ea3e5c57c087c046223096a97ea4e365f85eb6Chris Lattner    unsigned TokOffs = SourceMgr.getFullFilePos(Tok.getLocation());
2513245a0a1c7a4fd74fca845b2edba275bb126d773Chris Lattner    unsigned TokLen = Tok.getLength();
2523245a0a1c7a4fd74fca845b2edba275bb126d773Chris Lattner    switch (Tok.getKind()) {
253a745e8c52839d9c8dd0fd8d5276b4eab182ec7f2Chris Lattner    default: break;
254a745e8c52839d9c8dd0fd8d5276b4eab182ec7f2Chris Lattner    case tok::identifier: {
255a745e8c52839d9c8dd0fd8d5276b4eab182ec7f2Chris Lattner      // Fill in Result.IdentifierInfo, looking up the identifier in the
256a745e8c52839d9c8dd0fd8d5276b4eab182ec7f2Chris Lattner      // identifier table.
257a745e8c52839d9c8dd0fd8d5276b4eab182ec7f2Chris Lattner      IdentifierInfo *II = PP.LookUpIdentifierInfo(Tok, BufferStart+TokOffs);
258a745e8c52839d9c8dd0fd8d5276b4eab182ec7f2Chris Lattner
259a745e8c52839d9c8dd0fd8d5276b4eab182ec7f2Chris Lattner      // If this is a pp-identifier, for a keyword, highlight it as such.
260a745e8c52839d9c8dd0fd8d5276b4eab182ec7f2Chris Lattner      if (II->getTokenID() != tok::identifier) {
261c4586c234edd8df0477a895aebcbc3eb220aed6bChris Lattner        RB.InsertTextAfter(TokOffs, "<span class='keyword'>",
262c4586c234edd8df0477a895aebcbc3eb220aed6bChris Lattner                           strlen("<span class='keyword'>"));
263c4586c234edd8df0477a895aebcbc3eb220aed6bChris Lattner        RB.InsertTextBefore(TokOffs+TokLen, "</span>", strlen("</span>"));
264c4586c234edd8df0477a895aebcbc3eb220aed6bChris Lattner      }
265c4586c234edd8df0477a895aebcbc3eb220aed6bChris Lattner      break;
266a745e8c52839d9c8dd0fd8d5276b4eab182ec7f2Chris Lattner    }
2673245a0a1c7a4fd74fca845b2edba275bb126d773Chris Lattner    case tok::comment:
2683245a0a1c7a4fd74fca845b2edba275bb126d773Chris Lattner      RB.InsertTextAfter(TokOffs, "<span class='comment'>",
2693245a0a1c7a4fd74fca845b2edba275bb126d773Chris Lattner                         strlen("<span class='comment'>"));
2703245a0a1c7a4fd74fca845b2edba275bb126d773Chris Lattner      RB.InsertTextBefore(TokOffs+TokLen, "</span>", strlen("</span>"));
2713245a0a1c7a4fd74fca845b2edba275bb126d773Chris Lattner      break;
27274ea3e5c57c087c046223096a97ea4e365f85eb6Chris Lattner    case tok::hash:
27374ea3e5c57c087c046223096a97ea4e365f85eb6Chris Lattner      // FIXME: This isn't working because we're not in raw mode in the lexer.
27474ea3e5c57c087c046223096a97ea4e365f85eb6Chris Lattner      // Just cons up our own lexer here?
27574ea3e5c57c087c046223096a97ea4e365f85eb6Chris Lattner
27674ea3e5c57c087c046223096a97ea4e365f85eb6Chris Lattner      // If this is a preprocessor directive, all tokens to end of line are too.
27774ea3e5c57c087c046223096a97ea4e365f85eb6Chris Lattner      if (Tok.isAtStartOfLine()) {
27874ea3e5c57c087c046223096a97ea4e365f85eb6Chris Lattner        RB.InsertTextAfter(TokOffs, "<span class='directive'>",
27974ea3e5c57c087c046223096a97ea4e365f85eb6Chris Lattner                           strlen("<span class='directive'>"));
28074ea3e5c57c087c046223096a97ea4e365f85eb6Chris Lattner        // Find end of line.  This is a hack.
28174ea3e5c57c087c046223096a97ea4e365f85eb6Chris Lattner        const char *LineEnd = SourceMgr.getCharacterData(Tok.getLocation());
28274ea3e5c57c087c046223096a97ea4e365f85eb6Chris Lattner        unsigned TokEnd = TokOffs+strcspn(LineEnd, "\n\r");
28374ea3e5c57c087c046223096a97ea4e365f85eb6Chris Lattner        RB.InsertTextBefore(TokEnd, "</span>", strlen("</span>"));
28474ea3e5c57c087c046223096a97ea4e365f85eb6Chris Lattner      }
28574ea3e5c57c087c046223096a97ea4e365f85eb6Chris Lattner      break;
2863245a0a1c7a4fd74fca845b2edba275bb126d773Chris Lattner    }
2873245a0a1c7a4fd74fca845b2edba275bb126d773Chris Lattner
288a745e8c52839d9c8dd0fd8d5276b4eab182ec7f2Chris Lattner    L.LexRawToken(Tok);
28974ea3e5c57c087c046223096a97ea4e365f85eb6Chris Lattner  }
2903245a0a1c7a4fd74fca845b2edba275bb126d773Chris Lattner}
291c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner
292c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner/// HighlightMacros - This uses the macro table state from the end of the
293c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner/// file, to reexpand macros and insert (into the HTML) information about the
294c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner/// macro expansions.  This won't be perfectly perfect, but it will be
295c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner/// reasonably close.
296c54d50a4180520370c12dd7d06d035263d357d56Chris Lattnervoid html::HighlightMacros(Rewriter &R, unsigned FileID, Preprocessor &PP) {
297c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner  RewriteBuffer &RB = R.getEditBuffer(FileID);
298c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner
299c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner  // Inform the preprocessor that we don't want comments.
300c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner  PP.SetCommentRetentionState(false, false);
301c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner
302c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner  // Start parsing the specified input file.
303c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner  PP.EnterMainSourceFile();
304c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner
305c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner  // Lex all the tokens.
306c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner  const SourceManager &SourceMgr = PP.getSourceManager();
307c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner  Token Tok;
308c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner  PP.Lex(Tok);
309c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner  while (Tok.isNot(tok::eof)) {
310c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner    // Ignore non-macro tokens.
311c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner    if (!Tok.getLocation().isMacroID()) {
312c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner      PP.Lex(Tok);
313c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner      continue;
314c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner    }
315c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner
316c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner    // Ignore tokens whose logical location was not the main file.
317c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner    SourceLocation LLoc = SourceMgr.getLogicalLoc(Tok.getLocation());
318c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner    std::pair<unsigned, unsigned> LLocInfo =
319c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner      SourceMgr.getDecomposedFileLoc(LLoc);
320c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner
321c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner    if (LLocInfo.first != FileID) {
322c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner      PP.Lex(Tok);
323c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner      continue;
324c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner    }
325c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner
326c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner    // Okay, we have the first token of a macro expansion: highlight the
327c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner    // instantiation.
328c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner
329c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner    // Get the size of current macro call itself.
330c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner    // FIXME: This should highlight the args of a function-like
331c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner    // macro, using a heuristic.
332c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner    unsigned TokLen = Lexer::MeasureTokenLength(LLoc, SourceMgr);
333c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner
334c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner    unsigned TokOffs = LLocInfo.second;
335c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner    RB.InsertTextAfter(TokOffs, "<span class='macro'>",
336c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner                       strlen("<span class='macro'>"));
337c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner    RB.InsertTextBefore(TokOffs+TokLen, "</span>", strlen("</span>"));
338c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner
339c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner    // Okay, eat this token, getting the next one.
340c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner    PP.Lex(Tok);
341c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner
342c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner    // Skip all the rest of the tokens that are part of this macro
343c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner    // instantiation.  It would be really nice to pop up a window with all the
344c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner    // spelling of the tokens or something.
345c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner    while (!Tok.is(tok::eof) &&
346c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner           SourceMgr.getLogicalLoc(Tok.getLocation()) == LLoc)
347c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner      PP.Lex(Tok);
348c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner  }
349c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner}
350c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner
351c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner
352