blob: 79fff2885467fec2eeeb39a1397c193484033aa1 [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
Ted Kremenekb485cd12008-03-18 23:08:51 +000023//===----------------------------------------------------------------------===//
24// Basic operations.
25//===----------------------------------------------------------------------===//
26
Ted Kremenek6a340832008-03-18 21:19:49 +000027void html::EscapeText(Rewriter& R, unsigned FileID, bool EscapeSpaces) {
28
29 const llvm::MemoryBuffer *Buf = R.getSourceMgr().getBuffer(FileID);
30 const char* C = Buf->getBufferStart();
31 const char* FileEnd = Buf->getBufferEnd();
32
33 assert (C <= FileEnd);
34
35 for (unsigned FilePos = 0; C != FileEnd ; ++C, ++FilePos) {
36
37 SourceLocation Loc = SourceLocation::getFileLoc(FileID, FilePos);
38
39 switch (*C) {
40 default: break;
41
42 case ' ':
43 if (EscapeSpaces) R.ReplaceText(Loc, 1, "&#32;", 5);
44 break;
45
46 case '<': R.ReplaceText(Loc, 1, "&lt;", 4); break;
47 case '>': R.ReplaceText(Loc, 1, "&gt;", 4); break;
48 case '&': R.ReplaceText(Loc, 1, "&amp;", 5); break;
49 }
50 }
51}
52
Ted Kremenekb485cd12008-03-18 23:08:51 +000053
Ted Kremenek1b3188c2008-03-18 23:55:46 +000054static void TagOpen(Rewriter& R, const char* TagStr,
55 const char* Attr, const char* Content,
56 SourceLocation L, bool InsertBefore) {
Ted Kremenekb485cd12008-03-18 23:08:51 +000057
Ted Kremenek1b3188c2008-03-18 23:55:46 +000058 std::ostringstream os;
Ted Kremenekb485cd12008-03-18 23:08:51 +000059 os << '<' << TagStr;
60 if (Attr) os << ' ' << Attr;
61 os << '>';
62 if (Content) os << Content;
Ted Kremenek1b3188c2008-03-18 23:55:46 +000063
64 if (InsertBefore)
65 R.InsertTextBefore(L, os.str().c_str(), os.str().size());
66 else
67 R.InsertTextAfter(L, os.str().c_str(), os.str().size());
Ted Kremenekb485cd12008-03-18 23:08:51 +000068}
69
Ted Kremenek1b3188c2008-03-18 23:55:46 +000070static void TagClose(Rewriter& R, const char* TagStr, SourceLocation L,
71 bool Newline, bool InsertBefore) {
72
73 std::ostringstream os;
Ted Kremenekb485cd12008-03-18 23:08:51 +000074 os << "</" << TagStr << ">";
Ted Kremenek1b3188c2008-03-18 23:55:46 +000075 if (Newline) os << '\n';
76
77 if (InsertBefore)
78 R.InsertTextBefore(L, os.str().c_str(), os.str().size());
79 else
80 R.InsertTextAfter(L, os.str().c_str(), os.str().size());
Ted Kremenekb485cd12008-03-18 23:08:51 +000081}
82
Ted Kremenek6a340832008-03-18 21:19:49 +000083void html::InsertTag(Rewriter& R, html::Tags tag,
84 SourceLocation B, SourceLocation E,
Ted Kremenek1b3188c2008-03-18 23:55:46 +000085 const char* Attr, const char* Content, bool Newline,
86 bool OpenInsertBefore, bool CloseInsertBefore) {
Ted Kremenek6a340832008-03-18 21:19:49 +000087
88 const char* TagStr = 0;
89
90 switch (tag) {
91 default: break;
Ted Kremenek6a340832008-03-18 21:19:49 +000092 case BODY: TagStr = "body"; break;
Ted Kremenekb485cd12008-03-18 23:08:51 +000093 case DIV: TagStr = "div"; break;
94 case HEAD: TagStr = "head"; break;
95 case HTML: TagStr = "html"; break;
96 case PRE: TagStr = "pre"; break;
97 case SPAN: TagStr = "span"; break;
Ted Kremenek1b3188c2008-03-18 23:55:46 +000098 case STYLE: TagStr = "style"; break;
Ted Kremenek6a340832008-03-18 21:19:49 +000099 }
100
101 assert (TagStr && "Tag not supported.");
102
Ted Kremenekb485cd12008-03-18 23:08:51 +0000103 // Generate the opening tag. We also generate the closing
104 // tag of the start and end SourceLocations are the same.
105
Ted Kremenek1b3188c2008-03-18 23:55:46 +0000106 if (OpenInsertBefore) {
107 TagClose(R, TagStr, E, Newline, CloseInsertBefore);
108 TagOpen(R, TagStr, Attr, Content, B, true);
Ted Kremenek6a340832008-03-18 21:19:49 +0000109 }
Ted Kremenek1b3188c2008-03-18 23:55:46 +0000110 else {
111 TagOpen(R, TagStr, Attr, Content, B, false);
112 TagClose(R, TagStr, E, Newline, true);
Ted Kremenek6a340832008-03-18 21:19:49 +0000113 }
114}
Ted Kremenekb485cd12008-03-18 23:08:51 +0000115
116//===----------------------------------------------------------------------===//
117// High-level operations.
118//===----------------------------------------------------------------------===//
119
120static void AddLineNumber(Rewriter& R, unsigned LineNo,
121 SourceLocation B, SourceLocation E) {
122
123 // Add two "div" tags: one to contain the line number, and the other
124 // to contain the content of the line.
125
126 std::ostringstream os;
127 os << LineNo;
Ted Kremenek1b3188c2008-03-18 23:55:46 +0000128 html::InsertTag(R, html::SPAN, B, E, "style=lines");
129 html::InsertTag(R, html::SPAN, B, B, "style=nums", os.str().c_str());
Ted Kremenekb485cd12008-03-18 23:08:51 +0000130}
131
132void html::AddLineNumbers(Rewriter& R, unsigned FileID) {
133
134 const llvm::MemoryBuffer *Buf = R.getSourceMgr().getBuffer(FileID);
135 const char* FileBeg = Buf->getBufferStart();
136 const char* FileEnd = Buf->getBufferEnd();
137 const char* C = FileBeg;
138
139 assert (C <= FileEnd);
140
141 unsigned LineNo = 0;
142 unsigned FilePos = 0;
143
144 while (C != FileEnd) {
145
146 ++LineNo;
147 unsigned LineStartPos = FilePos;
148 unsigned LineEndPos = FileEnd - FileBeg;
149
150 assert (FilePos <= LineEndPos);
151 assert (C < FileEnd);
152
153 // Scan until the newline (or end-of-file).
154
155 for ( ; C != FileEnd ; ++C, ++FilePos)
156 if (*C == '\n') {
157 LineEndPos = FilePos;
158 break;
159 }
160
161 AddLineNumber(R, LineNo,
162 SourceLocation::getFileLoc(FileID, LineStartPos),
163 SourceLocation::getFileLoc(FileID, LineEndPos));
164
165 if (C != FileEnd) {
166 ++C;
167 ++FilePos;
168 }
169 }
170}