//== 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/Support/MemoryBuffer.h" #include using namespace clang; //===----------------------------------------------------------------------===// // Basic operations. //===----------------------------------------------------------------------===// void html::EscapeText(Rewriter& R, unsigned FileID, bool EscapeSpaces) { 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) { SourceLocation Loc = SourceLocation::getFileLoc(FileID, FilePos); switch (*C) { default: break; case ' ': if (EscapeSpaces) R.ReplaceText(Loc, 1, " ", 5); break; case '<': R.ReplaceText(Loc, 1, "<", 4); break; case '>': R.ReplaceText(Loc, 1, ">", 4); break; case '&': R.ReplaceText(Loc, 1, "&", 5); break; } } } static void TagOpen(Rewriter& R, const char* TagStr, const char* Attr, const char* Content, SourceLocation L, bool InsertBefore) { std::ostringstream os; os << '<' << TagStr; if (Attr) os << ' ' << Attr; os << '>'; if (Content) os << Content; if (InsertBefore) R.InsertTextBefore(L, os.str().c_str(), os.str().size()); else R.InsertTextAfter(L, os.str().c_str(), os.str().size()); } static void TagClose(Rewriter& R, const char* TagStr, SourceLocation L, bool Newline, bool InsertBefore) { std::ostringstream os; os << ""; if (Newline) os << '\n'; if (InsertBefore) R.InsertTextBefore(L, os.str().c_str(), os.str().size()); else R.InsertTextAfter(L, os.str().c_str(), os.str().size()); } void html::InsertTag(Rewriter& R, html::Tags tag, SourceLocation B, SourceLocation E, const char* Attr, const char* Content, bool Newline, bool OpenInsertBefore, bool CloseInsertBefore) { const char* TagStr = 0; switch (tag) { default: break; case BODY: TagStr = "body"; break; case DIV: TagStr = "div"; break; case HEAD: TagStr = "head"; break; case HTML: TagStr = "html"; break; case PRE: TagStr = "pre"; break; case SPAN: TagStr = "span"; break; case STYLE: TagStr = "style"; break; } assert (TagStr && "Tag not supported."); // Generate the opening tag. We also generate the closing // tag of the start and end SourceLocations are the same. if (OpenInsertBefore) { TagClose(R, TagStr, E, Newline, CloseInsertBefore); TagOpen(R, TagStr, Attr, Content, B, true); } else { TagOpen(R, TagStr, Attr, Content, B, false); TagClose(R, TagStr, E, Newline, true); } } //===----------------------------------------------------------------------===// // High-level operations. //===----------------------------------------------------------------------===// static void AddLineNumber(Rewriter& R, unsigned LineNo, SourceLocation B, SourceLocation E) { // Add two "div" tags: one to contain the line number, and the other // to contain the content of the line. std::ostringstream os; os << LineNo; html::InsertTag(R, html::SPAN, B, E, "style=lines"); html::InsertTag(R, html::SPAN, B, B, "style=nums", os.str().c_str()); } 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). for ( ; C != FileEnd ; ++C, ++FilePos) if (*C == '\n') { LineEndPos = FilePos; break; } AddLineNumber(R, LineNo, SourceLocation::getFileLoc(FileID, LineStartPos), SourceLocation::getFileLoc(FileID, LineEndPos)); if (C != FileEnd) { ++C; ++FilePos; } } }