control_code/
c1.rs

1//            DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
2//                    Version 2, December 2004
3//
4// Copyleft (ↄ) meh. <meh@schizofreni.co> | http://meh.schizofreni.co
5//
6// Everyone is permitted to copy and distribute verbatim or modified
7// copies of this license document, and changing it is allowed as long
8// as the name is changed.
9//
10//            DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
11//   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
12//
13//  0. You just DO WHAT THE FUCK YOU WANT TO.
14
15use 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}