But, unfortunately, this option does a nice job that goes beyond what I need. And the problem is that by going beyond it turns itself useless to address my current needs. It's true that it offers a tiny bit of flexibility:
But it is insufficient. The problem is that the syntax-highlighting is formatted via CSS internal styles of type text/css within a HTML comment within the well-known <style> tag. What is supposed to reflect the syntax-highlighting is within <span> tags of specific classes. Hence, I can't use it like that (not even portions of it) right away here in Blogger as I want:
<!DOCTYPE ... >
<html>
<head>
<title>framework.hxx</title>
<meta ... >
<style type="text/css">
<!--
body {...}
pre {...}
table {...}
.highlight-caret-row {...}
.ST1 {...}
.preprocessor {...}
.comment {...}
.literal {...}
.pragma-omp-keyword-directive {...}
.ST0 {...}
-->
</style>
</head>
<body>
...
11 <span class="literal">virtual</span>
~<span class="ST1">file</span>() {}
...
That is, not even portions of the above produce:
(unless with a completely inviable bit-by-bit editing)
11 virtual ~file() {}
I've got stuck to it for a while, a little sad I should say. Then I tried to surf the Web for possible help from others that could have had similar (or even the same) issue. It's true I've found them! But as for the "solutions", none would do it, unless perhaps after a long way installing a bunch of stuff far, far away, from where I stand and all that would render it inviable to me. So, I started trying to accept the facts and limitations. BUT, as a "willing to be" C++ programmer I had all the power of C++ at my fingertips. And that was when I decided to craft my own, yes, little, specific, C++ tool for achieving my goal and which I present below. Please, understand, it's the very first version of it, a bit crude one could honestly say, and with room for many improvements and optimizations, specially with respect to what tools from the C++ STL would be better suited for each task. Sometimes, or maybe most of the times, there is more than one way of doing something with the C++ STL. The code below was born on-the-fly, the opposite way as well-planed code should come into light, but anyway, I was yet a little skeptical about the intent. I view it today as a tiny (the tip of the iceberg) endeavor in exploring STL. BUT, at the same time it is also a strategy to "kick-off" and/or "get going" for later devising better approaches and so on. And that's all about it. Here's the code which shall speak for itself:
1 #include <cstdlib>
2
3 #include <locale>
4 #include <string>
5 #include <sstream>
6 #include <iostream>
7 #include <iterator>
8 #include <algorithm>
9 #include <map>
10
11 std::string load()
12 {
13 std::string file;
14 std::string line;
15
16 while ( std::getline( std::cin, line ) )
17 file += line + "\n";
18
19 return file;
20 }
21
22 using iterator = std::string::iterator;
23 using index = std::string::size_type;
24
25 const std::string keyword_style { "style" };
26 const std::string keyword_class { "class" };
27 const std::string keyword_pre { "pre" };
28
29 std::map< const std::string, std::string > map;
30
31 iterator find
(
const std::string & keyword,
const iterator p, const iterator q
)
32 {
33 return std::search( p, q, keyword.begin(), keyword.end() );
34 }
35
36 std::string trim( const std::string & source )
37 {
38 std::stringstream rv;
39
40 std::copy_if
41 (
42 source.begin(), source.end(),
43 std::ostream_iterator< char >( rv ),
44 [] ( char c ) { return !std::isspace( c, std::locale() ); }
45 );
46
47 return rv.str();
48 }
49
50 std::string nobg( const std::string & source )
51 {
52 const std::string bg_color { "background-color" };
53 std::string rv { source };
54
55 index bg_b = rv.find( bg_color );
56 if ( bg_b != std::string::npos )
57 {
58 index bg_e = rv.find( ';', bg_b + 1 );
59 if ( bg_e != std::string::npos )
60 return rv.erase( bg_b, bg_e - bg_b + 1 );
61 else
62 return rv.erase( bg_b, std::string::npos - bg_b );
63 }
64
65 return rv;
66 }
67
68 void load_styles( const iterator sb, const iterator se )
69 {
70 // Styles' stream: " target { style : value ; ... } ... "
71 std::stringstream ss;
72 std::copy( sb, se, std::ostream_iterator< char >( ss ) );
73
74 std::string target;
75 while ( std::getline( ss, target, '{' ) )
76 {
77 target = trim( target );
78
79 // Skip trimmed "targets" that had only \n
80 if ( target.size() > 0 )
81 {
82 // This program is special, not general,
83 // so I treat only this special case.
84 if ( target[0] == '.' )
85 target = target.substr( 1 );
86
87 std::string styles;
88 if ( std::getline( ss, styles, '}' ) )
89 map[ target ] = nobg( trim( styles ) );
90 }
91 }
92 }
93
94 void scan_styles( iterator & q, const iterator e )
95 {
96 // [q-1:e] == >...
97
98 const std::string keyword_style_end { "</style" };
99 const std::string comment_beg { "<!--" };
100 const std::string comment_end { "-->" };
101
102 // Where is </style...> ?
103 iterator se = find( keyword_style_end, q, e );
104 if ( se != e )
105 {
106 // Remember from where to later skip past > in </style...>
107 iterator kwse = se + keyword_style_end.size();
108
109 // Remember where styles begin.
110 iterator sb = q;
111
112 // Is there an optional <!-- ?
113 iterator c = find( comment_beg, sb, se );
114 if ( c != se )
115 {
116 // Skip the <!--
117 // In this case the styles are within comments
118 sb = c + comment_beg.size();
119
120 // Is there a --> ?
121 c = find( comment_end, sb, se );
122 if ( c != se )
123 // Remember where styles end
124 // Actually it would be c-1
125 // but algorithms are always [x:y)
126 // so c is OK as I'll get [sb:c) == [sb:c-1]
127 se = c;
128 else
129 // If there's a <!-- there must be a -->
130 ::exit( EXIT_FAILURE );
131 }
132
133 load_styles( sb, se );
134
135 // Now must commit the consumption of input
136 // regarding what has been processed earlier here above
137 q = std::find( kwse, e, '>' );
138 if ( q == e )
139 // Missing > in the closing tag </style
140 ::exit( EXIT_FAILURE );
141
142 q++;
143 }
144 else
145 // No matching </style...>
146 ::exit( EXIT_FAILURE );
147 }
148
149 void process_class( const iterator k, const iterator q )
150 {
151 // [k:q) == class...>
152
153 // Where is the value "..." as in class="..." ?
154 iterator vb = std::find( k + keyword_class.size(), q, '"');
155 if ( vb == q )
156 // There can't be a class attribute without a value
157 ::exit( EXIT_FAILURE );
158
159 // vb == "
160
161 iterator ve = std::find( vb+1, q, '"' );
162 if ( ve == q )
163 // If there was an opening " there must be a closing ".
164 ::exit( EXIT_FAILURE );
165
166 // ve == "
167
168 // [vb,ve] == "...xyz..."
169
170 // [vb+1, ve) == [vb+1, ve-1] == ...xyz...
171
172 // Get map key to be later inlined
173 std::stringstream key;
174 std::copy
(
vb+1, ve,
std::ostream_iterator< char >( key )
);
175
176 //
177 // The next 2 lines will effectively replace
178 // class...=..."..." for style="..." in the output
179 //
180
181 std::cout << "style=\"" << map[ key.str() ] << "\"";
182
183 // [ve+1,q) == "...>
184 std::copy
(
ve+1, q,
std::ostream_iterator< char >( std::cout )
);
185 }
186
187 void process_pre( const iterator k, const iterator q )
188 {
189 // [k:q) == pre...>
190
191 // Outputs in pre style="..."> where it was pre...>
192 std::cout << "pre style=\"" << map[ "pre" ] << "\">";
193 }
194
195 int main()
196 {
197 std::string input { load() };
198
199 auto p = input.begin();
200 auto e = input.end();
201
202 // I'll be walking over tags
203 p = std::find( p, e, '<' );
204 while ( p != e )
205 {
206 // Where the current tag ends?
207 auto q = std::find( p, e, '>' );
208
209 if ( q == e )
210 // Every tag marker must be well formed.
211 ::exit( EXIT_FAILURE );
212
213 // Move next to > of the opening tag
214 // [q-1:e] == >...
215 ++q;
216
217 // For now I don't care about closing tags
218 if ( p[1] != '/' )
219 {
220 // Select and process what matters
221 iterator k;
222
223 if ( ( k = find( keyword_style, p, q ) ) != q )
224 {
225 // q is passed by reference
226 // q will move next to > in </style...>
227 // </style...> is the only special closing tag
228 scan_styles( q, e );
229 }
230 else if ( ( k = find( keyword_class, p, q ) ) != q )
231 {
232 // [p:k] == <...c
233 std::copy
(
p, k,
std::ostream_iterator< char >( std::cout )
);
234
235 // [k:q-1] == class...>
236 process_class( k, q );
237 }
238 else if ( ( k = find( keyword_pre, p, q ) ) != q )
239 {
240 // [p:k] == <...p
241 std::copy
(
p, k,
std::ostream_iterator< char >( std::cout )
);
242
243 // [k:q-1] == pre...>
244 process_pre( k, q );
245 }
246 else
247 {
248 // q has already moved next to > in <...>
249 // [p:q) == <...>
250 std::copy
(
p, q,
std::ostream_iterator< char >( std::cout )
);
251 }
252 }
253 else
254 {
255 // Nothing that matters, </...>, just skip
256 // [p:q) == <...>
257 std::copy
(
p, q,
std::ostream_iterator< char >( std::cout )
);
258 }
259
260 // Going ahead to the next tag
261 // q points next to > in any previous <...>
262 p = q;
263 p = std::find( p, e, '<' );
264
265 // [q-1:p] == >...<
266 std::copy
(
q, p,
std::ostream_iterator< char >( std::cout )
);
267 }
268
269 return EXIT_SUCCESS;
270 }
The issue with this kind of C++ STL programming is that dealing with iterators required a lot of comments, otherwise one can very easily get messed up. But, imagine how worse than that things could be if dealing with plain pointers as in legacy C coding style...
After an easy and simple build of the above code, the program can be used as follows:
- Save the Print to HTML file from NetBeans where the program lives
- Pipe the file in through the program and redirect its output
(inliner happens to be the name I gave to the program)
$ cat code.html |./inliner >./code_inline_styled.html
The kind of formatted code that's output can be seen above throughout this post. I pasted-in the in-line-styled code and then applied the Courier font (to try staying consistent with all my previous postings).