Synopsis - Cross-Reference
File: /Synopsis/Parsers/Cxx/SXRBuffer.hh1// 2// Copyright (C) 2008 Stefan Seefeld 3// All rights reserved. 4// Licensed to the public under the terms of the GNU LGPL (>= 2), 5// see the file COPYING for details. 6// 7 8#ifndef SXRBuffer_hh_ 9#define SXRBuffer_hh_ 10 11#include <fstream> 12#include <string> 13#include <iostream> 14 15// An SXRBuffer generates a xml-ified version of the source file, with 16// identifiers suitably annotated to allow linking. 17// Since the processing of the parse tree is not monotonic (for example, 18// member functions are parsed only after the full class body has been seen), 19// the entries aren't generated in-order. We collect them here, then write out 20// the whole file once the translation has finished. 21class SXRBuffer 22{ 23public: 24 struct Entry 25 { 26 enum Kind { SPAN, XREF}; 27 //. Less-than functor to order entries within lines by column. 28 struct less 29 { 30 bool operator() (Entry const &a, Entry const &b) const 31 { return a.column < b.column;} 32 }; 33 34 Entry(unsigned int c, int l, Kind k, std::string const &n, std::string const &t, 35 std::string const &f, std::string const &d, bool a) 36 : column(c), length(l), kind(k), name(n), type(t), from(f), description(d), 37 continuation(a) {} 38 39 unsigned int column; 40 int length; 41 Kind kind; 42 std::string name; 43 std::string type; 44 std::string from; 45 std::string description; 46 bool continuation; 47 }; 48 49 SXRBuffer(std::string const &out, std::string const &in, std::string const &name) 50 // line numbers are reported starting from 1 51 : line_(1), column_(0), new_line_(true) 52 { 53 outbuf_.open(out.c_str(), std::ios_base::out); 54 inbuf_.open(in.c_str(), std::ios_base::in); 55 outbuf_.sputn("<sxr filename=\"", 15); 56 outbuf_.sputn(name.c_str(), name.size()); 57 outbuf_.sputn("\">\n", 3); 58 } 59 ~SXRBuffer() 60 { 61 outbuf_.sputn("</sxr>", 6); 62 inbuf_.close(); 63 outbuf_.close(); 64 } 65 66 void insert_span(unsigned int line, unsigned int column, int length, 67 std::string const &type) 68 { 69 Line &l = lines_[line]; 70 l.insert(Entry(column, length, Entry::SPAN, "", type, "", "", false)); 71 } 72 void insert_xref(unsigned int line, unsigned int column, unsigned int length, 73 std::string const &name, std::string const &type, 74 std::string const &from, std::string const &description, 75 bool continuation) 76 { 77 Line &l = lines_[line]; 78 l.insert(Entry(column, length, Entry::XREF, encode(name), 79 type, encode(from), encode(description), continuation)); 80 } 81 82 void write() 83 { 84 unsigned int line = 0; 85 while (advance(line, 0)) 86 { 87 Line &l = lines_[line]; 88 Line::iterator i = l.begin(); 89 while (i != l.end()) 90 { 91 Entry const &entry = *i; 92 advance(line, entry.column); 93 switch (entry.kind) 94 { 95 case Entry::SPAN: 96 insert("<span class=\"", 13); 97 insert(entry.type.data(), entry.type.size()); 98 insert("\">", 2); 99 if (entry.length == -1) finish_line(); 100 else advance(line, entry.column + entry.length); 101 insert("</span>", 7); 102 break; 103 case Entry::XREF: 104 insert("<a href=\"", 9); 105 insert(entry.name.data(), entry.name.size()); 106 insert("\" title=\"", 9); 107 insert(entry.description.data(), entry.description.size()); 108 insert("\" from=\"", 8); 109 insert(entry.from.data(), entry.from.size()); 110 insert("\" type=\"", 8); 111 insert(entry.type.data(), entry.type.size()); 112 if (entry.continuation) 113 insert("\" continuation=\"true", 20); 114 insert("\">", 2); 115 if (entry.length == -1) finish_line(); 116 else advance(line, entry.column + entry.length); 117 insert("</a>", 4); 118 break; 119 } 120 ++i; 121 } 122 ++line; 123 } 124 } 125 126private: 127 128 std::string encode(std::string const &n) 129 { 130 std::string retn; 131 for (std::string::const_iterator i = n.begin(); i != n.end(); ++i) 132 switch (*i) 133 { 134 case '<': 135 retn += "<"; 136 break; 137 case '>': 138 retn += ">"; 139 break; 140 case '&': 141 retn += "&"; 142 break; 143 case '"': 144 retn += """; 145 break; 146 default: 147 retn += *i; 148 } 149 return retn; 150 } 151 152 void insert(char const *s, unsigned int l) 153 { 154 if (new_line_) 155 { 156 outbuf_.sputn("<line>", 6); 157 new_line_ = false; 158 } 159 outbuf_.sputn(s, l); 160 } 161 162 void put(char c) 163 { 164 if (new_line_) 165 { 166 outbuf_.sputn("<line>", 6); 167 new_line_ = false; 168 } 169 switch (c) 170 { 171 case '\n': 172 outbuf_.sputn("</line>\n", 8); 173 ++line_; 174 column_ = 0; 175 new_line_ = true; 176 break; 177 case '&': 178 outbuf_.sputn("&", 5); 179 ++column_; 180 break; 181 case '<': 182 outbuf_.sputn("<", 4); 183 ++column_; 184 break; 185 case '>': 186 outbuf_.sputn(">", 4); 187 ++column_; 188 break; 189 default: 190 outbuf_.sputc(c); 191 ++column_; 192 break; 193 } 194 } 195 196 bool finish_line() 197 { 198 std::istreambuf_iterator<char> in(&inbuf_); 199 std::istreambuf_iterator<char> end; 200 while (in != end && *in != '\n') put(*in++); 201 return in == end; 202 } 203 204 // Advance till the given input source file position. 205 bool advance(unsigned int line, unsigned int column) 206 { 207 std::istreambuf_iterator<char> in(&inbuf_); 208 std::istreambuf_iterator<char> end; 209 while ((line_ < line || column_ < column) && in != end) 210 put(*in++); 211 return in != end; 212 } 213 214 typedef std::set<Entry, Entry::less> Line; 215 typedef std::map<int, Line> Map; 216 217 Map lines_; 218 219 std::filebuf inbuf_; 220 std::filebuf outbuf_; 221 unsigned int line_; 222 unsigned int column_; 223 bool new_line_; 224}; 225 226#endif