blob: f3371a01f8186b25af675c0711e30761ec7bf9ce [file] [log] [blame]
Ted Kremenek6a340832008-03-18 21:19:49 +00001//== HTMLRewrite.cpp - Translate source code into prettified HTML --*- C++ -*-//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file defines the HTMLRewriter clas, which is used to translate the
11// text of a source file into prettified HTML.
12//
13//===----------------------------------------------------------------------===//
14
15#include "clang/Rewrite/Rewriter.h"
16#include "clang/Rewrite/HTMLRewrite.h"
17#include "clang/Basic/SourceManager.h"
18#include "llvm/Support/MemoryBuffer.h"
19#include <sstream>
20
21using namespace clang;
22
23void html::EscapeText(Rewriter& R, unsigned FileID, bool EscapeSpaces) {
24
25 const llvm::MemoryBuffer *Buf = R.getSourceMgr().getBuffer(FileID);
26 const char* C = Buf->getBufferStart();
27 const char* FileEnd = Buf->getBufferEnd();
28
29 assert (C <= FileEnd);
30
31 for (unsigned FilePos = 0; C != FileEnd ; ++C, ++FilePos) {
32
33 SourceLocation Loc = SourceLocation::getFileLoc(FileID, FilePos);
34
35 switch (*C) {
36 default: break;
37
38 case ' ':
39 if (EscapeSpaces) R.ReplaceText(Loc, 1, "&#32;", 5);
40 break;
41
42 case '<': R.ReplaceText(Loc, 1, "&lt;", 4); break;
43 case '>': R.ReplaceText(Loc, 1, "&gt;", 4); break;
44 case '&': R.ReplaceText(Loc, 1, "&amp;", 5); break;
45 }
46 }
47}
48
Ted Kremenek053ef592008-03-27 17:15:29 +000049std::string html::EscapeText(const std::string& s, bool EscapeSpaces) {
50
51 unsigned len = s.size();
52 std::ostringstream os;
53
54 for (unsigned i = 0 ; i < len; ++i) {
55
56 char c = s[i];
57
58 switch (c) {
59 default:
60 os << c; break;
61
62 case ' ':
63 if (EscapeSpaces) os << "&#32;";
Ted Kremenek487f8272008-03-27 17:28:58 +000064 else os << ' ';
Ted Kremenek053ef592008-03-27 17:15:29 +000065 break;
66
67 case '<': os << "&lt;"; break;
68 case '>': os << "&gt;"; break;
69 case '&': os << "&amp;"; break;
70 }
71 }
72
73 return os.str();
74}
75
Ted Kremenekb485cd12008-03-18 23:08:51 +000076static void AddLineNumber(Rewriter& R, unsigned LineNo,
77 SourceLocation B, SourceLocation E) {
Ted Kremenekf8309972008-03-19 01:30:02 +000078
Ted Kremeneke8e019e2008-03-19 21:59:05 +000079 // Put the closing </tr> first.
Ted Kremenek13e479b2008-03-19 07:53:42 +000080
Ted Kremeneke8e019e2008-03-19 21:59:05 +000081 R.InsertCStrBefore(E, "</tr>");
Ted Kremenekb485cd12008-03-18 23:08:51 +000082
Ted Kremenekd6c13602008-03-19 05:07:26 +000083 if (B == E) // Handle empty lines.
Ted Kremeneke8e019e2008-03-19 21:59:05 +000084 R.InsertCStrBefore(B, "<td class=\"line\"> </td>");
Ted Kremenekd6c13602008-03-19 05:07:26 +000085 else {
Ted Kremeneke8e019e2008-03-19 21:59:05 +000086 R.InsertCStrBefore(E, "</td>");
87 R.InsertCStrBefore(B, "<td class=\"line\">");
Ted Kremenekd6c13602008-03-19 05:07:26 +000088 }
Ted Kremenekf8309972008-03-19 01:30:02 +000089
Ted Kremenekd6c13602008-03-19 05:07:26 +000090 // Insert a div tag for the line number.
91
Ted Kremenekb485cd12008-03-18 23:08:51 +000092 std::ostringstream os;
Ted Kremeneke8e019e2008-03-19 21:59:05 +000093 os << "<td class=\"num\">" << LineNo << "</td>";
Ted Kremenekd6c13602008-03-19 05:07:26 +000094
95 R.InsertStrBefore(B, os.str());
96
Ted Kremeneke8e019e2008-03-19 21:59:05 +000097 // Now prepend the <tr>.
Ted Kremenekd6c13602008-03-19 05:07:26 +000098
Ted Kremeneke8e019e2008-03-19 21:59:05 +000099 R.InsertCStrBefore(B, "<tr>");
Ted Kremenek13e479b2008-03-19 07:53:42 +0000100
Ted Kremenekb485cd12008-03-18 23:08:51 +0000101}
102
103void html::AddLineNumbers(Rewriter& R, unsigned FileID) {
104
105 const llvm::MemoryBuffer *Buf = R.getSourceMgr().getBuffer(FileID);
106 const char* FileBeg = Buf->getBufferStart();
107 const char* FileEnd = Buf->getBufferEnd();
108 const char* C = FileBeg;
109
110 assert (C <= FileEnd);
111
112 unsigned LineNo = 0;
113 unsigned FilePos = 0;
114
115 while (C != FileEnd) {
116
117 ++LineNo;
118 unsigned LineStartPos = FilePos;
119 unsigned LineEndPos = FileEnd - FileBeg;
120
121 assert (FilePos <= LineEndPos);
122 assert (C < FileEnd);
123
124 // Scan until the newline (or end-of-file).
125
126 for ( ; C != FileEnd ; ++C, ++FilePos)
127 if (*C == '\n') {
128 LineEndPos = FilePos;
129 break;
130 }
131
132 AddLineNumber(R, LineNo,
133 SourceLocation::getFileLoc(FileID, LineStartPos),
134 SourceLocation::getFileLoc(FileID, LineEndPos));
135
136 if (C != FileEnd) {
137 ++C;
138 ++FilePos;
139 }
Ted Kremenekd6c13602008-03-19 05:07:26 +0000140 }
141
142 // Add one big div tag that surrounds all of the code.
143
144 R.InsertCStrBefore(SourceLocation::getFileLoc(FileID, 0),
Ted Kremeneke8e019e2008-03-19 21:59:05 +0000145 "<table class=\"code\">\n");
Ted Kremenekd6c13602008-03-19 05:07:26 +0000146
147 R.InsertCStrAfter(SourceLocation::getFileLoc(FileID, FileEnd - FileBeg),
Ted Kremeneke8e019e2008-03-19 21:59:05 +0000148 "</table>");
Ted Kremenekb485cd12008-03-18 23:08:51 +0000149}
Ted Kremenekad0a2032008-03-19 06:14:37 +0000150
151void html::AddHeaderFooterInternalBuiltinCSS(Rewriter& R, unsigned FileID) {
152
153 const llvm::MemoryBuffer *Buf = R.getSourceMgr().getBuffer(FileID);
154 const char* FileStart = Buf->getBufferStart();
155 const char* FileEnd = Buf->getBufferEnd();
156
157 SourceLocation StartLoc = SourceLocation::getFileLoc(FileID, 0);
158 SourceLocation EndLoc = SourceLocation::getFileLoc(FileID, FileEnd-FileStart);
159
160 // Generate header
161
162 {
163 std::ostringstream os;
164
165 os << "<html>\n<head>\n"
Ted Kremenekeeacc522008-03-19 22:44:21 +0000166 << "<style type=\"text/css\">\n"
167 << " body { color:#000000; background-color:#ffffff }\n"
Ted Kremenek487f8272008-03-27 17:28:58 +0000168 << " body { font-family:Helvetica, sans-serif; font-size:10pt }\n"
169 << " h1 { font-size:12pt }\n"
Ted Kremeneke8e019e2008-03-19 21:59:05 +0000170 << " .code { border-spacing:0px; width:100%; }\n"
171 << " .code { font-family: \"Andale Mono\", fixed; font-size:10pt }\n"
172 << " .code { line-height: 1.2em }\n"
173 << " .num { width:2.5em; padding-right:2ex; background-color:#eeeeee }\n"
174 << " .num { text-align:right; font-size: smaller }\n"
Ted Kremenek0f1b67b2008-03-19 23:55:53 +0000175 << " .num { color:#444444 }\n"
Ted Kremeneke8e019e2008-03-19 21:59:05 +0000176 << " .line { padding-left: 1ex; border-left: 3px solid #ccc }\n"
177 << " .line { white-space: pre }\n"
Ted Kremenekeeacc522008-03-19 22:44:21 +0000178 << " .msg { background-color:#ff8000; color:#000000 }\n"
Ted Kremenek9d4e6592008-03-24 23:38:32 +0000179 << " .msg { -webkit-box-shadow:1px 1px 7px #000 }\n"
180 << " .msg { -webkit-border-radius:5px }\n"
Ted Kremenekeeacc522008-03-19 22:44:21 +0000181 << " .msg { border: solid 1px #944a00 }\n"
Ted Kremeneke8e019e2008-03-19 21:59:05 +0000182 << " .msg { font-family:Helvetica, sans-serif; font-size: smaller }\n"
Ted Kremenekdb87ca02008-03-19 22:06:25 +0000183 << " .msg { font-weight: bold }\n"
Ted Kremeneke8e019e2008-03-19 21:59:05 +0000184 << " .msg { float:left }\n"
Ted Kremenekeeacc522008-03-19 22:44:21 +0000185 << " .msg { padding:0.5em 1ex 0.5em 1ex }\n"
186 << " .msg { margin-top:10px; margin-bottom:10px }\n"
Ted Kremenek9d4e6592008-03-24 23:38:32 +0000187 << " .mrange { background-color:#ffcc66 }\n"
188 << " .mrange { border-bottom: 1px solid #ff8000 }\n"
Ted Kremeneke8e019e2008-03-19 21:59:05 +0000189 << "</style>\n</head>\n<body>";
Ted Kremenekad0a2032008-03-19 06:14:37 +0000190
191 R.InsertStrBefore(StartLoc, os.str());
192 }
193
194 // Generate footer
195
196 {
197 std::ostringstream os;
198
199 os << "</body></html>\n";
200 R.InsertStrAfter(EndLoc, os.str());
201 }
202}
203
204