blob: fc1627af02940a9b675a54e2633fdef4472f9d0c [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"
Chris Lattner57df3b92008-04-16 04:11:35 +000018#include "llvm/ADT/SmallString.h"
Ted Kremenek6a340832008-03-18 21:19:49 +000019#include "llvm/Support/MemoryBuffer.h"
20#include <sstream>
21
22using namespace clang;
23
Ted Kremenekfa5be362008-04-08 22:37:58 +000024void html::EscapeText(Rewriter& R, unsigned FileID,
25 bool EscapeSpaces, bool ReplaceTabs) {
Ted Kremenek6a340832008-03-18 21:19:49 +000026
27 const llvm::MemoryBuffer *Buf = R.getSourceMgr().getBuffer(FileID);
28 const char* C = Buf->getBufferStart();
29 const char* FileEnd = Buf->getBufferEnd();
30
31 assert (C <= FileEnd);
32
33 for (unsigned FilePos = 0; C != FileEnd ; ++C, ++FilePos) {
Ted Kremenek49cd6352008-04-03 07:12:29 +000034
Ted Kremenek6a340832008-03-18 21:19:49 +000035 switch (*C) {
36 default: break;
37
38 case ' ':
Ted Kremenek49cd6352008-04-03 07:12:29 +000039 if (EscapeSpaces) {
40 SourceLocation Loc = SourceLocation::getFileLoc(FileID, FilePos);
41 R.ReplaceText(Loc, 1, "&nbsp;", 6);
42 }
Ted Kremenek6a340832008-03-18 21:19:49 +000043 break;
44
Ted Kremenek49cd6352008-04-03 07:12:29 +000045 case '\t': {
Ted Kremenekfa5be362008-04-08 22:37:58 +000046 if (!ReplaceTabs)
47 break;
48
Ted Kremenek49cd6352008-04-03 07:12:29 +000049 SourceLocation Loc = SourceLocation::getFileLoc(FileID, FilePos);
Ted Kremenek4ce32cb2008-04-08 22:28:15 +000050
51 if (EscapeSpaces)
52 R.ReplaceText(Loc, 1, "&nbsp;&nbsp;&nbsp;&nbsp;", 6*4);
53 else
54 R.ReplaceText(Loc, 1, " ", 4);
55
Ted Kremenek49cd6352008-04-03 07:12:29 +000056 break;
57 }
58
59 case '<': {
60 SourceLocation Loc = SourceLocation::getFileLoc(FileID, FilePos);
61 R.ReplaceText(Loc, 1, "&lt;", 4);
62 break;
63 }
64
65 case '>': {
66 SourceLocation Loc = SourceLocation::getFileLoc(FileID, FilePos);
67 R.ReplaceText(Loc, 1, "&gt;", 4);
68 break;
69 }
70
71 case '&': {
72 SourceLocation Loc = SourceLocation::getFileLoc(FileID, FilePos);
73 R.ReplaceText(Loc, 1, "&amp;", 5);
74 break;
75 }
Ted Kremenek6a340832008-03-18 21:19:49 +000076 }
77 }
78}
79
Ted Kremenekfa5be362008-04-08 22:37:58 +000080std::string html::EscapeText(const std::string& s, bool EscapeSpaces,
81 bool ReplaceTabs) {
Ted Kremenek053ef592008-03-27 17:15:29 +000082
83 unsigned len = s.size();
84 std::ostringstream os;
85
86 for (unsigned i = 0 ; i < len; ++i) {
87
88 char c = s[i];
89
90 switch (c) {
91 default:
92 os << c; break;
93
94 case ' ':
Ted Kremenek8fb00162008-03-31 23:14:05 +000095 if (EscapeSpaces) os << "&nbsp;";
Ted Kremenek487f8272008-03-27 17:28:58 +000096 else os << ' ';
Ted Kremenek053ef592008-03-27 17:15:29 +000097 break;
98
Ted Kremenekfa5be362008-04-08 22:37:58 +000099 case '\t':
100 if (ReplaceTabs)
101 for (unsigned i = 0; i < 4; ++i) os << "&nbsp;";
102 else os << c;
103
104 break;
105
Ted Kremenek053ef592008-03-27 17:15:29 +0000106 case '<': os << "&lt;"; break;
107 case '>': os << "&gt;"; break;
108 case '&': os << "&amp;"; break;
109 }
110 }
111
112 return os.str();
113}
114
Ted Kremenekb485cd12008-03-18 23:08:51 +0000115static void AddLineNumber(Rewriter& R, unsigned LineNo,
116 SourceLocation B, SourceLocation E) {
Chris Lattner57df3b92008-04-16 04:11:35 +0000117 llvm::SmallString<100> Str;
118 Str += "<tr><td class=\"num\" id=\"LN";
119 Str.append_uint(LineNo);
120 Str += "\">";
121 Str.append_uint(LineNo);
122 Str += "</td><td class=\"line\">";
123
Ted Kremenek49cd6352008-04-03 07:12:29 +0000124 if (B == E) { // Handle empty lines.
Chris Lattner57df3b92008-04-16 04:11:35 +0000125 Str += " </td></tr>";
126 R.InsertTextBefore(B, &Str[0], Str.size());
127 } else {
128 R.InsertTextBefore(B, &Str[0], Str.size());
Ted Kremenek49cd6352008-04-03 07:12:29 +0000129 R.InsertCStrBefore(E, "</td></tr>");
130 }
Ted Kremenekb485cd12008-03-18 23:08:51 +0000131}
132
133void html::AddLineNumbers(Rewriter& R, unsigned FileID) {
134
135 const llvm::MemoryBuffer *Buf = R.getSourceMgr().getBuffer(FileID);
136 const char* FileBeg = Buf->getBufferStart();
137 const char* FileEnd = Buf->getBufferEnd();
138 const char* C = FileBeg;
139
140 assert (C <= FileEnd);
141
142 unsigned LineNo = 0;
143 unsigned FilePos = 0;
144
145 while (C != FileEnd) {
146
147 ++LineNo;
148 unsigned LineStartPos = FilePos;
149 unsigned LineEndPos = FileEnd - FileBeg;
150
151 assert (FilePos <= LineEndPos);
152 assert (C < FileEnd);
153
154 // Scan until the newline (or end-of-file).
155
Ted Kremenek49cd6352008-04-03 07:12:29 +0000156 while (C != FileEnd) {
157 char c = *C;
158 ++C;
159
160 if (c == '\n') {
161 LineEndPos = FilePos++;
Ted Kremenekb485cd12008-03-18 23:08:51 +0000162 break;
163 }
Ted Kremenek49cd6352008-04-03 07:12:29 +0000164
165 ++FilePos;
166 }
Ted Kremenekb485cd12008-03-18 23:08:51 +0000167
168 AddLineNumber(R, LineNo,
169 SourceLocation::getFileLoc(FileID, LineStartPos),
Ted Kremenek49cd6352008-04-03 07:12:29 +0000170 SourceLocation::getFileLoc(FileID, LineEndPos));
Ted Kremenekd6c13602008-03-19 05:07:26 +0000171 }
172
173 // Add one big div tag that surrounds all of the code.
174
175 R.InsertCStrBefore(SourceLocation::getFileLoc(FileID, 0),
Ted Kremeneke8e019e2008-03-19 21:59:05 +0000176 "<table class=\"code\">\n");
Ted Kremenekd6c13602008-03-19 05:07:26 +0000177
178 R.InsertCStrAfter(SourceLocation::getFileLoc(FileID, FileEnd - FileBeg),
Ted Kremeneke8e019e2008-03-19 21:59:05 +0000179 "</table>");
Ted Kremenekb485cd12008-03-18 23:08:51 +0000180}
Ted Kremenekad0a2032008-03-19 06:14:37 +0000181
182void html::AddHeaderFooterInternalBuiltinCSS(Rewriter& R, unsigned FileID) {
183
184 const llvm::MemoryBuffer *Buf = R.getSourceMgr().getBuffer(FileID);
185 const char* FileStart = Buf->getBufferStart();
186 const char* FileEnd = Buf->getBufferEnd();
187
188 SourceLocation StartLoc = SourceLocation::getFileLoc(FileID, 0);
189 SourceLocation EndLoc = SourceLocation::getFileLoc(FileID, FileEnd-FileStart);
190
191 // Generate header
192
Ted Kremenek70bcba62008-04-09 15:40:40 +0000193 R.InsertCStrBefore(StartLoc,
194 "<html>\n<head>\n"
195 "<style type=\"text/css\">\n"
196 " body { color:#000000; background-color:#ffffff }\n"
197 " body { font-family:Helvetica, sans-serif; font-size:10pt }\n"
Ted Kremenek4b0f8132008-04-15 21:25:08 +0000198 " h1 { font-size:14pt }\n"
Ted Kremenek70bcba62008-04-09 15:40:40 +0000199 " .code { border-spacing:0px; width:100%; }\n"
200 " .code { font-family: \"Andale Mono\", monospace; font-size:10pt }\n"
201 " .code { line-height: 1.2em }\n"
202 " .num { width:2.5em; padding-right:2ex; background-color:#eeeeee }\n"
203 " .num { text-align:right; font-size: smaller }\n"
204 " .num { color:#444444 }\n"
205 " .line { padding-left: 1ex; border-left: 3px solid #ccc }\n"
206 " .line { white-space: pre }\n"
207 " .msg { background-color:#fff8b4; color:#000000 }\n"
208 " .msg { -webkit-box-shadow:1px 1px 7px #000 }\n"
209 " .msg { -webkit-border-radius:5px }\n"
210 " .msg { font-family:Helvetica, sans-serif; font-size: smaller }\n"
211 " .msg { font-weight: bold }\n"
212 " .msg { float:left }\n"
213 " .msg { padding:0.5em 1ex 0.5em 1ex }\n"
214 " .msg { margin-top:10px; margin-bottom:10px }\n"
215 " .mrange { background-color:#dfddf3 }\n"
216 " .mrange { border-bottom:1px solid #6F9DBE }\n"
217 " .PathIndex { font-weight: bold }\n"
Ted Kremenek4b0f8132008-04-15 21:25:08 +0000218 " table.simpletable {\n"
219 " padding: 5px;\n"
220 " font-size:12pt;\n"
221 " margin:20px;\n"
222 " border-collapse: collapse; border-spacing: 0px;\n"
223 " }\n"
224 " td.rowname {\n"
225 " text-align:right; font-weight:bold; color:#444444;\n"
226 " padding-right:2ex; }\n"
Ted Kremenek70bcba62008-04-09 15:40:40 +0000227 "</style>\n</head>\n<body>");
228
Ted Kremenekad0a2032008-03-19 06:14:37 +0000229 // Generate footer
230
Ted Kremenek70bcba62008-04-09 15:40:40 +0000231 R.InsertCStrAfter(EndLoc, "</body></html>\n");
Ted Kremenekad0a2032008-03-19 06:14:37 +0000232}