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, " ", 5); 406a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek break; 416a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek 426a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek case '<': R.ReplaceText(Loc, 1, "<", 4); break; 436a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek case '>': R.ReplaceText(Loc, 1, ">", 4); break; 446a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek case '&': R.ReplaceText(Loc, 1, "&", 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