1 /*
2  * Copyright © 2017, 2018 Christian Persch
3  *
4  * This library is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License as published
6  * by the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public License
15  * along with this library.  If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #pragma once
19 
20 #include <cstdint>
21 #include <algorithm>
22 #include <string>
23 
24 #include "parser.hh"
25 
26 namespace vte {
27 
28 namespace parser {
29 
30 class Sequence;
31 
32 class Parser {
33 public:
34         friend class Sequence;
35 
Parser()36         Parser() noexcept
37         {
38                 vte_parser_init(&m_parser);
39         }
40         Parser(Parser const&) = delete;
41         Parser(Parser&&) = delete;
42 
~Parser()43         ~Parser() noexcept
44         {
45                 vte_parser_deinit(&m_parser);
46         }
47 
48         Parser& operator=(Parser const&) = delete;
49         Parser& operator=(Parser&&) = delete;
50 
feed(uint32_t raw)51         inline int feed(uint32_t raw) noexcept
52         {
53                 return vte_parser_feed(&m_parser, raw);
54         }
55 
reset()56         inline void reset() noexcept
57         {
58                 vte_parser_reset(&m_parser);
59         }
60 
set_dispatch_unripe(bool enable)61         inline void set_dispatch_unripe(bool enable) noexcept
62         {
63                 vte_parser_set_dispatch_unripe(&m_parser, enable);
64         }
65 
ignore_until_st()66         inline void ignore_until_st() noexcept
67         {
68                 vte_parser_ignore_until_st(&m_parser);
69         }
70 
71 protected:
72         vte_parser_t m_parser;
73 }; // class Parser
74 
75 class Sequence {
76 public:
77 
78         Sequence() = default;
79         Sequence(Sequence const&) = delete;
80         Sequence(Sequence&&) = delete;
81         ~Sequence() = default;
82 
Sequence(Parser & parser)83         Sequence(Parser& parser)
84         {
85                 m_seq = &parser.m_parser.seq;
86         }
87 
88         typedef int number;
89 
90         char* ucs4_to_utf8(gunichar const* str,
91                            ssize_t len = -1) const noexcept;
92 
93         void print() const noexcept;
94 
95         /* type:
96          *
97          *
98          * Returns: the type of the sequence, a value from the VTE_SEQ_* enum
99          */
type() const100         inline constexpr unsigned int type() const noexcept
101         {
102                 return m_seq->type;
103         }
104 
105         /* command:
106          *
107          * Returns: the command the sequence codes for, a value
108          *   from the VTE_CMD_* enum, or %VTE_CMD_NONE if the command is
109          *   unknown
110          */
command() const111         inline constexpr unsigned int command() const noexcept
112         {
113                 return m_seq->command;
114         }
115 
116         /* charset:
117          *
118          * This is the charset to use in a %VTE_CMD_GnDm, %VTE_CMD_GnDMm,
119          * %VTE_CMD_CnD or %VTE_CMD_DOCS command.
120          *
121          * Returns: the charset, a value from the VTE_CHARSET_* enum.
122          */
charset() const123         inline constexpr unsigned int charset() const noexcept
124         {
125                 return VTE_CHARSET_GET_CHARSET(m_seq->charset);
126         }
127 
128         /* slot:
129          *
130          * This is the slot in a %VTE_CMD_GnDm, %VTE_CMD_GnDMm,
131          * or %VTE_CMD_CnD command.
132          *
133          * Returns: the slot, a value from the 0..3 for Gn*, or 0..1 for CnD
134          */
slot() const135         inline constexpr unsigned int slot() const noexcept
136         {
137                 return VTE_CHARSET_GET_SLOT(m_seq->charset);
138         }
139 
140         /* introducer:
141          *
142          * This is the character introducing the sequence, if any.
143          *
144          * Returns: the introducing character
145          */
introducer() const146         inline constexpr uint32_t introducer() const noexcept
147         {
148                 return m_seq->introducer;
149         }
150 
151         /* terminator:
152          *
153          * This is the character terminating the sequence, or, for a
154          * %VTE_SEQ_GRAPHIC sequence, the graphic character.
155          *
156          * Returns: the terminating character
157          */
terminator() const158         inline constexpr uint32_t terminator() const noexcept
159         {
160                 return m_seq->terminator;
161         }
162 
163         /* st:
164          *
165          * This is the string terminator ending a OSC, DCS, APC, PM, or SOS sequence
166          *
167          * Returns: the string terminator character
168          */
st() const169         inline constexpr uint32_t st() const noexcept
170         {
171                 return m_seq->st;
172         }
173 
174         /* is_c1:
175          *
176          * Whether the sequence was introduced with a C0 or C1 control.
177          *
178          * Returns: true iff the introducer was a C1 control
179          */
is_c1() const180         inline constexpr bool is_c1() const noexcept
181         {
182                 return (introducer() & 0x80) != 0;
183         }
184 
185         /* is_st_c1:
186          *
187          * Whether the control string was terminated with a C0 or C1 control.
188          *
189          * Returns: true iff the terminator was the C1 ST
190          */
is_st_c1() const191         inline constexpr bool is_st_c1() const noexcept
192         {
193                 return (st() & 0x80) != 0;
194         }
195 
196         /* is_ripe:
197          *
198          * Whether the control string is complete.
199          * This returns true when the final character has been received,
200          * and false when the string terminator has been received.
201          * This is only meaningful for DCS sequences, which are dispatched
202          * twice.
203          *
204          * Returns: true iff the DCS sequence is complete
205          */
is_ripe() const206         inline constexpr bool is_ripe() const noexcept
207         {
208                 return st() != 0;
209         }
210 
is_unripe() const211         inline constexpr bool is_unripe() const noexcept
212         {
213                 return !is_ripe();
214         }
215 
216         /* intermediates:
217          *
218          * This is the pintro and intermediate characters in the sequence, if any.
219          *
220          * Returns: the intermediates
221          */
intermediates() const222         inline constexpr unsigned int intermediates() const noexcept
223         {
224                 return m_seq->intermediates;
225         }
226 
227         // FIXMEchpe: upgrade to C++17 and use the u32string_view version below, instead
228         /*
229          * string:
230          *
231          * This is the string argument of a DCS or OSC sequence.
232          *
233          * Returns: the string argument
234          */
string() const235         inline std::u32string string() const noexcept
236         {
237                 size_t len;
238                 auto buf = vte_seq_string_get(&m_seq->arg_str, &len);
239                 return std::u32string(reinterpret_cast<char32_t*>(buf), len);
240         }
241 
242         #if 0
243         /*
244          * string:
245          *
246          * This is the string argument of a DCS or OSC sequence.
247          *
248          * Returns: the string argument
249          */
250         inline constexpr std::u32string_view string() const noexcept
251         {
252                 size_t len = 0;
253                 auto buf = vte_seq_string_get(&m_seq->arg_str, &len);
254                 return std::u32string_view(buf, len);
255         }
256         #endif
257 
258         /*
259          * string:
260          *
261          * This is the string argument of a DCS or OSC sequence.
262          *
263          * Returns: the string argument
264          */
265         std::string string_utf8() const noexcept;
266 
string_param() const267         inline char* string_param() const noexcept
268         {
269                 size_t len = 0;
270                 auto buf = vte_seq_string_get(&m_seq->arg_str, &len);
271                 return ucs4_to_utf8(buf, len);
272         }
273 
274         /* size:
275          *
276          * Returns: the number of parameters
277          */
size() const278         inline constexpr unsigned int size() const noexcept
279         {
280                 return m_seq->n_args;
281         }
282 
283 
284         /* size:
285          *
286          * Returns: the number of parameter blocks, counting runs of subparameters
287          *   as only one parameter
288          */
size_final() const289         inline constexpr unsigned int size_final() const noexcept
290         {
291                 return m_seq->n_final_args;
292         }
293 
294         /* capacity:
295          *
296          * Returns: the number of parameter blocks, counting runs of subparameters
297          *   as only one parameter
298          */
capacity() const299         inline constexpr unsigned int capacity() const noexcept
300         {
301                 return G_N_ELEMENTS(m_seq->args);
302         }
303 
304         /* param:
305          * @idx:
306          * @default_v: the value to use for default parameters
307          *
308          * Returns: the value of the parameter at index @idx, or @default_v if
309          *   the parameter at this index has default value, or the index
310          *   is out of bounds
311          */
param(unsigned int idx,int default_v=-1) const312         inline constexpr int param(unsigned int idx,
313                                    int default_v = -1) const noexcept
314         {
315                 return __builtin_expect(idx < size(), 1) ? vte_seq_arg_value(m_seq->args[idx], default_v) : default_v;
316         }
317 
318         /* param:
319          * @idx:
320          * @default_v: the value to use for default parameters
321          * @min_v: the minimum value
322          * @max_v: the maximum value
323          *
324          * Returns: the value of the parameter at index @idx, or @default_v if
325          *   the parameter at this index has default value, or the index
326          *   is out of bounds. The returned value is clamped to the
327          *   range @min_v..@max_v (or returns min_v, if min_v > max_v).
328          */
param(unsigned int idx,int default_v,int min_v,int max_v) const329         inline constexpr int param(unsigned int idx,
330                                    int default_v,
331                                    int min_v,
332                                    int max_v) const noexcept
333         {
334                 auto v = param(idx, default_v);
335                 // not using std::clamp() since it's not guaranteed that min_v <= max_v
336                 return std::max(std::min(v, max_v), min_v);
337         }
338 
339         /* param_nonfinal:
340          * @idx:
341          *
342          * Returns: whether the parameter at @idx is nonfinal, i.e.
343          * there are more subparameters after it.
344          */
param_nonfinal(unsigned int idx) const345         inline constexpr bool param_nonfinal(unsigned int idx) const noexcept
346         {
347                 return __builtin_expect(idx < size(), 1) ? vte_seq_arg_nonfinal(m_seq->args[idx]) : false;
348         }
349 
350         /* param_default:
351          * @idx:
352          *
353          * Returns: whether the parameter at @idx has default value
354          */
param_default(unsigned int idx) const355         inline constexpr bool param_default(unsigned int idx) const noexcept
356         {
357                 return __builtin_expect(idx < size(), 1) ? vte_seq_arg_default(m_seq->args[idx]) : true;
358         }
359 
360         /* next:
361          * @idx:
362          *
363          * Returns: the index of the next parameter block
364          */
next(unsigned int idx) const365         inline constexpr unsigned int next(unsigned int idx) const noexcept
366         {
367                 /* Find the final parameter */
368                 while (param_nonfinal(idx))
369                         ++idx;
370                 /* And return the index after that one */
371                 return ++idx;
372         }
373 
cbegin() const374         inline constexpr unsigned int cbegin() const noexcept
375         {
376                 return 0;
377         }
378 
cend() const379         inline constexpr unsigned int cend() const noexcept
380         {
381                 return size();
382         }
383 
384         /* collect:
385          *
386          * Collects some final parameters.
387          *
388          * Returns: %true if the sequence parameter list begins with
389          *  a run of final parameters that were collected.
390          */
collect(unsigned int start_idx,std::initializer_list<int * > params,int default_v=-1) const391         inline constexpr bool collect(unsigned int start_idx,
392                                       std::initializer_list<int*> params,
393                                       int default_v = -1) const noexcept
394         {
395                 unsigned int idx = start_idx;
396                 for (auto i : params) {
397                         *i = param(idx, default_v);
398                         idx = next(idx);
399                 }
400 
401                 return (idx - start_idx) == params.size();
402         }
403 
404         /* collect1:
405          * @idx:
406          * @default_v:
407          *
408          * Collects one final parameter.
409          *
410          * Returns: the parameter value, or @default_v if the parameter has
411          *   default value or is not a final parameter
412          */
collect1(unsigned int idx,int default_v=-1) const413         inline constexpr int collect1(unsigned int idx,
414                                       int default_v = -1) const noexcept
415         {
416                 return __builtin_expect(idx < size(), 1) ? vte_seq_arg_value_final(m_seq->args[idx], default_v) : default_v;
417         }
418 
419         /* collect1:
420          * @idx:
421          * @default_v:
422          * @min_v:
423          * @max_v
424          *
425          * Collects one final parameter.
426          *
427          * Returns: the parameter value clamped to the @min_v .. @max_v range (or @min_v,
428          * if min_v > max_v),
429          *   or @default_v if the parameter has default value or is not a final parameter
430          */
collect1(unsigned int idx,int default_v,int min_v,int max_v) const431         inline constexpr int collect1(unsigned int idx,
432                                       int default_v,
433                                       int min_v,
434                                       int max_v) const noexcept
435         {
436                 int v = __builtin_expect(idx < size(), 1) ? vte_seq_arg_value_final(m_seq->args[idx], default_v) : default_v;
437                 // not using std::clamp() since it's not guaranteed that min_v <= max_v
438                 return std::max(std::min(v, max_v), min_v);
439         }
440 
441         /* collect_subparams:
442          *
443          * Collects some subparameters.
444          *
445          * Returns: %true if the sequence parameter list contains enough
446          *   subparams at @start_idx
447          */
collect_subparams(unsigned int start_idx,std::initializer_list<int * > params,int default_v=-1) const448         inline constexpr bool collect_subparams(unsigned int start_idx,
449                                                 std::initializer_list<int*> params,
450                                                 int default_v = -1) const noexcept
451         {
452                 unsigned int idx = start_idx;
453                 for (auto i : params) {
454                         *i = param(idx++, default_v);
455                 }
456 
457                 return idx <= next(start_idx);
458         }
459 
operator bool() const460         inline explicit operator bool() const { return m_seq != nullptr; }
461 
462         /* This is only used in the test suite */
seq_ptr()463         vte_seq_t** seq_ptr() { return &m_seq; }
464 
465 private:
466         vte_seq_t* m_seq{nullptr};
467 
468         char const* type_string() const;
469         char const* command_string() const;
470 }; // class Sequence
471 
472 /* Helper classes to unify UTF-32 and UTF-8 versions of SequenceBuilder.
473  * ::put will only be called with C1 controls, so it's ok to simplify
474  * the UTF-8 version to simply prepend 0xc2.
475  */
476 template<typename C>
477 class DirectEncoder {
478 public:
479         using string_type = std::basic_string<C>;
put(string_type & s,C const c) const480         inline void put(string_type& s, C const c) const noexcept
481         {
482                 s.push_back(c);
483         }
484 }; // class DirectEncoder
485 
486 class UTF8Encoder {
487 public:
488         using string_type = std::basic_string<char>;
put(string_type & s,unsigned char const c) const489         inline void put(string_type& s, unsigned char const c) const noexcept
490         {
491                 s.push_back(0xc2);
492                 s.push_back(c);
493         }
494 }; // class UTF8Encoder
495 
496 template<class S, class E = DirectEncoder<typename S::value_type>>
497 class SequenceBuilder {
498 public:
499         using string_type = S;
500         using encoder_type = E;
501 
502 private:
503         vte_seq_t m_seq;
504         string_type m_arg_str;
505         unsigned char m_intermediates[4];
506         unsigned char m_n_intermediates{0};
507         unsigned char m_param_intro{0};
508         encoder_type m_encoder;
509 
510 public:
SequenceBuilder(unsigned int type=VTE_SEQ_NONE)511         SequenceBuilder(unsigned int type = VTE_SEQ_NONE)
512         {
513                 memset(&m_seq, 0, sizeof(m_seq));
514                 set_type(type);
515         }
516 
SequenceBuilder(unsigned int type,uint32_t f)517         SequenceBuilder(unsigned int type,
518                         uint32_t f)
519                 : SequenceBuilder(type)
520         {
521                 set_final(f);
522         }
523 
SequenceBuilder(unsigned int type,string_type const & str)524         SequenceBuilder(unsigned int type,
525                         string_type const& str)
526                 : SequenceBuilder(type)
527         {
528                 set_string(str);
529         }
530 
SequenceBuilder(unsigned int type,string_type && str)531         SequenceBuilder(unsigned int type,
532                         string_type&& str)
533                 : SequenceBuilder(type)
534         {
535                 set_string(str);
536         }
537 
538         SequenceBuilder(SequenceBuilder const&) = delete;
539         SequenceBuilder(SequenceBuilder&&) = delete;
540         ~SequenceBuilder() = default;
541 
542         SequenceBuilder& operator= (SequenceBuilder const&) = delete;
543         SequenceBuilder& operator= (SequenceBuilder&&) = delete;
544 
type() const545         inline constexpr unsigned int type() const noexcept { return m_seq.type; }
546 
set_type(unsigned int type)547         inline void set_type(unsigned int type) noexcept
548         {
549                 m_seq.type = type;
550         }
551 
set_final(uint32_t t)552         inline void set_final(uint32_t t) noexcept
553         {
554                 m_seq.terminator = t;
555         }
556 
append_intermediate(unsigned char i)557         inline void append_intermediate(unsigned char i) noexcept
558         {
559                 assert(unsigned(m_n_intermediates + 1) <= (sizeof(m_intermediates)/sizeof(m_intermediates[0])));
560 
561                 m_intermediates[m_n_intermediates++] = i;
562         }
563 
append_intermediates(std::initializer_list<unsigned char> l)564         inline void append_intermediates(std::initializer_list<unsigned char> l) noexcept
565         {
566                 assert(m_n_intermediates + l.size() <= (sizeof(m_intermediates)/sizeof(m_intermediates[0])));
567 
568                 for (uint32_t i : l) {
569                         m_intermediates[m_n_intermediates++] = i;
570                 }
571         }
572 
set_param_intro(unsigned char p)573         inline void set_param_intro(unsigned char p) noexcept
574         {
575                 m_param_intro = p;
576         }
577 
append_param(int p)578         inline void append_param(int p) noexcept
579         {
580                 assert(m_seq.n_args + 1 <= (sizeof(m_seq.args) / sizeof(m_seq.args[0])));
581                 m_seq.args[m_seq.n_args++] = vte_seq_arg_init(std::min(p, 0xffff));
582         }
583 
584         /*
585          * append_parms:
586          * @params:
587          *
588          * Appends the parameters from @params to @this. Parameter values must be
589          * in the range -1..MAXUSHORT; use -2 to skip a parameter
590          *
591          */
append_params(std::initializer_list<int> params)592         inline void append_params(std::initializer_list<int> params) noexcept
593         {
594                 assert(m_seq.n_args + params.size() <= (sizeof(m_seq.args) / sizeof(m_seq.args[0])));
595                 for (auto p : params) {
596                         if (p == -2)
597                                 continue;
598 
599                         m_seq.args[m_seq.n_args++] = vte_seq_arg_init(std::min(p, 0xffff));
600                 }
601         }
602 
603         /*
604          * append_subparms:
605          * @subparams:
606          *
607          * Appends the subparameters from @params to @this. Subparameter values must be
608          * in the range -1..MAXUSHORT; use -2 to skip a subparameter
609          *
610          */
append_subparams(std::initializer_list<int> subparams)611         inline void append_subparams(std::initializer_list<int> subparams) noexcept
612         {
613                 assert(m_seq.n_args + subparams.size() <= (sizeof(m_seq.args) / sizeof(m_seq.args[0])));
614                 for (auto p : subparams) {
615                         if (p == -2)
616                                 continue;
617 
618                         int* arg = &m_seq.args[m_seq.n_args++];
619                         *arg = vte_seq_arg_init(std::min(p, 0xffff));
620                         vte_seq_arg_finish(arg, false);
621                 }
622                 vte_seq_arg_refinish(&m_seq.args[m_seq.n_args - 1], true);
623         }
624 
set_string(string_type const & str)625         inline void set_string(string_type const& str) noexcept
626         {
627                 m_arg_str = str;
628         }
629 
set_string(string_type && str)630         inline void set_string(string_type&& str) noexcept
631         {
632                 m_arg_str = str;
633         }
634 
635         enum class Introducer {
636                 NONE,
637                 DEFAULT,
638                 C0,
639                 C1
640         };
641 
642         enum class ST {
643                 NONE,
644                 DEFAULT,
645                 C0,
646                 C1,
647                 BEL
648         };
649 
650 
651 private:
append_introducer_(string_type & s,bool c1=true) const652         void append_introducer_(string_type& s,
653                                 bool c1 = true) const noexcept
654         {
655                 /* Introducer */
656                 if (c1) {
657                         switch (m_seq.type) {
658                         case VTE_SEQ_ESCAPE: m_encoder.put(s, 0x1b); break; // ESC
659                         case VTE_SEQ_CSI:    m_encoder.put(s, 0x9b); break; // CSI
660                         case VTE_SEQ_DCS:    m_encoder.put(s, 0x90); break; // DCS
661                         case VTE_SEQ_OSC:    m_encoder.put(s, 0x9d); break; // OSC
662                         case VTE_SEQ_APC:    m_encoder.put(s, 0x9f); break; // APC
663                         case VTE_SEQ_PM:     m_encoder.put(s, 0x9e); break; // PM
664                         case VTE_SEQ_SOS:    m_encoder.put(s, 0x98); break; // SOS
665                         case VTE_SEQ_SCI:    m_encoder.put(s, 0x9a); break; // SCI
666                         default: return;
667                         }
668                 } else {
669                         s.push_back(0x1B); // ESC
670                         switch (m_seq.type) {
671                         case VTE_SEQ_ESCAPE:                    break; // nothing more
672                         case VTE_SEQ_CSI:    s.push_back(0x5b); break; // [
673                         case VTE_SEQ_DCS:    s.push_back(0x50); break; // P
674                         case VTE_SEQ_OSC:    s.push_back(0x5d); break; // ]
675                         case VTE_SEQ_APC:    s.push_back(0x5f); break; // _
676                         case VTE_SEQ_PM:     s.push_back(0x5e); break; // ^
677                         case VTE_SEQ_SOS:    s.push_back(0x58); break; // X
678                         case VTE_SEQ_SCI:    s.push_back(0x5a); break; // Z
679                         default: return;
680                         }
681                 }
682         }
683 
append_introducer(string_type & s,bool c1=true,Introducer introducer=Introducer::DEFAULT) const684         void append_introducer(string_type& s,
685                                bool c1 = true,
686                                Introducer introducer = Introducer::DEFAULT) const noexcept
687         {
688                 switch (introducer) {
689                 case Introducer::NONE:
690                         break;
691                 case Introducer::DEFAULT:
692                         append_introducer_(s, c1);
693                         break;
694                 case Introducer::C0:
695                         append_introducer_(s, false);
696                         break;
697                 case Introducer::C1:
698                         append_introducer_(s, true);
699                 }
700         }
701 
append_params(string_type & s) const702         void append_params(string_type& s) const noexcept
703         {
704                 /* Parameters */
705                 switch (m_seq.type) {
706                 case VTE_SEQ_CSI:
707                 case VTE_SEQ_DCS: {
708 
709                         if (m_param_intro != 0)
710                                 s.push_back(m_param_intro);
711                         auto n_args = m_seq.n_args;
712                         for (unsigned int n = 0; n < n_args; n++) {
713                                 auto arg = vte_seq_arg_value(m_seq.args[n]);
714                                 if (n > 0) {
715                                         s.push_back(";:"[vte_seq_arg_nonfinal(m_seq.args[n])]);
716                                 }
717                                 if (arg >= 0) {
718                                         char buf[16];
719                                         int l = g_snprintf(buf, sizeof(buf), "%d", arg);
720                                         for (int j = 0; j < l; j++)
721                                                 s.push_back(buf[j]);
722                                 }
723                         }
724                         break;
725                 }
726                 default:
727                         break;
728                 }
729         }
730 
append_intermediates_and_final(string_type & s) const731         void append_intermediates_and_final(string_type& s) const noexcept
732         {
733                 /* Intermediates and Final */
734                 switch (m_seq.type) {
735                 case VTE_SEQ_ESCAPE:
736                 case VTE_SEQ_CSI:
737                 case VTE_SEQ_DCS:
738                         for (unsigned char n = 0; n < m_n_intermediates; n++)
739                                 s.push_back(m_intermediates[n]);
740                         [[fallthrough]];
741                 case VTE_SEQ_SCI:
742                         if (m_seq.terminator != 0)
743                                 s.push_back(m_seq.terminator);
744                         break;
745                 default:
746                         break;
747                 }
748         }
749 
append_arg_string(string_type & s,bool c1=false,ssize_t max_arg_str_len=-1,ST st=ST::DEFAULT) const750         void append_arg_string(string_type& s,
751                                bool c1 = false,
752                                ssize_t max_arg_str_len = -1,
753                                ST st = ST::DEFAULT) const noexcept
754         {
755                 /* String and ST */
756                 switch (m_seq.type) {
757                 case VTE_SEQ_DCS:
758                 case VTE_SEQ_OSC:
759 
760                         if (max_arg_str_len < 0)
761                                 s.append(m_arg_str, 0, max_arg_str_len);
762                         else
763                                 s.append(m_arg_str);
764 
765                         switch (st) {
766                         case ST::NONE:
767                                 // omit ST
768                                 break;
769                         case ST::DEFAULT:
770                                 if (c1) {
771                                         m_encoder.put(s, 0x9c); // ST
772                                 } else {
773                                         s.push_back(0x1b); // ESC
774                                         s.push_back(0x5c); // BACKSLASH
775                                 }
776                                 break;
777                         case ST::C0:
778                                 s.push_back(0x1b); // ESC
779                                 s.push_back(0x5c); // BACKSLASH
780                                 break;
781                         case ST::C1:
782                                 m_encoder.put(s, 0x9c); // ST
783                                 break;
784                         case ST::BEL:
785                                 s.push_back(0x7); // BEL
786                                 break;
787                         default:
788                                 break;
789                         }
790                 }
791         }
792 
793 public:
to_string(string_type & s,bool c1=false,ssize_t max_arg_str_len=-1,Introducer introducer=Introducer::DEFAULT,ST st=ST::DEFAULT) const794         void to_string(string_type& s,
795                        bool c1 = false,
796                        ssize_t max_arg_str_len = -1,
797                        Introducer introducer = Introducer::DEFAULT,
798                        ST st = ST::DEFAULT) const noexcept
799         {
800                 append_introducer(s, c1, introducer);
801                 append_params(s);
802                 append_intermediates_and_final(s);
803                 append_arg_string(s, c1, max_arg_str_len, st);
804         }
805 
806         /* The following are only used in the test suite */
reset_params()807         void reset_params() noexcept
808         {
809                 m_seq.n_args = 0;
810         }
811 
assert_equal(Sequence const & seq) const812         void assert_equal(Sequence const& seq) const noexcept
813         {
814                 g_assert_cmpuint(seq.type(), ==, m_seq.type);
815                 g_assert_cmphex(seq.terminator(), ==, m_seq.terminator);
816         }
817 
assert_equal_full(Sequence const & seq) const818         void assert_equal_full(Sequence const& seq) const noexcept
819         {
820                 assert_equal(seq);
821 
822                 auto type = seq.type();
823                 if (type == VTE_SEQ_CSI ||
824                     type == VTE_SEQ_DCS) {
825                         /* We may get one arg less back, if it's at default */
826                         if (m_seq.n_args != seq.size()) {
827                                 g_assert_cmpuint(m_seq.n_args, ==, seq.size() + 1);
828                                 g_assert_true(vte_seq_arg_default(m_seq.args[m_seq.n_args - 1]));
829                         }
830                         for (unsigned int n = 0; n < seq.size(); n++)
831                                 g_assert_cmpint(vte_seq_arg_value(m_seq.args[n]), ==, seq.param(n));
832                 }
833         }
834 }; // class SequenceBuilder
835 
836 using u8SequenceBuilder = SequenceBuilder<std::string, UTF8Encoder>;
837 using u32SequenceBuilder = SequenceBuilder<std::u32string>;
838 
839 class ReplyBuilder : public u8SequenceBuilder {
840 public:
ReplyBuilder(unsigned int reply,std::initializer_list<int> params)841         ReplyBuilder(unsigned int reply,
842                      std::initializer_list<int> params)
843         {
844                 switch (reply) {
845 #define _VTE_REPLY_PARAMS(params) append_params(params);
846 #define _VTE_REPLY_STRING(str) set_string(str);
847 #define _VTE_REPLY(cmd,type,final,pintro,intermediate,code) \
848                 case VTE_REPLY_##cmd: \
849                         set_type(VTE_SEQ_##type); \
850                         set_final(final); \
851                         set_param_intro(VTE_SEQ_PARAMETER_CHAR_##pintro); \
852                         if (VTE_SEQ_INTERMEDIATE_CHAR_##intermediate != VTE_SEQ_INTERMEDIATE_CHAR_NONE) \
853                                 append_intermediate(VTE_SEQ_INTERMEDIATE_CHAR_##intermediate); \
854                         code \
855                         break;
856 #include "parser-reply.hh"
857 #undef _VTE_REPLY
858 #undef _VTE_REPLY_PARAMS
859 #undef _VTE_REPLY_STRING
860                 default:
861                         assert(false);
862                         break;
863                 }
864                 append_params(params);
865         }
866 
867 }; // class ReplyBuilder
868 
869 class StringTokeniser {
870 public:
871         using string_type = std::string;
872         using char_type = std::string::value_type;
873 
874 private:
875         string_type const& m_string;
876         char_type m_separator{';'};
877 
878 public:
StringTokeniser(string_type & s,char_type separator=';')879         StringTokeniser(string_type& s,
880                         char_type separator = ';')
881                 : m_string{s},
882                   m_separator{separator}
883         {
884         }
885 
StringTokeniser(string_type && s,char_type separator=';')886         StringTokeniser(string_type&& s,
887                         char_type separator = ';')
888                 : m_string{s},
889                   m_separator{separator}
890         {
891         }
892 
893         StringTokeniser(StringTokeniser const&) = delete;
894         StringTokeniser(StringTokeniser&&) = delete;
895         ~StringTokeniser() = default;
896 
897         StringTokeniser& operator=(StringTokeniser const&) = delete;
898         StringTokeniser& operator=(StringTokeniser&&) = delete;
899 
900         /*
901          * const_iterator:
902          *
903          * InputIterator for string tokens.
904          */
905         class const_iterator {
906         public:
907                 using difference_type = ptrdiff_t;
908                 using value_type = string_type;
909                 using pointer = string_type;
910                 using reference = string_type;
911                 using iterator_category = std::input_iterator_tag;
912                 using size_type = string_type::size_type;
913 
914         private:
915                 string_type const* m_string;
916                 char_type m_separator{';'};
917                 string_type::size_type m_position;
918                 string_type::size_type m_next_separator;
919 
920         public:
const_iterator(string_type const * str,char_type separator,size_type position)921                 const_iterator(string_type const* str,
922                                char_type separator,
923                                size_type position)
924                         : m_string{str},
925                           m_separator{separator},
926                           m_position{position},
927                           m_next_separator{m_string->find(m_separator, m_position)}
928                 {
929                 }
930 
const_iterator(string_type const * str,char_type separator)931                 const_iterator(string_type const* str,
932                                char_type separator)
933                         : m_string{str},
934                           m_separator{separator},
935                           m_position{string_type::npos},
936                           m_next_separator{string_type::npos}
937                 {
938                 }
939 
940                 const_iterator(const_iterator const&) = default;
const_iterator(const_iterator && o)941                 const_iterator(const_iterator&& o)
942                         : m_string{o.m_string},
943                           m_separator{o.m_separator},
944                           m_position{o.m_position},
945                           m_next_separator{o.m_next_separator}
946                 {
947                 }
948 
949                 ~const_iterator() = default;
950 
operator =(const_iterator const & o)951                 const_iterator& operator=(const_iterator const& o)
952                 {
953                         m_string = o.m_string;
954                         m_separator = o.m_separator;
955                         m_position = o.m_position;
956                         m_next_separator = o.m_next_separator;
957                         return *this;
958                 }
959 
operator =(const_iterator && o)960                 const_iterator& operator=(const_iterator&& o)
961                 {
962                         m_string = std::move(o.m_string);
963                         m_separator = o.m_separator;
964                         m_position = o.m_position;
965                         m_next_separator = o.m_next_separator;
966                         return *this;
967                 }
968 
operator ==(const_iterator const & o) const969                 inline bool operator==(const_iterator const& o) const noexcept
970                 {
971                         return m_position == o.m_position;
972                 }
973 
operator !=(const_iterator const & o) const974                 inline bool operator!=(const_iterator const& o) const noexcept
975                 {
976                         return m_position != o.m_position;
977                 }
978 
operator ++()979                 inline const_iterator& operator++() noexcept
980                 {
981                         if (m_next_separator != string_type::npos) {
982                                 m_position = ++m_next_separator;
983                                 m_next_separator = m_string->find(m_separator, m_position);
984                         } else
985                                 m_position = string_type::npos;
986 
987                         return *this;
988                 }
989 
990                 /*
991                  * number:
992                  *
993                  * Returns the value of the iterator as a number, or -1
994                  *   if the string could not be parsed as a number, or
995                  *   the parsed values exceeds the uint16_t range.
996                  *
997                  * Returns: true if a number was parsed
998                  */
number(int & v) const999                 bool number(int& v) const noexcept
1000                 {
1001                         auto const s = size();
1002                         if (s == 0) {
1003                                 v = -1;
1004                                 return true;
1005                         }
1006 
1007                         v = 0;
1008                         size_type i;
1009                         for (i = 0; i < s; ++i) {
1010                                 char_type c = (*m_string)[m_position + i];
1011                                 if (c < '0' || c > '9')
1012                                         return false;
1013 
1014                                 v = v * 10 + (c - '0');
1015                                 if (v > 0xffff)
1016                                         return false;
1017                         }
1018 
1019                         /* All consumed? */
1020                         return i == s;
1021                 }
1022 
size() const1023                 inline size_type size() const noexcept
1024                 {
1025                         if (m_next_separator != string_type::npos)
1026                                 return m_next_separator - m_position;
1027                         else
1028                                 return m_string->size() - m_position;
1029                 }
1030 
size_remaining() const1031                 inline size_type size_remaining() const noexcept
1032                 {
1033                         return m_string->size() - m_position;
1034                 }
1035 
operator *() const1036                 inline string_type operator*() const noexcept
1037                 {
1038                         return m_string->substr(m_position, size());
1039                 }
1040 
1041                 /*
1042                  * string_remaining:
1043                  *
1044                  * Returns the whole string left, including possibly more separators.
1045                  */
string_remaining() const1046                 inline string_type string_remaining() const noexcept
1047                 {
1048                         return m_string->substr(m_position);
1049                 }
1050 
append(string_type & str) const1051                 inline void append(string_type& str) const noexcept
1052                 {
1053                         str.append(m_string->substr(m_position, size()));
1054                 }
1055 
append_remaining(string_type & str) const1056                 inline void append_remaining(string_type& str) const noexcept
1057                 {
1058                         str.append(m_string->substr(m_position));
1059                 }
1060 
1061         }; // class const_iterator
1062 
cbegin(char_type c=';') const1063         inline const_iterator cbegin(char_type c = ';') const noexcept
1064         {
1065                 return const_iterator(&m_string, m_separator, 0);
1066         }
1067 
cend() const1068         inline const_iterator cend() const noexcept
1069         {
1070                 return const_iterator(&m_string, m_separator);
1071         }
1072 
begin(char_type c=';') const1073         inline const_iterator begin(char_type c = ';') const noexcept
1074         {
1075                 return cbegin();
1076         }
1077 
end() const1078         inline const_iterator end() const noexcept
1079         {
1080                 return cend();
1081         }
1082 
1083 }; // class StringTokeniser
1084 
1085 } // namespace parser
1086 
1087 } // namespace vte
1088