1use std::io::{self, Write};
16use std::str;
17use nom::IResult;
18use {Format};
19
20#[derive(Eq, PartialEq, Clone, Debug)]
21pub enum C1 {
22 PaddingCharacter,
23 HighOctetPreset,
24 BreakPermittedHere,
25 NoBreakHere,
26 Index,
27 NextLine,
28 StartSelectedArea,
29 EndSelectedArea,
30 HorizontalTabulationSet,
31 HorizontalTabulationWithJustification,
32 VerticalTabulationSet,
33 PartialLineDown,
34 PartialLineUp,
35 ReverseIndex,
36 SingleShiftTwo,
37 SingleShiftThree,
38 DeviceControl,
39 PrivateUseOne,
40 PrivateUseTwo,
41 SetTransmitState,
42 CancelCharacter,
43 MessageWaiting,
44 StartProtectedArea,
45 EndProtectedArea,
46 String,
47 SingleGraphicCharacter,
48 SingleCharacter,
49 ControlSequence(::CSI::T),
50 OperatingSystemCommand,
51 PrivacyMessage,
52 ApplicationProgramCommand,
53 End,
54}
55
56use self::C1::*;
57
58impl Format for C1 {
59 fn fmt<W: Write>(&self, mut f: W) -> io::Result<()> {
60 macro_rules! write {
61 ($code:expr) => (
62 try!(f.write_all(&[0x1B, $code - 0x40]));
63 );
64 }
65
66 match *self {
67 PaddingCharacter =>
68 write!(0x80),
69
70 HighOctetPreset =>
71 write!(0x81),
72
73 BreakPermittedHere =>
74 write!(0x82),
75
76 NoBreakHere =>
77 write!(0x83),
78
79 Index =>
80 write!(0x84),
81
82 NextLine =>
83 write!(0x85),
84
85 StartSelectedArea =>
86 write!(0x86),
87
88 EndSelectedArea =>
89 write!(0x87),
90
91 HorizontalTabulationSet =>
92 write!(0x88),
93
94 HorizontalTabulationWithJustification =>
95 write!(0x89),
96
97 VerticalTabulationSet =>
98 write!(0x8A),
99
100 PartialLineDown =>
101 write!(0x8B),
102
103 PartialLineUp =>
104 write!(0x8C),
105
106 ReverseIndex =>
107 write!(0x8D),
108
109 SingleShiftTwo =>
110 write!(0x8E),
111
112 SingleShiftThree =>
113 write!(0x8F),
114
115 DeviceControl => {
116 write!(0x90);
117 }
118
119 PrivateUseOne =>
120 write!(0x91),
121
122 PrivateUseTwo =>
123 write!(0x92),
124
125 SetTransmitState =>
126 write!(0x93),
127
128 CancelCharacter =>
129 write!(0x94),
130
131 MessageWaiting =>
132 write!(0x95),
133
134 StartProtectedArea =>
135 write!(0x96),
136
137 EndProtectedArea =>
138 write!(0x97),
139
140 String =>
141 write!(0x98),
142
143 SingleGraphicCharacter =>
144 write!(0x99),
145
146 SingleCharacter =>
147 write!(0x9A),
148
149 ControlSequence(ref value) =>
150 try!(value.fmt(f)),
151
152 OperatingSystemCommand =>
153 write!(0x9D),
154
155 PrivacyMessage =>
156 write!(0x9E),
157
158 ApplicationProgramCommand =>
159 write!(0x9F),
160
161 End =>
162 write!(0x9C),
163 }
164
165 Ok(())
166 }
167}
168
169named!(pub parse<C1>,
170 alt!(two | one));
171
172named!(one<C1>,
173 switch!(take!(1),
174 b"\x9B" => call!(CSI) |
175 b"\x9D" => call!(OSC) |
176
177 b"\x80" => call!(PAD) |
178 b"\x81" => call!(HOP) |
179 b"\x82" => call!(BPH) |
180 b"\x83" => call!(NBH) |
181 b"\x84" => call!(IND) |
182 b"\x85" => call!(NEL) |
183 b"\x86" => call!(SSA) |
184 b"\x87" => call!(ESA) |
185 b"\x88" => call!(HTS) |
186 b"\x89" => call!(HTJ) |
187 b"\x8A" => call!(VTS) |
188 b"\x8B" => call!(PLD) |
189 b"\x8C" => call!(PLU) |
190 b"\x8D" => call!(RI) |
191 b"\x8E" => call!(SS2) |
192 b"\x8F" => call!(SS3) |
193 b"\x90" => call!(DCS) |
194 b"\x91" => call!(PU1) |
195 b"\x92" => call!(PU2) |
196 b"\x93" => call!(STS) |
197 b"\x94" => call!(CCH) |
198 b"\x95" => call!(MW) |
199 b"\x96" => call!(SPA) |
200 b"\x97" => call!(EPA) |
201 b"\x98" => call!(SOS) |
202 b"\x99" => call!(SGCI) |
203 b"\x9A" => call!(SCI) |
204 b"\x9E" => call!(PM) |
205 b"\x9F" => call!(APC)));
206
207named!(two<C1>,
208 do_parse!(tag!(b"\x1B") >>
209 res: switch!(take!(1),
210 b"\x5B" => call!(CSI) |
211 b"\x5D" => call!(OSC) |
212
213 b"\x40" => call!(PAD) |
214 b"\x41" => call!(HOP) |
215 b"\x42" => call!(BPH) |
216 b"\x43" => call!(NBH) |
217 b"\x44" => call!(IND) |
218 b"\x45" => call!(NEL) |
219 b"\x46" => call!(SSA) |
220 b"\x47" => call!(ESA) |
221 b"\x48" => call!(HTS) |
222 b"\x49" => call!(HTJ) |
223 b"\x4A" => call!(VTS) |
224 b"\x4B" => call!(PLD) |
225 b"\x4C" => call!(PLU) |
226 b"\x4D" => call!(RI) |
227 b"\x4E" => call!(SS2) |
228 b"\x4F" => call!(SS3) |
229 b"\x50" => call!(DCS) |
230 b"\x51" => call!(PU1) |
231 b"\x52" => call!(PU2) |
232 b"\x53" => call!(STS) |
233 b"\x54" => call!(CCH) |
234 b"\x55" => call!(MW) |
235 b"\x56" => call!(SPA) |
236 b"\x57" => call!(EPA) |
237 b"\x58" => call!(SOS) |
238 b"\x59" => call!(SGCI) |
239 b"\x5A" => call!(SCI) |
240 b"\x5E" => call!(PM) |
241 b"\x5F" => call!(APC)) >>
242
243 (res)));
244
245named!(PAD<C1>,
246 value!(PaddingCharacter));
247
248named!(HOP<C1>,
249 value!(HighOctetPreset));
250
251named!(BPH<C1>,
252 value!(BreakPermittedHere));
253
254named!(NBH<C1>,
255 value!(NoBreakHere));
256
257named!(IND<C1>,
258 value!(Index));
259
260named!(NEL<C1>,
261 value!(NextLine));
262
263named!(SSA<C1>,
264 value!(StartSelectedArea));
265
266named!(ESA<C1>,
267 value!(EndSelectedArea));
268
269named!(HTS<C1>,
270 value!(HorizontalTabulationSet));
271
272named!(HTJ<C1>,
273 value!(HorizontalTabulationWithJustification));
274
275named!(VTS<C1>,
276 value!(VerticalTabulationSet));
277
278named!(PLD<C1>,
279 value!(PartialLineDown));
280
281named!(PLU<C1>,
282 value!(PartialLineUp));
283
284named!(RI<C1>,
285 value!(ReverseIndex));
286
287named!(SS2<C1>,
288 value!(SingleShiftTwo));
289
290named!(SS3<C1>,
291 value!(SingleShiftThree));
292
293named!(DCS<C1>,
294 value!(DeviceControl));
295
296named!(PU1<C1>,
297 value!(PrivateUseOne));
298
299named!(PU2<C1>,
300 value!(PrivateUseTwo));
301
302named!(STS<C1>,
303 value!(SetTransmitState));
304
305named!(CCH<C1>,
306 value!(CancelCharacter));
307
308named!(MW<C1>,
309 value!(MessageWaiting));
310
311named!(SPA<C1>,
312 value!(StartProtectedArea));
313
314named!(EPA<C1>,
315 value!(EndProtectedArea));
316
317named!(SOS<C1>,
318 value!(String));
319
320named!(SGCI<C1>,
321 value!(SingleGraphicCharacter));
322
323named!(SCI<C1>,
324 value!(SingleCharacter));
325
326named!(CSI<C1>,
327 map!(call!(::CSI::parse), |res| ControlSequence(res)));
328
329named!(ST,
330 alt!(tag!(b"\x9C") | tag!(b"\x1B\x5C")));
331
332named!(OSC<C1>,
333 value!(OperatingSystemCommand));
334
335named!(PM<C1>,
336 value!(PrivacyMessage));
337
338named!(APC<C1>,
339 value!(ApplicationProgramCommand));
340
341named!(pub string<&str>,
342 map!(terminated!(take_while!(is_string), is_end),
343 |s| unsafe { str::from_utf8_unchecked(s) }));
344
345#[inline]
346pub fn is_string(c: u8) -> bool {
347 const TABLE: [u8; 256] = [
348 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0,
349 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
350 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
351 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
352 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
353 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
354 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
355 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
356 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
357 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
358 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
359 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
360 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
361 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
362 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
363 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
364 ];
365
366 TABLE[c as usize] == 1
367}
368
369#[inline]
370pub fn is_end(i: &[u8]) -> IResult<&[u8], &[u8]> {
371 alt!(i, ST | tag!(b"\x07"))
372}
373
374pub mod shim {
375 pub use super::C1 as T;
376 pub use super::C1::*;
377 pub use super::{parse, string, is_string, is_end};
378}
379
380#[cfg(test)]
381mod test {
382 mod parse {
383 use {Control, C1, parse};
384
385 macro_rules! test {
386 ($string:expr => $item:expr) => (
387 assert_eq!(Control::C1($item),
388 parse($string).unwrap().1);
389 );
390 }
391
392 #[test]
393 fn pad() {
394 test!(b"\x80" =>
395 C1::PaddingCharacter);
396
397 test!(b"\x1B\x40" =>
398 C1::PaddingCharacter);
399 }
400
401 #[test]
402 fn hop() {
403 test!(b"\x81" =>
404 C1::HighOctetPreset);
405
406 test!(b"\x1B\x41" =>
407 C1::HighOctetPreset);
408 }
409
410 #[test]
411 fn bph() {
412 test!(b"\x82" =>
413 C1::BreakPermittedHere);
414
415 test!(b"\x1B\x42" =>
416 C1::BreakPermittedHere);
417 }
418
419 #[test]
420 fn nbh() {
421 test!(b"\x83" =>
422 C1::NoBreakHere);
423
424 test!(b"\x1B\x43" =>
425 C1::NoBreakHere);
426 }
427
428 #[test]
429 fn ind() {
430 test!(b"\x84" =>
431 C1::Index);
432
433 test!(b"\x1B\x44" =>
434 C1::Index);
435 }
436
437 #[test]
438 fn nel() {
439 test!(b"\x85" =>
440 C1::NextLine);
441
442 test!(b"\x1B\x45" =>
443 C1::NextLine);
444 }
445
446 #[test]
447 fn ssa() {
448 test!(b"\x86" =>
449 C1::StartSelectedArea);
450
451 test!(b"\x1B\x46" =>
452 C1::StartSelectedArea);
453 }
454
455 #[test]
456 fn esa() {
457 test!(b"\x87" =>
458 C1::EndSelectedArea);
459
460 test!(b"\x1B\x47" =>
461 C1::EndSelectedArea);
462 }
463
464 #[test]
465 fn hts() {
466 test!(b"\x88" =>
467 C1::HorizontalTabulationSet);
468
469 test!(b"\x1B\x48" =>
470 C1::HorizontalTabulationSet);
471 }
472
473 #[test]
474 fn htj() {
475 test!(b"\x89" =>
476 C1::HorizontalTabulationWithJustification);
477
478 test!(b"\x1B\x49" =>
479 C1::HorizontalTabulationWithJustification);
480 }
481
482 #[test]
483 fn vts() {
484 test!(b"\x8A" =>
485 C1::VerticalTabulationSet);
486
487 test!(b"\x1B\x4A" =>
488 C1::VerticalTabulationSet);
489 }
490
491 #[test]
492 fn pld() {
493 test!(b"\x8B" =>
494 C1::PartialLineDown);
495
496 test!(b"\x1B\x4B" =>
497 C1::PartialLineDown);
498 }
499
500 #[test]
501 fn plu() {
502 test!(b"\x8C" =>
503 C1::PartialLineUp);
504
505 test!(b"\x1B\x4C" =>
506 C1::PartialLineUp);
507 }
508
509 #[test]
510 fn ri() {
511 test!(b"\x8D" =>
512 C1::ReverseIndex);
513
514 test!(b"\x1B\x4D" =>
515 C1::ReverseIndex);
516 }
517
518 #[test]
519 fn ss2() {
520 test!(b"\x8E" =>
521 C1::SingleShiftTwo);
522
523 test!(b"\x1B\x4E" =>
524 C1::SingleShiftTwo);
525 }
526
527 #[test]
528 fn ss3() {
529 test!(b"\x8F" =>
530 C1::SingleShiftThree);
531
532 test!(b"\x1B\x4F" =>
533 C1::SingleShiftThree);
534 }
535
536 #[test]
537 fn dcs() {
538 test!(b"\x90" =>
539 C1::DeviceControl);
540
541 test!(b"\x1B\x50" =>
542 C1::DeviceControl);
543 }
544
545 #[test]
546 fn sts() {
547 test!(b"\x93" =>
548 C1::SetTransmitState);
549
550 test!(b"\x1B\x53" =>
551 C1::SetTransmitState);
552 }
553
554 #[test]
555 fn cch() {
556 test!(b"\x94" =>
557 C1::CancelCharacter);
558
559 test!(b"\x1B\x54" =>
560 C1::CancelCharacter);
561 }
562
563 #[test]
564 fn mw() {
565 test!(b"\x95" =>
566 C1::MessageWaiting);
567
568 test!(b"\x1B\x55" =>
569 C1::MessageWaiting);
570 }
571
572 #[test]
573 fn spa() {
574 test!(b"\x96" =>
575 C1::StartProtectedArea);
576
577 test!(b"\x1B\x56" =>
578 C1::StartProtectedArea);
579 }
580
581 #[test]
582 fn epa() {
583 test!(b"\x97" =>
584 C1::EndProtectedArea);
585
586 test!(b"\x1B\x57" =>
587 C1::EndProtectedArea);
588 }
589
590 #[test]
591 fn sos() {
592 test!(b"\x98" =>
593 C1::String);
594
595 test!(b"\x1B\x58" =>
596 C1::String);
597 }
598
599 #[test]
600 fn sgci() {
601 test!(b"\x99" =>
602 C1::SingleGraphicCharacter);
603
604 test!(b"\x1B\x59" =>
605 C1::SingleGraphicCharacter);
606 }
607
608 #[test]
609 fn sci() {
610 test!(b"\x9A" =>
611 C1::SingleCharacter);
612
613 test!(b"\x1B\x5A" =>
614 C1::SingleCharacter);
615 }
616
617 #[test]
618 fn osc() {
619 test!(b"\x9D" =>
620 C1::OperatingSystemCommand);
621
622 test!(b"\x1B\x5D" =>
623 C1::OperatingSystemCommand);
624 }
625
626 #[test]
627 fn pn() {
628 test!(b"\x9E" =>
629 C1::PrivacyMessage);
630
631 test!(b"\x1B\x5E" =>
632 C1::PrivacyMessage);
633 }
634
635 #[test]
636 fn apc() {
637 test!(b"\x9F" =>
638 C1::ApplicationProgramCommand);
639
640 test!(b"\x1B\x5F" =>
641 C1::ApplicationProgramCommand);
642 }
643 }
644
645 mod format {
646 use {Control, C1, format, parse};
647
648 macro_rules! test {
649 ($code:expr) => (
650 let item = Control::C1($code);
651 assert_eq!(item, parse(&format(&item)).unwrap().1);
652 );
653 }
654
655 #[test]
656 fn pad() {
657 test!(C1::PaddingCharacter);
658 }
659
660 #[test]
661 fn hop() {
662 test!(C1::HighOctetPreset);
663 }
664
665 #[test]
666 fn bph() {
667 test!(C1::BreakPermittedHere);
668 }
669
670 #[test]
671 fn nbh() {
672 test!(C1::NoBreakHere);
673 }
674
675 #[test]
676 fn ind() {
677 test!(C1::Index);
678 }
679
680 #[test]
681 fn nel() {
682 test!(C1::NextLine);
683 }
684
685 #[test]
686 fn ssa() {
687 test!(C1::StartSelectedArea);
688 }
689
690 #[test]
691 fn esa() {
692 test!(C1::EndSelectedArea);
693 }
694
695 #[test]
696 fn hts() {
697 test!(C1::HorizontalTabulationSet);
698 }
699
700 #[test]
701 fn htj() {
702 test!(C1::HorizontalTabulationWithJustification);
703 }
704
705 #[test]
706 fn vts() {
707 test!(C1::VerticalTabulationSet);
708 }
709
710 #[test]
711 fn pld() {
712 test!(C1::PartialLineDown);
713 }
714
715 #[test]
716 fn plu() {
717 test!(C1::PartialLineUp);
718 }
719
720 #[test]
721 fn ri() {
722 test!(C1::ReverseIndex);
723 }
724
725 #[test]
726 fn ss2() {
727 test!(C1::SingleShiftTwo);
728 }
729
730 #[test]
731 fn ss3() {
732 test!(C1::SingleShiftThree);
733 }
734
735 #[test]
736 fn dcs() {
737 test!(C1::DeviceControl);
738 }
739
740 #[test]
741 fn sts() {
742 test!(C1::SetTransmitState);
743 }
744
745 #[test]
746 fn cch() {
747 test!(C1::CancelCharacter);
748 }
749
750 #[test]
751 fn mw() {
752 test!(C1::MessageWaiting);
753 }
754
755 #[test]
756 fn spa() {
757 test!(C1::StartProtectedArea);
758 }
759
760 #[test]
761 fn epa() {
762 test!(C1::EndProtectedArea);
763 }
764
765 #[test]
766 fn sos() {
767 test!(C1::String);
768 }
769
770 #[test]
771 fn sgci() {
772 test!(C1::SingleGraphicCharacter);
773 }
774
775 #[test]
776 fn sci() {
777 test!(C1::SingleCharacter);
778 }
779
780 #[test]
781 fn osc() {
782 test!(C1::OperatingSystemCommand);
783 }
784
785 #[test]
786 fn pn() {
787 test!(C1::PrivacyMessage);
788 }
789
790 #[test]
791 fn apc() {
792 test!(C1::ApplicationProgramCommand);
793 }
794 }
795}