HTMLRewrite.cpp revision fa5be3617294f0e3c341f0ecb6b2076478b1b5ac
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
23fa5be3617294f0e3c341f0ecb6b2076478b1b5acTed Kremenekvoid html::EscapeText(Rewriter& R, unsigned FileID,
24fa5be3617294f0e3c341f0ecb6b2076478b1b5acTed Kremenek                      bool EscapeSpaces, bool ReplaceTabs) {
256a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek
266a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek  const llvm::MemoryBuffer *Buf = R.getSourceMgr().getBuffer(FileID);
276a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek  const char* C = Buf->getBufferStart();
286a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek  const char* FileEnd = Buf->getBufferEnd();
296a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek
306a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek  assert (C <= FileEnd);
316a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek
326a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek  for (unsigned FilePos = 0; C != FileEnd ; ++C, ++FilePos) {
3349cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek
346a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek    switch (*C) {
356a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek      default: break;
366a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek
376a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek      case ' ':
3849cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek        if (EscapeSpaces) {
3949cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek          SourceLocation Loc = SourceLocation::getFileLoc(FileID, FilePos);
4049cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek          R.ReplaceText(Loc, 1, "&nbsp;", 6);
4149cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek        }
426a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek        break;
436a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek
4449cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek      case '\t': {
45fa5be3617294f0e3c341f0ecb6b2076478b1b5acTed Kremenek        if (!ReplaceTabs)
46fa5be3617294f0e3c341f0ecb6b2076478b1b5acTed Kremenek          break;
47fa5be3617294f0e3c341f0ecb6b2076478b1b5acTed Kremenek
4849cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek        SourceLocation Loc = SourceLocation::getFileLoc(FileID, FilePos);
494ce32cb52b19102216f3120b81b4de5227b8d5f0Ted Kremenek
504ce32cb52b19102216f3120b81b4de5227b8d5f0Ted Kremenek        if (EscapeSpaces)
514ce32cb52b19102216f3120b81b4de5227b8d5f0Ted Kremenek          R.ReplaceText(Loc, 1, "&nbsp;&nbsp;&nbsp;&nbsp;", 6*4);
524ce32cb52b19102216f3120b81b4de5227b8d5f0Ted Kremenek        else
534ce32cb52b19102216f3120b81b4de5227b8d5f0Ted Kremenek          R.ReplaceText(Loc, 1, "    ", 4);
544ce32cb52b19102216f3120b81b4de5227b8d5f0Ted Kremenek
5549cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek        break;
5649cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek      }
5749cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek
5849cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek      case '<': {
5949cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek        SourceLocation Loc = SourceLocation::getFileLoc(FileID, FilePos);
6049cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek        R.ReplaceText(Loc, 1, "&lt;", 4);
6149cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek        break;
6249cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek      }
6349cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek
6449cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek      case '>': {
6549cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek        SourceLocation Loc = SourceLocation::getFileLoc(FileID, FilePos);
6649cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek        R.ReplaceText(Loc, 1, "&gt;", 4);
6749cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek        break;
6849cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek      }
6949cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek
7049cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek      case '&': {
7149cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek        SourceLocation Loc = SourceLocation::getFileLoc(FileID, FilePos);
7249cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek        R.ReplaceText(Loc, 1, "&amp;", 5);
7349cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek        break;
7449cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek      }
756a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek    }
766a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek  }
776a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek}
786a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek
79fa5be3617294f0e3c341f0ecb6b2076478b1b5acTed Kremenekstd::string html::EscapeText(const std::string& s, bool EscapeSpaces,
80fa5be3617294f0e3c341f0ecb6b2076478b1b5acTed Kremenek                             bool ReplaceTabs) {
81053ef593fa9d2b890645a914eee203231fb34458Ted Kremenek
82053ef593fa9d2b890645a914eee203231fb34458Ted Kremenek  unsigned len = s.size();
83053ef593fa9d2b890645a914eee203231fb34458Ted Kremenek  std::ostringstream os;
84053ef593fa9d2b890645a914eee203231fb34458Ted Kremenek
85053ef593fa9d2b890645a914eee203231fb34458Ted Kremenek  for (unsigned i = 0 ; i < len; ++i) {
86053ef593fa9d2b890645a914eee203231fb34458Ted Kremenek
87053ef593fa9d2b890645a914eee203231fb34458Ted Kremenek    char c = s[i];
88053ef593fa9d2b890645a914eee203231fb34458Ted Kremenek
89053ef593fa9d2b890645a914eee203231fb34458Ted Kremenek    switch (c) {
90053ef593fa9d2b890645a914eee203231fb34458Ted Kremenek      default:
91053ef593fa9d2b890645a914eee203231fb34458Ted Kremenek        os << c; break;
92053ef593fa9d2b890645a914eee203231fb34458Ted Kremenek
93053ef593fa9d2b890645a914eee203231fb34458Ted Kremenek      case ' ':
948fb001684fb7740d6bed973f927bc33bc7473ff7Ted Kremenek        if (EscapeSpaces) os << "&nbsp;";
95487f827a7f8e9b2c89aec0d35b6154cb17116444Ted Kremenek        else os << ' ';
96053ef593fa9d2b890645a914eee203231fb34458Ted Kremenek        break;
97053ef593fa9d2b890645a914eee203231fb34458Ted Kremenek
98fa5be3617294f0e3c341f0ecb6b2076478b1b5acTed Kremenek        case '\t':
99fa5be3617294f0e3c341f0ecb6b2076478b1b5acTed Kremenek          if (ReplaceTabs)
100fa5be3617294f0e3c341f0ecb6b2076478b1b5acTed Kremenek            for (unsigned i = 0; i < 4; ++i) os << "&nbsp;";
101fa5be3617294f0e3c341f0ecb6b2076478b1b5acTed Kremenek          else os << c;
102fa5be3617294f0e3c341f0ecb6b2076478b1b5acTed Kremenek
103fa5be3617294f0e3c341f0ecb6b2076478b1b5acTed Kremenek          break;
104fa5be3617294f0e3c341f0ecb6b2076478b1b5acTed Kremenek
105053ef593fa9d2b890645a914eee203231fb34458Ted Kremenek        case '<': os << "&lt;"; break;
106053ef593fa9d2b890645a914eee203231fb34458Ted Kremenek        case '>': os << "&gt;"; break;
107053ef593fa9d2b890645a914eee203231fb34458Ted Kremenek        case '&': os << "&amp;"; break;
108053ef593fa9d2b890645a914eee203231fb34458Ted Kremenek    }
109053ef593fa9d2b890645a914eee203231fb34458Ted Kremenek  }
110053ef593fa9d2b890645a914eee203231fb34458Ted Kremenek
111053ef593fa9d2b890645a914eee203231fb34458Ted Kremenek  return os.str();
112053ef593fa9d2b890645a914eee203231fb34458Ted Kremenek}
113053ef593fa9d2b890645a914eee203231fb34458Ted Kremenek
114b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenekstatic void AddLineNumber(Rewriter& R, unsigned LineNo,
115b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek                          SourceLocation B, SourceLocation E) {
116f830997de6ca8aa9526a9f4bb44593c19040ca85Ted Kremenek
117b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek  std::ostringstream os;
118356708cb339d3f727ff85f9fb251e4f8d4e5bd1cTed Kremenek  os << "<tr><td class=\"num\" id=\"LN" << LineNo << "\">"
119356708cb339d3f727ff85f9fb251e4f8d4e5bd1cTed Kremenek     << LineNo << "</td><td class=\"line\">";
12013e479b2b74771738a5e5c5dc1c270416924b126Ted Kremenek
12149cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek  if (B == E) { // Handle empty lines.
12249cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek    os << " </td></tr>";
12349cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek    R.InsertStrBefore(B, os.str());
12449cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek  }
12549cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek  else {
12649cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek    R.InsertStrBefore(B, os.str());
12749cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek    R.InsertCStrBefore(E, "</td></tr>");
12849cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek  }
129b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek}
130b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek
131b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenekvoid html::AddLineNumbers(Rewriter& R, unsigned FileID) {
132b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek
133b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek  const llvm::MemoryBuffer *Buf = R.getSourceMgr().getBuffer(FileID);
134b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek  const char* FileBeg = Buf->getBufferStart();
135b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek  const char* FileEnd = Buf->getBufferEnd();
136b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek  const char* C = FileBeg;
137b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek
138b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek  assert (C <= FileEnd);
139b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek
140b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek  unsigned LineNo = 0;
141b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek  unsigned FilePos = 0;
142b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek
143b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek  while (C != FileEnd) {
144b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek
145b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek    ++LineNo;
146b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek    unsigned LineStartPos = FilePos;
147b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek    unsigned LineEndPos = FileEnd - FileBeg;
148b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek
149b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek    assert (FilePos <= LineEndPos);
150b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek    assert (C < FileEnd);
151b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek
152b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek    // Scan until the newline (or end-of-file).
153b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek
15449cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek    while (C != FileEnd) {
15549cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek      char c = *C;
15649cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek      ++C;
15749cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek
15849cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek      if (c == '\n') {
15949cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek        LineEndPos = FilePos++;
160b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek        break;
161b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek      }
16249cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek
16349cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek      ++FilePos;
16449cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek    }
165b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek
166b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek    AddLineNumber(R, LineNo,
167b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek                  SourceLocation::getFileLoc(FileID, LineStartPos),
16849cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek                  SourceLocation::getFileLoc(FileID, LineEndPos));
169d6c1360c2bf234c73572a865f119d0518aca8154Ted Kremenek  }
170d6c1360c2bf234c73572a865f119d0518aca8154Ted Kremenek
171d6c1360c2bf234c73572a865f119d0518aca8154Ted Kremenek  // Add one big div tag that surrounds all of the code.
172d6c1360c2bf234c73572a865f119d0518aca8154Ted Kremenek
173d6c1360c2bf234c73572a865f119d0518aca8154Ted Kremenek  R.InsertCStrBefore(SourceLocation::getFileLoc(FileID, 0),
174e8e019ede11579bce271bee0b2b0b543bd9833a5Ted Kremenek                     "<table class=\"code\">\n");
175d6c1360c2bf234c73572a865f119d0518aca8154Ted Kremenek
176d6c1360c2bf234c73572a865f119d0518aca8154Ted Kremenek  R.InsertCStrAfter(SourceLocation::getFileLoc(FileID, FileEnd - FileBeg),
177e8e019ede11579bce271bee0b2b0b543bd9833a5Ted Kremenek                    "</table>");
178b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek}
179ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek
180ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenekvoid html::AddHeaderFooterInternalBuiltinCSS(Rewriter& R, unsigned FileID) {
181ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek
182ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek  const llvm::MemoryBuffer *Buf = R.getSourceMgr().getBuffer(FileID);
183ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek  const char* FileStart = Buf->getBufferStart();
184ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek  const char* FileEnd = Buf->getBufferEnd();
185ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek
186ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek  SourceLocation StartLoc = SourceLocation::getFileLoc(FileID, 0);
187ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek  SourceLocation EndLoc = SourceLocation::getFileLoc(FileID, FileEnd-FileStart);
188ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek
189ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek  // Generate header
190ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek
191ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek  {
192ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek    std::ostringstream os;
193ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek
194ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek    os << "<html>\n<head>\n"
195eeacc5203ae1defadbe647b3b22b0432e23f4393Ted Kremenek       << "<style type=\"text/css\">\n"
196eeacc5203ae1defadbe647b3b22b0432e23f4393Ted Kremenek       << " body { color:#000000; background-color:#ffffff }\n"
197487f827a7f8e9b2c89aec0d35b6154cb17116444Ted Kremenek       << " body { font-family:Helvetica, sans-serif; font-size:10pt }\n"
198487f827a7f8e9b2c89aec0d35b6154cb17116444Ted Kremenek       << " h1 { font-size:12pt }\n"
199e8e019ede11579bce271bee0b2b0b543bd9833a5Ted Kremenek       << " .code { border-spacing:0px; width:100%; }\n"
2006ccb91abc37700e646139f49c448ccdbf14eb575Chris Lattner       << " .code { font-family: \"Andale Mono\", monospace; font-size:10pt }\n"
201e8e019ede11579bce271bee0b2b0b543bd9833a5Ted Kremenek       << " .code { line-height: 1.2em }\n"
202e8e019ede11579bce271bee0b2b0b543bd9833a5Ted Kremenek       << " .num { width:2.5em; padding-right:2ex; background-color:#eeeeee }\n"
203e8e019ede11579bce271bee0b2b0b543bd9833a5Ted Kremenek       << " .num { text-align:right; font-size: smaller }\n"
2040f1b67bc25058b71eacc0d9ef85075fff23e7b31Ted Kremenek       << " .num { color:#444444 }\n"
205e8e019ede11579bce271bee0b2b0b543bd9833a5Ted Kremenek       << " .line { padding-left: 1ex; border-left: 3px solid #ccc }\n"
206e8e019ede11579bce271bee0b2b0b543bd9833a5Ted Kremenek       << " .line { white-space: pre }\n"
2077e54eede4079085f35b91cc9a4f5c38a1c4f9890Ted Kremenek       << " .msg { background-color:#fff8b4; color:#000000 }\n"
2089d4e659fce4e0cc7cb36fce9fedb42a3e4c38496Ted Kremenek       << " .msg { -webkit-box-shadow:1px 1px 7px #000 }\n"
2099d4e659fce4e0cc7cb36fce9fedb42a3e4c38496Ted Kremenek       << " .msg { -webkit-border-radius:5px }\n"
210e8e019ede11579bce271bee0b2b0b543bd9833a5Ted Kremenek       << " .msg { font-family:Helvetica, sans-serif; font-size: smaller }\n"
211db87ca09df48d3cc6ac868debd68c72c878a0daaTed Kremenek       << " .msg { font-weight: bold }\n"
212e8e019ede11579bce271bee0b2b0b543bd9833a5Ted Kremenek       << " .msg { float:left }\n"
213eeacc5203ae1defadbe647b3b22b0432e23f4393Ted Kremenek       << " .msg { padding:0.5em 1ex 0.5em 1ex }\n"
214eeacc5203ae1defadbe647b3b22b0432e23f4393Ted Kremenek       << " .msg { margin-top:10px; margin-bottom:10px }\n"
215f23621f1fc448cab7d896cd80e3abf35cb97af1fTed Kremenek       << " .mrange { background-color:#dfddf3 }\n"
2169e628a02f43a93d30d5be7680ce5c3bbccf6ce79Ted Kremenek       << " .mrange { border-bottom:1px solid #6F9DBE }\n"
217718ceb13e078ff99d3338e643c7ea6cf797b0e8bTed Kremenek       << " .PathIndex { font-weight: bold }\n"
218e8e019ede11579bce271bee0b2b0b543bd9833a5Ted Kremenek       << "</style>\n</head>\n<body>";
219ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek
220ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek    R.InsertStrBefore(StartLoc, os.str());
221ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek  }
222ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek
223ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek  // Generate footer
224ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek
225ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek  {
226ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek    std::ostringstream os;
227ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek
228ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek    os << "</body></html>\n";
229ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek    R.InsertStrAfter(EndLoc, os.str());
230ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek  }
231ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek}
232ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek
233ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek
234