//== HTMLRewrite.cpp - Translate source code into prettified HTML --*- C++ -*-// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file defines the HTMLRewriter clas, which is used to translate the // text of a source file into prettified HTML. // //===----------------------------------------------------------------------===// #include "clang/Rewrite/Rewriter.h" #include "clang/Rewrite/HTMLRewrite.h" #include "clang/Basic/SourceManager.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/MemoryBuffer.h" #include using namespace clang; void html::EscapeText(Rewriter& R, unsigned FileID, bool EscapeSpaces, bool ReplaceTabs) { const llvm::MemoryBuffer *Buf = R.getSourceMgr().getBuffer(FileID); const char* C = Buf->getBufferStart(); const char* FileEnd = Buf->getBufferEnd(); assert (C <= FileEnd); for (unsigned FilePos = 0; C != FileEnd ; ++C, ++FilePos) { switch (*C) { default: break; case ' ': if (EscapeSpaces) { SourceLocation Loc = SourceLocation::getFileLoc(FileID, FilePos); R.ReplaceText(Loc, 1, " ", 6); } break; case '\t': { if (!ReplaceTabs) break; SourceLocation Loc = SourceLocation::getFileLoc(FileID, FilePos); if (EscapeSpaces) R.ReplaceText(Loc, 1, "    ", 6*4); else R.ReplaceText(Loc, 1, " ", 4); break; } case '<': { SourceLocation Loc = SourceLocation::getFileLoc(FileID, FilePos); R.ReplaceText(Loc, 1, "<", 4); break; } case '>': { SourceLocation Loc = SourceLocation::getFileLoc(FileID, FilePos); R.ReplaceText(Loc, 1, ">", 4); break; } case '&': { SourceLocation Loc = SourceLocation::getFileLoc(FileID, FilePos); R.ReplaceText(Loc, 1, "&", 5); break; } } } } std::string html::EscapeText(const std::string& s, bool EscapeSpaces, bool ReplaceTabs) { unsigned len = s.size(); std::ostringstream os; for (unsigned i = 0 ; i < len; ++i) { char c = s[i]; switch (c) { default: os << c; break; case ' ': if (EscapeSpaces) os << " "; else os << ' '; break; case '\t': if (ReplaceTabs) for (unsigned i = 0; i < 4; ++i) os << " "; else os << c; break; case '<': os << "<"; break; case '>': os << ">"; break; case '&': os << "&"; break; } } return os.str(); } static void AddLineNumber(Rewriter& R, unsigned LineNo, SourceLocation B, SourceLocation E) { llvm::SmallString<100> Str; Str += ""; Str.append_uint(LineNo); Str += ""; if (B == E) { // Handle empty lines. Str += " "; R.InsertTextBefore(B, &Str[0], Str.size()); } else { R.InsertTextBefore(B, &Str[0], Str.size()); R.InsertCStrBefore(E, ""); } } void html::AddLineNumbers(Rewriter& R, unsigned FileID) { const llvm::MemoryBuffer *Buf = R.getSourceMgr().getBuffer(FileID); const char* FileBeg = Buf->getBufferStart(); const char* FileEnd = Buf->getBufferEnd(); const char* C = FileBeg; assert (C <= FileEnd); unsigned LineNo = 0; unsigned FilePos = 0; while (C != FileEnd) { ++LineNo; unsigned LineStartPos = FilePos; unsigned LineEndPos = FileEnd - FileBeg; assert (FilePos <= LineEndPos); assert (C < FileEnd); // Scan until the newline (or end-of-file). while (C != FileEnd) { char c = *C; ++C; if (c == '\n') { LineEndPos = FilePos++; break; } ++FilePos; } AddLineNumber(R, LineNo, SourceLocation::getFileLoc(FileID, LineStartPos), SourceLocation::getFileLoc(FileID, LineEndPos)); } // Add one big div tag that surrounds all of the code. R.InsertCStrBefore(SourceLocation::getFileLoc(FileID, 0), "\n"); R.InsertCStrAfter(SourceLocation::getFileLoc(FileID, FileEnd - FileBeg), "
"); } void html::AddHeaderFooterInternalBuiltinCSS(Rewriter& R, unsigned FileID) { const llvm::MemoryBuffer *Buf = R.getSourceMgr().getBuffer(FileID); const char* FileStart = Buf->getBufferStart(); const char* FileEnd = Buf->getBufferEnd(); SourceLocation StartLoc = SourceLocation::getFileLoc(FileID, 0); SourceLocation EndLoc = SourceLocation::getFileLoc(FileID, FileEnd-FileStart); // Generate header R.InsertCStrBefore(StartLoc, "\n\n" "\n\n"); // Generate footer R.InsertCStrAfter(EndLoc, "\n"); }