HTMLRewrite.cpp revision ad0a203130dc5d1fb7231b88767174511424fa98
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"
176a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek#include "clang/Basic/SourceManager.h"
186a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek#include "llvm/Support/MemoryBuffer.h"
196a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek#include <sstream>
206a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek
216a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenekusing namespace clang;
226a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek
236a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenekvoid html::EscapeText(Rewriter& R, unsigned FileID, bool EscapeSpaces) {
246a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek
256a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek  const llvm::MemoryBuffer *Buf = R.getSourceMgr().getBuffer(FileID);
266a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek  const char* C = Buf->getBufferStart();
276a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek  const char* FileEnd = Buf->getBufferEnd();
286a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek
296a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek  assert (C <= FileEnd);
306a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek
316a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek  for (unsigned FilePos = 0; C != FileEnd ; ++C, ++FilePos) {
326a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek
336a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek    SourceLocation Loc = SourceLocation::getFileLoc(FileID, FilePos);
346a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek
356a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek    switch (*C) {
366a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek      default: break;
376a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek
386a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek      case ' ':
396a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek        if (EscapeSpaces) R.ReplaceText(Loc, 1, "&#32;", 5);
406a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek        break;
416a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek
426a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek      case '<': R.ReplaceText(Loc, 1, "&lt;", 4); break;
436a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek      case '>': R.ReplaceText(Loc, 1, "&gt;", 4); break;
446a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek      case '&': R.ReplaceText(Loc, 1, "&amp;", 5); break;
456a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek    }
466a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek  }
476a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek}
486a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek
49b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenekstatic void AddLineNumber(Rewriter& R, unsigned LineNo,
50b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek                          SourceLocation B, SourceLocation E) {
51f830997de6ca8aa9526a9f4bb44593c19040ca85Ted Kremenek
52d6c1360c2bf234c73572a865f119d0518aca8154Ted Kremenek  // Surround the line text with a div tag.
53f830997de6ca8aa9526a9f4bb44593c19040ca85Ted Kremenek
54d6c1360c2bf234c73572a865f119d0518aca8154Ted Kremenek  if (B == E) // Handle empty lines.
55d6c1360c2bf234c73572a865f119d0518aca8154Ted Kremenek    R.InsertCStrBefore(B, "<div class=\"lines\"> </div>");
56d6c1360c2bf234c73572a865f119d0518aca8154Ted Kremenek  else {
57d6c1360c2bf234c73572a865f119d0518aca8154Ted Kremenek    R.InsertCStrBefore(E, "</div>");
58d6c1360c2bf234c73572a865f119d0518aca8154Ted Kremenek    R.InsertCStrBefore(B, "<div class=\"lines\">");
59d6c1360c2bf234c73572a865f119d0518aca8154Ted Kremenek  }
60d6c1360c2bf234c73572a865f119d0518aca8154Ted Kremenek
61d6c1360c2bf234c73572a865f119d0518aca8154Ted Kremenek  // Insert a div tag for the line number.
62b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek
63b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek  std::ostringstream os;
64d6c1360c2bf234c73572a865f119d0518aca8154Ted Kremenek  os << "<div class=\"nums\">" << LineNo << "</div>";
65d6c1360c2bf234c73572a865f119d0518aca8154Ted Kremenek
66d6c1360c2bf234c73572a865f119d0518aca8154Ted Kremenek  R.InsertStrBefore(B, os.str());
67d6c1360c2bf234c73572a865f119d0518aca8154Ted Kremenek
68d6c1360c2bf234c73572a865f119d0518aca8154Ted Kremenek  // Now surround the whole line with another div tag.
69d6c1360c2bf234c73572a865f119d0518aca8154Ted Kremenek
70d6c1360c2bf234c73572a865f119d0518aca8154Ted Kremenek  R.InsertCStrBefore(B, "<div class=\"codeline\">");
71d6c1360c2bf234c73572a865f119d0518aca8154Ted Kremenek  R.InsertCStrAfter(E, "</div>");
72b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek}
73b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek
74b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenekvoid html::AddLineNumbers(Rewriter& R, unsigned FileID) {
75b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek
76b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek  const llvm::MemoryBuffer *Buf = R.getSourceMgr().getBuffer(FileID);
77b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek  const char* FileBeg = Buf->getBufferStart();
78b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek  const char* FileEnd = Buf->getBufferEnd();
79b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek  const char* C = FileBeg;
80b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek
81b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek  assert (C <= FileEnd);
82b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek
83b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek  unsigned LineNo = 0;
84b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek  unsigned FilePos = 0;
85b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek
86b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek  while (C != FileEnd) {
87b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek
88b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek    ++LineNo;
89b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek    unsigned LineStartPos = FilePos;
90b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek    unsigned LineEndPos = FileEnd - FileBeg;
91b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek
92b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek    assert (FilePos <= LineEndPos);
93b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek    assert (C < FileEnd);
94b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek
95b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek    // Scan until the newline (or end-of-file).
96b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek
97b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek    for ( ; C != FileEnd ; ++C, ++FilePos)
98b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek      if (*C == '\n') {
99b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek        LineEndPos = FilePos;
100b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek        break;
101b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek      }
102b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek
103b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek    AddLineNumber(R, LineNo,
104b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek                  SourceLocation::getFileLoc(FileID, LineStartPos),
105b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek                  SourceLocation::getFileLoc(FileID, LineEndPos));
106b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek
107b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek    if (C != FileEnd) {
108b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek      ++C;
109b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek      ++FilePos;
110b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek    }
111d6c1360c2bf234c73572a865f119d0518aca8154Ted Kremenek  }
112d6c1360c2bf234c73572a865f119d0518aca8154Ted Kremenek
113d6c1360c2bf234c73572a865f119d0518aca8154Ted Kremenek  // Add one big div tag that surrounds all of the code.
114d6c1360c2bf234c73572a865f119d0518aca8154Ted Kremenek
115d6c1360c2bf234c73572a865f119d0518aca8154Ted Kremenek  R.InsertCStrBefore(SourceLocation::getFileLoc(FileID, 0),
116d6c1360c2bf234c73572a865f119d0518aca8154Ted Kremenek                     "<div id=\"codeblock\">");
117d6c1360c2bf234c73572a865f119d0518aca8154Ted Kremenek
118d6c1360c2bf234c73572a865f119d0518aca8154Ted Kremenek  R.InsertCStrAfter(SourceLocation::getFileLoc(FileID, FileEnd - FileBeg),
119d6c1360c2bf234c73572a865f119d0518aca8154Ted Kremenek                    "</div>");
120b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek}
121ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek
122ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenekvoid html::AddHeaderFooterInternalBuiltinCSS(Rewriter& R, unsigned FileID) {
123ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek
124ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek  const llvm::MemoryBuffer *Buf = R.getSourceMgr().getBuffer(FileID);
125ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek  const char* FileStart = Buf->getBufferStart();
126ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek  const char* FileEnd = Buf->getBufferEnd();
127ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek
128ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek  SourceLocation StartLoc = SourceLocation::getFileLoc(FileID, 0);
129ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek  SourceLocation EndLoc = SourceLocation::getFileLoc(FileID, FileEnd-FileStart);
130ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek
131ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek  // Generate header
132ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek
133ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek  {
134ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek    std::ostringstream os;
135ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek
136ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek    os << "<html>\n<head>\n"
137ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek    << " <style type=\"text/css\">\n"
138ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek    << "  .codeblock { width:100% }\n"
139ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek    << "  .codeline { font-family: \"Andale Mono\", fixed; font-size:10pt }\n"
140ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek    << "  .codeline { height:1.5em; line-height:1.5em }\n"
141ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek    << "  .nums, .lines { float:left; height:100% }\n"
142ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek    << "  .nums { background-color: #eeeeee }\n"
143ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek    << "  .nums { font-size:smaller }\n"
144ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek    << "  .nums { width:2.5em; padding-right:2ex; text-align:right }\n"
145ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek    << "  .lines { padding-left: 1ex; border-left: 3px solid #ccc }\n"
146ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek    << "  .lines { white-space: pre }\n"
147ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek    << " </style>\n"
148ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek    << "</head>\n"
149ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek    << "<body>";
150ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek
151ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek    R.InsertStrBefore(StartLoc, os.str());
152ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek  }
153ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek
154ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek  // Generate footer
155ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek
156ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek  {
157ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek    std::ostringstream os;
158ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek
159ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek    os << "</body></html>\n";
160ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek    R.InsertStrAfter(EndLoc, os.str());
161ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek  }
162ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek}
163ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek
164ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek
165