Line data Source code
1 : // Copyright (c) 2013-2025 Made to Order Software Corp. All Rights Reserved
2 : //
3 : // https://snapwebsites.org/project/snaplogger
4 : // contact@m2osw.com
5 : //
6 : // This program is free software; you can redistribute it and/or modify
7 : // it under the terms of the GNU General Public License as published by
8 : // the Free Software Foundation; either version 2 of the License, or
9 : // (at your option) any later version.
10 : //
11 : // This program is distributed in the hope that it will be useful,
12 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : // GNU General Public License for more details.
15 : //
16 : // You should have received a copy of the GNU General Public License along
17 : // with this program; if not, write to the Free Software Foundation, Inc.,
18 : // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 :
20 : /** \file
21 : * \brief Implementation of the ANSI converter.
22 : *
23 : * This file implements a class that takes output from a console and
24 : * convert it in various ways such as HTML, markdown, or plain text.
25 : */
26 :
27 : // self
28 : //
29 : #include "snaplogger/exception.h"
30 : #include "snaplogger/convert_ansi.h"
31 :
32 :
33 : // libutf8
34 : //
35 : #include <libutf8/base.h>
36 : #include <libutf8/iterator.h>
37 : #include <libutf8/libutf8.h>
38 :
39 :
40 : // snapdev
41 : //
42 : #include <snapdev/hexadecimal_string.h>
43 : #include <snapdev/join_strings.h>
44 :
45 :
46 : // C++
47 : //
48 : #include <iostream>
49 :
50 :
51 : // last include
52 : //
53 : #include <snapdev/poison.h>
54 :
55 :
56 :
57 : namespace snaplogger
58 : {
59 :
60 :
61 : namespace
62 : {
63 :
64 :
65 : constexpr char32_t const ESCAPE = U'\x1B'; // Escape code
66 :
67 : constexpr std::uint32_t const g_colors[] =
68 : {
69 : 0x000000, 0xde382b, 0x39b54a, 0xffc706, 0x006fb8, 0x762671, 0x2cb5e9, 0xcccccc,
70 : 0x808080, 0xff0000, 0x00ff00, 0xffff00, 0x0000ff, 0xff00ff, 0x00ffff, 0xffffff,
71 : 0x000000, 0x00005f, 0x000087, 0x0000af, 0x0000d7, 0x0000ff, 0x005f00, 0x005f5f,
72 : 0x005f87, 0x005faf, 0x005fd7, 0x005fff, 0x008700, 0x00875f, 0x008787, 0x0087af,
73 : 0x0087d7, 0x0087ff, 0x00af00, 0x00af5f, 0x00af87, 0x00afaf, 0x00afd7, 0x00afff,
74 : 0x00d700, 0x00d75f, 0x00d787, 0x00d7af, 0x00d7d7, 0x00d7ff, 0x00ff00, 0x00ff5f,
75 : 0x00ff87, 0x00ffaf, 0x00ffd7, 0x00ffff, 0x5f0000, 0x5f005f, 0x5f0087, 0x5f00af,
76 : 0x5f00d7, 0x5f00ff, 0x5f5f00, 0x5f5f5f, 0x5f5f87, 0x5f5faf, 0x5f5fd7, 0x5f5fff,
77 : 0x5f8700, 0x5f875f, 0x5f8787, 0x5f87af, 0x5f87d7, 0x5f87ff, 0x5faf00, 0x5faf5f,
78 : 0x5faf87, 0x5fafaf, 0x5fafd7, 0x5fafff, 0x5fd700, 0x5fd75f, 0x5fd787, 0x5fd7af,
79 : 0x5fd7d7, 0x5fd7ff, 0x5fff00, 0x5fff5f, 0x5fff87, 0x5fffaf, 0x5fffd7, 0x5fffff,
80 : 0x870000, 0x87005f, 0x870087, 0x8700af, 0x8700d7, 0x8700ff, 0x875f00, 0x875f5f,
81 : 0x875f87, 0x875faf, 0x875fd7, 0x875fff, 0x878700, 0x87875f, 0x878787, 0x8787af,
82 : 0x8787d7, 0x8787ff, 0x87af00, 0x87af5f, 0x87af87, 0x87afaf, 0x87afd7, 0x87afff,
83 : 0x87d700, 0x87d75f, 0x87d787, 0x87d7af, 0x87d7d7, 0x87d7ff, 0x87ff00, 0x87ff5f,
84 : 0x87ff87, 0x87ffaf, 0x87ffd7, 0x87ffff, 0xaf0000, 0xaf005f, 0xaf0087, 0xaf00af,
85 : 0xaf00d7, 0xaf00ff, 0xaf5f00, 0xaf5f5f, 0xaf5f87, 0xaf5faf, 0xaf5fd7, 0xaf5fff,
86 : 0xaf8700, 0xaf875f, 0xaf8787, 0xaf87af, 0xaf87d7, 0xaf87ff, 0xafaf00, 0xafaf5f,
87 : 0xafaf87, 0xafafaf, 0xafafd7, 0xafafff, 0xafd700, 0xafd75f, 0xafd787, 0xafd7af,
88 : 0xafd7d7, 0xafd7ff, 0xafff00, 0xafff5f, 0xafff87, 0xafffaf, 0xafffd7, 0xafffff,
89 : 0xd70000, 0xd7005f, 0xd70087, 0xd700af, 0xd700d7, 0xd700ff, 0xd75f00, 0xd75f5f,
90 : 0xd75f87, 0xd75faf, 0xd75fd7, 0xd75fff, 0xd78700, 0xd7875f, 0xd78787, 0xd787af,
91 : 0xd787d7, 0xd787ff, 0xd7af00, 0xd7af5f, 0xd7af87, 0xd7afaf, 0xd7afd7, 0xd7afff,
92 : 0xd7d700, 0xd7d75f, 0xd7d787, 0xd7d7af, 0xd7d7d7, 0xd7d7ff, 0xd7ff00, 0xd7ff5f,
93 : 0xd7ff87, 0xd7ffaf, 0xd7ffd7, 0xd7ffff, 0xff0000, 0xff005f, 0xff0087, 0xff00af,
94 : 0xff00d7, 0xff00ff, 0xff5f00, 0xff5f5f, 0xff5f87, 0xff5faf, 0xff5fd7, 0xff5fff,
95 : 0xff8700, 0xff875f, 0xff8787, 0xff87af, 0xff87d7, 0xff87ff, 0xffaf00, 0xffaf5f,
96 : 0xffaf87, 0xffafaf, 0xffafd7, 0xffafff, 0xffd700, 0xffd75f, 0xffd787, 0xffd7af,
97 : 0xffd7d7, 0xffd7ff, 0xffff00, 0xffff5f, 0xffff87, 0xffffaf, 0xffffd7, 0xffffff,
98 : 0x080808, 0x121212, 0x1c1c1c, 0x262626, 0x303030, 0x3a3a3a, 0x444444, 0x4e4e4e,
99 : 0x585858, 0x626262, 0x6c6c6c, 0x767676, 0x808080, 0x8a8a8a, 0x949494, 0x9e9e9e,
100 : 0xa8a8a8, 0xb2b2b2, 0xbcbcbc, 0xc6c6c6, 0xd0d0d0, 0xdadada, 0xe4e4e4, 0xeeeeee,
101 : };
102 :
103 :
104 :
105 : }
106 : // no name namespace
107 :
108 :
109 :
110 :
111 1112369 : convert_ansi::convert_ansi(ansi_output_t type)
112 1112369 : : f_type(type)
113 : {
114 1112369 : }
115 :
116 :
117 3 : ansi_output_t convert_ansi::get_type() const
118 : {
119 3 : return f_type;
120 : }
121 :
122 :
123 315 : void convert_ansi::set_optimize(bool optimize)
124 : {
125 315 : f_optimize = optimize;
126 315 : }
127 :
128 :
129 318 : bool convert_ansi::get_optimize() const
130 : {
131 318 : return f_optimize;
132 : }
133 :
134 :
135 210 : void convert_ansi::set_br(bool br)
136 : {
137 210 : f_br = br;
138 210 : }
139 :
140 :
141 213 : bool convert_ansi::get_br() const
142 : {
143 213 : return f_br;
144 : }
145 :
146 :
147 1112891 : void convert_ansi::write(std::string const & in)
148 : {
149 1112891 : f_data.push_back(in);
150 1112891 : }
151 :
152 :
153 1112891 : std::string convert_ansi::read()
154 : {
155 : // we assume that on a following up call you have brand new data
156 : // so we need to make sure the state was properly reset
157 : //
158 1112891 : f_graphical_state = GRAPHICAL_STATE_NORMAL;
159 1112891 : f_graphical_state_for_styles = GRAPHICAL_STATE_NORMAL;
160 1112891 : f_current_graphical_state = GRAPHICAL_STATE_NORMAL;
161 1112891 : f_result.clear();
162 : //f_param_pos = 0;
163 1112891 : f_state = state_t::ANSI_STATE_PLAIN_TEXT;
164 1112891 : f_conceal = false;
165 1112891 : f_span_open = false;
166 1112891 : f_invalid_input = false;
167 :
168 1112891 : char32_t last(U'\0');
169 : for(;;)
170 : {
171 7816677 : char32_t wc(last);
172 7816677 : if(wc == U'\0')
173 : {
174 7816669 : wc = getc();
175 : }
176 : else
177 : {
178 8 : last = U'\0';
179 : }
180 7816677 : if(wc == U'\r')
181 : {
182 15 : wc = getc();
183 15 : if(wc != U'\n')
184 : {
185 8 : last = wc;
186 8 : wc = U'\n';
187 : }
188 : }
189 7816677 : if(wc == libutf8::EOS)
190 : {
191 1112891 : break;
192 : }
193 :
194 6703786 : switch(f_state)
195 : {
196 1134242 : case state_t::ANSI_STATE_PLAIN_TEXT:
197 1134242 : if(wc == ESCAPE)
198 : {
199 1114229 : f_state = state_t::ANSI_STATE_ESCAPE;
200 : }
201 20013 : else if(wc != U'\0' && !f_conceal)
202 : {
203 19838 : switch(f_type)
204 : {
205 13405 : case ansi_output_t::ANSI_OUTPUT_HTML:
206 13405 : if(!iswspace(wc))
207 : {
208 11680 : start_style();
209 : }
210 13405 : switch(wc)
211 : {
212 5 : case U'"':
213 5 : f_result += """;
214 5 : break;
215 :
216 5 : case U'&':
217 5 : f_result += "&";
218 5 : break;
219 :
220 5 : case U'\'':
221 5 : f_result += "'";
222 5 : break;
223 :
224 10 : case U'<':
225 10 : f_result += "<";
226 10 : break;
227 :
228 10 : case U'>': // important for xhtml
229 10 : f_result += ">";
230 10 : break;
231 :
232 15 : case U'\n':
233 15 : if(f_br)
234 : {
235 12 : f_result += "<br/>";
236 : }
237 15 : f_result += '\n';
238 15 : break;
239 :
240 13355 : default:
241 13355 : f_result += libutf8::to_u8string(wc);
242 13355 : break;
243 :
244 : }
245 13405 : break;
246 :
247 2681 : case ansi_output_t::ANSI_OUTPUT_MARKDOWN:
248 2681 : if(iswspace(wc))
249 : {
250 345 : if(f_graphical_state != f_current_graphical_state
251 60 : && f_current_graphical_state != GRAPHICAL_STATE_NORMAL)
252 : {
253 60 : end_style();
254 60 : f_current_graphical_state = GRAPHICAL_STATE_NORMAL;
255 : }
256 : }
257 : else
258 : {
259 2336 : start_style();
260 : }
261 2681 : switch(wc)
262 : {
263 16 : case U'*':
264 : case U'-':
265 : case U'#':
266 : case U'_':
267 : case U'<':
268 : case U'>':
269 : case U'`':
270 : case U'[':
271 : case U'\\':
272 16 : f_result += '\\';
273 16 : f_result += static_cast<char>(wc);
274 16 : break;
275 :
276 3 : case U'\n':
277 3 : end_style();
278 3 : f_current_graphical_state = GRAPHICAL_STATE_NORMAL;
279 3 : f_result += '\n';
280 3 : break;
281 :
282 2662 : default:
283 2662 : f_result += libutf8::to_u8string(wc);
284 2662 : break;
285 :
286 : }
287 2681 : break;
288 :
289 3752 : case ansi_output_t::ANSI_OUTPUT_PLAIN_TEXT:
290 3752 : f_result += libutf8::to_u8string(wc);
291 3752 : break;
292 :
293 : }
294 : }
295 1134242 : break;
296 :
297 1114229 : case state_t::ANSI_STATE_ESCAPE:
298 1114229 : if(wc == U'[')
299 : {
300 : // Escape + '[' = Control Sequence Introducer
301 : //
302 1114222 : f_state = state_t::ANSI_STATE_PARAMETERS;
303 1114222 : f_parameters.push_back(0);
304 : }
305 : else
306 : {
307 : // we lose the Escape in case of an invalid CSI start
308 : //
309 7 : f_result += libutf8::to_u8string(wc);
310 :
311 7 : f_state = state_t::ANSI_STATE_PLAIN_TEXT;
312 : }
313 1114229 : break;
314 :
315 4455315 : case state_t::ANSI_STATE_PARAMETERS:
316 4455315 : if(wc >= U'@' && wc <= U'\x7E')
317 : {
318 : // ends the sequence and process it
319 : //
320 1114222 : switch(wc)
321 : {
322 1114046 : case U'm':
323 1114046 : apply_graphical_rendition();
324 1114046 : break;
325 :
326 133 : case U'A':
327 : case U'B':
328 : case U'C':
329 : case U'D':
330 : case U'E':
331 : case U'F':
332 : case U'G':
333 : case U'H':
334 : case U'J':
335 : case U'K':
336 : case U'S':
337 : case U'T':
338 : case U'f':
339 : case U'h':
340 : case U'i':
341 : case U'l':
342 : case U'n':
343 : case U's':
344 : case U'u':
345 : // valid but ignored
346 133 : break;
347 :
348 43 : default:
349 : // this is not really invalid, just unsupported
350 : //
351 43 : f_invalid_input = true;
352 43 : break;
353 :
354 : }
355 :
356 1114222 : f_parameters.clear();
357 :
358 1114222 : f_state = state_t::ANSI_STATE_PLAIN_TEXT;
359 : }
360 3341093 : else if(wc >= U'0' && wc <= U'9')
361 : {
362 2228446 : f_parameters[f_parameters.size() - 1] *= 10;
363 2228446 : f_parameters[f_parameters.size() - 1] += wc - U'0';
364 : }
365 : else
366 : {
367 : // we expect ';' or ':' here because all the sequences we
368 : // support are expected to have such as the separator
369 : // (the ':' is at times used for color definitions)
370 : //
371 1112647 : if(wc != U';'
372 1111988 : && wc != U':')
373 : {
374 : // "invalid" is not automatically true, but we do not
375 : // recognize other sequences at the moment
376 : //
377 1111988 : f_invalid_input = true;
378 : }
379 1112647 : f_parameters.push_back(0);
380 : }
381 4455315 : break;
382 :
383 : }
384 6703786 : }
385 :
386 1112891 : end_style();
387 :
388 1112891 : return f_result;
389 : }
390 :
391 :
392 1114046 : void convert_ansi::apply_graphical_rendition()
393 : {
394 3340346 : for(f_param_pos = 0; static_cast<std::size_t>(f_param_pos) < f_parameters.size();)
395 : {
396 : //std::cerr << "\n--- PARAMS! switch: " << f_parameters[f_param_pos] << "\n";
397 2226300 : switch(f_parameters[f_param_pos])
398 : {
399 680 : case 0:
400 680 : update_style(GRAPHICAL_STATE_NORMAL, GRAPHICAL_STATE_ALL);
401 680 : ++f_param_pos;
402 680 : f_conceal = false;
403 680 : break;
404 :
405 14 : case 1:
406 14 : update_style(GRAPHICAL_STATE_BOLD, GRAPHICAL_STATE_LIGHT);
407 14 : ++f_param_pos;
408 14 : break;
409 :
410 1112002 : case 2:
411 1112002 : update_style(GRAPHICAL_STATE_LIGHT, GRAPHICAL_STATE_BOLD);
412 1112002 : ++f_param_pos;
413 1112002 : break;
414 :
415 1112002 : case 3:
416 1112002 : update_style(GRAPHICAL_STATE_ITALIC);
417 1112002 : ++f_param_pos;
418 1112002 : break;
419 :
420 92 : case 4:
421 92 : update_style(GRAPHICAL_STATE_UNDERLINE, GRAPHICAL_STATE_DOUBLE_UNDERLINE);
422 92 : ++f_param_pos;
423 92 : break;
424 :
425 14 : case 5:
426 14 : update_style(GRAPHICAL_STATE_SLOW_BLINK, GRAPHICAL_STATE_FAST_BLINK);
427 14 : ++f_param_pos;
428 14 : break;
429 :
430 14 : case 6:
431 14 : update_style(GRAPHICAL_STATE_FAST_BLINK, GRAPHICAL_STATE_SLOW_BLINK);
432 14 : ++f_param_pos;
433 14 : break;
434 :
435 21 : case 7:
436 21 : update_style(GRAPHICAL_STATE_INVERSE);
437 21 : ++f_param_pos;
438 21 : break;
439 :
440 14 : case 8:
441 14 : f_conceal = true;
442 14 : ++f_param_pos;
443 14 : break;
444 :
445 140 : case 9:
446 140 : update_style(GRAPHICAL_STATE_CROSS_OUT);
447 140 : ++f_param_pos;
448 140 : break;
449 :
450 84 : case 21:
451 84 : update_style(GRAPHICAL_STATE_DOUBLE_UNDERLINE, GRAPHICAL_STATE_UNDERLINE);
452 84 : ++f_param_pos;
453 84 : break;
454 :
455 14 : case 22:
456 14 : update_style(0, GRAPHICAL_STATE_BOLD | GRAPHICAL_STATE_LIGHT);
457 14 : ++f_param_pos;
458 14 : break;
459 :
460 7 : case 23:
461 7 : update_style(0, GRAPHICAL_STATE_ITALIC);
462 7 : ++f_param_pos;
463 7 : break;
464 :
465 14 : case 24:
466 14 : update_style(0, GRAPHICAL_STATE_UNDERLINE | GRAPHICAL_STATE_DOUBLE_UNDERLINE);
467 14 : ++f_param_pos;
468 14 : break;
469 :
470 14 : case 25:
471 14 : update_style(0, GRAPHICAL_STATE_SLOW_BLINK | GRAPHICAL_STATE_FAST_BLINK);
472 14 : ++f_param_pos;
473 14 : break;
474 :
475 7 : case 26:
476 7 : update_style(GRAPHICAL_STATE_PROPORTIONAL);
477 7 : ++f_param_pos;
478 7 : break;
479 :
480 7 : case 27:
481 7 : update_style(0, GRAPHICAL_STATE_INVERSE);
482 7 : ++f_param_pos;
483 7 : break;
484 :
485 7 : case 28:
486 7 : f_conceal = false;
487 7 : ++f_param_pos;
488 7 : break;
489 :
490 7 : case 29:
491 7 : update_style(0, GRAPHICAL_STATE_CROSS_OUT);
492 7 : ++f_param_pos;
493 7 : break;
494 :
495 56 : case 30:
496 : case 31:
497 : case 32:
498 : case 33:
499 : case 34:
500 : case 35:
501 : case 36:
502 : case 37:
503 : // the first 8 colors are the "standard" CSI colors
504 : //
505 56 : f_foreground_color = g_colors[f_parameters[f_param_pos] - 30];
506 56 : update_style(GRAPHICAL_STATE_FOREGROUND_COLOR);
507 56 : ++f_param_pos;
508 56 : break;
509 :
510 57 : case 38:
511 57 : f_foreground_color = get_color(true);
512 57 : update_style(GRAPHICAL_STATE_FOREGROUND_COLOR);
513 57 : break;
514 :
515 161 : case 39:
516 161 : f_foreground_color = 0;
517 161 : update_style(0, GRAPHICAL_STATE_FOREGROUND_COLOR);
518 161 : ++f_param_pos;
519 161 : break;
520 :
521 56 : case 40:
522 : case 41:
523 : case 42:
524 : case 43:
525 : case 44:
526 : case 45:
527 : case 46:
528 : case 47:
529 : // the first 8 colors are the "standard" CSI colors
530 : //
531 56 : f_background_color = g_colors[f_parameters[f_param_pos] - 40];
532 56 : update_style(GRAPHICAL_STATE_BACKGROUND_COLOR);
533 56 : ++f_param_pos;
534 56 : break;
535 :
536 44 : case 48:
537 44 : f_background_color = get_color(false);
538 44 : update_style(GRAPHICAL_STATE_BACKGROUND_COLOR);
539 44 : break;
540 :
541 147 : case 49:
542 147 : f_background_color = 0;
543 147 : update_style(0, GRAPHICAL_STATE_BACKGROUND_COLOR);
544 147 : ++f_param_pos;
545 147 : break;
546 :
547 7 : case 50:
548 7 : update_style(0, GRAPHICAL_STATE_PROPORTIONAL);
549 7 : ++f_param_pos;
550 7 : break;
551 :
552 140 : case 53:
553 140 : update_style(GRAPHICAL_STATE_OVERLINE);
554 140 : ++f_param_pos;
555 140 : break;
556 :
557 7 : case 55:
558 7 : update_style(0, GRAPHICAL_STATE_OVERLINE);
559 7 : ++f_param_pos;
560 7 : break;
561 :
562 21 : case 58:
563 21 : f_underline_color = get_color(false);
564 21 : update_style(GRAPHICAL_STATE_UNDERLINE_COLOR);
565 21 : break;
566 :
567 14 : case 59:
568 14 : f_underline_color = 0;
569 14 : update_style(0, GRAPHICAL_STATE_UNDERLINE_COLOR);
570 14 : ++f_param_pos;
571 14 : break;
572 :
573 28 : case 73:
574 28 : update_style(GRAPHICAL_STATE_SUPERSCRIPT, GRAPHICAL_STATE_SUBSCRIPT);
575 28 : ++f_param_pos;
576 28 : break;
577 :
578 28 : case 74:
579 28 : update_style(GRAPHICAL_STATE_SUBSCRIPT, GRAPHICAL_STATE_SUPERSCRIPT);
580 28 : ++f_param_pos;
581 28 : break;
582 :
583 28 : case 75:
584 28 : update_style(0, GRAPHICAL_STATE_SUBSCRIPT | GRAPHICAL_STATE_SUPERSCRIPT);
585 28 : ++f_param_pos;
586 28 : break;
587 :
588 56 : case 90:
589 : case 91:
590 : case 92:
591 : case 93:
592 : case 94:
593 : case 95:
594 : case 96:
595 : case 97:
596 : // the next 8 colors are the "bright" CSI colors
597 : //
598 56 : f_foreground_color = g_colors[f_parameters[f_param_pos] - (90 - 8)];
599 56 : update_style(GRAPHICAL_STATE_FOREGROUND_COLOR);
600 56 : ++f_param_pos;
601 56 : break;
602 :
603 56 : case 100:
604 : case 101:
605 : case 102:
606 : case 103:
607 : case 104:
608 : case 105:
609 : case 106:
610 : case 107:
611 : // the next 8 colors are the "bright" CSI colors
612 : //
613 56 : f_background_color = g_colors[f_parameters[f_param_pos] - (100 - 8)];
614 56 : update_style(GRAPHICAL_STATE_BACKGROUND_COLOR);
615 56 : ++f_param_pos;
616 56 : break;
617 :
618 : // ignore the following
619 : //
620 140 : case 10: // fonts
621 : case 11:
622 : case 12:
623 : case 13:
624 : case 14:
625 : case 15:
626 : case 16:
627 : case 17:
628 : case 18:
629 : case 19:
630 : case 20:
631 : case 51: // framed
632 : case 52: // encircled
633 : case 54: // cancel framed / encircled
634 : case 60: // ideogram
635 : case 61:
636 : case 62:
637 : case 63:
638 : case 64:
639 : case 65:
640 140 : ++f_param_pos;
641 140 : break;
642 :
643 100 : default:
644 : // undefined, that means invalid
645 : //
646 100 : f_invalid_input = true;
647 100 : f_param_pos = -1;
648 100 : break;
649 :
650 : }
651 : }
652 1114046 : }
653 :
654 :
655 122 : std::int32_t convert_ansi::get_color(bool support_transparent)
656 : {
657 122 : if(f_parameters.size() >= static_cast<std::size_t>(f_param_pos) + 2UL)
658 : {
659 122 : switch(f_parameters[f_param_pos + 1])
660 : {
661 : //case 0: // app. specific, we do not support that one
662 :
663 16 : case 1:
664 16 : if(support_transparent)
665 : {
666 14 : f_param_pos += 2;
667 14 : return -1;
668 : }
669 2 : break;
670 :
671 41 : case 2:
672 41 : if(f_parameters.size() >= static_cast<std::size_t>(f_param_pos) + 5UL)
673 : {
674 38 : if(f_parameters[f_param_pos + 2] < 256
675 37 : && f_parameters[f_param_pos + 3] < 256
676 75 : && f_parameters[f_param_pos + 4] < 256)
677 : {
678 : // RGB
679 : std::int32_t const color(
680 35 : (f_parameters[f_param_pos + 2] << 16)
681 35 : | (f_parameters[f_param_pos + 3] << 8)
682 35 : | (f_parameters[f_param_pos + 4] << 0));
683 35 : f_param_pos += 5;
684 35 : return color;
685 : }
686 : }
687 6 : break;
688 :
689 20 : case 3:
690 20 : if(f_parameters.size() >= static_cast<std::size_t>(f_param_pos) + 5UL)
691 : {
692 17 : if(f_parameters[f_param_pos + 2] < 256
693 16 : && f_parameters[f_param_pos + 3] < 256
694 33 : && f_parameters[f_param_pos + 4] < 256)
695 : {
696 : // CMY -> RGB
697 : std::int32_t const color(
698 14 : ((255 - f_parameters[f_param_pos + 2]) << 16)
699 14 : | ((255 - f_parameters[f_param_pos + 3]) << 8)
700 14 : | ((255 - f_parameters[f_param_pos + 4]) << 0));
701 14 : f_param_pos += 5;
702 14 : return color;
703 : }
704 : }
705 6 : break;
706 :
707 22 : case 4:
708 22 : if(f_parameters.size() >= static_cast<std::size_t>(f_param_pos) + 6UL)
709 : {
710 18 : if(f_parameters[f_param_pos + 2] < 256
711 17 : && f_parameters[f_param_pos + 3] < 256
712 16 : && f_parameters[f_param_pos + 4] < 256
713 35 : && f_parameters[f_param_pos + 5] < 256)
714 : {
715 : // CMYK -> RGB
716 14 : int const percent(255 - f_parameters[f_param_pos + 5]);
717 : std::int32_t const color(
718 14 : (((255 - f_parameters[f_param_pos + 2]) * percent / 255) << 16)
719 14 : | (((255 - f_parameters[f_param_pos + 3]) * percent / 255) << 8)
720 14 : | (((255 - f_parameters[f_param_pos + 4]) * percent / 255) << 0));
721 14 : f_param_pos += 6;
722 14 : return color;
723 : }
724 : }
725 8 : break;
726 :
727 23 : case 5:
728 23 : if(f_parameters.size() >= static_cast<std::size_t>(f_param_pos) + 3UL)
729 : {
730 22 : if(f_parameters[f_param_pos + 2] < 256)
731 : {
732 21 : std::int32_t const color(g_colors[f_parameters[f_param_pos + 2]]);
733 21 : f_param_pos += 3;
734 21 : return color;
735 : }
736 : }
737 2 : break;
738 :
739 : }
740 : }
741 24 : f_param_pos = -1;
742 24 : f_invalid_input = true;
743 :
744 24 : return 0;
745 : }
746 :
747 :
748 2226039 : void convert_ansi::update_style(graphical_state_t new_state, graphical_state_t replaced_states)
749 : {
750 2226039 : f_graphical_state |= new_state;
751 2226039 : f_graphical_state &= ~replaced_states;
752 2226039 : }
753 :
754 :
755 14016 : void convert_ansi::start_style()
756 : {
757 : // is that state already set?
758 : // if so, we have nothing to do here
759 : //
760 14016 : if(f_graphical_state == f_current_graphical_state)
761 : {
762 13137 : return;
763 : }
764 879 : end_style();
765 879 : f_current_graphical_state = f_graphical_state;
766 :
767 : // when clearing we may end up with no more graphical style
768 : //
769 879 : if(f_current_graphical_state == GRAPHICAL_STATE_NORMAL)
770 : {
771 285 : return;
772 : }
773 :
774 594 : if(f_type == ansi_output_t::ANSI_OUTPUT_HTML)
775 : {
776 495 : open_span();
777 : }
778 : else
779 : {
780 99 : start_markdown();
781 : }
782 : }
783 :
784 :
785 1113833 : void convert_ansi::end_style()
786 : {
787 1113833 : if(f_current_graphical_state != GRAPHICAL_STATE_NORMAL)
788 : {
789 594 : if(f_type == ansi_output_t::ANSI_OUTPUT_HTML)
790 : {
791 495 : close_span();
792 : }
793 : else
794 : {
795 99 : end_markdown();
796 : }
797 : }
798 1113833 : }
799 :
800 :
801 495 : void convert_ansi::open_span()
802 : {
803 495 : std::list<std::string> tags;
804 495 : std::list<std::string> classes;
805 :
806 495 : f_graphical_state_for_styles |= f_current_graphical_state;
807 :
808 495 : if((f_current_graphical_state & GRAPHICAL_STATE_BOLD) != 0)
809 : {
810 10 : if(f_optimize)
811 : {
812 12 : tags.push_back("<b>");
813 : }
814 : else
815 : {
816 18 : classes.push_back("ansi-b");
817 : }
818 : }
819 :
820 495 : if((f_current_graphical_state & GRAPHICAL_STATE_LIGHT) != 0)
821 : {
822 30 : classes.push_back("ansi-l");
823 : }
824 :
825 495 : if((f_current_graphical_state & GRAPHICAL_STATE_ITALIC) != 0)
826 : {
827 10 : if(f_optimize)
828 : {
829 12 : tags.push_back("<i>");
830 : }
831 : else
832 : {
833 18 : classes.push_back("ansi-i");
834 : }
835 : }
836 :
837 495 : if((f_current_graphical_state & GRAPHICAL_STATE_SLOW_BLINK) != 0)
838 : {
839 30 : classes.push_back("ansi-sb");
840 : }
841 :
842 495 : if((f_current_graphical_state & GRAPHICAL_STATE_FAST_BLINK) != 0)
843 : {
844 30 : classes.push_back("ansi-fb");
845 : }
846 :
847 495 : if((f_current_graphical_state & GRAPHICAL_STATE_PROPORTIONAL) != 0)
848 : {
849 15 : classes.push_back("ansi-p");
850 : }
851 :
852 495 : if((f_current_graphical_state & GRAPHICAL_STATE_SUPERSCRIPT) != 0)
853 : {
854 20 : if(f_optimize)
855 : {
856 24 : tags.push_back("<sup>");
857 : }
858 : else
859 : {
860 36 : classes.push_back("ansi-sup");
861 : }
862 : }
863 :
864 495 : if((f_current_graphical_state & GRAPHICAL_STATE_SUBSCRIPT) != 0)
865 : {
866 20 : if(f_optimize)
867 : {
868 24 : tags.push_back("<sub>");
869 : }
870 : else
871 : {
872 36 : classes.push_back("ansi-sub");
873 : }
874 : }
875 :
876 495 : switch(f_current_graphical_state & (GRAPHICAL_STATE_UNDERLINE | GRAPHICAL_STATE_DOUBLE_UNDERLINE | GRAPHICAL_STATE_OVERLINE | GRAPHICAL_STATE_CROSS_OUT))
877 : {
878 330 : case 0:
879 330 : break;
880 :
881 25 : case GRAPHICAL_STATE_UNDERLINE:
882 25 : if(f_optimize)
883 : {
884 30 : tags.push_back("<u>");
885 : }
886 : else
887 : {
888 45 : classes.push_back("ansi-u");
889 : }
890 25 : break;
891 :
892 10 : case GRAPHICAL_STATE_DOUBLE_UNDERLINE:
893 30 : classes.push_back("ansi-d");
894 10 : break;
895 :
896 10 : case GRAPHICAL_STATE_OVERLINE:
897 30 : classes.push_back("ansi-v");
898 10 : break;
899 :
900 10 : case GRAPHICAL_STATE_CROSS_OUT:
901 10 : if(f_optimize)
902 : {
903 12 : tags.push_back("<s>");
904 : }
905 : else
906 : {
907 18 : classes.push_back("ansi-s");
908 : }
909 10 : break;
910 :
911 10 : case GRAPHICAL_STATE_DOUBLE_UNDERLINE | GRAPHICAL_STATE_CROSS_OUT:
912 30 : classes.push_back("ansi-ds");
913 10 : break;
914 :
915 10 : case GRAPHICAL_STATE_DOUBLE_UNDERLINE | GRAPHICAL_STATE_OVERLINE:
916 30 : classes.push_back("ansi-dv");
917 10 : break;
918 :
919 30 : case GRAPHICAL_STATE_DOUBLE_UNDERLINE | GRAPHICAL_STATE_OVERLINE | GRAPHICAL_STATE_CROSS_OUT:
920 90 : classes.push_back("ansi-dvs");
921 30 : break;
922 :
923 10 : case GRAPHICAL_STATE_UNDERLINE | GRAPHICAL_STATE_CROSS_OUT:
924 10 : if(f_optimize)
925 : {
926 12 : tags.push_back("<u><s>");
927 : }
928 : else
929 : {
930 18 : classes.push_back("ansi-us");
931 : }
932 10 : break;
933 :
934 10 : case GRAPHICAL_STATE_UNDERLINE | GRAPHICAL_STATE_OVERLINE:
935 30 : classes.push_back("ansi-uv");
936 10 : break;
937 :
938 30 : case GRAPHICAL_STATE_UNDERLINE | GRAPHICAL_STATE_OVERLINE | GRAPHICAL_STATE_CROSS_OUT:
939 90 : classes.push_back("ansi-uvs");
940 30 : break;
941 :
942 10 : case GRAPHICAL_STATE_OVERLINE | GRAPHICAL_STATE_CROSS_OUT:
943 30 : classes.push_back("ansi-vs");
944 10 : break;
945 :
946 : // LCOV_EXCL_START
947 : default:
948 : throw logger_logic_error(
949 : "unhandled underline + double underline + overline + cross out case (0x"
950 : + snapdev::int_to_hex(f_current_graphical_state & (GRAPHICAL_STATE_UNDERLINE | GRAPHICAL_STATE_DOUBLE_UNDERLINE | GRAPHICAL_STATE_OVERLINE | GRAPHICAL_STATE_CROSS_OUT), false, 4)
951 : + ")");
952 : // LCOV_EXCL_STOP
953 :
954 : }
955 :
956 1485 : f_result += snapdev::join_strings(tags, "");
957 :
958 495 : bool add_colors(false);
959 495 : std::int32_t foreground_color(0x000000);
960 495 : std::int32_t background_color(0xffffff);
961 :
962 495 : if((f_current_graphical_state & GRAPHICAL_STATE_FOREGROUND_COLOR) != 0)
963 : {
964 115 : add_colors = true;
965 115 : foreground_color = f_foreground_color;
966 : }
967 :
968 495 : if((f_current_graphical_state & GRAPHICAL_STATE_BACKGROUND_COLOR) != 0)
969 : {
970 105 : add_colors = true;
971 105 : background_color = f_background_color;
972 : }
973 :
974 495 : if((f_current_graphical_state & GRAPHICAL_STATE_INVERSE) != 0
975 25 : && foreground_color != -1)
976 : {
977 20 : add_colors = true;
978 20 : std::swap(foreground_color, background_color);
979 : }
980 :
981 495 : bool const add_underline_color((f_current_graphical_state & GRAPHICAL_STATE_UNDERLINE_COLOR) != 0);
982 :
983 495 : if(!classes.empty() || add_colors || add_underline_color)
984 : {
985 455 : f_span_open = true;
986 455 : f_result += "<span";
987 :
988 455 : if(!classes.empty())
989 : {
990 218 : f_result += " class=\"";
991 654 : f_result += snapdev::join_strings(classes, " ");
992 218 : f_result += '"';
993 : }
994 :
995 455 : if(add_colors || add_underline_color)
996 : {
997 240 : f_result += " style=\"";
998 240 : if(add_colors)
999 : {
1000 235 : if(foreground_color != -1)
1001 : {
1002 225 : f_result += "color:#";
1003 225 : f_result += snapdev::int_to_hex(foreground_color, false, 6);
1004 : }
1005 : else
1006 : {
1007 10 : f_result += "opacity:0%";
1008 : }
1009 235 : f_result += ";background-color:#";
1010 235 : f_result += snapdev::int_to_hex(background_color, false, 6);
1011 : }
1012 240 : if(add_underline_color)
1013 : {
1014 10 : if(add_colors)
1015 : {
1016 5 : f_result += ';';
1017 : }
1018 10 : f_result += "text-decoration-color:#";
1019 10 : f_result += snapdev::int_to_hex(f_underline_color, false, 6);
1020 : }
1021 240 : f_result += '"';
1022 : }
1023 :
1024 455 : f_result += '>';
1025 : }
1026 990 : }
1027 :
1028 :
1029 495 : void convert_ansi::close_span()
1030 : {
1031 495 : if(f_span_open)
1032 : {
1033 455 : f_result += "</span>";
1034 455 : f_span_open = false;
1035 : }
1036 :
1037 495 : if(f_optimize)
1038 : {
1039 198 : switch(f_current_graphical_state & (GRAPHICAL_STATE_UNDERLINE | GRAPHICAL_STATE_DOUBLE_UNDERLINE | GRAPHICAL_STATE_OVERLINE | GRAPHICAL_STATE_CROSS_OUT))
1040 : {
1041 10 : case GRAPHICAL_STATE_UNDERLINE:
1042 10 : f_result += "</u>";
1043 10 : break;
1044 :
1045 4 : case GRAPHICAL_STATE_CROSS_OUT:
1046 4 : f_result += "</s>";
1047 4 : break;
1048 :
1049 4 : case GRAPHICAL_STATE_UNDERLINE | GRAPHICAL_STATE_CROSS_OUT:
1050 4 : f_result += "</s></u>";
1051 4 : break;
1052 :
1053 180 : default:
1054 : // other cases make use of the <span> tag
1055 180 : break;
1056 :
1057 : }
1058 198 : if((f_current_graphical_state & GRAPHICAL_STATE_SUBSCRIPT) != 0)
1059 : {
1060 8 : f_result += "</sub>";
1061 : }
1062 198 : if((f_current_graphical_state & GRAPHICAL_STATE_SUPERSCRIPT) != 0)
1063 : {
1064 8 : f_result += "</sup>";
1065 : }
1066 198 : if((f_current_graphical_state & GRAPHICAL_STATE_ITALIC) != 0)
1067 : {
1068 4 : f_result += "</i>";
1069 : }
1070 198 : if((f_current_graphical_state & GRAPHICAL_STATE_BOLD) != 0)
1071 : {
1072 4 : f_result += "</b>";
1073 : }
1074 : }
1075 495 : }
1076 :
1077 :
1078 99 : void convert_ansi::start_markdown()
1079 : {
1080 99 : if((f_current_graphical_state & GRAPHICAL_STATE_BOLD) != 0)
1081 : {
1082 2 : f_result += "*";
1083 : }
1084 99 : if((f_current_graphical_state & GRAPHICAL_STATE_ITALIC) != 0)
1085 : {
1086 2 : f_result += "**";
1087 : }
1088 99 : }
1089 :
1090 :
1091 99 : void convert_ansi::end_markdown()
1092 : {
1093 99 : if((f_current_graphical_state & GRAPHICAL_STATE_ITALIC) != 0)
1094 : {
1095 2 : f_result += "**";
1096 : }
1097 99 : if((f_current_graphical_state & GRAPHICAL_STATE_BOLD) != 0)
1098 : {
1099 2 : f_result += "*";
1100 : }
1101 99 : }
1102 :
1103 :
1104 : /** \brief Get the HTML styles to add to your style tag.
1105 : *
1106 : * After you are done with the read() function, you must call this function
1107 : * to get all the styles. For the most part, the tags are assigned classes
1108 : * and these are defined in these styles.
1109 : *
1110 : * Note that the function does not generate the `<style>` tag. That way you
1111 : * can include these in your existing tag.
1112 : *
1113 : * I use abbreviations to make the names shorter:
1114 : *
1115 : * * bold -- b
1116 : * * cross out -- s
1117 : * * double underline -- d
1118 : * * double underline + cross out -- ds
1119 : * * double underline + overline -- dv
1120 : * * double underline + overline + cross out -- dvs
1121 : * * fast blink -- fb
1122 : * * italic -- i
1123 : * * light -- l
1124 : * * outline -- o
1125 : * * overline -- v
1126 : * * overline + cross out -- vs
1127 : * * proportional -- p
1128 : * * slow blink -- sb
1129 : * * subscript -- sub
1130 : * * superscript -- sup
1131 : * * underline -- u
1132 : * * underline + cross out -- us
1133 : * * underline + overline -- uv
1134 : * * underline + overline + cross out -- uvs
1135 : *
1136 : * \param[in] apply_to_defaults Whether the default optimization tags should
1137 : * be tweaked by this CSS code.
1138 : *
1139 : * \return Styles that can be added inside your main \<style> tag.
1140 : */
1141 582 : std::string convert_ansi::get_styles(bool apply_to_detauls) const
1142 : {
1143 582 : std::string styles;
1144 :
1145 582 : if(f_type == ansi_output_t::ANSI_OUTPUT_HTML)
1146 : {
1147 372 : if((f_graphical_state_for_styles & GRAPHICAL_STATE_BOLD) != 0)
1148 : {
1149 6 : if(apply_to_detauls && f_optimize)
1150 : {
1151 2 : styles += "b,";
1152 : }
1153 6 : styles += ".ansi-b{font-weight:bold}\n";
1154 : }
1155 :
1156 372 : if((f_graphical_state_for_styles & GRAPHICAL_STATE_LIGHT) != 0)
1157 : {
1158 6 : styles += ".ansi-l{font-weight:light}\n";
1159 : }
1160 :
1161 372 : if((f_graphical_state_for_styles & GRAPHICAL_STATE_ITALIC) != 0)
1162 : {
1163 6 : if(apply_to_detauls && f_optimize)
1164 : {
1165 2 : styles += "i,";
1166 : }
1167 6 : styles += ".ansi-i{font-style:italic}\n";
1168 : }
1169 :
1170 372 : if((f_graphical_state_for_styles & (GRAPHICAL_STATE_SLOW_BLINK | GRAPHICAL_STATE_FAST_BLINK)) != 0)
1171 : {
1172 12 : styles += "@keyframes ansi-blinker{50%{opacity:0}}\n";
1173 : }
1174 :
1175 372 : if((f_graphical_state_for_styles & GRAPHICAL_STATE_SLOW_BLINK) != 0)
1176 : {
1177 6 : styles += ".ansi-sb{animation:ansi-blinker 2s linear infinite}\n";
1178 : }
1179 :
1180 372 : if((f_graphical_state_for_styles & GRAPHICAL_STATE_FAST_BLINK) != 0)
1181 : {
1182 6 : styles += ".ansi-fb{animation:ansi-blinker 0.4s linear infinite}\n";
1183 : }
1184 :
1185 372 : if((f_graphical_state_for_styles & GRAPHICAL_STATE_PROPORTIONAL) != 0)
1186 : {
1187 3 : styles += ".ansi-p{font-family:sans-serif}\n";
1188 : }
1189 :
1190 372 : if((f_graphical_state_for_styles & GRAPHICAL_STATE_SUPERSCRIPT) != 0)
1191 : {
1192 12 : if(apply_to_detauls && f_optimize)
1193 : {
1194 4 : styles += "sup,";
1195 : }
1196 12 : styles += ".ansi-sup{font-size:60%;vertical-align:super}\n";
1197 : }
1198 :
1199 372 : if((f_graphical_state_for_styles & GRAPHICAL_STATE_SUBSCRIPT) != 0)
1200 : {
1201 12 : if(apply_to_detauls && f_optimize)
1202 : {
1203 4 : styles += "sub,";
1204 : }
1205 12 : styles += ".ansi-sub{font-size:60%;vertical-align:sub}\n";
1206 : }
1207 :
1208 : // TODO: the following if() test is a simplification, we could change
1209 : // that to only include the classes we used instead
1210 : //
1211 372 : if((f_graphical_state_for_styles & (GRAPHICAL_STATE_UNDERLINE | GRAPHICAL_STATE_DOUBLE_UNDERLINE | GRAPHICAL_STATE_OVERLINE | GRAPHICAL_STATE_CROSS_OUT)) != 0)
1212 : {
1213 : // Note: The double style applies to both, the overline and
1214 : // the underline; in the XTerm console, though it
1215 : // only applies to the underline; to simplify here
1216 : // especially since I've never seen it used anyway,
1217 : // I keep it as is (double on both ends)
1218 :
1219 : // CROSS OUT on its own
1220 : //
1221 93 : if(apply_to_detauls && f_optimize)
1222 : {
1223 31 : styles += "s,";
1224 : }
1225 93 : styles += ".ansi-s{text-decoration-line:line-through}\n";
1226 :
1227 : // UNDERLINE on its own
1228 : //
1229 93 : if(apply_to_detauls && f_optimize)
1230 : {
1231 31 : styles += "u,";
1232 : }
1233 93 : styles += ".ansi-u{text-decoration-line:underline}\n";
1234 :
1235 : // DOUBLE UNDERLINE on its own
1236 : //
1237 93 : styles += ".ansi-d{text-decoration-line:underline;text-decoration-style:double}\n";
1238 :
1239 : // OVERLINE on its own
1240 : //
1241 93 : styles += ".ansi-v{text-decoration-line:overline;}\n";
1242 :
1243 : // UNDERLINE + CROSS OUT
1244 : //
1245 93 : styles += ".ansi-us{text-decoration-line:underline line-through}\n";
1246 :
1247 : // UNDERLINE + OVERLINE
1248 : //
1249 93 : styles += ".ansi-uv{text-decoration-line:underline overline}\n";
1250 :
1251 : // UNDERLINE + OVERLINE + CROSS OUT
1252 : //
1253 93 : styles += ".ansi-uvs{text-decoration-line:underline overline line-through}\n";
1254 :
1255 : // DOUBLE UNDERLINE + CROSS OUT
1256 : //
1257 93 : styles += ".ansi-ds{text-decoration-line:underline line-through;text-decoration-style:double}\n";
1258 :
1259 : // DOUBLE UNDERLINE + OVERLINE
1260 : //
1261 93 : styles += ".ansi-dv{text-decoration-line:underline overline;text-decoration-style:double}\n";
1262 :
1263 : // DOUBLE UNDERLINE + OVERLINE + CROSS OUT
1264 : //
1265 93 : styles += ".ansi-dvs{text-decoration-line:underline overline line-through;text-decoration-style:double}\n";
1266 :
1267 : // OVERLINE + CROSS OUT
1268 : //
1269 93 : styles += ".ansi-vs{text-decoration-line:overline line-through}\n";
1270 : }
1271 : }
1272 :
1273 582 : return styles;
1274 : } // LCOV_EXCL_LINE
1275 :
1276 :
1277 : /** \brief Check whether any of the input was considered invalid.
1278 : *
1279 : * If the input data could not be read 100% without errors (skipping
1280 : * sequence of unknown character sequences) then this function returns
1281 : * true to signal that there was at least one error.
1282 : *
1283 : * \return true if a sequence of bytes in the input was not considered valid.
1284 : */
1285 1112891 : bool convert_ansi::has_invalid_data() const
1286 : {
1287 1112891 : return f_invalid_input;
1288 : }
1289 :
1290 :
1291 : /** \brief Get the following character as a Unicode value.
1292 : *
1293 : * This function reads the input data for one character. It converts
1294 : * the character to a full char32_t character (i.e. a Unicode rune).
1295 : *
1296 : * \todo
1297 : * A Unicode character sequence that ends up being broken in two separate
1298 : * strings (see write()) is not properly recognized. We'd need to support
1299 : * such one day.
1300 : *
1301 : * \return The Unicode character or libutf8::EOS if no more data is available.
1302 : */
1303 7816684 : char32_t convert_ansi::getc()
1304 : {
1305 8929576 : while(!f_data.empty())
1306 : {
1307 7816685 : if(f_pos >= f_data.front().length())
1308 : {
1309 1112891 : f_data.pop_front();
1310 1112891 : f_pos = 0;
1311 : }
1312 : else
1313 : {
1314 6703794 : char32_t wc(U'\0');
1315 6703794 : char const * end(f_data.front().data() + f_pos);
1316 6703794 : char const * start(end);
1317 6703794 : std::size_t len(f_data.front().length() - f_pos);
1318 6703794 : int const r(libutf8::mbstowc(wc, end, len));
1319 :
1320 : // on invalid UTF-8 sequences, we may skip many bytes at once
1321 : // the following takes that in account
1322 : //
1323 6703794 : f_pos += end - start;
1324 :
1325 6703794 : if(r > 0)
1326 : {
1327 6703793 : return wc;
1328 : }
1329 : // if r == 0, we reached the end of the string
1330 : // otherwise we got an error and want to make a note of that
1331 : //
1332 1 : if(r != 0)
1333 : {
1334 1 : f_invalid_input = true;
1335 : }
1336 : }
1337 : }
1338 :
1339 : // done, no more input data
1340 : //
1341 1112891 : return libutf8::EOS;
1342 : }
1343 :
1344 :
1345 :
1346 : }
1347 : // namespace snaplogger
1348 : // vim: ts=4 sw=4 et
|