blob: f8c96cca3944058f87fc117e2ac8991dfa79701b [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
54static void TagOpen(std::ostringstream& os, const char* TagStr,
55 const char* Attr, const char* Content) {
56
57 os << '<' << TagStr;
58 if (Attr) os << ' ' << Attr;
59 os << '>';
60 if (Content) os << Content;
61}
62
63static void TagClose(std::ostringstream& os, const char* TagStr) {
64 os << "</" << TagStr << ">";
65}
66
Ted Kremenek6a340832008-03-18 21:19:49 +000067void html::InsertTag(Rewriter& R, html::Tags tag,
68 SourceLocation B, SourceLocation E,
Ted Kremenekb485cd12008-03-18 23:08:51 +000069 const char* Attributes,
70 const char* Content, bool Newline,
71 bool OpenInsertBefore, bool CloseInsertAfter) {
Ted Kremenek6a340832008-03-18 21:19:49 +000072
73 const char* TagStr = 0;
74
75 switch (tag) {
76 default: break;
Ted Kremenek6a340832008-03-18 21:19:49 +000077 case BODY: TagStr = "body"; break;
Ted Kremenekb485cd12008-03-18 23:08:51 +000078 case DIV: TagStr = "div"; break;
79 case HEAD: TagStr = "head"; break;
80 case HTML: TagStr = "html"; break;
81 case PRE: TagStr = "pre"; break;
82 case SPAN: TagStr = "span"; break;
Ted Kremenek6a340832008-03-18 21:19:49 +000083 }
84
85 assert (TagStr && "Tag not supported.");
86
Ted Kremenekb485cd12008-03-18 23:08:51 +000087 // Generate the opening tag. We also generate the closing
88 // tag of the start and end SourceLocations are the same.
89
90 {
91 std::ostringstream os;
92 TagOpen(os, TagStr, Attributes, Content);
93 if (B == E) {
94 TagClose(os, TagStr);
95 if (Newline) os << '\n';
96 }
Ted Kremenekc22efea2008-03-18 21:26:34 +000097
Ted Kremenekb485cd12008-03-18 23:08:51 +000098 if (OpenInsertBefore)
99 R.InsertTextBefore(B, os.str().c_str(), os.str().size());
Ted Kremenekc22efea2008-03-18 21:26:34 +0000100 else
Ted Kremenekb485cd12008-03-18 23:08:51 +0000101 R.InsertTextAfter(B, os.str().c_str(), os.str().size());
Ted Kremenek6a340832008-03-18 21:19:49 +0000102 }
103
Ted Kremenekb485cd12008-03-18 23:08:51 +0000104 // Generate the closing tag if the start and end SourceLocations
105 // are different.
106
107 if (B != E) {
108 std::ostringstream os;
109 TagClose(os, TagStr);
110 if (Newline) os << '\n';
Ted Kremenekc22efea2008-03-18 21:26:34 +0000111
Ted Kremenekb485cd12008-03-18 23:08:51 +0000112 if (CloseInsertAfter)
113 R.InsertTextAfter(E, os.str().c_str(), os.str().size());
Ted Kremenekc22efea2008-03-18 21:26:34 +0000114 else
Ted Kremenekb485cd12008-03-18 23:08:51 +0000115 R.InsertTextBefore(E, os.str().c_str(), os.str().size());
Ted Kremenek6a340832008-03-18 21:19:49 +0000116 }
117}
Ted Kremenekb485cd12008-03-18 23:08:51 +0000118
119//===----------------------------------------------------------------------===//
120// High-level operations.
121//===----------------------------------------------------------------------===//
122
123static void AddLineNumber(Rewriter& R, unsigned LineNo,
124 SourceLocation B, SourceLocation E) {
125
126 // Add two "div" tags: one to contain the line number, and the other
127 // to contain the content of the line.
128
129 std::ostringstream os;
130 os << LineNo;
131 html::InsertTag(R, html::SPAN, B, E, "class=Line");
132 html::InsertTag(R, html::SPAN, B, B, "class=Num", os.str().c_str());
133}
134
135void html::AddLineNumbers(Rewriter& R, unsigned FileID) {
136
137 const llvm::MemoryBuffer *Buf = R.getSourceMgr().getBuffer(FileID);
138 const char* FileBeg = Buf->getBufferStart();
139 const char* FileEnd = Buf->getBufferEnd();
140 const char* C = FileBeg;
141
142 assert (C <= FileEnd);
143
144 unsigned LineNo = 0;
145 unsigned FilePos = 0;
146
147 while (C != FileEnd) {
148
149 ++LineNo;
150 unsigned LineStartPos = FilePos;
151 unsigned LineEndPos = FileEnd - FileBeg;
152
153 assert (FilePos <= LineEndPos);
154 assert (C < FileEnd);
155
156 // Scan until the newline (or end-of-file).
157
158 for ( ; C != FileEnd ; ++C, ++FilePos)
159 if (*C == '\n') {
160 LineEndPos = FilePos;
161 break;
162 }
163
164 AddLineNumber(R, LineNo,
165 SourceLocation::getFileLoc(FileID, LineStartPos),
166 SourceLocation::getFileLoc(FileID, LineEndPos));
167
168 if (C != FileEnd) {
169 ++C;
170 ++FilePos;
171 }
172 }
173}