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