From dca1c5c633981aa96932e0d50d3e27fe7de7a2b2 Mon Sep 17 00:00:00 2001 From: Joe Wilm Date: Mon, 12 Sep 2016 10:51:13 -0700 Subject: [PATCH 01/99] WIP --- .gitignore | 2 + Cargo.toml | 6 ++ codegen/Cargo.toml | 8 ++ codegen/README.md | 11 ++ codegen/src/ext.rs | 242 ++++++++++++++++++++++++++++++++++++++++++++ codegen/src/main.rs | 18 ++++ src/definitions.rs | 74 ++++++++++++++ src/lib.rs | 53 ++++++++++ src/table.rs.in | 214 +++++++++++++++++++++++++++++++++++++++ 9 files changed, 628 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 codegen/Cargo.toml create mode 100644 codegen/README.md create mode 100644 codegen/src/ext.rs create mode 100644 codegen/src/main.rs create mode 100644 src/definitions.rs create mode 100644 src/lib.rs create mode 100644 src/table.rs.in diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..a9d37c56 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +target +Cargo.lock diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 00000000..cf36ebb0 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "fun-table" +version = "0.1.0" +authors = ["Joe Wilm "] + +[dependencies] diff --git a/codegen/Cargo.toml b/codegen/Cargo.toml new file mode 100644 index 00000000..a48de052 --- /dev/null +++ b/codegen/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "codegen" +version = "0.1.0" +authors = ["Joe Wilm "] + +[dependencies] +syntex = "0.43.0" +syntex_syntax = "0.43.0" diff --git a/codegen/README.md b/codegen/README.md new file mode 100644 index 00000000..d13aa5db --- /dev/null +++ b/codegen/README.md @@ -0,0 +1,11 @@ +codegen +======= + +Depends on libsyntex and generates table.rs from table.rs.in. This code is +separate from the main vtparse crate since compiling libsyntex takes ~1 +eternity. + +## Usage + +`cargo run` in the codegen folder will process `table.rs.in` and output +`table.rs`. The latter file should be committed back into the repo. diff --git a/codegen/src/ext.rs b/codegen/src/ext.rs new file mode 100644 index 00000000..3a089358 --- /dev/null +++ b/codegen/src/ext.rs @@ -0,0 +1,242 @@ +use syntex::Registry; + +use syntex_syntax::ast::{ExprKind, MetaItem, Arm, Expr, PatKind, LitKind, Pat}; +use syntex_syntax::codemap::Span; +use syntex_syntax::ext::base::{Annotatable, ExtCtxt, MacEager, MacResult, DummyResult}; +use syntex_syntax::ext::build::AstBuilder; +use syntex_syntax::parse::token::{Token, InternedString, DelimToken}; +use syntex_syntax::parse::parser::Parser; +use syntex_syntax::parse::PResult; +use syntex_syntax::ptr::P; +use syntex_syntax::tokenstream::TokenTree; + +use definitions::{State, Action}; + +pub fn register(registry: &mut Registry) { + registry.add_macro("state_table", expand_state_table); +} + +fn state_from_str(s: &S) -> Result + where S: AsRef +{ + Ok(match s.as_ref() { + "State::Anywhere" => State::Anywhere, + "State::CsiEntry" => State::CsiEntry, + "State::CsiIgnore" => State::CsiIgnore, + "State::CsiIntermediate" => State::CsiIntermediate, + "State::CsiParam" => State::CsiParam, + "State::DcsEntry" => State::DcsEntry, + "State::DcsIgnore" => State::DcsIgnore, + "State::DcsIntermediate" => State::DcsIntermediate, + "State::DcsParam" => State::DcsParam, + "State::DcsPassthrough" => State::DcsPassthrough, + "State::Escape" => State::Escape, + "State::EscapeIntermediate" => State::EscapeIntermediate, + "State::Ground" => State::Ground, + "State::OscString" => State::OscString, + "State::SosPmApcString" => State::SosPmApcString, + _ => return Err(()) + }) +} + +fn parse_table_input_mappings<'a>(parser: &mut Parser<'a>) -> PResult<'a, Vec> { + // Must start on open brace + try!(parser.expect(&Token::OpenDelim(DelimToken::Brace))); + + let mut arms: Vec = Vec::new(); + while parser.token != Token::CloseDelim(DelimToken::Brace) { + match parser.parse_arm() { + Ok(arm) => arms.push(arm), + Err(mut e) => { + // Recover by skipping to the end of the block. + return Err(e); + } + } + } + + // Consume the closing brace + parser.bump(); + Ok(arms) +} + +/// Expressions describing state transitions and actions +#[derive(Debug)] +struct TableDefinitionExprs { + state_expr: P, + mapping_arms: Vec, +} + +fn state_from_expr(expr: P, cx: &mut ExtCtxt) -> Result { + let s = match expr.node { + ExprKind::Path(ref _qself, ref path) => { + path.to_string() + }, + _ => { + cx.span_err(expr.span, "expected State"); + return Err(()) + } + }; + + state_from_str(&s).map_err(|_| { + cx.span_err(expr.span, "expected State"); + () + }) +} + +fn u8_lit_from_expr(expr: &Expr, cx: &mut ExtCtxt) -> Result { + static MSG: &'static str = "expected u8 int literal"; + + match expr.node { + ExprKind::Lit(ref lit) => { + match lit.node { + LitKind::Int(val, _) => { + Ok(val as u8) + }, + _ => { + cx.span_err(lit.span, MSG); + return Err(()); + } + } + }, + _ => { + cx.span_err(expr.span, MSG); + return Err(()); + } + } +} + +fn input_mapping_from_arm(arm: Arm, cx: &mut ExtCtxt) -> Result { + let Arm { pats, body, .. } = arm; + + let input = try!(InputDefinition::from_pat(&pats[0], cx)); + let transition = try!(Transition::from_expr(&body, cx)); + + Ok(InputMapping { + input: input, + transition: transition, + }) +} + +/// What happens when certain input is received +enum Transition { + State(State), + Action(Action), + StateAction(State, Action), +} + +impl Transition { + fn from_expr(expr: &Expr, cx: &mut ExtCtxt) -> Result { + unimplemented!(); + } +} + +enum InputDefinition { + Specific(u8), + Range { start: u8, end: u8 } +} + +impl InputDefinition { + fn from_pat(pat: &Pat, cx: &mut ExtCtxt) -> Result { + Ok(match pat.node { + PatKind::Lit(ref lit_expr) => { + InputDefinition::Specific(try!(u8_lit_from_expr(&lit_expr, cx))) + }, + PatKind::Range(ref start_expr, ref end_expr) => { + InputDefinition::Range { + start: try!(u8_lit_from_expr(start_expr, cx)), + end: try!(u8_lit_from_expr(end_expr, cx)), + } + }, + _ => { + cx.span_err(pat.span, "expected literal or range expression"); + return Err(()) + } + }) + } +} + +struct InputMapping { + input: InputDefinition, + transition: Transition, +} + +struct TableDefinition { + state: State, + mappings: Vec, +} + +fn parse_raw_definitions( + definitions: Vec, + cx: &mut ExtCtxt +) -> Result, ()> { + let mut out = Vec::new(); + + for raw in definitions { + let TableDefinitionExprs { state_expr, mapping_arms } = raw; + let state = try!(state_from_expr(state_expr, cx)); + + let mut mappings = Vec::new(); + for arm in mapping_arms { + mappings.push(try!(input_mapping_from_arm(arm, cx))); + } + + out.push(TableDefinition { + state: state, + mappings: mappings, + }) + } + + Ok(out) +} + +fn parse_table_definition<'a>(parser: &mut Parser<'a>) -> PResult<'a, TableDefinitionExprs> { + let state_expr = try!(parser.parse_expr()); + try!(parser.expect(&Token::FatArrow)); + let mappings = try!(parse_table_input_mappings(parser)); + + Ok(TableDefinitionExprs { + state_expr: state_expr, + mapping_arms: mappings + }) +} + +fn parse_table_definition_list<'a>(parser: &mut Parser<'a>) + -> PResult<'a, Vec> +{ + let mut definitions = Vec::new(); + while parser.token != Token::Eof { + definitions.push(try!(parse_table_definition(parser))); + parser.eat(&Token::Comma); + } + + Ok(definitions) +} + +fn expand_state_table<'cx>( + cx: &'cx mut ExtCtxt, + sp: Span, + args: &[TokenTree]) + -> Box +{ + macro_rules! ptry { + ($pres:expr) => { + match $pres { + Ok(val) => val, + Err(mut err) => { + err.emit(); + return DummyResult::any(sp); + } + } + } + } + + // Parse the lookup spec + let mut parser: Parser = cx.new_parser_from_tts(args); + let definitions = ptry!(parse_table_definition_list(&mut parser)); + let definitions = match parse_raw_definitions(definitions, cx) { + Ok(definitions) => definitions, + Err(_) => return DummyResult::any(sp), + }; + + panic!("End of current implementation, go write some more :)"); +} diff --git a/codegen/src/main.rs b/codegen/src/main.rs new file mode 100644 index 00000000..d1994bb6 --- /dev/null +++ b/codegen/src/main.rs @@ -0,0 +1,18 @@ +extern crate syntex; +extern crate syntex_syntax; + +mod ext; + +#[path="../../src/definitions.rs"] +pub mod definitions; + +use std::path::Path; + +fn main() { + let src = &Path::new("../src/table.rs.in"); + let dst = &Path::new("../src/table.rs"); + + let mut registry = syntex::Registry::new(); + ext::register(&mut registry); + registry.expand("state_table", src, dst); +} diff --git a/src/definitions.rs b/src/definitions.rs new file mode 100644 index 00000000..f8875591 --- /dev/null +++ b/src/definitions.rs @@ -0,0 +1,74 @@ +#[derive(Debug)] +pub enum State { + Anywhere = 0, + CsiEntry = 1, + CsiIgnore = 2, + CsiIntermediate = 3, + CsiParam = 4, + DcsEntry = 5, + DcsIgnore = 6, + DcsIntermediate = 7, + DcsParam = 8, + DcsPassthrough = 9, + Escape = 10, + EscapeIntermediate = 11, + Ground = 12, + OscString = 13, + SosPmApcString = 14, + Unused__ = 15, +} + +#[derive(Debug)] +pub enum Action { + None = 0, + Clear = 1, + Collect = 2, + CsiDispatch = 3, + EscDispatch = 4, + Execute = 5, + Hook = 6, + Ignore = 7, + OscEnd = 8, + OscPut = 9, + OscStart = 10, + Param = 11, + Print = 12, + Put = 13, + Unhook = 14, + Unused__ = 15, +} + +/// Unpack a u8 into a State and Action +/// +/// The implementation of this assumes that there are *precisely* 16 variants for both Action and +/// State. Furthermore, it assumes that the enums are tag-only; that is, there is no data in any +/// variant. +/// +/// Bad things will happen if those invariants are violated. +#[inline(always)] +fn unpack(delta: u8) -> (State, Action) { + ( + // Action is stored in bottom 4 bits + unsafe { ::std::mem::transmute(delta & 0x0f) }, + + // State is stored in top 4 bits + unsafe { ::std::mem::transmute(delta >> 4) }, + ) +} + +#[cfg(test)] +mod tests { + use super::{State, Action, unpack}; + #[test] + fn unpack_state_action() { + match unpack(0xee) { + (State::SosPmApcString, Action::Unhook) => (), + _ => panic!("unpack failed"), + } + + match unpack(0xff) { + (State::Unused__, Action::Unused__) => (), + _ => panic!("unpack failed"), + } + } +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 00000000..d7dadad5 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,53 @@ +mod table; +mod definitions; + +pub use definitions::{Action, State, unpack}; + +use table::{EXIT_ACTIONS, ENTRY_ACTIONS, STATE_CHANGE}; + +impl State { + /// Get exit action for this state + #[inline(always)] + pub fn exit_action(&self) -> Action { + unsafe { + ::table::EXIT_ACTIONS.get_unchecked(*self as usize) + } + } + + /// Get entry action for this state + #[inline(always)] + pub fn entry_action(&self) -> Action { + unsafe { + ::table::ENTRY_ACTIONS.get_unchecked(*self as usize) + } + } +} + + +// struct StateMachine { +// state: State, +// } +// +// trait Parser { +// fn csi_entry(&mut self, c: char); +// fn csi_param(&mut self, c: char); +// } +// +// struct Foo; +// +// impl Parser for Foo { +// fn csi_entry(&mut self, c: char) { +// println!("csi_entry char={:?}", c); +// } +// fn csi_param(&mut self, c: char) { +// println!("csi_param char={:?}", c); +// } +// } +// +// #[test] +// fn it_works() { +// let table: u8 = &[Parser::csi_entry, Parser::csi_param]; +// let mut foo = Foo; +// table[0](&mut foo, 'b'); +// } + diff --git a/src/table.rs.in b/src/table.rs.in new file mode 100644 index 00000000..9c39f5ea --- /dev/null +++ b/src/table.rs.in @@ -0,0 +1,214 @@ +/// This is the state change table. It's indexed first by current state and then by the next +/// character in the pty stream. +/// +/// TODO implement a syntax extension that runs via syntex in build.rs to actually turn this into a +/// table. +static STATE_CHANGE: [[u8; 256]; 16] = state_table! { + State::Anywhere => { + 0x18 => (Action::Execute, State::Ground), + 0x1a => (Action::Execute, State::Ground), + 0x80...0x8f => (Action::Execute, State::Ground), + 0x91...0x97 => (Action::Execute, State::Ground), + 0x99 => (Action::Execute, State::Ground), + 0x9a => (Action::Execute, State::Ground), + 0x9c => (Action::Execute, State::Ground), + 0x1b => State::Escape, + 0x98 => State::SosPmApcString, + 0x9e => State::SosPmApcString, + 0x9f => State::SosPmApcString, + 0x90 => State::DcsEntry, + 0x9d => State::OscString, + 0x9b => State::CsiEntry, + }, + + State::Ground => { + 0x00...0x17 => Action::Execute, + 0x19 => Action::Execute, + 0x1c...0x1f => Action::Execute, + 0x20...0x7f => Action::Print, + 0x80...0x8f => Action::Execute, + 0x91...0x9a => Action::Execute, + 0x9c => Action::Execute + }, + + State::Escape => { + 0x00...0x17 => Action::Execute, + 0x19 => Action::Execute, + 0x1c...0x1f => Action::Execute, + 0x7f => Action::Ignore, + 0x20...0x2f => (Action::Collect, State::EscapeIntermediate), + 0x30...0x4f => (Action::EscDispatch, State::Ground), + 0x51...0x57 => (Action::EscDispatch, State::Ground), + 0x59 => (Action::EscDispatch, State::Ground), + 0x5a => (Action::EscDispatch, State::Ground), + 0x5c => (Action::EscDispatch, State::Ground), + 0x60...0x7e => (Action::EscDispatch, State::Ground), + 0x5b => State::CsiEntry, + 0x5d => State::OscString, + 0x50 => State::DcsEntry, + 0x58 => State::SosPmApcString, + 0x5e => State::SosPmApcString, + 0x5f => State::SosPmApcString, + }, + + State::EscapeIntermediate => { + 0x00...0x17 => Action::Execute, + 0x19 => Action::Execute, + 0x1c...0x1f => Action::Execute, + 0x20...0x2f => Action::Collect, + 0x7f => Action::Ignore, + 0x30...0x7e => (Action::EscDispatch, State::Ground) + }, + + State::CsiEntry => { + 0x00...0x17 => Action::Execute, + 0x19 => Action::Execute, + 0x1c...0x1f => Action::Execute, + 0x7f => Action::Ignore, + 0x20...0x2f => (Action::Collect, State::CsiIntermediate), + 0x3a => State::CsiIgnore, + 0x30...0x39 => (Action::Param, State::CsiParam), + 0x3b => (Action::Param, State::CsiParam), + 0x3c...0x3f => (Action::Collect, State::CsiParam), + 0x40...0x7e => (Action::CsiDispatch, State::Ground) + }, + + State::CsiIgnore => { + 0x00...0x17 => Action::Execute, + 0x19 => Action::Execute, + 0x1c...0x1f => Action::Execute, + 0x20...0x3f => Action::Ignore, + 0x7f => Action::Ignore, + 0x40...0x7e => State::Ground, + }, + + State::CsiParam => { + 0x00...0x17 => Action::Execute, + 0x19 => Action::Execute, + 0x1c...0x1f => Action::Execute, + 0x30...0x39 => Action::Param, + 0x3b => Action::Param, + 0x7f => Action::Ignore, + 0x3a => State::CsiIgnore, + 0x3c...0x3f => State::CsiIgnore, + 0x20...0x2f => (Action::Collect, State::CsiIntermediate), + 0x40...0x7e => (Action::CsiDispatch, State::Ground) + }, + + State::CsiIntermediate => { + 0x00...0x17 => Action::Execute, + 0x19 => Action::Execute, + 0x1c...0x1f => Action::Execute, + 0x20...0x2f => Action::Collect, + 0x7f => Action::Ignore, + 0x30...0x3f => State::CsiIgnore, + 0x40...0x7e => (Action::CsiDispatch, State::Ground), + }, + + State::DcsEntry => { + 0x00...0x17 => Action::Ignore, + 0x19 => Action::Ignore, + 0x1c...0x1f => Action::Ignore, + 0x7f => Action::Ignore, + 0x3a => State::DcsIgnore, + 0x20...0x2f => (Action::Collect, State::DcsIntermediate), + 0x30...0x39 => (Action::Param, State::DcsParam), + 0x3b => (Action::Param, State::DcsParam), + 0x3c...0x3f => (Action::Collect, State::DcsParam), + 0x40...0x7e => State::DcsPassthrough + }, + + State::DcsIntermediate => { + 0x00...0x17 => Action::Ignore, + 0x19 => Action::Ignore, + 0x1c...0x1f => Action::Ignore, + 0x20...0x2f => Action::Collect, + 0x7f => Action::Ignore, + 0x30...0x3f => State::DcsIgnore, + 0x40...0x7e => State::DcsPassthrough + }, + + State::DcsIgnore => { + 0x00...0x17 => Action::Ignore, + 0x19 => Action::Ignore, + 0x1c...0x1f => Action::Ignore, + 0x20...0x7f => Action::Ignore, + 0x9c => State::Ground + }, + + State::DcsParam => { + 0x00...0x17 => Action::Ignore, + 0x19 => Action::Ignore, + 0x1c...0x1f => Action::Ignore, + 0x30...0x39 => Action::Param, + 0x3b => Action::Param, + 0x7f => Action::Ignore, + 0x3a => State::DcsIgnore, + 0x3c...0x3f => State::DcsIgnore, + 0x20...0x2f => (Action::Collect, State::DcsIntermediate), + 0x40...0x7e => State::DcsPassthrough + }, + + State::DcsPassthrough => { + 0x00...0x17 => Action::Put, + 0x19 => Action::Put, + 0x1c...0x1f => Action::Put, + 0x20...0x7e => Action::Put, + 0x7f => Action::Ignore, + 0x9c => State::Ground, + }, + + State::SosPmApcString => { + 0x00...0x17 => Action::Ignore, + 0x19 => Action::Ignore, + 0x1c...0x1f => Action::Ignore, + 0x20...0x7f => Action::Ignore, + 0x9c => State::Ground + }, + + State::OscString => { + 0x00...0x17 => Action::Ignore, + 0x19 => Action::Ignore, + 0x1c...0x1f => Action::Ignore, + 0x20...0x7f => Action::OscPut, + 0x9c => State::Ground, + } +}; + +static ENTRY_ACTIONS: &'static [Action] = &[ + Action::None, // State::Anywhere + Action::Clear, // State::CsiEntry + Action::None, // State::CsiIgnore + Action::None, // State::CsiIntermediate + Action::None, // State::CsiParam + Action::Clear, // State::DcsEntry + Action::None, // State::DcsIgnore + Action::None, // State::DcsIntermediate + Action::None, // State::DcsParam + Action::Hook, // State::DcsPassthrough + Action::Clear, // State::Escape + Action::None, // State::EscapeIntermediate + Action::None, // State::Ground + Action::OscStart, // State::OscString + Action::None, // State::SosPmApcString + Action::None, // State::Unused__ +]; + +static EXIT_ACTIONS: &'static [Action] = &[ + Action::None, // State::Anywhere + Action::None, // State::CsiEntry + Action::None, // State::CsiIgnore + Action::None, // State::CsiIntermediate + Action::None, // State::CsiParam + Action::None, // State::DcsEntry + Action::None, // State::DcsIgnore + Action::None, // State::DcsIntermediate + Action::None, // State::DcsParam + Action::Unhook, // State::DcsPassthrough + Action::None, // State::Escape + Action::None, // State::EscapeIntermediate + Action::None, // State::Ground + Action::OscEnd, // State::OscString + Action::None, // State::SosPmApcString + Action::None, // State::Unused__ +]; From fd3e43699f48c2c6a4912714e88372a19cc1f928 Mon Sep 17 00:00:00 2001 From: Joe Wilm Date: Mon, 12 Sep 2016 21:21:31 -0700 Subject: [PATCH 02/99] Finish Transition parser --- codegen/src/ext.rs | 86 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 85 insertions(+), 1 deletion(-) diff --git a/codegen/src/ext.rs b/codegen/src/ext.rs index 3a089358..8c633252 100644 --- a/codegen/src/ext.rs +++ b/codegen/src/ext.rs @@ -39,6 +39,29 @@ fn state_from_str(s: &S) -> Result }) } +fn action_from_str(s: &S) -> Result + where S: AsRef +{ + Ok(match s.as_ref() { + "Action::None" => Action::None, + "Action::Clear" => Action::Clear, + "Action::Collect" => Action::Collect, + "Action::CsiDispatch" => Action::CsiDispatch, + "Action::EscDispatch" => Action::EscDispatch, + "Action::Execute" => Action::Execute, + "Action::Hook" => Action::Hook, + "Action::Ignore" => Action::Ignore, + "Action::OscEnd" => Action::OscEnd, + "Action::OscPut" => Action::OscPut, + "Action::OscStart" => Action::OscStart, + "Action::Param" => Action::Param, + "Action::Print" => Action::Print, + "Action::Put" => Action::Put, + "Action::Unhook" => Action::Unhook, + _ => return Err(()) + }) +} + fn parse_table_input_mappings<'a>(parser: &mut Parser<'a>) -> PResult<'a, Vec> { // Must start on open brace try!(parser.expect(&Token::OpenDelim(DelimToken::Brace))); @@ -118,6 +141,7 @@ fn input_mapping_from_arm(arm: Arm, cx: &mut ExtCtxt) -> Result Result { - unimplemented!(); + match expr.node { + ExprKind::Tup(ref tup_exprs) => { + let mut action = None; + let mut state = None; + + for tup_expr in tup_exprs { + if let ExprKind::Path(_, ref path) = tup_expr.node { + let path_str = path.to_string(); + if path_str.starts_with('A') { + action = Some(try!(action_from_str(&path_str) + .map_err(|_| { + cx.span_err(expr.span, "invalid action"); + }))); + } else { + state = Some(try!(state_from_str(&path_str) + .map_err(|_| { + cx.span_err(expr.span, "invalid state"); + }))); + } + } + } + + match (action, state) { + (Some(action), Some(state)) => Ok(Transition::StateAction(state, action)), + (None, Some(state)) => Ok(Transition::State(state)), + (Some(action), None) => Ok(Transition::Action(action)), + _ => { + cx.span_err(expr.span, "expected Action and/or State"); + Err(()) + } + } + }, + ExprKind::Path(_, ref path) => { + // Path can be Action or State + let path_str = path.to_string(); + + if path_str.starts_with('A') { + let action = try!(action_from_str(&path_str) + .map_err(|_| { + cx.span_err(expr.span, "invalid action"); + })); + Ok(Transition::Action(action)) + } else { + let state = try!(state_from_str(&path_str) + .map_err(|_| { + cx.span_err(expr.span, "invalid state"); + })); + + Ok(Transition::State(state)) + } + }, + _ => { + cx.span_err(expr.span, "expected Action and/or State"); + Err(()) + } + } } } +#[derive(Debug)] enum InputDefinition { Specific(u8), Range { start: u8, end: u8 } @@ -155,11 +235,13 @@ impl InputDefinition { } } +#[derive(Debug)] struct InputMapping { input: InputDefinition, transition: Transition, } +#[derive(Debug)] struct TableDefinition { state: State, mappings: Vec, @@ -238,5 +320,7 @@ fn expand_state_table<'cx>( Err(_) => return DummyResult::any(sp), }; + println!("definitions: {:?}", definitions); + panic!("End of current implementation, go write some more :)"); } From 18ced2005087045bf5f83aa070f654eeb2ad955f Mon Sep 17 00:00:00 2001 From: Joe Wilm Date: Tue, 13 Sep 2016 09:09:33 -0700 Subject: [PATCH 03/99] Finish implementing codegen for state table When modifying table.rs.in, `cargo run` must be run in the `codegen` crate. The result of expansion is included in the source tree so that consumers don't need to pull in syntex just to compile. --- codegen/src/ext.rs | 62 +++++++- src/definitions.rs | 6 +- src/lib.rs | 4 +- src/table.rs | 372 +++++++++++++++++++++++++++++++++++++++++++++ src/table.rs.in | 12 +- 5 files changed, 442 insertions(+), 14 deletions(-) create mode 100644 src/table.rs diff --git a/codegen/src/ext.rs b/codegen/src/ext.rs index 8c633252..01244353 100644 --- a/codegen/src/ext.rs +++ b/codegen/src/ext.rs @@ -1,6 +1,6 @@ use syntex::Registry; -use syntex_syntax::ast::{ExprKind, MetaItem, Arm, Expr, PatKind, LitKind, Pat}; +use syntex_syntax::ast::{self, ExprKind, MetaItem, Arm, Expr, PatKind, LitKind, Pat}; use syntex_syntax::codemap::Span; use syntex_syntax::ext::base::{Annotatable, ExtCtxt, MacEager, MacResult, DummyResult}; use syntex_syntax::ext::build::AstBuilder; @@ -148,6 +148,19 @@ enum Transition { StateAction(State, Action), } +impl Transition { + // State is stored in the top 4 bits + fn pack_u8(&self) -> u8 { + match *self { + Transition::State(ref state) => (*state as u8) << 4, + Transition::Action(ref action) => *action as u8, + Transition::StateAction(ref state, ref action) => { + ((*state as u8) << 4) & (*action as u8) + } + } + } +} + impl Transition { fn from_expr(expr: &Expr, cx: &mut ExtCtxt) -> Result { match expr.node { @@ -294,6 +307,48 @@ fn parse_table_definition_list<'a>(parser: &mut Parser<'a>) Ok(definitions) } +fn build_state_tables(defs: T) -> [[u8; 256]; 16] + where T: AsRef<[TableDefinition]> +{ + let mut result = [[0u8; 256]; 16]; + + for def in defs.as_ref() { + let state = def.state; + let state = state as u8; + let transitions = &mut result[state as usize]; + + for mapping in &def.mappings { + let trans = mapping.transition.pack_u8(); + match mapping.input { + InputDefinition::Specific(idx) => { + transitions[idx as usize] = trans; + }, + InputDefinition::Range { start, end } => { + for idx in start..end { + transitions[idx as usize] = trans; + } + transitions[end as usize] = trans; + }, + } + } + } + + result +} + +fn build_table_ast(cx: &mut ExtCtxt, sp: Span, table: [[u8; 256]; 16]) -> P { + let table = table.iter() + .map(|list| { + let exprs = list.iter() + .map(|num| cx.expr_u8(sp, *num)) + .collect(); + cx.expr_vec(sp, exprs) + }) + .collect(); + + cx.expr_vec(sp, table) +} + fn expand_state_table<'cx>( cx: &'cx mut ExtCtxt, sp: Span, @@ -320,7 +375,8 @@ fn expand_state_table<'cx>( Err(_) => return DummyResult::any(sp), }; - println!("definitions: {:?}", definitions); + let table = build_state_tables(&definitions); + let ast = build_table_ast(cx, sp, table); - panic!("End of current implementation, go write some more :)"); + MacEager::expr(ast) } diff --git a/src/definitions.rs b/src/definitions.rs index f8875591..485609c4 100644 --- a/src/definitions.rs +++ b/src/definitions.rs @@ -1,4 +1,4 @@ -#[derive(Debug)] +#[derive(Debug, Copy, Clone)] pub enum State { Anywhere = 0, CsiEntry = 1, @@ -18,7 +18,7 @@ pub enum State { Unused__ = 15, } -#[derive(Debug)] +#[derive(Debug, Clone, Copy)] pub enum Action { None = 0, Clear = 1, @@ -46,7 +46,7 @@ pub enum Action { /// /// Bad things will happen if those invariants are violated. #[inline(always)] -fn unpack(delta: u8) -> (State, Action) { +pub fn unpack(delta: u8) -> (State, Action) { ( // Action is stored in bottom 4 bits unsafe { ::std::mem::transmute(delta & 0x0f) }, diff --git a/src/lib.rs b/src/lib.rs index d7dadad5..95ac4c8b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,7 +10,7 @@ impl State { #[inline(always)] pub fn exit_action(&self) -> Action { unsafe { - ::table::EXIT_ACTIONS.get_unchecked(*self as usize) + *::table::EXIT_ACTIONS.get_unchecked(*self as usize) } } @@ -18,7 +18,7 @@ impl State { #[inline(always)] pub fn entry_action(&self) -> Action { unsafe { - ::table::ENTRY_ACTIONS.get_unchecked(*self as usize) + *::table::ENTRY_ACTIONS.get_unchecked(*self as usize) } } } diff --git a/src/table.rs b/src/table.rs new file mode 100644 index 00000000..80f9a806 --- /dev/null +++ b/src/table.rs @@ -0,0 +1,372 @@ + +/// This is the state change table. It's indexed first by current state and then by the next +/// character in the pty stream. +use definitions::{State, Action}; + +pub static STATE_CHANGE: [[u8; 256]; 16] = + [ + + + + + + + + + + + + + + + [0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 160u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 80u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 224u8, 0u8, + 0u8, 16u8, 0u8, 208u8, 224u8, 224u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8], + [5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, + 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 0u8, 5u8, 0u8, 0u8, + 5u8, 5u8, 5u8, 5u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 32u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 7u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8], + [5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, + 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 0u8, 5u8, 0u8, 0u8, + 5u8, 5u8, 5u8, 5u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, + 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, + 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 192u8, 192u8, 192u8, 192u8, + 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, + 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, + 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, + 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, + 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, + 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 7u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8], + [5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, + 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 0u8, 5u8, 0u8, 0u8, + 5u8, 5u8, 5u8, 5u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, + 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, + 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 7u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8], + [5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, + 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 0u8, 5u8, 0u8, 0u8, + 5u8, 5u8, 5u8, 5u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 11u8, 11u8, 11u8, 11u8, 11u8, 11u8, 11u8, + 11u8, 11u8, 11u8, 32u8, 11u8, 32u8, 32u8, 32u8, 32u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 7u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8], + [7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, + 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 0u8, 7u8, 0u8, 0u8, + 7u8, 7u8, 7u8, 7u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 96u8, 0u8, 0u8, 0u8, 0u8, 0u8, 144u8, 144u8, 144u8, 144u8, + 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, + 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, + 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, + 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, + 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, + 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 7u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8], + [7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, + 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 0u8, 7u8, 0u8, 0u8, + 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, + 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, + 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, + 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, + 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, + 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, + 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, + 7u8, 7u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 192u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8], + [7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, + 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 0u8, 7u8, 0u8, 0u8, + 7u8, 7u8, 7u8, 7u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, + 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 96u8, 96u8, 96u8, 96u8, 96u8, 96u8, 96u8, + 96u8, 96u8, 96u8, 96u8, 96u8, 96u8, 96u8, 96u8, 96u8, 144u8, 144u8, + 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, + 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, + 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, + 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, + 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, + 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, + 144u8, 7u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8], + [7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, + 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 0u8, 7u8, 0u8, 0u8, + 7u8, 7u8, 7u8, 7u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 11u8, 11u8, 11u8, 11u8, 11u8, 11u8, 11u8, + 11u8, 11u8, 11u8, 96u8, 11u8, 96u8, 96u8, 96u8, 96u8, 144u8, 144u8, + 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, + 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, + 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, + 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, + 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, + 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, + 144u8, 7u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8], + [13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, + 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, + 0u8, 13u8, 0u8, 0u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, + 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, + 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, + 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, + 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, + 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, + 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, + 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, + 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 7u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 192u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8], + [5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, + 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 0u8, 5u8, 0u8, 0u8, + 5u8, 5u8, 5u8, 5u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 80u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 224u8, 0u8, 0u8, 16u8, 0u8, 208u8, 224u8, 224u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 7u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8], + [5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, + 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 0u8, 5u8, 0u8, 0u8, + 5u8, 5u8, 5u8, 5u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, + 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 7u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8], + [5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, + 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 0u8, 5u8, 0u8, 0u8, + 5u8, 5u8, 5u8, 5u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, + 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, + 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, + 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, + 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, + 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, + 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, + 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, + 12u8, 12u8, 12u8, 12u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, + 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 0u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, + 5u8, 5u8, 5u8, 5u8, 0u8, 5u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8], + [7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, + 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 0u8, 7u8, 0u8, 0u8, + 7u8, 7u8, 7u8, 7u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, + 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, + 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, + 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, + 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, + 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, + 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, + 9u8, 9u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 192u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8], + [7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, + 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 0u8, 7u8, 0u8, 0u8, + 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, + 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, + 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, + 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, + 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, + 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, + 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, + 7u8, 7u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 192u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8], + [0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8]]; + +pub static ENTRY_ACTIONS: &'static [Action] = + &[Action::None, // State::Anywhere + Action::Clear, // State::CsiEntry + Action::None, // State::CsiIgnore + Action::None, // State::CsiIntermediate + Action::None, // State::CsiParam + Action::Clear, // State::DcsEntry + Action::None, // State::DcsIgnore + Action::None, // State::DcsIntermediate + Action::None, // State::DcsParam + Action::Hook, // State::DcsPassthrough + Action::Clear, // State::Escape + Action::None, // State::EscapeIntermediate + Action::None, // State::Ground + Action::OscStart, // State::OscString + Action::None, // State::SosPmApcString + Action::None]; + // State::Unused__ + +pub static EXIT_ACTIONS: &'static [Action] = + &[Action::None, // State::Anywhere + Action::None, // State::CsiEntry + Action::None, // State::CsiIgnore + Action::None, // State::CsiIntermediate + Action::None, // State::CsiParam + Action::None, // State::DcsEntry + Action::None, // State::DcsIgnore + Action::None, // State::DcsIntermediate + Action::None, // State::DcsParam + Action::Unhook, // State::DcsPassthrough + Action::None, // State::Escape + Action::None, // State::EscapeIntermediate + Action::None, // State::Ground + Action::OscEnd, // State::OscString + Action::None, // State::SosPmApcString + Action::None]; // State::Unused__ diff --git a/src/table.rs.in b/src/table.rs.in index 9c39f5ea..d6af8199 100644 --- a/src/table.rs.in +++ b/src/table.rs.in @@ -1,9 +1,9 @@ /// This is the state change table. It's indexed first by current state and then by the next /// character in the pty stream. -/// -/// TODO implement a syntax extension that runs via syntex in build.rs to actually turn this into a -/// table. -static STATE_CHANGE: [[u8; 256]; 16] = state_table! { + +use definitions::{State, Action}; + +pub static STATE_CHANGE: [[u8; 256]; 16] = state_table! { State::Anywhere => { 0x18 => (Action::Execute, State::Ground), 0x1a => (Action::Execute, State::Ground), @@ -175,7 +175,7 @@ static STATE_CHANGE: [[u8; 256]; 16] = state_table! { } }; -static ENTRY_ACTIONS: &'static [Action] = &[ +pub static ENTRY_ACTIONS: &'static [Action] = &[ Action::None, // State::Anywhere Action::Clear, // State::CsiEntry Action::None, // State::CsiIgnore @@ -194,7 +194,7 @@ static ENTRY_ACTIONS: &'static [Action] = &[ Action::None, // State::Unused__ ]; -static EXIT_ACTIONS: &'static [Action] = &[ +pub static EXIT_ACTIONS: &'static [Action] = &[ Action::None, // State::Anywhere Action::None, // State::CsiEntry Action::None, // State::CsiIgnore From 5fdda06c3b48d7a5976a0e865f689247bc4fc855 Mon Sep 17 00:00:00 2001 From: Joe Wilm Date: Tue, 13 Sep 2016 20:24:48 -0700 Subject: [PATCH 04/99] wip parser --- src/lib.rs | 99 ++++++++++++++++++++++++++++++++++++++++++++----- src/table.rs | 2 +- src/table.rs.in | 2 +- 3 files changed, 91 insertions(+), 12 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 95ac4c8b..86de7e3f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,7 +10,7 @@ impl State { #[inline(always)] pub fn exit_action(&self) -> Action { unsafe { - *::table::EXIT_ACTIONS.get_unchecked(*self as usize) + *EXIT_ACTIONS.get_unchecked(*self as usize) } } @@ -18,20 +18,99 @@ impl State { #[inline(always)] pub fn entry_action(&self) -> Action { unsafe { - *::table::ENTRY_ACTIONS.get_unchecked(*self as usize) + *ENTRY_ACTIONS.get_unchecked(*self as usize) } } } -// struct StateMachine { -// state: State, -// } -// -// trait Parser { -// fn csi_entry(&mut self, c: char); -// fn csi_param(&mut self, c: char); -// } +pub struct StateMachine { + state: State, + parser: P, +} + +impl StateMachine

{ + pub fn advance(&mut self, byte: u8) { + // Handle state changes in the anywhere state before evaluating changes + // for current state. + let mut change = STATE_CHANGE[State::Anywhere as usize][byte as usize]; + if change == 0 { + change = STATE_CHANGE[self.state as usize][byte as usize]; + } + + // Unpack into a state and action + let (state, action) = unpack(change); + + self.perform_state_change(state, action, byte); + } + + fn perform_state_change(&mut self, state: State, action: Action, byte: u8) { + macro_rules! maybe_action { + ($action:expr, $arg:expr) => { + match $action { + Action::None | Action::Unused__ => (), + action => { + self.perform_action(action, $arg); + }, + } + } + } + + match state { + State::Anywhere | State::Unused__ => { + // Just run the action + self.perform_action(action, byte); + }, + state => { + // Exit action for previous state + let exit_action = self.state.exit_action(); + maybe_action!(exit_action, 0); + + // Transition action + maybe_action!(action, byte); + + // Entry action for new state + maybe_action!(state.entry_action(), 0); + + // Assume the new state + self.state = state; + } + } + } + + /// XXX I don't think this handles UTF-8 properly. Hmm... + fn perform_action(&mut self, action: Action, byte: u8) { + unimplemented!(); + + match action { + Action::Execute => self.parser.execute(byte), + Action::Hook => self.parser.hook(byte), + Action::Put => self.parser.put(byte), + Action::OscStart => self.parser.osc_start(byte), + Action::OscPut => self.parser.osc_put(byte), + Action::OscEnd => self.parser.osc_end(byte), + Action::Unhook => self.parser.unhook(byte), + Action::CsiDispatch => self.parser.csi_dispatch(byte), + Action::EscDispatch => self.parser.esc_dispatch(byte), + Action::Ignore | Action::None | Action::Unused__=> (), + Action::Collect => { + unimplemented!(); + }, + Action::Param => { + unimplemented!(); + }, + Action::Clear => { + unimplemented!(); + } + } + } +} + +pub trait Parser { + fn csi_entry(&mut self, byte: u8); + fn csi_param(&mut self, byte: u8); +} + // // struct Foo; // diff --git a/src/table.rs b/src/table.rs index 80f9a806..ebee5cf9 100644 --- a/src/table.rs +++ b/src/table.rs @@ -1,7 +1,7 @@ /// This is the state change table. It's indexed first by current state and then by the next /// character in the pty stream. -use definitions::{State, Action}; +use definitions::Action; pub static STATE_CHANGE: [[u8; 256]; 16] = [ diff --git a/src/table.rs.in b/src/table.rs.in index d6af8199..7414c2af 100644 --- a/src/table.rs.in +++ b/src/table.rs.in @@ -1,7 +1,7 @@ /// This is the state change table. It's indexed first by current state and then by the next /// character in the pty stream. -use definitions::{State, Action}; +use definitions::Action; pub static STATE_CHANGE: [[u8; 256]; 16] = state_table! { State::Anywhere => { From 0e9785ccc1d2c440d4251df74c909964fd46f312 Mon Sep 17 00:00:00 2001 From: Joe Wilm Date: Fri, 16 Sep 2016 20:24:37 -0700 Subject: [PATCH 05/99] Add custom Debug for ext::Transition This shows the variant in addition to the packed value - much more helpful when debugging. --- codegen/src/ext.rs | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/codegen/src/ext.rs b/codegen/src/ext.rs index 01244353..94fdd518 100644 --- a/codegen/src/ext.rs +++ b/codegen/src/ext.rs @@ -1,3 +1,5 @@ +use std::fmt; + use syntex::Registry; use syntex_syntax::ast::{self, ExprKind, MetaItem, Arm, Expr, PatKind, LitKind, Pat}; @@ -141,21 +143,35 @@ fn input_mapping_from_arm(arm: Arm, cx: &mut ExtCtxt) -> Result fmt::Result { + match *self { + Transition::State(state) => try!(write!(f, "State({:?})", state)), + Transition::Action(action) => try!(write!(f, "Action({:?})", action)), + Transition::StateAction(state, action) => { + try!(write!(f, "StateAction({:?}, {:?})", state, action)); + } + } + + write!(f, " -> {:?}", self.pack_u8()) + } +} + impl Transition { // State is stored in the top 4 bits fn pack_u8(&self) -> u8 { match *self { - Transition::State(ref state) => (*state as u8) << 4, - Transition::Action(ref action) => *action as u8, - Transition::StateAction(ref state, ref action) => { - ((*state as u8) << 4) & (*action as u8) + Transition::State(state) => state as u8, + Transition::Action(action) => (action as u8) << 4, + Transition::StateAction(state, action) => { + ((action as u8) << 4) | (state as u8) } } } From 171ad08b4e98bd23dd1aa9d28731c12dde35bba2 Mon Sep 17 00:00:00 2001 From: Joe Wilm Date: Fri, 16 Sep 2016 20:25:43 -0700 Subject: [PATCH 06/99] Add test for ext::Transition Debugging --- codegen/src/ext.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/codegen/src/ext.rs b/codegen/src/ext.rs index 94fdd518..d489bf0e 100644 --- a/codegen/src/ext.rs +++ b/codegen/src/ext.rs @@ -396,3 +396,15 @@ fn expand_state_table<'cx>( MacEager::expr(ast) } + +#[cfg(test)] +mod tests { + use definitions::{State, Action}; + use super::Transition; + + #[test] + fn pack_u8() { + let transition = Transition::StateAction(State::CsiParam, Action::Collect); + assert_eq!(transition.pack_u8(), 0x24); + } +} From 19c27105cc7a69bbe5b27714023c6fb27f676f12 Mon Sep 17 00:00:00 2001 From: Joe Wilm Date: Fri, 16 Sep 2016 20:26:01 -0700 Subject: [PATCH 07/99] Fix errors in codegen --- codegen/src/ext.rs | 8 ++++---- codegen/src/main.rs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/codegen/src/ext.rs b/codegen/src/ext.rs index d489bf0e..cef22671 100644 --- a/codegen/src/ext.rs +++ b/codegen/src/ext.rs @@ -2,11 +2,11 @@ use std::fmt; use syntex::Registry; -use syntex_syntax::ast::{self, ExprKind, MetaItem, Arm, Expr, PatKind, LitKind, Pat}; +use syntex_syntax::ast::{self, ExprKind, Arm, Expr, PatKind, LitKind, Pat}; use syntex_syntax::codemap::Span; -use syntex_syntax::ext::base::{Annotatable, ExtCtxt, MacEager, MacResult, DummyResult}; +use syntex_syntax::ext::base::{ExtCtxt, MacEager, MacResult, DummyResult}; use syntex_syntax::ext::build::AstBuilder; -use syntex_syntax::parse::token::{Token, InternedString, DelimToken}; +use syntex_syntax::parse::token::{Token, DelimToken}; use syntex_syntax::parse::parser::Parser; use syntex_syntax::parse::PResult; use syntex_syntax::ptr::P; @@ -72,7 +72,7 @@ fn parse_table_input_mappings<'a>(parser: &mut Parser<'a>) -> PResult<'a, Vec arms.push(arm), - Err(mut e) => { + Err(e) => { // Recover by skipping to the end of the block. return Err(e); } diff --git a/codegen/src/main.rs b/codegen/src/main.rs index d1994bb6..64bddd9b 100644 --- a/codegen/src/main.rs +++ b/codegen/src/main.rs @@ -14,5 +14,5 @@ fn main() { let mut registry = syntex::Registry::new(); ext::register(&mut registry); - registry.expand("state_table", src, dst); + registry.expand("state_table", src, dst).expect("expand stable_table ok"); } From 4c2932c8b6c6c6e286963b496bc3c487266d5673 Mon Sep 17 00:00:00 2001 From: Joe Wilm Date: Fri, 16 Sep 2016 20:32:52 -0700 Subject: [PATCH 08/99] Add fixed table.rs --- src/table.rs | 363 +++++++++++++++++++++++++++------------------------ 1 file changed, 189 insertions(+), 174 deletions(-) diff --git a/src/table.rs b/src/table.rs index ebee5cf9..923c7eb4 100644 --- a/src/table.rs +++ b/src/table.rs @@ -20,7 +20,7 @@ pub static STATE_CHANGE: [[u8; 256]; 16] = [0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 160u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 92u8, 0u8, 92u8, 10u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, @@ -28,85 +28,69 @@ pub static STATE_CHANGE: [[u8; 256]; 16] = 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 92u8, 92u8, 92u8, 92u8, 92u8, 92u8, 92u8, 92u8, 92u8, 92u8, + 92u8, 92u8, 92u8, 92u8, 92u8, 92u8, 5u8, 92u8, 92u8, 92u8, 92u8, 92u8, + 92u8, 92u8, 14u8, 92u8, 92u8, 1u8, 92u8, 13u8, 14u8, 14u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 80u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 224u8, 0u8, - 0u8, 16u8, 0u8, 208u8, 224u8, 224u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8], + [80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, + 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, + 0u8, 80u8, 0u8, 0u8, 80u8, 80u8, 80u8, 80u8, 35u8, 35u8, 35u8, 35u8, + 35u8, 35u8, 35u8, 35u8, 35u8, 35u8, 35u8, 35u8, 35u8, 35u8, 35u8, 35u8, + 180u8, 180u8, 180u8, 180u8, 180u8, 180u8, 180u8, 180u8, 180u8, 180u8, + 2u8, 180u8, 36u8, 36u8, 36u8, 36u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, + 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, + 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, + 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, + 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, + 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 112u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8], - [5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, - 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 0u8, 5u8, 0u8, 0u8, - 5u8, 5u8, 5u8, 5u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 32u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 7u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8], - [5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, - 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 0u8, 5u8, 0u8, 0u8, - 5u8, 5u8, 5u8, 5u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, - 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, - 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 192u8, 192u8, 192u8, 192u8, - 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, - 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, - 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, - 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, - 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, - 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 7u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8], - [5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, - 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 0u8, 5u8, 0u8, 0u8, - 5u8, 5u8, 5u8, 5u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, - 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, - 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 7u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8], + [80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, + 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, + 0u8, 80u8, 0u8, 0u8, 80u8, 80u8, 80u8, 80u8, 112u8, 112u8, 112u8, 112u8, + 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, + 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, + 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 12u8, 12u8, + 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, + 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, + 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, + 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, + 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, + 12u8, 112u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8], - [5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, - 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 0u8, 5u8, 0u8, 0u8, - 5u8, 5u8, 5u8, 5u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 11u8, 11u8, 11u8, 11u8, 11u8, 11u8, 11u8, - 11u8, 11u8, 11u8, 32u8, 11u8, 32u8, 32u8, 32u8, 32u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8], + [80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, + 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, + 0u8, 80u8, 0u8, 0u8, 80u8, 80u8, 80u8, 80u8, 32u8, 32u8, 32u8, 32u8, + 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, + 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, + 2u8, 2u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, + 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, + 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, + 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, + 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, + 60u8, 60u8, 60u8, 60u8, 60u8, 112u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 7u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, @@ -114,81 +98,80 @@ pub static STATE_CHANGE: [[u8; 256]; 16] = 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8], + [80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, + 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, + 0u8, 80u8, 0u8, 0u8, 80u8, 80u8, 80u8, 80u8, 35u8, 35u8, 35u8, 35u8, + 35u8, 35u8, 35u8, 35u8, 35u8, 35u8, 35u8, 35u8, 35u8, 35u8, 35u8, 35u8, + 176u8, 176u8, 176u8, 176u8, 176u8, 176u8, 176u8, 176u8, 176u8, 176u8, + 2u8, 176u8, 2u8, 2u8, 2u8, 2u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, + 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, + 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, + 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, + 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, + 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 112u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8], - [7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, - 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 0u8, 7u8, 0u8, 0u8, - 7u8, 7u8, 7u8, 7u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 96u8, 0u8, 0u8, 0u8, 0u8, 0u8, 144u8, 144u8, 144u8, 144u8, - 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, - 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, - 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, - 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, - 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, - 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 7u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8], + [112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, + 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, + 112u8, 112u8, 112u8, 112u8, 0u8, 112u8, 0u8, 0u8, 112u8, 112u8, 112u8, + 112u8, 39u8, 39u8, 39u8, 39u8, 39u8, 39u8, 39u8, 39u8, 39u8, 39u8, 39u8, + 39u8, 39u8, 39u8, 39u8, 39u8, 184u8, 184u8, 184u8, 184u8, 184u8, 184u8, + 184u8, 184u8, 184u8, 184u8, 6u8, 184u8, 40u8, 40u8, 40u8, 40u8, 9u8, + 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, + 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, + 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, + 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, + 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 112u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8], - [7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, - 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 0u8, 7u8, 0u8, 0u8, - 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, - 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, - 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, - 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, - 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, - 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, - 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, - 7u8, 7u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 192u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8], - [7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, - 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 0u8, 7u8, 0u8, 0u8, - 7u8, 7u8, 7u8, 7u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, - 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 96u8, 96u8, 96u8, 96u8, 96u8, 96u8, 96u8, - 96u8, 96u8, 96u8, 96u8, 96u8, 96u8, 96u8, 96u8, 96u8, 144u8, 144u8, - 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, - 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, - 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, - 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, - 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, - 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, - 144u8, 7u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8], + [112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, + 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, + 112u8, 112u8, 112u8, 112u8, 0u8, 112u8, 0u8, 0u8, 112u8, 112u8, 112u8, + 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, + 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, + 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, + 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, + 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, + 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, + 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, + 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, + 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, + 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 12u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8], - [7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, - 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 0u8, 7u8, 0u8, 0u8, - 7u8, 7u8, 7u8, 7u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 11u8, 11u8, 11u8, 11u8, 11u8, 11u8, 11u8, - 11u8, 11u8, 11u8, 96u8, 11u8, 96u8, 96u8, 96u8, 96u8, 144u8, 144u8, - 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, - 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, - 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, - 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, - 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, - 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, - 144u8, 7u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8], + [112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, + 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, + 112u8, 112u8, 112u8, 112u8, 0u8, 112u8, 0u8, 0u8, 112u8, 112u8, 112u8, + 112u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, + 32u8, 32u8, 32u8, 32u8, 32u8, 6u8, 6u8, 6u8, 6u8, 6u8, 6u8, 6u8, 6u8, + 6u8, 6u8, 6u8, 6u8, 6u8, 6u8, 6u8, 6u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, + 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, + 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, + 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, + 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, + 9u8, 112u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, @@ -198,55 +181,79 @@ pub static STATE_CHANGE: [[u8; 256]; 16] = 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8], - [13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, - 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, - 0u8, 13u8, 0u8, 0u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, - 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, - 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, - 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, - 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, - 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, - 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, - 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, - 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 13u8, 7u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 192u8, 0u8, 0u8, 0u8, 0u8, + [112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, + 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, + 112u8, 112u8, 112u8, 112u8, 0u8, 112u8, 0u8, 0u8, 112u8, 112u8, 112u8, + 112u8, 39u8, 39u8, 39u8, 39u8, 39u8, 39u8, 39u8, 39u8, 39u8, 39u8, 39u8, + 39u8, 39u8, 39u8, 39u8, 39u8, 176u8, 176u8, 176u8, 176u8, 176u8, 176u8, + 176u8, 176u8, 176u8, 176u8, 6u8, 176u8, 6u8, 6u8, 6u8, 6u8, 9u8, 9u8, + 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, + 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, + 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, + 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, + 9u8, 9u8, 9u8, 9u8, 9u8, 112u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8], - [5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, - 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 0u8, 5u8, 0u8, 0u8, - 5u8, 5u8, 5u8, 5u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 80u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 224u8, 0u8, 0u8, 16u8, 0u8, 208u8, 224u8, 224u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8], + [208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, + 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, + 208u8, 208u8, 208u8, 208u8, 0u8, 208u8, 0u8, 0u8, 208u8, 208u8, 208u8, + 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, + 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, + 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, + 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, + 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, + 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, + 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, + 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, + 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, + 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 112u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 12u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 7u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8], + [80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, + 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, + 0u8, 80u8, 0u8, 0u8, 80u8, 80u8, 80u8, 80u8, 43u8, 43u8, 43u8, 43u8, + 43u8, 43u8, 43u8, 43u8, 43u8, 43u8, 43u8, 43u8, 43u8, 43u8, 43u8, 43u8, + 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, + 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, + 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 5u8, 76u8, 76u8, 76u8, + 76u8, 76u8, 76u8, 76u8, 14u8, 76u8, 76u8, 1u8, 76u8, 13u8, 14u8, 14u8, + 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, + 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, + 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 112u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8], - [5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, - 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 0u8, 5u8, 0u8, 0u8, - 5u8, 5u8, 5u8, 5u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, - 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 7u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8], + [80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, + 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, + 0u8, 80u8, 0u8, 0u8, 80u8, 80u8, 80u8, 80u8, 32u8, 32u8, 32u8, 32u8, + 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, + 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, + 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, + 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, + 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, + 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, + 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, + 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 112u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, @@ -255,65 +262,73 @@ pub static STATE_CHANGE: [[u8; 256]; 16] = 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8], - [5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, - 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 0u8, 5u8, 0u8, 0u8, - 5u8, 5u8, 5u8, 5u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, - 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, - 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, - 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, - 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, - 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, - 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, - 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, - 12u8, 12u8, 12u8, 12u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, - 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, 0u8, 5u8, 5u8, 5u8, 5u8, 5u8, 5u8, - 5u8, 5u8, 5u8, 5u8, 0u8, 5u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8], + [80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, + 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, + 0u8, 80u8, 0u8, 0u8, 80u8, 80u8, 80u8, 80u8, 192u8, 192u8, 192u8, 192u8, + 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, + 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, + 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, + 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, + 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, + 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, + 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, + 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, + 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, + 192u8, 192u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, + 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 0u8, 80u8, 80u8, 80u8, 80u8, + 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 0u8, 80u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8], - [7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, - 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 0u8, 7u8, 0u8, 0u8, - 7u8, 7u8, 7u8, 7u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, - 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, - 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, - 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, - 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, - 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, - 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, - 9u8, 9u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8], + [112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, + 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, + 112u8, 112u8, 112u8, 112u8, 0u8, 112u8, 0u8, 0u8, 112u8, 112u8, 112u8, + 112u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, + 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, + 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, + 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, + 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, + 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, + 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, + 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, + 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, + 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 192u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 12u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8], - [7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, - 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 0u8, 7u8, 0u8, 0u8, - 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, - 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, - 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, - 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, - 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, - 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, - 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, - 7u8, 7u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8], + [112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, + 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, + 112u8, 112u8, 112u8, 112u8, 0u8, 112u8, 0u8, 0u8, 112u8, 112u8, 112u8, + 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, + 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, + 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, + 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, + 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, + 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, + 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, + 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, + 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, + 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 192u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 12u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8], + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8], [0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, From 8553c85a9962fb2dda185cf86a72979fd4b755ff Mon Sep 17 00:00:00 2001 From: Joe Wilm Date: Fri, 16 Sep 2016 20:33:36 -0700 Subject: [PATCH 09/99] Fix some comments --- src/definitions.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/definitions.rs b/src/definitions.rs index 485609c4..42fb26e4 100644 --- a/src/definitions.rs +++ b/src/definitions.rs @@ -48,10 +48,10 @@ pub enum Action { #[inline(always)] pub fn unpack(delta: u8) -> (State, Action) { ( - // Action is stored in bottom 4 bits + // State is stored in bottom 4 bits unsafe { ::std::mem::transmute(delta & 0x0f) }, - // State is stored in top 4 bits + // Action is stored in top 4 bits unsafe { ::std::mem::transmute(delta >> 4) }, ) } From 8da0d9e67feeaaf5eab9a078cd5968bd45f47fe5 Mon Sep 17 00:00:00 2001 From: Joe Wilm Date: Fri, 16 Sep 2016 20:33:51 -0700 Subject: [PATCH 10/99] Expand unpack state/action tests --- src/definitions.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/definitions.rs b/src/definitions.rs index 42fb26e4..5177ca60 100644 --- a/src/definitions.rs +++ b/src/definitions.rs @@ -66,6 +66,11 @@ mod tests { _ => panic!("unpack failed"), } + match unpack(0x0f) { + (State::Unused__, Action::None) => (), + _ => panic!("unpack failed"), + } + match unpack(0xff) { (State::Unused__, Action::Unused__) => (), _ => panic!("unpack failed"), From 5505121f6e67d1f39ff4d3aaea739b73e1a17345 Mon Sep 17 00:00:00 2001 From: Joe Wilm Date: Fri, 16 Sep 2016 20:34:05 -0700 Subject: [PATCH 11/99] Rename crate --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index cf36ebb0..3ccedb1e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "fun-table" +name = "vtparse" version = "0.1.0" authors = ["Joe Wilm "] From 930f8cc30a5bc4943c1b56e18cf1a3f8bb00bc2a Mon Sep 17 00:00:00 2001 From: Joe Wilm Date: Fri, 16 Sep 2016 20:34:39 -0700 Subject: [PATCH 12/99] Implement first version of parser Includes an example `parselog` which prints all of the actions a Parser implementation is given the opportunity to handle. One way to test this is to pipe vim into it: vim | target/release/examples/parselog And type `:q` to quit. Vim won't show up, but it still accepts input. This version of the parser doesn't handle UTF-8. It's implemented as described by http://vt100.net/emu/dec_ansi_parser which did not include UTF-8 support. Next steps are adding UTF-8 support. --- examples/parselog.rs | 69 ++++++++++++++++++++++ src/lib.rs | 134 ++++++++++++++++++++++++++++--------------- 2 files changed, 157 insertions(+), 46 deletions(-) create mode 100644 examples/parselog.rs diff --git a/examples/parselog.rs b/examples/parselog.rs new file mode 100644 index 00000000..804c3994 --- /dev/null +++ b/examples/parselog.rs @@ -0,0 +1,69 @@ +//! Parse input from stdin and log actions on stdout +extern crate vtparse; + +use std::io::{self, Read}; + +use vtparse::{StateMachine, Parser}; + +/// A type implementing Parser that just logs actions +struct Log; + +impl Parser for Log { + fn print(&mut self, _machine: &StateMachine, c: char) { + println!("[print] {:?}", c); + } + fn execute(&mut self, _machine: &StateMachine, byte: u8) { + println!("[execute] byte={:02x}", byte); + } + fn hook(&mut self, _machine: &StateMachine, byte: u8) { + println!("[hook] byte={:02x}", byte); + } + fn put(&mut self, _machine: &StateMachine, byte: u8) { + println!("[put] byte={:02x}", byte); + } + fn osc_start(&mut self, _machine: &StateMachine, byte: u8) { + println!("[osc_start] byte={:02x}", byte); + } + fn osc_put(&mut self, _machine: &StateMachine, byte: u8) { + println!("[osc_put] byte={:02x}", byte); + } + fn osc_end(&mut self, _machine: &StateMachine, byte: u8) { + println!("[osc_end] byte={:02x}", byte); + } + fn unhook(&mut self, _machine: &StateMachine, byte: u8) { + println!("[unhook] byte={:02x}", byte); + } + fn csi_dispatch(&mut self, machine: &StateMachine, c: char) { + println!("[csi_dispatch] params={:?}, intermediates={:?}, action={:?}", + machine.params(), machine.intermediates(), c); + } + fn esc_dispatch(&mut self, machine: &StateMachine, byte: u8) { + println!("[csi_dispatch] params={:?}, intermediates={:?}, action={:?}", + machine.params(), machine.intermediates(), byte as char); + } +} + +fn main() { + let input = io::stdin(); + let mut handle = input.lock(); + + let mut statemachine = StateMachine::new(); + let mut parser = Log; + + let mut buf: [u8; 2048] = unsafe { std::mem::uninitialized() }; + + loop { + match handle.read(&mut buf) { + Ok(0) => break, + Ok(n) => { + for byte in &buf[..n] { + statemachine.advance(&mut parser, *byte); + } + }, + Err(err) => { + println!("err: {}", err); + break; + } + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 86de7e3f..73326bc5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,16 +24,48 @@ impl State { } -pub struct StateMachine { +const MAX_INTERMEDIATES: usize = 2; +const MAX_PARAMS: usize = 16; + +/// ANSI VTE Parser +/// +/// As described in http://vt100.net/emu/dec_ansi_parser +/// +/// TODO: utf8 support +pub struct StateMachine { state: State, - parser: P, + intermediates: [u8; MAX_INTERMEDIATES], + intermediate_idx: usize, + params: [i64; MAX_PARAMS], + num_params: usize, + ignoring: bool } -impl StateMachine

{ - pub fn advance(&mut self, byte: u8) { +impl StateMachine { + pub fn new() -> StateMachine { + StateMachine { + state: State::Ground, + intermediates: [0u8; MAX_INTERMEDIATES], + intermediate_idx: 0, + params: [0i64; MAX_PARAMS], + num_params: 0, + ignoring: false, + } + } + + pub fn params(&self) -> &[i64] { + &self.params[..self.num_params] + } + + pub fn intermediates(&self) -> &[u8] { + &self.intermediates[..self.intermediate_idx] + } + + pub fn advance(&mut self, parser: &mut P, byte: u8) { // Handle state changes in the anywhere state before evaluating changes // for current state. let mut change = STATE_CHANGE[State::Anywhere as usize][byte as usize]; + if change == 0 { change = STATE_CHANGE[self.state as usize][byte as usize]; } @@ -41,16 +73,18 @@ impl StateMachine

{ // Unpack into a state and action let (state, action) = unpack(change); - self.perform_state_change(state, action, byte); + self.perform_state_change(parser, state, action, byte); } - fn perform_state_change(&mut self, state: State, action: Action, byte: u8) { + fn perform_state_change

(&mut self, parser: &mut P, state: State, action: Action, byte: u8) + where P: Parser + { macro_rules! maybe_action { ($action:expr, $arg:expr) => { match $action { Action::None | Action::Unused__ => (), action => { - self.perform_action(action, $arg); + self.perform_action(parser, action, $arg); }, } } @@ -59,7 +93,7 @@ impl StateMachine

{ match state { State::Anywhere | State::Unused__ => { // Just run the action - self.perform_action(action, byte); + self.perform_action(parser, action, byte); }, state => { // Exit action for previous state @@ -78,55 +112,63 @@ impl StateMachine

{ } } - /// XXX I don't think this handles UTF-8 properly. Hmm... - fn perform_action(&mut self, action: Action, byte: u8) { - unimplemented!(); - + fn perform_action(&mut self, parser: &mut P, action: Action, byte: u8) { match action { - Action::Execute => self.parser.execute(byte), - Action::Hook => self.parser.hook(byte), - Action::Put => self.parser.put(byte), - Action::OscStart => self.parser.osc_start(byte), - Action::OscPut => self.parser.osc_put(byte), - Action::OscEnd => self.parser.osc_end(byte), - Action::Unhook => self.parser.unhook(byte), - Action::CsiDispatch => self.parser.csi_dispatch(byte), - Action::EscDispatch => self.parser.esc_dispatch(byte), + Action::Print => parser.print(self, byte as char), + Action::Execute => parser.execute(self, byte), + Action::Hook => parser.hook(self, byte), + Action::Put => parser.put(self, byte), + Action::OscStart => parser.osc_start(self, byte), + Action::OscPut => parser.osc_put(self, byte), + Action::OscEnd => parser.osc_end(self, byte), + Action::Unhook => parser.unhook(self, byte), + Action::CsiDispatch => parser.csi_dispatch(self, byte as char), + Action::EscDispatch => parser.esc_dispatch(self, byte), Action::Ignore | Action::None | Action::Unused__=> (), Action::Collect => { - unimplemented!(); + if self.intermediate_idx == MAX_INTERMEDIATES { + self.ignoring = true; + } else { + self.intermediates[self.intermediate_idx] = byte; + self.intermediate_idx += 1; + } }, Action::Param => { - unimplemented!(); + // if byte == ';' + if byte == 0x3b { + // end of param; advance to next + self.num_params += 1; + let idx = self.num_params - 1; // borrowck + self.params[idx] = 0; + } else { + if self.num_params == 0 { + self.num_params = 1; + self.params[0] = 0; + } + + let idx = self.num_params - 1; + self.params[idx] *= 10; + self.params[idx] += (byte - ('0' as u8)) as i64; + } }, Action::Clear => { - unimplemented!(); + self.intermediate_idx = 0; + self.num_params = 0; + self.ignoring = false; } } } } pub trait Parser { - fn csi_entry(&mut self, byte: u8); - fn csi_param(&mut self, byte: u8); + fn print(&mut self, &StateMachine, c: char); + fn execute(&mut self, &StateMachine, byte: u8); + fn hook(&mut self, &StateMachine, byte: u8); + fn put(&mut self, &StateMachine, byte: u8); + fn osc_start(&mut self, &StateMachine, byte: u8); + fn osc_put(&mut self, &StateMachine, byte: u8); + fn osc_end(&mut self, &StateMachine, byte: u8); + fn unhook(&mut self, &StateMachine, byte: u8); + fn csi_dispatch(&mut self, &StateMachine, c: char); + fn esc_dispatch(&mut self, &StateMachine, byte: u8); } - -// -// struct Foo; -// -// impl Parser for Foo { -// fn csi_entry(&mut self, c: char) { -// println!("csi_entry char={:?}", c); -// } -// fn csi_param(&mut self, c: char) { -// println!("csi_param char={:?}", c); -// } -// } -// -// #[test] -// fn it_works() { -// let table: u8 = &[Parser::csi_entry, Parser::csi_param]; -// let mut foo = Foo; -// table[0](&mut foo, 'b'); -// } - From cffdb6de59ceb3fd9983a1c19476e5109da8db97 Mon Sep 17 00:00:00 2001 From: Joe Wilm Date: Sat, 17 Sep 2016 15:51:45 -0700 Subject: [PATCH 13/99] Add support for UTF-8 This adds a table-driven UTF-8 parser which only has a single branch for the entire parser. UTF-8 support is essentially bolted onto the VTE parser. Not the most elegant, but it does prevent the transition tables from blowing up. Instead of refactoring the syntax extension to handle both table definitions, I've opted to copy/paste now for both simplicities sake and because I can't see a clear path to a minimal shared solution. --- codegen/src/ext/mod.rs | 2 + codegen/src/ext/utf8.rs | 386 ++++++++++++++++++++++++++++++ codegen/src/{ext.rs => ext/vt.rs} | 10 +- codegen/src/main.rs | 15 +- examples/parselog.rs | 2 +- src/definitions.rs | 8 +- src/lib.rs | 49 +++- src/table.rs | 19 +- src/table.rs.in | 14 +- src/utf8/mod.rs | 91 +++++++ src/utf8/table.rs | 184 ++++++++++++++ src/utf8/table.rs.in | 60 +++++ src/utf8/types.rs | 77 ++++++ 13 files changed, 887 insertions(+), 30 deletions(-) create mode 100644 codegen/src/ext/mod.rs create mode 100644 codegen/src/ext/utf8.rs rename codegen/src/{ext.rs => ext/vt.rs} (97%) create mode 100644 src/utf8/mod.rs create mode 100644 src/utf8/table.rs create mode 100644 src/utf8/table.rs.in create mode 100644 src/utf8/types.rs diff --git a/codegen/src/ext/mod.rs b/codegen/src/ext/mod.rs new file mode 100644 index 00000000..c28d9f7d --- /dev/null +++ b/codegen/src/ext/mod.rs @@ -0,0 +1,2 @@ +pub mod utf8; +pub mod vt; diff --git a/codegen/src/ext/utf8.rs b/codegen/src/ext/utf8.rs new file mode 100644 index 00000000..5b73081e --- /dev/null +++ b/codegen/src/ext/utf8.rs @@ -0,0 +1,386 @@ +//! Macro expansion for the utf8 parser state table +use std::fmt; + +use syntex::Registry; + +use syntex_syntax::ast::{self, ExprKind, Arm, Expr, PatKind, LitKind, Pat}; +use syntex_syntax::codemap::Span; +use syntex_syntax::ext::base::{ExtCtxt, MacEager, MacResult, DummyResult}; +use syntex_syntax::ext::build::AstBuilder; +use syntex_syntax::parse::token::{Token, DelimToken}; +use syntex_syntax::parse::parser::Parser; +use syntex_syntax::parse::PResult; +use syntex_syntax::ptr::P; +use syntex_syntax::tokenstream::TokenTree; + +#[path="../../../src/utf8/types.rs"] +mod types; + +use self::types::{State, Action, pack}; + +pub fn register(registry: &mut Registry) { + registry.add_macro("utf8_state_table", expand_state_table); +} + +fn state_from_str(s: &S) -> Result + where S: AsRef +{ + Ok(match s.as_ref() { + "State::Ground" => State::Ground, + "State::Tail3" => State::Tail3, + "State::Tail2" => State::Tail2, + "State::Tail1" => State::Tail1, + "State::U3_2_e0" => State::U3_2_e0, + "State::U3_2_ed" => State::U3_2_ed, + "State::Utf8_4_3_f0" => State::Utf8_4_3_f0, + "State::Utf8_4_3_f4" => State::Utf8_4_3_f4, + _ => return Err(()) + }) +} + +fn action_from_str(s: &S) -> Result + where S: AsRef +{ + Ok(match s.as_ref() { + "Action::InvalidSequence" => Action::InvalidSequence, + "Action::EmitByte" => Action::EmitByte, + "Action::SetByte1" => Action::SetByte1, + "Action::SetByte2" => Action::SetByte2, + "Action::SetByte2Top" => Action::SetByte2Top, + "Action::SetByte3" => Action::SetByte3, + "Action::SetByte3Top" => Action::SetByte3Top, + "Action::SetByte4" => Action::SetByte4, + _ => return Err(()) + }) +} + +fn parse_table_input_mappings<'a>(parser: &mut Parser<'a>) -> PResult<'a, Vec> { + // Must start on open brace + try!(parser.expect(&Token::OpenDelim(DelimToken::Brace))); + + let mut arms: Vec = Vec::new(); + while parser.token != Token::CloseDelim(DelimToken::Brace) { + match parser.parse_arm() { + Ok(arm) => arms.push(arm), + Err(e) => { + // Recover by skipping to the end of the block. + return Err(e); + } + } + } + + // Consume the closing brace + parser.bump(); + Ok(arms) +} + +/// Expressions describing state transitions and actions +#[derive(Debug)] +struct TableDefinitionExprs { + state_expr: P, + mapping_arms: Vec, +} + +fn state_from_expr(expr: P, cx: &mut ExtCtxt) -> Result { + let s = match expr.node { + ExprKind::Path(ref _qself, ref path) => { + path.to_string() + }, + _ => { + cx.span_err(expr.span, "expected State"); + return Err(()) + } + }; + + state_from_str(&s).map_err(|_| { + cx.span_err(expr.span, "expected State"); + () + }) +} + +fn u8_lit_from_expr(expr: &Expr, cx: &mut ExtCtxt) -> Result { + static MSG: &'static str = "expected u8 int literal"; + + match expr.node { + ExprKind::Lit(ref lit) => { + match lit.node { + LitKind::Int(val, _) => { + Ok(val as u8) + }, + _ => { + cx.span_err(lit.span, MSG); + return Err(()); + } + } + }, + _ => { + cx.span_err(expr.span, MSG); + return Err(()); + } + } +} + +fn input_mapping_from_arm(arm: Arm, cx: &mut ExtCtxt) -> Result { + let Arm { pats, body, .. } = arm; + + let input = try!(InputDefinition::from_pat(&pats[0], cx)); + let transition = try!(Transition::from_expr(&body, cx)); + + Ok(InputMapping { + input: input, + transition: transition, + }) +} + +/// What happens when certain input is received +#[derive(Copy, Clone)] +enum Transition { + State(State), + Action(Action), + StateAction(State, Action), +} + +impl fmt::Debug for Transition { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Transition::State(state) => try!(write!(f, "State({:?})", state)), + Transition::Action(action) => try!(write!(f, "Action({:?})", action)), + Transition::StateAction(state, action) => { + try!(write!(f, "StateAction({:?}, {:?})", state, action)); + } + } + + write!(f, " -> {:?}", self.pack_u8()) + } +} + +impl Transition { + // State is stored in the top 4 bits + fn pack_u8(&self) -> u8 { + match *self { + Transition::State(state) => pack(state, Action::InvalidSequence), + Transition::Action(action) => pack(State::Ground, action), + Transition::StateAction(state, action) => pack(state, action), + } + } +} + +impl Transition { + fn from_expr(expr: &Expr, cx: &mut ExtCtxt) -> Result { + match expr.node { + ExprKind::Tup(ref tup_exprs) => { + let mut action = None; + let mut state = None; + + for tup_expr in tup_exprs { + if let ExprKind::Path(_, ref path) = tup_expr.node { + let path_str = path.to_string(); + if path_str.starts_with('A') { + action = Some(try!(action_from_str(&path_str) + .map_err(|_| { + cx.span_err(expr.span, "invalid action"); + }))); + } else { + state = Some(try!(state_from_str(&path_str) + .map_err(|_| { + cx.span_err(expr.span, "invalid state"); + }))); + } + } + } + + match (action, state) { + (Some(action), Some(state)) => Ok(Transition::StateAction(state, action)), + (None, Some(state)) => Ok(Transition::State(state)), + (Some(action), None) => Ok(Transition::Action(action)), + _ => { + cx.span_err(expr.span, "expected Action and/or State"); + Err(()) + } + } + }, + ExprKind::Path(_, ref path) => { + // Path can be Action or State + let path_str = path.to_string(); + + if path_str.starts_with('A') { + let action = try!(action_from_str(&path_str) + .map_err(|_| { + cx.span_err(expr.span, "invalid action"); + })); + Ok(Transition::Action(action)) + } else { + let state = try!(state_from_str(&path_str) + .map_err(|_| { + cx.span_err(expr.span, "invalid state"); + })); + + Ok(Transition::State(state)) + } + }, + _ => { + cx.span_err(expr.span, "expected Action and/or State"); + Err(()) + } + } + } +} + +#[derive(Debug)] +enum InputDefinition { + Specific(u8), + Range { start: u8, end: u8 } +} + +impl InputDefinition { + fn from_pat(pat: &Pat, cx: &mut ExtCtxt) -> Result { + Ok(match pat.node { + PatKind::Lit(ref lit_expr) => { + InputDefinition::Specific(try!(u8_lit_from_expr(&lit_expr, cx))) + }, + PatKind::Range(ref start_expr, ref end_expr) => { + InputDefinition::Range { + start: try!(u8_lit_from_expr(start_expr, cx)), + end: try!(u8_lit_from_expr(end_expr, cx)), + } + }, + _ => { + cx.span_err(pat.span, "expected literal or range expression"); + return Err(()) + } + }) + } +} + +#[derive(Debug)] +struct InputMapping { + input: InputDefinition, + transition: Transition, +} + +#[derive(Debug)] +struct TableDefinition { + state: State, + mappings: Vec, +} + +fn parse_raw_definitions( + definitions: Vec, + cx: &mut ExtCtxt +) -> Result, ()> { + let mut out = Vec::new(); + + for raw in definitions { + let TableDefinitionExprs { state_expr, mapping_arms } = raw; + let state = try!(state_from_expr(state_expr, cx)); + + let mut mappings = Vec::new(); + for arm in mapping_arms { + mappings.push(try!(input_mapping_from_arm(arm, cx))); + } + + out.push(TableDefinition { + state: state, + mappings: mappings, + }) + } + + Ok(out) +} + +fn parse_table_definition<'a>(parser: &mut Parser<'a>) -> PResult<'a, TableDefinitionExprs> { + let state_expr = try!(parser.parse_expr()); + try!(parser.expect(&Token::FatArrow)); + let mappings = try!(parse_table_input_mappings(parser)); + + Ok(TableDefinitionExprs { + state_expr: state_expr, + mapping_arms: mappings + }) +} + +fn parse_table_definition_list<'a>(parser: &mut Parser<'a>) + -> PResult<'a, Vec> +{ + let mut definitions = Vec::new(); + while parser.token != Token::Eof { + definitions.push(try!(parse_table_definition(parser))); + parser.eat(&Token::Comma); + } + + Ok(definitions) +} + +fn build_state_tables(defs: T) -> [[u8; 256]; 8] + where T: AsRef<[TableDefinition]> +{ + let mut result = [[0u8; 256]; 8]; + + for def in defs.as_ref() { + let state = def.state; + let state = state as u8; + let transitions = &mut result[state as usize]; + + for mapping in &def.mappings { + let trans = mapping.transition.pack_u8(); + match mapping.input { + InputDefinition::Specific(idx) => { + transitions[idx as usize] = trans; + }, + InputDefinition::Range { start, end } => { + for idx in start..end { + transitions[idx as usize] = trans; + } + transitions[end as usize] = trans; + }, + } + } + } + + result +} + +fn build_table_ast(cx: &mut ExtCtxt, sp: Span, table: [[u8; 256]; 8]) -> P { + let table = table.iter() + .map(|list| { + let exprs = list.iter() + .map(|num| cx.expr_u8(sp, *num)) + .collect(); + cx.expr_vec(sp, exprs) + }) + .collect(); + + cx.expr_vec(sp, table) +} + +fn expand_state_table<'cx>( + cx: &'cx mut ExtCtxt, + sp: Span, + args: &[TokenTree]) + -> Box +{ + macro_rules! ptry { + ($pres:expr) => { + match $pres { + Ok(val) => val, + Err(mut err) => { + err.emit(); + return DummyResult::any(sp); + } + } + } + } + + // Parse the lookup spec + let mut parser: Parser = cx.new_parser_from_tts(args); + let definitions = ptry!(parse_table_definition_list(&mut parser)); + let definitions = match parse_raw_definitions(definitions, cx) { + Ok(definitions) => definitions, + Err(_) => return DummyResult::any(sp), + }; + + let table = build_state_tables(&definitions); + let ast = build_table_ast(cx, sp, table); + + MacEager::expr(ast) +} diff --git a/codegen/src/ext.rs b/codegen/src/ext/vt.rs similarity index 97% rename from codegen/src/ext.rs rename to codegen/src/ext/vt.rs index cef22671..3f5bcf39 100644 --- a/codegen/src/ext.rs +++ b/codegen/src/ext/vt.rs @@ -1,3 +1,4 @@ +//! Macro expansion for the virtual terminal parser state table use std::fmt; use syntex::Registry; @@ -12,10 +13,13 @@ use syntex_syntax::parse::PResult; use syntex_syntax::ptr::P; use syntex_syntax::tokenstream::TokenTree; -use definitions::{State, Action}; +#[path="../../../src/definitions.rs"] +mod definitions; + +use self::definitions::{State, Action}; pub fn register(registry: &mut Registry) { - registry.add_macro("state_table", expand_state_table); + registry.add_macro("vt_state_table", expand_state_table); } fn state_from_str(s: &S) -> Result @@ -37,6 +41,7 @@ fn state_from_str(s: &S) -> Result "State::Ground" => State::Ground, "State::OscString" => State::OscString, "State::SosPmApcString" => State::SosPmApcString, + "State::Utf8" => State::Utf8, _ => return Err(()) }) } @@ -60,6 +65,7 @@ fn action_from_str(s: &S) -> Result "Action::Print" => Action::Print, "Action::Put" => Action::Put, "Action::Unhook" => Action::Unhook, + "Action::BeginUtf8" => Action::BeginUtf8, _ => return Err(()) }) } diff --git a/codegen/src/main.rs b/codegen/src/main.rs index 64bddd9b..5f8d1530 100644 --- a/codegen/src/main.rs +++ b/codegen/src/main.rs @@ -1,18 +1,23 @@ +#![allow(dead_code)] extern crate syntex; extern crate syntex_syntax; mod ext; -#[path="../../src/definitions.rs"] -pub mod definitions; - use std::path::Path; fn main() { + // Expand VT parser state table + let mut registry = syntex::Registry::new(); + ext::vt::register(&mut registry); let src = &Path::new("../src/table.rs.in"); let dst = &Path::new("../src/table.rs"); + registry.expand("vt_state_table", src, dst).expect("expand vt_stable_table ok"); + // Expand UTF8 parser state table let mut registry = syntex::Registry::new(); - ext::register(&mut registry); - registry.expand("state_table", src, dst).expect("expand stable_table ok"); + ext::utf8::register(&mut registry); + let src = &Path::new("../src/utf8/table.rs.in"); + let dst = &Path::new("../src/utf8/table.rs"); + registry.expand("utf8_state_table", src, dst).expect("expand utf8_stable_table ok"); } diff --git a/examples/parselog.rs b/examples/parselog.rs index 804c3994..f4ae86a9 100644 --- a/examples/parselog.rs +++ b/examples/parselog.rs @@ -9,7 +9,7 @@ use vtparse::{StateMachine, Parser}; struct Log; impl Parser for Log { - fn print(&mut self, _machine: &StateMachine, c: char) { + fn print(&mut self, c: char) { println!("[print] {:?}", c); } fn execute(&mut self, _machine: &StateMachine, byte: u8) { diff --git a/src/definitions.rs b/src/definitions.rs index 5177ca60..ded49cfc 100644 --- a/src/definitions.rs +++ b/src/definitions.rs @@ -15,7 +15,7 @@ pub enum State { Ground = 12, OscString = 13, SosPmApcString = 14, - Unused__ = 15, + Utf8 = 15, } #[derive(Debug, Clone, Copy)] @@ -35,7 +35,7 @@ pub enum Action { Print = 12, Put = 13, Unhook = 14, - Unused__ = 15, + BeginUtf8 = 15, } /// Unpack a u8 into a State and Action @@ -67,12 +67,12 @@ mod tests { } match unpack(0x0f) { - (State::Unused__, Action::None) => (), + (State::Utf8, Action::None) => (), _ => panic!("unpack failed"), } match unpack(0xff) { - (State::Unused__, Action::Unused__) => (), + (State::Utf8, Action::BeginUtf8) => (), _ => panic!("unpack failed"), } } diff --git a/src/lib.rs b/src/lib.rs index 73326bc5..17e265e5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,6 @@ mod table; mod definitions; +mod utf8; pub use definitions::{Action, State, unpack}; @@ -27,6 +28,20 @@ impl State { const MAX_INTERMEDIATES: usize = 2; const MAX_PARAMS: usize = 16; +struct VtUtf8Receiver<'a, P: Parser + 'a>(&'a mut P, &'a mut State); + +impl<'a, P: Parser> utf8::Receiver for VtUtf8Receiver<'a, P> { + fn codepoint(&mut self, c: char) { + self.0.print(c); + *self.1 = State::Ground; + } + + fn invalid_sequence(&mut self) { + self.0.print('�'); + *self.1 = State::Ground; + } +} + /// ANSI VTE Parser /// /// As described in http://vt100.net/emu/dec_ansi_parser @@ -38,7 +53,8 @@ pub struct StateMachine { intermediate_idx: usize, params: [i64; MAX_PARAMS], num_params: usize, - ignoring: bool + ignoring: bool, + utf8_parser: utf8::Parser, } impl StateMachine { @@ -50,6 +66,7 @@ impl StateMachine { params: [0i64; MAX_PARAMS], num_params: 0, ignoring: false, + utf8_parser: utf8::Parser::new(), } } @@ -62,6 +79,12 @@ impl StateMachine { } pub fn advance(&mut self, parser: &mut P, byte: u8) { + // Utf8 characters are handled out-of-band. + if let State::Utf8 = self.state { + self.process_utf8(parser, byte); + return; + } + // Handle state changes in the anywhere state before evaluating changes // for current state. let mut change = STATE_CHANGE[State::Anywhere as usize][byte as usize]; @@ -76,13 +99,22 @@ impl StateMachine { self.perform_state_change(parser, state, action, byte); } + #[inline] + fn process_utf8

(&mut self, parser: &mut P, byte: u8) + where P: Parser + { + let mut receiver = VtUtf8Receiver(parser, &mut self.state); + let utf8_parser = &mut self.utf8_parser; + utf8_parser.advance(&mut receiver, byte); + } + fn perform_state_change

(&mut self, parser: &mut P, state: State, action: Action, byte: u8) where P: Parser { macro_rules! maybe_action { ($action:expr, $arg:expr) => { match $action { - Action::None | Action::Unused__ => (), + Action::None => (), action => { self.perform_action(parser, action, $arg); }, @@ -91,7 +123,7 @@ impl StateMachine { } match state { - State::Anywhere | State::Unused__ => { + State::Anywhere => { // Just run the action self.perform_action(parser, action, byte); }, @@ -114,7 +146,7 @@ impl StateMachine { fn perform_action(&mut self, parser: &mut P, action: Action, byte: u8) { match action { - Action::Print => parser.print(self, byte as char), + Action::Print => parser.print(byte as char), Action::Execute => parser.execute(self, byte), Action::Hook => parser.hook(self, byte), Action::Put => parser.put(self, byte), @@ -124,7 +156,7 @@ impl StateMachine { Action::Unhook => parser.unhook(self, byte), Action::CsiDispatch => parser.csi_dispatch(self, byte as char), Action::EscDispatch => parser.esc_dispatch(self, byte), - Action::Ignore | Action::None | Action::Unused__=> (), + Action::Ignore | Action::None => (), Action::Collect => { if self.intermediate_idx == MAX_INTERMEDIATES { self.ignoring = true; @@ -155,13 +187,16 @@ impl StateMachine { self.intermediate_idx = 0; self.num_params = 0; self.ignoring = false; - } + }, + Action::BeginUtf8 => { + self.process_utf8(parser, byte); + }, } } } pub trait Parser { - fn print(&mut self, &StateMachine, c: char); + fn print(&mut self, c: char); fn execute(&mut self, &StateMachine, byte: u8); fn hook(&mut self, &StateMachine, byte: u8); fn put(&mut self, &StateMachine, byte: u8); diff --git a/src/table.rs b/src/table.rs index 923c7eb4..d2034b87 100644 --- a/src/table.rs +++ b/src/table.rs @@ -6,6 +6,9 @@ use definitions::Action; pub static STATE_CHANGE: [[u8; 256]; 16] = [ + // Beginning of UTF-8 2 byte sequence + // Beginning of UTF-8 3 byte sequence + // Beginning of UTF-8 4 byte sequence @@ -280,11 +283,13 @@ pub static STATE_CHANGE: [[u8; 256]; 16] = 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 0u8, 80u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8], + 0u8, 0u8, 0u8, 0u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, + 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, + 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, + 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, + 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, + 255u8, 255u8, 255u8, 255u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8], [112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 0u8, 112u8, 0u8, 0u8, 112u8, 112u8, 112u8, @@ -366,7 +371,7 @@ pub static ENTRY_ACTIONS: &'static [Action] = Action::OscStart, // State::OscString Action::None, // State::SosPmApcString Action::None]; - // State::Unused__ + // State::Utf8 pub static EXIT_ACTIONS: &'static [Action] = &[Action::None, // State::Anywhere @@ -384,4 +389,4 @@ pub static EXIT_ACTIONS: &'static [Action] = Action::None, // State::Ground Action::OscEnd, // State::OscString Action::None, // State::SosPmApcString - Action::None]; // State::Unused__ + Action::None]; // State::Utf8 diff --git a/src/table.rs.in b/src/table.rs.in index 7414c2af..f5a838d0 100644 --- a/src/table.rs.in +++ b/src/table.rs.in @@ -3,7 +3,7 @@ use definitions::Action; -pub static STATE_CHANGE: [[u8; 256]; 16] = state_table! { +pub static STATE_CHANGE: [[u8; 256]; 16] = vt_state_table! { State::Anywhere => { 0x18 => (Action::Execute, State::Ground), 0x1a => (Action::Execute, State::Ground), @@ -28,7 +28,13 @@ pub static STATE_CHANGE: [[u8; 256]; 16] = state_table! { 0x20...0x7f => Action::Print, 0x80...0x8f => Action::Execute, 0x91...0x9a => Action::Execute, - 0x9c => Action::Execute + 0x9c => Action::Execute, + // Beginning of UTF-8 2 byte sequence + 0xc2...0xdf => (State::Utf8, Action::BeginUtf8), + // Beginning of UTF-8 3 byte sequence + 0xe0...0xef => (State::Utf8, Action::BeginUtf8), + // Beginning of UTF-8 4 byte sequence + 0xf0...0xf4 => (State::Utf8, Action::BeginUtf8), }, State::Escape => { @@ -191,7 +197,7 @@ pub static ENTRY_ACTIONS: &'static [Action] = &[ Action::None, // State::Ground Action::OscStart, // State::OscString Action::None, // State::SosPmApcString - Action::None, // State::Unused__ + Action::None, // State::Utf8 ]; pub static EXIT_ACTIONS: &'static [Action] = &[ @@ -210,5 +216,5 @@ pub static EXIT_ACTIONS: &'static [Action] = &[ Action::None, // State::Ground Action::OscEnd, // State::OscString Action::None, // State::SosPmApcString - Action::None, // State::Unused__ + Action::None, // State::Utf8 ]; diff --git a/src/utf8/mod.rs b/src/utf8/mod.rs new file mode 100644 index 00000000..3d099b16 --- /dev/null +++ b/src/utf8/mod.rs @@ -0,0 +1,91 @@ +//! A table-driven UTF-8 Parser +//! +//! This module implements a table-driven UTF-8 parser which should +//! theoretically contain the minimal number of branches (1). The only branch is +//! on the `Action` returned from unpacking a transition. +use std::char; + +mod types; +use self::types::{State, Action, unpack}; + +mod table; +use self::table::TRANSITIONS; + +/// Handles codepoint and invalid sequence events from the parser. +pub trait Receiver { + /// Code point parsed + /// + /// Called with the codepoint + fn codepoint(&mut self, char); + + /// Invalid sequence encountered + fn invalid_sequence(&mut self); +} + +/// A parser for Utf8 Characters +/// +/// Repeatedly call `advance` with bytes to emit Utf8 characters +pub struct Parser { + point: u32, + state: State, +} + +/// Continuation bytes are masked with this value. +const CONTINUATION_MASK: u8 = 0b0011_1111; + +impl Parser { + /// Create a new Parser + pub fn new() -> Parser { + Parser { + point: 0, + state: State::Ground, + } + } + + pub fn advance(&mut self, receiver: &mut R, byte: u8) + where R: Receiver + { + let cur = self.state as usize; + let change = TRANSITIONS[cur][byte as usize]; + let (state, action) = unsafe { unpack(change) }; + + self.perform_action(receiver, byte, action); + self.state = state; + } + + fn perform_action(&mut self, receiver: &mut R, byte: u8, action: Action) + where R: Receiver + { + match action { + Action::InvalidSequence => { + self.point = 0; + receiver.invalid_sequence(); + }, + Action::EmitByte => { + receiver.codepoint(byte as char); + }, + Action::SetByte1 => { + let point = self.point | ((byte & CONTINUATION_MASK) as u32); + let c = unsafe { char::from_u32_unchecked(point) }; + self.point = 0; + + receiver.codepoint(c); + }, + Action::SetByte2 => { + self.point |= ((byte & CONTINUATION_MASK) as u32) << 6; + }, + Action::SetByte2Top => { + self.point |= ((byte & 0b0001_1111) as u32) << 6; + }, + Action::SetByte3 => { + self.point |= ((byte & CONTINUATION_MASK) as u32) << 12; + }, + Action::SetByte3Top => { + self.point |= ((byte & 0b0000_1111) as u32) << 12; + }, + Action::SetByte4 => { + self.point |= ((byte & 0b0000_0111) as u32) << 18; + }, + } + } +} diff --git a/src/utf8/table.rs b/src/utf8/table.rs new file mode 100644 index 00000000..5a1292b2 --- /dev/null +++ b/src/utf8/table.rs @@ -0,0 +1,184 @@ +//! UTF-8 Parse Transition Table + +/// Transition table for parsing UTF-8. This is built from the grammar described +/// at https://tools.ietf.org/html/rfc3629#section-4 which I have copied and +/// formatted below. +/// +/// # UTF-8 Grammar +/// +/// ```ignore +/// UTF8-octets = *( UTF8-char ) +/// UTF8-char = UTF8-1 / UTF8-2 / UTF8-3 / UTF8-4 +/// UTF8-1 = %x00-7F +/// UTF8-2 = %xC2-DF UTF8-tail +/// UTF8-3 = %xE0 %xA0-BF UTF8-tail / +/// %xE1-EC 2( UTF8-tail ) / +/// %xED %x80-9F UTF8-tail / +/// %xEE-EF 2( UTF8-tail ) +/// UTF8-4 = %xF0 %x90-BF 2( UTF8-tail ) / +/// %xF1-F3 3( UTF8-tail ) / +/// %xF4 %x80-8F 2( UTF8-tail ) +/// UTF8-tail = %x80-BF +/// ``` +/// +/// Not specifying an action in this table is equivalent to specifying +/// Action::InvalidSequence. Not specifying a state is equivalent to specifying +/// state::ground. +pub static TRANSITIONS: [[u8; 256]; 8] = + [[16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, + 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, + 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, + 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, + 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, + 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, + 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, + 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, + 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, + 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, + 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 67u8, 67u8, 67u8, 67u8, 67u8, 67u8, 67u8, 67u8, + 67u8, 67u8, 67u8, 67u8, 67u8, 67u8, 67u8, 67u8, 67u8, 67u8, 67u8, 67u8, + 67u8, 67u8, 67u8, 67u8, 67u8, 67u8, 67u8, 67u8, 67u8, 67u8, 100u8, 98u8, + 98u8, 98u8, 98u8, 98u8, 98u8, 98u8, 98u8, 98u8, 98u8, 98u8, 98u8, 101u8, + 98u8, 98u8, 118u8, 113u8, 113u8, 113u8, 119u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8], + [0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, + 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, + 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, + 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, + 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, + 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8], + [0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, + 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, + 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, + 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, + 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, + 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8], + [0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, + 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, + 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, + 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, + 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, + 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8], + [0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, + 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, + 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, + 51u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8], + [0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, + 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, + 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8], + [0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, + 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, + 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, + 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, + 82u8, 82u8, 82u8, 82u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8], + [0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, + 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8]]; diff --git a/src/utf8/table.rs.in b/src/utf8/table.rs.in new file mode 100644 index 00000000..2acafe70 --- /dev/null +++ b/src/utf8/table.rs.in @@ -0,0 +1,60 @@ +//! UTF-8 Parse Transition Table + +/// Transition table for parsing UTF-8. This is built from the grammar described +/// at https://tools.ietf.org/html/rfc3629#section-4 which I have copied and +/// formatted below. +/// +/// # UTF-8 Grammar +/// +/// ```ignore +/// UTF8-octets = *( UTF8-char ) +/// UTF8-char = UTF8-1 / UTF8-2 / UTF8-3 / UTF8-4 +/// UTF8-1 = %x00-7F +/// UTF8-2 = %xC2-DF UTF8-tail +/// UTF8-3 = %xE0 %xA0-BF UTF8-tail / +/// %xE1-EC 2( UTF8-tail ) / +/// %xED %x80-9F UTF8-tail / +/// %xEE-EF 2( UTF8-tail ) +/// UTF8-4 = %xF0 %x90-BF 2( UTF8-tail ) / +/// %xF1-F3 3( UTF8-tail ) / +/// %xF4 %x80-8F 2( UTF8-tail ) +/// UTF8-tail = %x80-BF +/// ``` +/// +/// Not specifying an action in this table is equivalent to specifying +/// Action::InvalidSequence. Not specifying a state is equivalent to specifying +/// state::ground. +pub static TRANSITIONS: [[u8; 256]; 8] = utf8_state_table! { + State::Ground => { + 0x00...0x7f => (State::Ground, Action::EmitByte), + 0xc2...0xdf => (State::Tail1, Action::SetByte2Top), + 0xe0 => (State::U3_2_e0, Action::SetByte3Top), + 0xe1...0xec => (State::Tail2, Action::SetByte3Top), + 0xed => (State::U3_2_ed, Action::SetByte3Top), + 0xee...0xef => (State::Tail2, Action::SetByte3Top), + 0xf0 => (State::Utf8_4_3_f0, Action::SetByte4), + 0xf1...0xf3 => (State::Tail3, Action::SetByte4), + 0xf4 => (State::Utf8_4_3_f4, Action::SetByte4), + }, + State::U3_2_e0 => { + 0xa0...0xbf => (State::Tail1, Action::SetByte2), + }, + State::U3_2_ed => { + 0x80...0x9f => (State::Tail1, Action::SetByte2), + }, + State::Utf8_4_3_f0 => { + 0x90...0xbf => (State::Tail2, Action::SetByte3), + }, + State::Utf8_4_3_f4 => { + 0x80...0x8f => (State::Tail2, Action::SetByte3), + }, + State::Tail3 => { + 0x80...0xbf => (State::Tail2, Action::SetByte3), + }, + State::Tail2 => { + 0x80...0xbf => (State::Tail1, Action::SetByte2), + }, + State::Tail1 => { + 0x80...0xbf => (State::Ground, Action::SetByte1), + }, +}; diff --git a/src/utf8/types.rs b/src/utf8/types.rs new file mode 100644 index 00000000..4c604f41 --- /dev/null +++ b/src/utf8/types.rs @@ -0,0 +1,77 @@ +//! Types supporting the UTF-8 parser +#![allow(non_camel_case_types)] +use std::mem; + +/// States the parser can be in. +/// +/// There is a state for each initial input of the 3 and 4 byte sequences since +/// the following bytes are subject to different conditions than a tail byte. +#[allow(dead_code)] +#[derive(Debug, Copy, Clone)] +pub enum State { + /// Ground state; expect anything + Ground = 0, + /// 3 tail bytes + Tail3 = 1, + /// 2 tail bytes + Tail2 = 2, + /// 1 tail byte + Tail1 = 3, + /// UTF8-3 starting with E0 + U3_2_e0 = 4, + /// UTF8-3 starting with ED + U3_2_ed = 5, + /// UTF8-4 starting with F0 + Utf8_4_3_f0 = 6, + /// UTF8-4 starting with F4 + Utf8_4_3_f4 = 7, +} + +/// Action to take when receiving a byte +#[allow(dead_code)] +#[derive(Debug, Copy, Clone)] +pub enum Action { + /// Unexpected byte; sequence is invalid + InvalidSequence = 0, + /// Received valid 7-bit ASCII byte which can be directly emitted. + EmitByte = 1, + /// Set the bottom continuation byte + SetByte1 = 2, + /// Set the 2nd-from-last continuation byte + SetByte2 = 3, + /// Set the 2nd-from-last byte which is part of a two byte sequence + SetByte2Top = 4, + /// Set the 3rd-from-last continuation byte + SetByte3 = 5, + /// Set the 3rd-from-last byte which is part of a three byte sequence + SetByte3Top = 6, + /// Set the top byte of a four byte sequence. + SetByte4 = 7, +} + +/// Convert a state and action to a u8 +/// +/// State will be the bottom 4 bits and action the top 4 +#[inline] +#[allow(dead_code)] +pub fn pack(state: State, action: Action) -> u8 { + ((action as u8) << 4) | (state as u8) +} + +/// Convert a u8 to a state and action +/// +/// # Unsafety +/// +/// If this function is called with a byte that wasn't encoded with the `pack` +/// function in this module, there is no guarantee that a valid state and action +/// can be produced. +#[inline] +pub unsafe fn unpack(val: u8) -> (State, Action) { + ( + // State is stored in bottom 4 bits + mem::transmute(val & 0x0f), + + // Action is stored in top 4 bits + mem::transmute(val >> 4), + ) +} From 98276717f6335a92a97ddec72edb9348768d1e4e Mon Sep 17 00:00:00 2001 From: Joe Wilm Date: Sat, 17 Sep 2016 15:55:15 -0700 Subject: [PATCH 14/99] Remove UTF-8 TODO comment --- src/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 17e265e5..e31ac14c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -45,8 +45,6 @@ impl<'a, P: Parser> utf8::Receiver for VtUtf8Receiver<'a, P> { /// ANSI VTE Parser /// /// As described in http://vt100.net/emu/dec_ansi_parser -/// -/// TODO: utf8 support pub struct StateMachine { state: State, intermediates: [u8; MAX_INTERMEDIATES], From 85388ab070fbc41c8cce3ffbfbcc0d1d917109e0 Mon Sep 17 00:00:00 2001 From: Joe Wilm Date: Sat, 17 Sep 2016 16:52:57 -0700 Subject: [PATCH 15/99] Rename and document vte crate --- Cargo.toml | 2 +- examples/parselog.rs | 59 ++++++++------ src/definitions.rs | 2 + src/lib.rs | 189 +++++++++++++++++++++++++++++++++---------- 4 files changed, 182 insertions(+), 70 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3ccedb1e..1e38f87e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "vtparse" +name = "vte" version = "0.1.0" authors = ["Joe Wilm "] diff --git a/examples/parselog.rs b/examples/parselog.rs index f4ae86a9..5c1836b2 100644 --- a/examples/parselog.rs +++ b/examples/parselog.rs @@ -3,51 +3,60 @@ extern crate vtparse; use std::io::{self, Read}; -use vtparse::{StateMachine, Parser}; - -/// A type implementing Parser that just logs actions +/// A type implementing Perform that just logs actions struct Log; -impl Parser for Log { +impl vte::Perform for Log { fn print(&mut self, c: char) { println!("[print] {:?}", c); } - fn execute(&mut self, _machine: &StateMachine, byte: u8) { - println!("[execute] byte={:02x}", byte); + + fn execute(&mut self, byte: u8) { + println!("[execute] {:02x}", byte); } - fn hook(&mut self, _machine: &StateMachine, byte: u8) { - println!("[hook] byte={:02x}", byte); + + fn hook(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, byte: u8) { + println!("[hook] params={:?}, intermediates={:?}, ignore={:?}, byte={:02x}", + params, intermediates, ignore, byte); } - fn put(&mut self, _machine: &StateMachine, byte: u8) { - println!("[put] byte={:02x}", byte); + + fn put(&mut self, byte: u8) { + println!("[put] {:02x}", byte); } - fn osc_start(&mut self, _machine: &StateMachine, byte: u8) { - println!("[osc_start] byte={:02x}", byte); + + fn unhook(&mut self, byte: u8) { + println!("[unhook] {:02x}", byte); } - fn osc_put(&mut self, _machine: &StateMachine, byte: u8) { - println!("[osc_put] byte={:02x}", byte); + + fn osc_start(&mut self) { + println!("[osc_start]"); } - fn osc_end(&mut self, _machine: &StateMachine, byte: u8) { - println!("[osc_end] byte={:02x}", byte); + + fn osc_put(&mut self, byte: u8) { + println!("[osc_put] {:02x}", byte); } - fn unhook(&mut self, _machine: &StateMachine, byte: u8) { - println!("[unhook] byte={:02x}", byte); + + fn osc_end(&mut self, byte: u8) { + println!("[osc_end] {:02x}", byte); } - fn csi_dispatch(&mut self, machine: &StateMachine, c: char) { - println!("[csi_dispatch] params={:?}, intermediates={:?}, action={:?}", - machine.params(), machine.intermediates(), c); + + fn csi_dispatch(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, c: char) { + println!("[csi_dispatch] params={:?}, intermediates={:?}, ignore={:?}, char={:?}", + params, intermediates, ignore, c); } - fn esc_dispatch(&mut self, machine: &StateMachine, byte: u8) { - println!("[csi_dispatch] params={:?}, intermediates={:?}, action={:?}", - machine.params(), machine.intermediates(), byte as char); + + fn esc_dispatch(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, byte: u8) { + println!("[esc_dispatch] params={:?}, intermediates={:?}, ignore={:?}, byte={:02x}", + params, intermediates, ignore, byte); } + } fn main() { let input = io::stdin(); let mut handle = input.lock(); - let mut statemachine = StateMachine::new(); + let mut statemachine = vte::Parser::new(); let mut parser = Log; let mut buf: [u8; 2048] = unsafe { std::mem::uninitialized() }; diff --git a/src/definitions.rs b/src/definitions.rs index ded49cfc..d8faf538 100644 --- a/src/definitions.rs +++ b/src/definitions.rs @@ -1,3 +1,4 @@ +#[allow(dead_code)] #[derive(Debug, Copy, Clone)] pub enum State { Anywhere = 0, @@ -18,6 +19,7 @@ pub enum State { Utf8 = 15, } +#[allow(dead_code)] #[derive(Debug, Clone, Copy)] pub enum Action { None = 0, diff --git a/src/lib.rs b/src/lib.rs index e31ac14c..71953fde 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,8 +1,33 @@ +//! Parser for implementing virtual terminal emulators +//! +//! [`Parser`] is implemented according to [Paul Williams' ANSI parser +//! state machine]. The state machine doesn't assign meaning to the parsed data +//! and is thus not itself sufficient for writing a terminal emulator. Instead, +//! it is expected that an implementation of [`Perform`] is provided which does +//! something useful with the parsed data. The [`Parser`] handles the book +//! keeping, and the [`Perform`] gets to simply handle actions. +//! +//! # Examples +//! +//! For an example of using the [`Parser`] please see the examples folder. The example included +//! there simply logs all the actions [`Perform`] does. One quick thing to see it in action is to +//! pipe `vim` into it +//! +//! ```ignore +//! cargo build --release --example parselog +//! vim | target/release/examples/parselog +//! ``` +//! +//! Just type `:q` to exit. +//! +//! [`Parser`]: struct.Parser.html +//! [`Perform`]: trait.Perform.html +//! [Paul Williams' ANSI parser state machine]: http://vt100.net/emu/dec_ansi_parser mod table; mod definitions; mod utf8; -pub use definitions::{Action, State, unpack}; +use definitions::{Action, State, unpack}; use table::{EXIT_ACTIONS, ENTRY_ACTIONS, STATE_CHANGE}; @@ -28,9 +53,9 @@ impl State { const MAX_INTERMEDIATES: usize = 2; const MAX_PARAMS: usize = 16; -struct VtUtf8Receiver<'a, P: Parser + 'a>(&'a mut P, &'a mut State); +struct VtUtf8Receiver<'a, P: Perform + 'a>(&'a mut P, &'a mut State); -impl<'a, P: Parser> utf8::Receiver for VtUtf8Receiver<'a, P> { +impl<'a, P: Perform> utf8::Receiver for VtUtf8Receiver<'a, P> { fn codepoint(&mut self, c: char) { self.0.print(c); *self.1 = State::Ground; @@ -42,10 +67,10 @@ impl<'a, P: Parser> utf8::Receiver for VtUtf8Receiver<'a, P> { } } -/// ANSI VTE Parser +/// Parser for raw _VTE_ protocol which delegates actions to a [`Perform`] /// -/// As described in http://vt100.net/emu/dec_ansi_parser -pub struct StateMachine { +/// [`Perform`]: trait.Perform.html +pub struct Parser { state: State, intermediates: [u8; MAX_INTERMEDIATES], intermediate_idx: usize, @@ -55,9 +80,10 @@ pub struct StateMachine { utf8_parser: utf8::Parser, } -impl StateMachine { - pub fn new() -> StateMachine { - StateMachine { +impl Parser { + /// Create a new Parser + pub fn new() -> Parser { + Parser { state: State::Ground, intermediates: [0u8; MAX_INTERMEDIATES], intermediate_idx: 0, @@ -68,18 +94,23 @@ impl StateMachine { } } - pub fn params(&self) -> &[i64] { + fn params(&self) -> &[i64] { &self.params[..self.num_params] } - pub fn intermediates(&self) -> &[u8] { + fn intermediates(&self) -> &[u8] { &self.intermediates[..self.intermediate_idx] } - pub fn advance(&mut self, parser: &mut P, byte: u8) { + /// Advance the parser state + /// + /// Requires a [`Perform`] in case `byte` triggers an action + /// + /// [`Perform`]: trait.Perform.html + pub fn advance(&mut self, performer: &mut P, byte: u8) { // Utf8 characters are handled out-of-band. if let State::Utf8 = self.state { - self.process_utf8(parser, byte); + self.process_utf8(performer, byte); return; } @@ -94,27 +125,27 @@ impl StateMachine { // Unpack into a state and action let (state, action) = unpack(change); - self.perform_state_change(parser, state, action, byte); + self.perform_state_change(performer, state, action, byte); } #[inline] - fn process_utf8

(&mut self, parser: &mut P, byte: u8) - where P: Parser + fn process_utf8

(&mut self, performer: &mut P, byte: u8) + where P: Perform { - let mut receiver = VtUtf8Receiver(parser, &mut self.state); + let mut receiver = VtUtf8Receiver(performer, &mut self.state); let utf8_parser = &mut self.utf8_parser; utf8_parser.advance(&mut receiver, byte); } - fn perform_state_change

(&mut self, parser: &mut P, state: State, action: Action, byte: u8) - where P: Parser + fn perform_state_change

(&mut self, performer: &mut P, state: State, action: Action, byte: u8) + where P: Perform { macro_rules! maybe_action { ($action:expr, $arg:expr) => { match $action { Action::None => (), action => { - self.perform_action(parser, action, $arg); + self.perform_action(performer, action, $arg); }, } } @@ -123,7 +154,7 @@ impl StateMachine { match state { State::Anywhere => { // Just run the action - self.perform_action(parser, action, byte); + self.perform_action(performer, action, byte); }, state => { // Exit action for previous state @@ -142,18 +173,39 @@ impl StateMachine { } } - fn perform_action(&mut self, parser: &mut P, action: Action, byte: u8) { + fn perform_action(&mut self, performer: &mut P, action: Action, byte: u8) { match action { - Action::Print => parser.print(byte as char), - Action::Execute => parser.execute(self, byte), - Action::Hook => parser.hook(self, byte), - Action::Put => parser.put(self, byte), - Action::OscStart => parser.osc_start(self, byte), - Action::OscPut => parser.osc_put(self, byte), - Action::OscEnd => parser.osc_end(self, byte), - Action::Unhook => parser.unhook(self, byte), - Action::CsiDispatch => parser.csi_dispatch(self, byte as char), - Action::EscDispatch => parser.esc_dispatch(self, byte), + Action::Print => performer.print(byte as char), + Action::Execute => performer.execute(byte), + Action::Hook => { + performer.hook( + self.params(), + self.intermediates(), + self.ignoring, + byte + ); + }, + Action::Put => performer.put(byte), + Action::OscStart => performer.osc_start(), + Action::OscPut => performer.osc_put(byte), + Action::OscEnd => performer.osc_end(byte), + Action::Unhook => performer.unhook(byte), + Action::CsiDispatch => { + performer.csi_dispatch( + self.params(), + self.intermediates(), + self.ignoring, + byte as char + ); + } + Action::EscDispatch => { + performer.esc_dispatch( + self.params(), + self.intermediates(), + self.ignoring, + byte + ); + }, Action::Ignore | Action::None => (), Action::Collect => { if self.intermediate_idx == MAX_INTERMEDIATES { @@ -187,21 +239,70 @@ impl StateMachine { self.ignoring = false; }, Action::BeginUtf8 => { - self.process_utf8(parser, byte); + self.process_utf8(performer, byte); }, } } } -pub trait Parser { - fn print(&mut self, c: char); - fn execute(&mut self, &StateMachine, byte: u8); - fn hook(&mut self, &StateMachine, byte: u8); - fn put(&mut self, &StateMachine, byte: u8); - fn osc_start(&mut self, &StateMachine, byte: u8); - fn osc_put(&mut self, &StateMachine, byte: u8); - fn osc_end(&mut self, &StateMachine, byte: u8); - fn unhook(&mut self, &StateMachine, byte: u8); - fn csi_dispatch(&mut self, &StateMachine, c: char); - fn esc_dispatch(&mut self, &StateMachine, byte: u8); +/// Performs actions requested by the Parser +/// +/// Actions in this case mean, for example, handling a CSI escape sequence describing cursor +/// movement, or simply printing characters to the screen. +/// +/// The methods on this type correspond to actions described in +/// http://vt100.net/emu/dec_ansi_parser. I've done my best to describe them in +/// a useful way in my own words for completeness, but the site should be +/// referenced if something isn't clear. If the site disappears at some point in +/// the future, consider checking archive.org. +pub trait Perform { + /// Draw a character to the screen and update states + fn print(&mut self, char); + + /// Execute a C0 or C1 control function + fn execute(&mut self, byte: u8); + + /// Invoked when a final character arrives in first part of device control string + /// + /// The control function should be determined from the private marker, final character, and + /// execute with a parameter list. A handler should be selected for remaining characters in the + /// string; the handler function should subsequently be called by `put` for every character in + /// the control string. + /// + /// The `ignore` flag indicates that more than two intermediates arrived and + /// subsequent characters were ignored. + fn hook(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, byte: u8); + + /// Pass bytes as part of a device control string to the handle chosen in `hook`. C0 controls + /// will also be passed to the handler. + fn put(&mut self, byte: u8); + + /// Called when a device control string is terminated + /// + /// The previously selected handler should be notified that the DCS has + /// terminated. + fn unhook(&mut self, byte: u8); + + /// Notifies the start of an Operating System Command + fn osc_start(&mut self); + + /// Receives characters for the OSC control string + /// + /// Apparently characters don't need buffering here. + fn osc_put(&mut self, byte: u8); + + /// Called when the OSC has terminated + fn osc_end(&mut self, byte: u8); + + /// A final character has arrived for a CSI sequence + /// + /// The `ignore` flag indicates that more than two intermediates arrived and + /// subsequent characters were ignored. + fn csi_dispatch(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, char); + + /// The final character of an escape sequence has arrived. + /// + /// The `ignore` flag indicates that more than two intermediates arrived and + /// subsequent characters were ignored. + fn esc_dispatch(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, byte: u8); } From 917080a5c27b3310daab135f9bfdbc531cb54186 Mon Sep 17 00:00:00 2001 From: Joe Wilm Date: Sat, 17 Sep 2016 17:02:29 -0700 Subject: [PATCH 16/99] Move utf8 parsing into separate crate --- Cargo.toml | 3 ++- codegen/src/ext/utf8.rs | 2 +- codegen/src/main.rs | 4 ++-- src/lib.rs | 3 ++- utf8parse/Cargo.toml | 6 ++++++ src/utf8/mod.rs => utf8parse/src/lib.rs | 10 ++++++---- {src/utf8 => utf8parse/src}/table.rs | 0 {src/utf8 => utf8parse/src}/table.rs.in | 0 {src/utf8 => utf8parse/src}/types.rs | 0 9 files changed, 19 insertions(+), 9 deletions(-) create mode 100644 utf8parse/Cargo.toml rename src/utf8/mod.rs => utf8parse/src/lib.rs (90%) rename {src/utf8 => utf8parse/src}/table.rs (100%) rename {src/utf8 => utf8parse/src}/table.rs.in (100%) rename {src/utf8 => utf8parse/src}/types.rs (100%) diff --git a/Cargo.toml b/Cargo.toml index 1e38f87e..494ece65 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,4 +3,5 @@ name = "vte" version = "0.1.0" authors = ["Joe Wilm "] -[dependencies] +[dependencies.utf8parse] +path = "./utf8parse" diff --git a/codegen/src/ext/utf8.rs b/codegen/src/ext/utf8.rs index 5b73081e..17ebc223 100644 --- a/codegen/src/ext/utf8.rs +++ b/codegen/src/ext/utf8.rs @@ -13,7 +13,7 @@ use syntex_syntax::parse::PResult; use syntex_syntax::ptr::P; use syntex_syntax::tokenstream::TokenTree; -#[path="../../../src/utf8/types.rs"] +#[path="../../../utf8parse/src/types.rs"] mod types; use self::types::{State, Action, pack}; diff --git a/codegen/src/main.rs b/codegen/src/main.rs index 5f8d1530..0d21577b 100644 --- a/codegen/src/main.rs +++ b/codegen/src/main.rs @@ -17,7 +17,7 @@ fn main() { // Expand UTF8 parser state table let mut registry = syntex::Registry::new(); ext::utf8::register(&mut registry); - let src = &Path::new("../src/utf8/table.rs.in"); - let dst = &Path::new("../src/utf8/table.rs"); + let src = &Path::new("../utf8parse/src/table.rs.in"); + let dst = &Path::new("../utf8parse/src/table.rs"); registry.expand("utf8_state_table", src, dst).expect("expand utf8_stable_table ok"); } diff --git a/src/lib.rs b/src/lib.rs index 71953fde..f449e13b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -23,9 +23,10 @@ //! [`Parser`]: struct.Parser.html //! [`Perform`]: trait.Perform.html //! [Paul Williams' ANSI parser state machine]: http://vt100.net/emu/dec_ansi_parser +extern crate utf8parse as utf8; + mod table; mod definitions; -mod utf8; use definitions::{Action, State, unpack}; diff --git a/utf8parse/Cargo.toml b/utf8parse/Cargo.toml new file mode 100644 index 00000000..882b1080 --- /dev/null +++ b/utf8parse/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "utf8parse" +version = "0.1.0" +authors = ["Joe Wilm "] + +[dependencies] diff --git a/src/utf8/mod.rs b/utf8parse/src/lib.rs similarity index 90% rename from src/utf8/mod.rs rename to utf8parse/src/lib.rs index 3d099b16..9585642e 100644 --- a/src/utf8/mod.rs +++ b/utf8parse/src/lib.rs @@ -13,12 +13,10 @@ use self::table::TRANSITIONS; /// Handles codepoint and invalid sequence events from the parser. pub trait Receiver { - /// Code point parsed - /// - /// Called with the codepoint + /// Called whenever a codepoint is parsed successfully fn codepoint(&mut self, char); - /// Invalid sequence encountered + /// Called when an invalid_sequence is detected fn invalid_sequence(&mut self); } @@ -42,6 +40,10 @@ impl Parser { } } + /// Advance the parser + /// + /// The provider receiver will be called whenever a codepoint is completed or an invalid + /// sequence is detected. pub fn advance(&mut self, receiver: &mut R, byte: u8) where R: Receiver { diff --git a/src/utf8/table.rs b/utf8parse/src/table.rs similarity index 100% rename from src/utf8/table.rs rename to utf8parse/src/table.rs diff --git a/src/utf8/table.rs.in b/utf8parse/src/table.rs.in similarity index 100% rename from src/utf8/table.rs.in rename to utf8parse/src/table.rs.in diff --git a/src/utf8/types.rs b/utf8parse/src/types.rs similarity index 100% rename from src/utf8/types.rs rename to utf8parse/src/types.rs From 02301e8f2a9a4641ab893c48c0b0d3ee231d4e6b Mon Sep 17 00:00:00 2001 From: Joe Wilm Date: Sat, 17 Sep 2016 17:03:47 -0700 Subject: [PATCH 17/99] Fix import in example --- examples/parselog.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/parselog.rs b/examples/parselog.rs index 5c1836b2..e04fd1eb 100644 --- a/examples/parselog.rs +++ b/examples/parselog.rs @@ -1,5 +1,5 @@ //! Parse input from stdin and log actions on stdout -extern crate vtparse; +extern crate vte; use std::io::{self, Read}; From 2c82ecce14c3f6acd0e26b60ac4b7e02d771de50 Mon Sep 17 00:00:00 2001 From: Joe Wilm Date: Sat, 17 Sep 2016 17:06:49 -0700 Subject: [PATCH 18/99] Add README.md --- README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 00000000..aa1a8384 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +vte +=== + +Parser for implementing virtual terminal emulators in Rust. + +The parser is implemented according to [Paul Williams' ANSI parser state +machine]. The state machine doesn't assign meaning to the parsed data and is +thus not itself sufficient for writing a terminal emulator. Instead, it is +expected that an implementation of the `Perform` trait which does something +useful with the parsed data. The [`Parser`] handles the book keeping, and the +[`Perform`] gets to simply handle actions. + +See the [docs] for more info. + +[Paul Williams' ANSI parser state machine]: http://vt100.net/emu/dec_ansi_parser +[docs]: https://docs.rs/crate/vte/ From a7711f9639a22a4fdfd125bb57d831c0c436ec3e Mon Sep 17 00:00:00 2001 From: Joe Wilm Date: Sat, 17 Sep 2016 17:08:16 -0700 Subject: [PATCH 19/99] Add developer note to README --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index aa1a8384..dea21dd0 100644 --- a/README.md +++ b/README.md @@ -12,5 +12,11 @@ useful with the parsed data. The [`Parser`] handles the book keeping, and the See the [docs] for more info. +## Developer Notes + +If contributing to either `vte` or the `utf8parse` crate and modifying a +_table.rs.in_ file, make sure to `cargo run` from the _codegen_ folder so that +the compiled tables are updated. + [Paul Williams' ANSI parser state machine]: http://vt100.net/emu/dec_ansi_parser [docs]: https://docs.rs/crate/vte/ From 458eb1710cf2e21f72aefe0cdda5296ed76bb2b9 Mon Sep 17 00:00:00 2001 From: Joe Wilm Date: Sat, 17 Sep 2016 17:20:02 -0700 Subject: [PATCH 20/99] Update Cargo.tomls for publishing and add LICENSEs --- Cargo.toml | 5 ++ LICENSE-APACHE | 176 +++++++++++++++++++++++++++++++++++++++++++ LICENSE-MIT | 25 ++++++ README.md | 4 +- utf8parse/Cargo.toml | 5 ++ 5 files changed, 213 insertions(+), 2 deletions(-) create mode 100644 LICENSE-APACHE create mode 100644 LICENSE-MIT diff --git a/Cargo.toml b/Cargo.toml index 494ece65..cb2d9f16 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,11 @@ name = "vte" version = "0.1.0" authors = ["Joe Wilm "] +license = "Apache-2.0 OR MIT" +description = "Parser for implementing terminal emulators" +keywords = ["ansi", "vte", "parser", "terminal"] +repository = "https://github.com/jwilm/vte" +documentation = "https://docs.rs/vte/" [dependencies.utf8parse] path = "./utf8parse" diff --git a/LICENSE-APACHE b/LICENSE-APACHE new file mode 100644 index 00000000..1b5ec8b7 --- /dev/null +++ b/LICENSE-APACHE @@ -0,0 +1,176 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS diff --git a/LICENSE-MIT b/LICENSE-MIT new file mode 100644 index 00000000..bb419c21 --- /dev/null +++ b/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2016 Joe Wilm + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md index dea21dd0..f10f0626 100644 --- a/README.md +++ b/README.md @@ -7,8 +7,8 @@ The parser is implemented according to [Paul Williams' ANSI parser state machine]. The state machine doesn't assign meaning to the parsed data and is thus not itself sufficient for writing a terminal emulator. Instead, it is expected that an implementation of the `Perform` trait which does something -useful with the parsed data. The [`Parser`] handles the book keeping, and the -[`Perform`] gets to simply handle actions. +useful with the parsed data. The `Parser` handles the book keeping, and the +`Perform` gets to simply handle actions. See the [docs] for more info. diff --git a/utf8parse/Cargo.toml b/utf8parse/Cargo.toml index 882b1080..bd0946bf 100644 --- a/utf8parse/Cargo.toml +++ b/utf8parse/Cargo.toml @@ -2,5 +2,10 @@ name = "utf8parse" version = "0.1.0" authors = ["Joe Wilm "] +license = "Apache-2.0 OR MIT" +description = "Table-driven UTF-8 parser" +keywords = ["utf8", "parse", "table"] +repository = "https://github.com/jwilm/vte" +documentation = "https://docs.rs/utf8parse/" [dependencies] From 0caff0de30802ad5b68e60df6f296a003ed8a810 Mon Sep 17 00:00:00 2001 From: Joe Wilm Date: Sat, 17 Sep 2016 17:26:44 -0700 Subject: [PATCH 21/99] Specify version for utf8parse dependency --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index cb2d9f16..ef38bcbb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,3 +10,4 @@ documentation = "https://docs.rs/vte/" [dependencies.utf8parse] path = "./utf8parse" +version = "0.1" From b40dff0cecc20a3dafbd5b20c5a55c6c0e7ea15f Mon Sep 17 00:00:00 2001 From: Joe Wilm Date: Sat, 17 Sep 2016 17:30:19 -0700 Subject: [PATCH 22/99] Add crates.io badge --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index f10f0626..191994f9 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ vte === +[![Crates.io Version](https://img.shields.io/crates/v/vte.svg)](https://crates.io/crates/vte/) + Parser for implementing virtual terminal emulators in Rust. The parser is implemented according to [Paul Williams' ANSI parser state From edcb3d6defc69413f6b81a8c56be4ffbd638563d Mon Sep 17 00:00:00 2001 From: Joe Wilm Date: Sun, 18 Sep 2016 11:19:26 -0700 Subject: [PATCH 23/99] Lightly clean up code Apparently byte character literals are a thing :). --- src/lib.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index f449e13b..1a477008 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -217,8 +217,7 @@ impl Parser { } }, Action::Param => { - // if byte == ';' - if byte == 0x3b { + if byte == b';' { // end of param; advance to next self.num_params += 1; let idx = self.num_params - 1; // borrowck @@ -231,7 +230,7 @@ impl Parser { let idx = self.num_params - 1; self.params[idx] *= 10; - self.params[idx] += (byte - ('0' as u8)) as i64; + self.params[idx] += (byte - b'0') as i64; } }, Action::Clear => { From a15a9c3cf75fe08abdd4c7572e49a3daf6680064 Mon Sep 17 00:00:00 2001 From: Joe Wilm Date: Sun, 18 Sep 2016 11:19:57 -0700 Subject: [PATCH 24/99] Add inline attributes to vte stuff --- src/lib.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 1a477008..d66f6bbf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -95,10 +95,12 @@ impl Parser { } } + #[inline] fn params(&self) -> &[i64] { &self.params[..self.num_params] } + #[inline] fn intermediates(&self) -> &[u8] { &self.intermediates[..self.intermediate_idx] } @@ -108,6 +110,7 @@ impl Parser { /// Requires a [`Perform`] in case `byte` triggers an action /// /// [`Perform`]: trait.Perform.html + #[inline] pub fn advance(&mut self, performer: &mut P, byte: u8) { // Utf8 characters are handled out-of-band. if let State::Utf8 = self.state { @@ -138,6 +141,7 @@ impl Parser { utf8_parser.advance(&mut receiver, byte); } + #[inline] fn perform_state_change

(&mut self, performer: &mut P, state: State, action: Action, byte: u8) where P: Perform { @@ -174,6 +178,7 @@ impl Parser { } } + #[inline] fn perform_action(&mut self, performer: &mut P, action: Action, byte: u8) { match action { Action::Print => performer.print(byte as char), From 955bc84adfc5719455038653edd40725416df9c2 Mon Sep 17 00:00:00 2001 From: Joe Wilm Date: Sun, 18 Sep 2016 11:21:43 -0700 Subject: [PATCH 25/99] Publish vte 0.1.1 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index ef38bcbb..01143c96 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "vte" -version = "0.1.0" +version = "0.1.1" authors = ["Joe Wilm "] license = "Apache-2.0 OR MIT" description = "Parser for implementing terminal emulators" From 5509849473c7549c95b6a3ef87af8075c50d5da7 Mon Sep 17 00:00:00 2001 From: Joe Wilm Date: Mon, 19 Sep 2016 07:59:55 -0700 Subject: [PATCH 26/99] Fix bug with OSC string termination Apparently 0x07 is frequently used. Not handling this causes SSH prompts to never appear! --- Cargo.toml | 2 +- src/lib.rs | 5 +++++ src/table.rs | 2 +- src/table.rs.in | 4 +++- 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 01143c96..34f65f20 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "vte" -version = "0.1.1" +version = "0.1.2" authors = ["Joe Wilm "] license = "Apache-2.0 OR MIT" description = "Parser for implementing terminal emulators" diff --git a/src/lib.rs b/src/lib.rs index d66f6bbf..9b2c0476 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,6 +20,11 @@ //! //! Just type `:q` to exit. //! +//! # Differences from original state machine description +//! +//! * UTF-8 Support for Input +//! * OSC Strings can be terminated by 0x07 +//! //! [`Parser`]: struct.Parser.html //! [`Perform`]: trait.Perform.html //! [Paul Williams' ANSI parser state machine]: http://vt100.net/emu/dec_ansi_parser diff --git a/src/table.rs b/src/table.rs index d2034b87..5bb52c04 100644 --- a/src/table.rs +++ b/src/table.rs @@ -290,7 +290,7 @@ pub static STATE_CHANGE: [[u8; 256]; 16] = 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8], - [112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, + [112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 12u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 0u8, 112u8, 0u8, 0u8, 112u8, 112u8, 112u8, 112u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, diff --git a/src/table.rs.in b/src/table.rs.in index f5a838d0..3017e332 100644 --- a/src/table.rs.in +++ b/src/table.rs.in @@ -173,7 +173,9 @@ pub static STATE_CHANGE: [[u8; 256]; 16] = vt_state_table! { }, State::OscString => { - 0x00...0x17 => Action::Ignore, + 0x00...0x06 => Action::Ignore, + 0x07 => State::Ground, + 0x08...0x17 => Action::Ignore, 0x19 => Action::Ignore, 0x1c...0x1f => Action::Ignore, 0x20...0x7f => Action::OscPut, From b016827f471041320996f3273b4e3058501d7edf Mon Sep 17 00:00:00 2001 From: Liz Baillie Date: Wed, 5 Oct 2016 09:10:12 -0700 Subject: [PATCH 27/99] adds UTF8parse test and associated UTF-8 test file --- utf8parse/src/UTF-8-demo.txt | 212 +++++++++++++++++++++++++++++++++++ utf8parse/src/lib.rs | 39 +++++++ 2 files changed, 251 insertions(+) create mode 100644 utf8parse/src/UTF-8-demo.txt diff --git a/utf8parse/src/UTF-8-demo.txt b/utf8parse/src/UTF-8-demo.txt new file mode 100644 index 00000000..4363f27b --- /dev/null +++ b/utf8parse/src/UTF-8-demo.txt @@ -0,0 +1,212 @@ + +UTF-8 encoded sample plain-text file +‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾ + +Markus Kuhn [ˈmaʳkʊs kuːn] — 2002-07-25 + + +The ASCII compatible UTF-8 encoding used in this plain-text file +is defined in Unicode, ISO 10646-1, and RFC 2279. + + +Using Unicode/UTF-8, you can write in emails and source code things such as + +Mathematics and sciences: + + ∮ E⋅da = Q, n → ∞, ∑ f(i) = ∏ g(i), ⎧⎡⎛┌─────┐⎞⎤⎫ + ⎪⎢⎜│a²+b³ ⎟⎥⎪ + ∀x∈ℝ: ⌈x⌉ = −⌊−x⌋, α ∧ ¬β = ¬(¬α ∨ β), ⎪⎢⎜│───── ⎟⎥⎪ + ⎪⎢⎜⎷ c₈ ⎟⎥⎪ + ℕ ⊆ ℕ₀ ⊂ ℤ ⊂ ℚ ⊂ ℝ ⊂ ℂ, ⎨⎢⎜ ⎟⎥⎬ + ⎪⎢⎜ ∞ ⎟⎥⎪ + ⊥ < a ≠ b ≡ c ≤ d ≪ ⊤ ⇒ (⟦A⟧ ⇔ ⟪B⟫), ⎪⎢⎜ ⎲ ⎟⎥⎪ + ⎪⎢⎜ ⎳aⁱ-bⁱ⎟⎥⎪ + 2H₂ + O₂ ⇌ 2H₂O, R = 4.7 kΩ, ⌀ 200 mm ⎩⎣⎝i=1 ⎠⎦⎭ + +Linguistics and dictionaries: + + ði ıntəˈnæʃənəl fəˈnɛtık əsoʊsiˈeıʃn + Y [ˈʏpsilɔn], Yen [jɛn], Yoga [ˈjoːgɑ] + +APL: + + ((V⍳V)=⍳⍴V)/V←,V ⌷←⍳→⍴∆∇⊃‾⍎⍕⌈ + +Nicer typography in plain text files: + + ╔══════════════════════════════════════════╗ + ║ ║ + ║ • ‘single’ and “double” quotes ║ + ║ ║ + ║ • Curly apostrophes: “We’ve been here” ║ + ║ ║ + ║ • Latin-1 apostrophe and accents: '´` ║ + ║ ║ + ║ • ‚deutsche‘ „Anführungszeichen“ ║ + ║ ║ + ║ • †, ‡, ‰, •, 3–4, —, −5/+5, ™, … ║ + ║ ║ + ║ • ASCII safety test: 1lI|, 0OD, 8B ║ + ║ ╭─────────╮ ║ + ║ • the euro symbol: │ 14.95 € │ ║ + ║ ╰─────────╯ ║ + ╚══════════════════════════════════════════╝ + +Combining characters: + + STARGΛ̊TE SG-1, a = v̇ = r̈, a⃑ ⊥ b⃑ + +Greek (in Polytonic): + + The Greek anthem: + + Σὲ γνωρίζω ἀπὸ τὴν κόψη + τοῦ σπαθιοῦ τὴν τρομερή, + σὲ γνωρίζω ἀπὸ τὴν ὄψη + ποὺ μὲ βία μετράει τὴ γῆ. + + ᾿Απ᾿ τὰ κόκκαλα βγαλμένη + τῶν ῾Ελλήνων τὰ ἱερά + καὶ σὰν πρῶτα ἀνδρειωμένη + χαῖρε, ὦ χαῖρε, ᾿Ελευθεριά! + + From a speech of Demosthenes in the 4th century BC: + + Οὐχὶ ταὐτὰ παρίσταταί μοι γιγνώσκειν, ὦ ἄνδρες ᾿Αθηναῖοι, + ὅταν τ᾿ εἰς τὰ πράγματα ἀποβλέψω καὶ ὅταν πρὸς τοὺς + λόγους οὓς ἀκούω· τοὺς μὲν γὰρ λόγους περὶ τοῦ + τιμωρήσασθαι Φίλιππον ὁρῶ γιγνομένους, τὰ δὲ πράγματ᾿ + εἰς τοῦτο προήκοντα, ὥσθ᾿ ὅπως μὴ πεισόμεθ᾿ αὐτοὶ + πρότερον κακῶς σκέψασθαι δέον. οὐδέν οὖν ἄλλο μοι δοκοῦσιν + οἱ τὰ τοιαῦτα λέγοντες ἢ τὴν ὑπόθεσιν, περὶ ἧς βουλεύεσθαι, + οὐχὶ τὴν οὖσαν παριστάντες ὑμῖν ἁμαρτάνειν. ἐγὼ δέ, ὅτι μέν + ποτ᾿ ἐξῆν τῇ πόλει καὶ τὰ αὑτῆς ἔχειν ἀσφαλῶς καὶ Φίλιππον + τιμωρήσασθαι, καὶ μάλ᾿ ἀκριβῶς οἶδα· ἐπ᾿ ἐμοῦ γάρ, οὐ πάλαι + γέγονεν ταῦτ᾿ ἀμφότερα· νῦν μέντοι πέπεισμαι τοῦθ᾿ ἱκανὸν + προλαβεῖν ἡμῖν εἶναι τὴν πρώτην, ὅπως τοὺς συμμάχους + σώσομεν. ἐὰν γὰρ τοῦτο βεβαίως ὑπάρξῃ, τότε καὶ περὶ τοῦ + τίνα τιμωρήσεταί τις καὶ ὃν τρόπον ἐξέσται σκοπεῖν· πρὶν δὲ + τὴν ἀρχὴν ὀρθῶς ὑποθέσθαι, μάταιον ἡγοῦμαι περὶ τῆς + τελευτῆς ὁντινοῦν ποιεῖσθαι λόγον. + + Δημοσθένους, Γ´ ᾿Ολυνθιακὸς + +Georgian: + + From a Unicode conference invitation: + + გთხოვთ ახლავე გაიაროთ რეგისტრაცია Unicode-ის მეათე საერთაშორისო + კონფერენციაზე დასასწრებად, რომელიც გაიმართება 10-12 მარტს, + ქ. მაინცში, გერმანიაში. კონფერენცია შეჰკრებს ერთად მსოფლიოს + ექსპერტებს ისეთ დარგებში როგორიცაა ინტერნეტი და Unicode-ი, + ინტერნაციონალიზაცია და ლოკალიზაცია, Unicode-ის გამოყენება + ოპერაციულ სისტემებსა, და გამოყენებით პროგრამებში, შრიფტებში, + ტექსტების დამუშავებასა და მრავალენოვან კომპიუტერულ სისტემებში. + +Russian: + + From a Unicode conference invitation: + + Зарегистрируйтесь сейчас на Десятую Международную Конференцию по + Unicode, которая состоится 10-12 марта 1997 года в Майнце в Германии. + Конференция соберет широкий круг экспертов по вопросам глобального + Интернета и Unicode, локализации и интернационализации, воплощению и + применению Unicode в различных операционных системах и программных + приложениях, шрифтах, верстке и многоязычных компьютерных системах. + +Thai (UCS Level 2): + + Excerpt from a poetry on The Romance of The Three Kingdoms (a Chinese + classic 'San Gua'): + + [----------------------------|------------------------] + ๏ แผ่นดินฮั่นเสื่อมโทรมแสนสังเวช พระปกเกศกองบู๊กู้ขึ้นใหม่ + สิบสองกษัตริย์ก่อนหน้าแลถัดไป สององค์ไซร้โง่เขลาเบาปัญญา + ทรงนับถือขันทีเป็นที่พึ่ง บ้านเมืองจึงวิปริตเป็นนักหนา + โฮจิ๋นเรียกทัพทั่วหัวเมืองมา หมายจะฆ่ามดชั่วตัวสำคัญ + เหมือนขับไสไล่เสือจากเคหา รับหมาป่าเข้ามาเลยอาสัญ + ฝ่ายอ้องอุ้นยุแยกให้แตกกัน ใช้สาวนั้นเป็นชนวนชื่นชวนใจ + พลันลิฉุยกุยกีกลับก่อเหตุ ช่างอาเพศจริงหนาฟ้าร้องไห้ + ต้องรบราฆ่าฟันจนบรรลัย ฤๅหาใครค้ำชูกู้บรรลังก์ ฯ + + (The above is a two-column text. If combining characters are handled + correctly, the lines of the second column should be aligned with the + | character above.) + +Ethiopian: + + Proverbs in the Amharic language: + + ሰማይ አይታረስ ንጉሥ አይከሰስ። + ብላ ካለኝ እንደአባቴ በቆመጠኝ። + ጌጥ ያለቤቱ ቁምጥና ነው። + ደሀ በሕልሙ ቅቤ ባይጠጣ ንጣት በገደለው። + የአፍ ወለምታ በቅቤ አይታሽም። + አይጥ በበላ ዳዋ ተመታ። + ሲተረጉሙ ይደረግሙ። + ቀስ በቀስ፥ ዕንቁላል በእግሩ ይሄዳል። + ድር ቢያብር አንበሳ ያስር። + ሰው እንደቤቱ እንጅ እንደ ጉረቤቱ አይተዳደርም። + እግዜር የከፈተውን ጉሮሮ ሳይዘጋው አይድርም። + የጎረቤት ሌባ፥ ቢያዩት ይስቅ ባያዩት ያጠልቅ። + ሥራ ከመፍታት ልጄን ላፋታት። + ዓባይ ማደሪያ የለው፥ ግንድ ይዞ ይዞራል። + የእስላም አገሩ መካ የአሞራ አገሩ ዋርካ። + ተንጋሎ ቢተፉ ተመልሶ ባፉ። + ወዳጅህ ማር ቢሆን ጨርስህ አትላሰው። + እግርህን በፍራሽህ ልክ ዘርጋ። + +Runes: + + ᚻᛖ ᚳᚹᚫᚦ ᚦᚫᛏ ᚻᛖ ᛒᚢᛞᛖ ᚩᚾ ᚦᚫᛗ ᛚᚪᚾᛞᛖ ᚾᚩᚱᚦᚹᛖᚪᚱᛞᚢᛗ ᚹᛁᚦ ᚦᚪ ᚹᛖᛥᚫ + + (Old English, which transcribed into Latin reads 'He cwaeth that he + bude thaem lande northweardum with tha Westsae.' and means 'He said + that he lived in the northern land near the Western Sea.') + +Braille: + + ⡌⠁⠧⠑ ⠼⠁⠒ ⡍⠜⠇⠑⠹⠰⠎ ⡣⠕⠌ + + ⡍⠜⠇⠑⠹ ⠺⠁⠎ ⠙⠑⠁⠙⠒ ⠞⠕ ⠃⠑⠛⠔ ⠺⠊⠹⠲ ⡹⠻⠑ ⠊⠎ ⠝⠕ ⠙⠳⠃⠞ + ⠱⠁⠞⠑⠧⠻ ⠁⠃⠳⠞ ⠹⠁⠞⠲ ⡹⠑ ⠗⠑⠛⠊⠌⠻ ⠕⠋ ⠙⠊⠎ ⠃⠥⠗⠊⠁⠇ ⠺⠁⠎ + ⠎⠊⠛⠝⠫ ⠃⠹ ⠹⠑ ⠊⠇⠻⠛⠹⠍⠁⠝⠂ ⠹⠑ ⠊⠇⠻⠅⠂ ⠹⠑ ⠥⠝⠙⠻⠞⠁⠅⠻⠂ + ⠁⠝⠙ ⠹⠑ ⠡⠊⠑⠋ ⠍⠳⠗⠝⠻⠲ ⡎⠊⠗⠕⠕⠛⠑ ⠎⠊⠛⠝⠫ ⠊⠞⠲ ⡁⠝⠙ + ⡎⠊⠗⠕⠕⠛⠑⠰⠎ ⠝⠁⠍⠑ ⠺⠁⠎ ⠛⠕⠕⠙ ⠥⠏⠕⠝ ⠰⡡⠁⠝⠛⠑⠂ ⠋⠕⠗ ⠁⠝⠹⠹⠔⠛ ⠙⠑ + ⠡⠕⠎⠑ ⠞⠕ ⠏⠥⠞ ⠙⠊⠎ ⠙⠁⠝⠙ ⠞⠕⠲ + + ⡕⠇⠙ ⡍⠜⠇⠑⠹ ⠺⠁⠎ ⠁⠎ ⠙⠑⠁⠙ ⠁⠎ ⠁ ⠙⠕⠕⠗⠤⠝⠁⠊⠇⠲ + + ⡍⠔⠙⠖ ⡊ ⠙⠕⠝⠰⠞ ⠍⠑⠁⠝ ⠞⠕ ⠎⠁⠹ ⠹⠁⠞ ⡊ ⠅⠝⠪⠂ ⠕⠋ ⠍⠹ + ⠪⠝ ⠅⠝⠪⠇⠫⠛⠑⠂ ⠱⠁⠞ ⠹⠻⠑ ⠊⠎ ⠏⠜⠞⠊⠊⠥⠇⠜⠇⠹ ⠙⠑⠁⠙ ⠁⠃⠳⠞ + ⠁ ⠙⠕⠕⠗⠤⠝⠁⠊⠇⠲ ⡊ ⠍⠊⠣⠞ ⠙⠁⠧⠑ ⠃⠑⠲ ⠔⠊⠇⠔⠫⠂ ⠍⠹⠎⠑⠇⠋⠂ ⠞⠕ + ⠗⠑⠛⠜⠙ ⠁ ⠊⠕⠋⠋⠔⠤⠝⠁⠊⠇ ⠁⠎ ⠹⠑ ⠙⠑⠁⠙⠑⠌ ⠏⠊⠑⠊⠑ ⠕⠋ ⠊⠗⠕⠝⠍⠕⠝⠛⠻⠹ + ⠔ ⠹⠑ ⠞⠗⠁⠙⠑⠲ ⡃⠥⠞ ⠹⠑ ⠺⠊⠎⠙⠕⠍ ⠕⠋ ⠳⠗ ⠁⠝⠊⠑⠌⠕⠗⠎ + ⠊⠎ ⠔ ⠹⠑ ⠎⠊⠍⠊⠇⠑⠆ ⠁⠝⠙ ⠍⠹ ⠥⠝⠙⠁⠇⠇⠪⠫ ⠙⠁⠝⠙⠎ + ⠩⠁⠇⠇ ⠝⠕⠞ ⠙⠊⠌⠥⠗⠃ ⠊⠞⠂ ⠕⠗ ⠹⠑ ⡊⠳⠝⠞⠗⠹⠰⠎ ⠙⠕⠝⠑ ⠋⠕⠗⠲ ⡹⠳ + ⠺⠊⠇⠇ ⠹⠻⠑⠋⠕⠗⠑ ⠏⠻⠍⠊⠞ ⠍⠑ ⠞⠕ ⠗⠑⠏⠑⠁⠞⠂ ⠑⠍⠏⠙⠁⠞⠊⠊⠁⠇⠇⠹⠂ ⠹⠁⠞ + ⡍⠜⠇⠑⠹ ⠺⠁⠎ ⠁⠎ ⠙⠑⠁⠙ ⠁⠎ ⠁ ⠙⠕⠕⠗⠤⠝⠁⠊⠇⠲ + + (The first couple of paragraphs of "A Christmas Carol" by Dickens) + +Compact font selection example text: + + ABCDEFGHIJKLMNOPQRSTUVWXYZ /0123456789 + abcdefghijklmnopqrstuvwxyz £©µÀÆÖÞßéöÿ + –—‘“”„†•…‰™œŠŸž€ ΑΒΓΔΩαβγδω АБВГДабвгд + ∀∂∈ℝ∧∪≡∞ ↑↗↨↻⇣ ┐┼╔╘░►☺♀ fi�⑀₂ἠḂӥẄɐː⍎אԱა + +Greetings in various languages: + + Hello world, Καλημέρα κόσμε, コンニチハ + +Box drawing alignment tests: █ + ▉ + ╔══╦══╗ ┌──┬──┐ ╭──┬──╮ ╭──┬──╮ ┏━━┳━━┓ ┎┒┏┑ ╷ ╻ ┏┯┓ ┌┰┐ ▊ ╱╲╱╲╳╳╳ + ║┌─╨─┐║ │╔═╧═╗│ │╒═╪═╕│ │╓─╁─╖│ ┃┌─╂─┐┃ ┗╃╄┙ ╶┼╴╺╋╸┠┼┨ ┝╋┥ ▋ ╲╱╲╱╳╳╳ + ║│╲ ╱│║ │║ ║│ ││ │ ││ │║ ┃ ║│ ┃│ ╿ │┃ ┍╅╆┓ ╵ ╹ ┗┷┛ └┸┘ ▌ ╱╲╱╲╳╳╳ + ╠╡ ╳ ╞╣ ├╢ ╟┤ ├┼─┼─┼┤ ├╫─╂─╫┤ ┣┿╾┼╼┿┫ ┕┛┖┚ ┌┄┄┐ ╎ ┏┅┅┓ ┋ ▍ ╲╱╲╱╳╳╳ + ║│╱ ╲│║ │║ ║│ ││ │ ││ │║ ┃ ║│ ┃│ ╽ │┃ ░░▒▒▓▓██ ┊ ┆ ╎ ╏ ┇ ┋ ▎ + ║└─╥─┘║ │╚═╤═╝│ │╘═╪═╛│ │╙─╀─╜│ ┃└─╂─┘┃ ░░▒▒▓▓██ ┊ ┆ ╎ ╏ ┇ ┋ ▏ + ╚══╩══╝ └──┴──┘ ╰──┴──╯ ╰──┴──╯ ┗━━┻━━┛ ▗▄▖▛▀▜ └╌╌┘ ╎ ┗╍╍┛ ┋ ▁▂▃▄▅▆▇█ + ▝▀▘▙▄▟ diff --git a/utf8parse/src/lib.rs b/utf8parse/src/lib.rs index 9585642e..e75f197a 100644 --- a/utf8parse/src/lib.rs +++ b/utf8parse/src/lib.rs @@ -91,3 +91,42 @@ impl Parser { } } } + +#[cfg(test)] +mod tests { + use std::io::Read; + use std::fs::File; + use Receiver; + use Parser; + + impl Receiver for String { + fn codepoint(&mut self, c: char) { + self.push(c); + } + + fn invalid_sequence(&mut self) { + } + } + + #[test] + fn utf8parse_test() { + let mut buffer = String::new(); + let mut file = File::open("src/UTF-8-demo.txt").unwrap(); + let mut parser = Parser::new(); + + // read the file to a buffer + file.read_to_string(&mut buffer).expect("Reading file to string"); + + // standard library implementation + let expected = String::from_utf8(buffer.as_bytes().to_vec()).unwrap(); + + // utf8parse implementation + let mut actual = String::new(); + + for byte in buffer.as_bytes().to_vec() { + parser.advance(&mut actual, byte) + } + + assert_eq!(actual, expected); + } +} From 69cedd0221a6c55c91ad460121c10a25f618a0d6 Mon Sep 17 00:00:00 2001 From: Joe Wilm Date: Fri, 21 Oct 2016 08:25:01 -0700 Subject: [PATCH 28/99] Add travis.yml --- .travis.yml | 10 ++++++++++ README.md | 1 + 2 files changed, 11 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..29be0546 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,10 @@ +language: rust + +cache: cargo + +rust: + - stable + - nightly + +script: + - cd utf8parse && cargo test diff --git a/README.md b/README.md index 191994f9..9033b05e 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ vte === +[![Build Status](https://travis-ci.org/jwilm/vte.svg?branch=master)](https://travis-ci.org/jwilm/vte) [![Crates.io Version](https://img.shields.io/crates/v/vte.svg)](https://crates.io/crates/vte/) Parser for implementing virtual terminal emulators in Rust. From 3149ed008ad0694a85ca50231e3d6833998d53cf Mon Sep 17 00:00:00 2001 From: Joe Wilm Date: Tue, 10 Jan 2017 20:50:21 -0800 Subject: [PATCH 29/99] Version 0.2 Changelog has details, but this basically made OSC handling way easier for dependents. --- CHANGELOG.md | 9 +++ Cargo.toml | 2 +- examples/parselog.rs | 22 ++----- src/lib.rs | 150 ++++++++++++++++++++++++++++++++++++++----- 4 files changed, 150 insertions(+), 33 deletions(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..af2ed8d7 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,9 @@ +CHANGELOG +========= + +## 0.2.0 + +- Removes `osc_start`, `osc_put`, and `osc_end` +- Adds `osc_dispatch` which simply receives a list of parameters +- Removes `byte: u8` parameter from `hook` and `unhook` because it's always + zero. diff --git a/Cargo.toml b/Cargo.toml index 34f65f20..127a3c7b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "vte" -version = "0.1.2" +version = "0.2.0" authors = ["Joe Wilm "] license = "Apache-2.0 OR MIT" description = "Parser for implementing terminal emulators" diff --git a/examples/parselog.rs b/examples/parselog.rs index e04fd1eb..86751c98 100644 --- a/examples/parselog.rs +++ b/examples/parselog.rs @@ -15,29 +15,21 @@ impl vte::Perform for Log { println!("[execute] {:02x}", byte); } - fn hook(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, byte: u8) { - println!("[hook] params={:?}, intermediates={:?}, ignore={:?}, byte={:02x}", - params, intermediates, ignore, byte); + fn hook(&mut self, params: &[i64], intermediates: &[u8], ignore: bool) { + println!("[hook] params={:?}, intermediates={:?}, ignore={:?}", + params, intermediates, ignore); } fn put(&mut self, byte: u8) { println!("[put] {:02x}", byte); } - fn unhook(&mut self, byte: u8) { - println!("[unhook] {:02x}", byte); - } - - fn osc_start(&mut self) { - println!("[osc_start]"); - } - - fn osc_put(&mut self, byte: u8) { - println!("[osc_put] {:02x}", byte); + fn unhook(&mut self) { + println!("[unhook]"); } - fn osc_end(&mut self, byte: u8) { - println!("[osc_end] {:02x}", byte); + fn osc_dispatch(&mut self, params: &[&[u8]]) { + println!("[csi_dispatch] params={:?}", params); } fn csi_dispatch(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, c: char) { diff --git a/src/lib.rs b/src/lib.rs index 9b2c0476..8ec62c5d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,6 +30,8 @@ //! [Paul Williams' ANSI parser state machine]: http://vt100.net/emu/dec_ansi_parser extern crate utf8parse as utf8; +use std::mem; + mod table; mod definitions; @@ -57,6 +59,7 @@ impl State { const MAX_INTERMEDIATES: usize = 2; +const MAX_OSC_RAW: usize = 1024; const MAX_PARAMS: usize = 16; struct VtUtf8Receiver<'a, P: Perform + 'a>(&'a mut P, &'a mut State); @@ -82,6 +85,10 @@ pub struct Parser { intermediate_idx: usize, params: [i64; MAX_PARAMS], num_params: usize, + osc_raw: [u8; MAX_OSC_RAW], + osc_params: [(usize, usize); MAX_PARAMS], + osc_idx: usize, + osc_num_params: usize, ignoring: bool, utf8_parser: utf8::Parser, } @@ -95,6 +102,10 @@ impl Parser { intermediate_idx: 0, params: [0i64; MAX_PARAMS], num_params: 0, + osc_raw: [0; MAX_OSC_RAW], + osc_params: [(0, 0); MAX_PARAMS], + osc_idx: 0, + osc_num_params: 0, ignoring: false, utf8_parser: utf8::Parser::new(), } @@ -183,6 +194,23 @@ impl Parser { } } + /// Separate method for osc_dispatch that borrows self as read-only + /// + /// The aliasing is needed here for multiple slices into self.osc_raw + #[inline] + fn osc_dispatch(&self, performer: &mut P) { + let mut slices: [&[u8]; MAX_PARAMS] = unsafe { mem::uninitialized() }; + + for i in 0..self.osc_num_params { + let indices = self.osc_params[i]; + slices[i] = &self.osc_raw[indices.0..indices.1]; + } + + performer.osc_dispatch( + &slices[..self.osc_num_params], + ); + } + #[inline] fn perform_action(&mut self, performer: &mut P, action: Action, byte: u8) { match action { @@ -193,14 +221,59 @@ impl Parser { self.params(), self.intermediates(), self.ignoring, - byte ); }, Action::Put => performer.put(byte), - Action::OscStart => performer.osc_start(), - Action::OscPut => performer.osc_put(byte), - Action::OscEnd => performer.osc_end(byte), - Action::Unhook => performer.unhook(byte), + Action::OscStart => { + self.osc_idx = 0; + self.osc_num_params = 0; + }, + Action::OscPut => { + let idx = self.osc_idx; + if idx == self.osc_raw.len() { + return; + } + + // Param separator + if byte == b';' { + let param_idx = self.osc_num_params; + match param_idx { + // Only process up to MAX_PARAMS + MAX_PARAMS => return, + + // First param is special - 0 to current byte index + 0 => { + self.osc_params[param_idx] = (0, idx); + }, + + // All other params depend on previous indexing + _ => { + let prev = self.osc_params[param_idx - 1]; + let begin = prev.1; + self.osc_params[param_idx] = (begin, idx); + } + } + + self.osc_num_params += 1; + } else { + self.osc_raw[idx] = byte; + self.osc_idx += 1; + } + }, + Action::OscEnd => { + let param_idx = self.osc_num_params; + let idx = self.osc_idx; + // Finish last parameter if not already maxed + if param_idx != MAX_PARAMS { + let prev = self.osc_params[param_idx - 1]; + let begin = prev.1; + self.osc_params[param_idx] = (begin, idx); + } + self.osc_num_params += 1; + + self.osc_dispatch(performer); + }, + Action::Unhook => performer.unhook(), Action::CsiDispatch => { performer.csi_dispatch( self.params(), @@ -281,7 +354,7 @@ pub trait Perform { /// /// The `ignore` flag indicates that more than two intermediates arrived and /// subsequent characters were ignored. - fn hook(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, byte: u8); + fn hook(&mut self, params: &[i64], intermediates: &[u8], ignore: bool); /// Pass bytes as part of a device control string to the handle chosen in `hook`. C0 controls /// will also be passed to the handler. @@ -291,18 +364,10 @@ pub trait Perform { /// /// The previously selected handler should be notified that the DCS has /// terminated. - fn unhook(&mut self, byte: u8); + fn unhook(&mut self); - /// Notifies the start of an Operating System Command - fn osc_start(&mut self); - - /// Receives characters for the OSC control string - /// - /// Apparently characters don't need buffering here. - fn osc_put(&mut self, byte: u8); - - /// Called when the OSC has terminated - fn osc_end(&mut self, byte: u8); + /// Dispatch an operating system command + fn osc_dispatch(&mut self, params: &[&[u8]]); /// A final character has arrived for a CSI sequence /// @@ -316,3 +381,54 @@ pub trait Perform { /// subsequent characters were ignored. fn esc_dispatch(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, byte: u8); } + +#[cfg(test)] +mod tests { + use super::{Parser, Perform}; + + static OSC_BYTES: &'static [u8] = &[0x9d, // Begin OSC + b'2', b';', b'j', b'w', b'i', b'l', b'm', b'@', b'j', b'w', b'i', b'l', + b'm', b'-', b'd', b'e', b's', b'k', b':', b' ', b'~', b'/', b'c', b'o', + b'd', b'e', b'/', b'a', b'l', b'a', b'c', b'r', b'i', b't', b't', b'y', + 0x07 // End OSC + ]; + + #[test] + fn parse_osc() { + #[derive(Default)] + struct OscDispatcher { + dispatched_osc: bool + } + + // All empty bodies except osc_dispatch + impl Perform for OscDispatcher { + fn print(&mut self, _: char) {} + fn execute(&mut self, _byte: u8) {} + fn hook(&mut self, _params: &[i64], _intermediates: &[u8], _ignore: bool) {} + fn put(&mut self, _byte: u8) {} + fn unhook(&mut self) {} + fn osc_dispatch(&mut self, params: &[&[u8]]) { + // Set a flag so we know these assertions all run + self.dispatched_osc = true; + assert_eq!(params.len(), 2); + assert_eq!(params[0], &OSC_BYTES[1..2]); + assert_eq!(params[1], &OSC_BYTES[3..(OSC_BYTES.len() - 1)]); + } + fn csi_dispatch(&mut self, _params: &[i64], _intermediates: &[u8], _ignore: bool, _c: char) {} + fn esc_dispatch(&mut self, _params: &[i64], _intermediates: &[u8], _ignore: bool, _byte: u8) {} + } + + // Create dispatcher and check state + let mut dispatcher = OscDispatcher::default(); + assert_eq!(dispatcher.dispatched_osc, false); + + // Run parser using OSC_BYTES + let mut parser = Parser::new(); + for byte in OSC_BYTES { + parser.advance(&mut dispatcher, *byte); + } + + // Check that flag is set and thus osc_dispatch assertions ran. + assert!(dispatcher.dispatched_osc); + } +} From 5efa369bddf7de23cc290d5170f86bc36d3384f0 Mon Sep 17 00:00:00 2001 From: Joe Wilm Date: Tue, 10 Jan 2017 21:16:03 -0800 Subject: [PATCH 30/99] Fix bug with OSC parsing An osc_dispatch with zero params would cause an underflow and index out of bounds of self.osc_params. --- Cargo.toml | 2 +- src/lib.rs | 81 ++++++++++++++++++++++++++++++++++++------------------ 2 files changed, 56 insertions(+), 27 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 127a3c7b..4c5d4c1c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "vte" -version = "0.2.0" +version = "0.2.1" authors = ["Joe Wilm "] license = "Apache-2.0 OR MIT" description = "Parser for implementing terminal emulators" diff --git a/src/lib.rs b/src/lib.rs index 8ec62c5d..eb4ef94f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -263,11 +263,22 @@ impl Parser { Action::OscEnd => { let param_idx = self.osc_num_params; let idx = self.osc_idx; - // Finish last parameter if not already maxed - if param_idx != MAX_PARAMS { - let prev = self.osc_params[param_idx - 1]; - let begin = prev.1; - self.osc_params[param_idx] = (begin, idx); + + match param_idx { + // Finish last parameter if not already maxed + MAX_PARAMS => (), + + // First param is special - 0 to current byte index + 0 => { + self.osc_params[param_idx] = (0, idx); + }, + + // All other params depend on previous indexing + _ => { + let prev = self.osc_params[param_idx - 1]; + let begin = prev.1; + self.osc_params[param_idx] = (begin, idx); + } } self.osc_num_params += 1; @@ -393,38 +404,56 @@ mod tests { 0x07 // End OSC ]; + #[derive(Default)] + struct OscDispatcher { + dispatched_osc: bool, + params: Vec>, + } + + // All empty bodies except osc_dispatch + impl Perform for OscDispatcher { + fn print(&mut self, _: char) {} + fn execute(&mut self, _byte: u8) {} + fn hook(&mut self, _params: &[i64], _intermediates: &[u8], _ignore: bool) {} + fn put(&mut self, _byte: u8) {} + fn unhook(&mut self) {} + fn osc_dispatch(&mut self, params: &[&[u8]]) { + // Set a flag so we know these assertions all run + self.dispatched_osc = true; + self.params = params.iter().map(|p| p.to_vec()).collect(); + } + fn csi_dispatch(&mut self, _params: &[i64], _intermediates: &[u8], _ignore: bool, _c: char) {} + fn esc_dispatch(&mut self, _params: &[i64], _intermediates: &[u8], _ignore: bool, _byte: u8) {} + } + #[test] fn parse_osc() { - #[derive(Default)] - struct OscDispatcher { - dispatched_osc: bool - } + // Create dispatcher and check state + let mut dispatcher = OscDispatcher::default(); + assert_eq!(dispatcher.dispatched_osc, false); - // All empty bodies except osc_dispatch - impl Perform for OscDispatcher { - fn print(&mut self, _: char) {} - fn execute(&mut self, _byte: u8) {} - fn hook(&mut self, _params: &[i64], _intermediates: &[u8], _ignore: bool) {} - fn put(&mut self, _byte: u8) {} - fn unhook(&mut self) {} - fn osc_dispatch(&mut self, params: &[&[u8]]) { - // Set a flag so we know these assertions all run - self.dispatched_osc = true; - assert_eq!(params.len(), 2); - assert_eq!(params[0], &OSC_BYTES[1..2]); - assert_eq!(params[1], &OSC_BYTES[3..(OSC_BYTES.len() - 1)]); - } - fn csi_dispatch(&mut self, _params: &[i64], _intermediates: &[u8], _ignore: bool, _c: char) {} - fn esc_dispatch(&mut self, _params: &[i64], _intermediates: &[u8], _ignore: bool, _byte: u8) {} + // Run parser using OSC_BYTES + let mut parser = Parser::new(); + for byte in OSC_BYTES { + parser.advance(&mut dispatcher, *byte); } + // Check that flag is set and thus osc_dispatch assertions ran. + assert!(dispatcher.dispatched_osc); + assert_eq!(dispatcher.params.len(), 2); + assert_eq!(dispatcher.params[0], &OSC_BYTES[1..2]); + assert_eq!(dispatcher.params[1], &OSC_BYTES[3..(OSC_BYTES.len() - 1)]); + } + + #[test] + fn parse_empty_osc() { // Create dispatcher and check state let mut dispatcher = OscDispatcher::default(); assert_eq!(dispatcher.dispatched_osc, false); // Run parser using OSC_BYTES let mut parser = Parser::new(); - for byte in OSC_BYTES { + for byte in &[0x9d, 0x07] { parser.advance(&mut dispatcher, *byte); } From 8c7fb776df288cf189fca60e211c5dd3a5c9241a Mon Sep 17 00:00:00 2001 From: Joe Wilm Date: Thu, 2 Feb 2017 08:15:03 -0800 Subject: [PATCH 31/99] Fix bug parsing CSI attributes The sequence \E[;4m previously produced a param list of [4], but the expected result is [0, 4]. The semicolon indicated that a param has been completed. Since no byte is specified, it should be zero. This fixes an issue with the save/restore cursor test in vttest for Alacritty. --- Cargo.toml | 2 +- src/lib.rs | 65 +++++++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 55 insertions(+), 12 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4c5d4c1c..97411538 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "vte" -version = "0.2.1" +version = "0.2.2" authors = ["Joe Wilm "] license = "Apache-2.0 OR MIT" description = "Parser for implementing terminal emulators" diff --git a/src/lib.rs b/src/lib.rs index eb4ef94f..a697b179 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -84,6 +84,8 @@ pub struct Parser { intermediates: [u8; MAX_INTERMEDIATES], intermediate_idx: usize, params: [i64; MAX_PARAMS], + param: i64, + collecting_param: bool, num_params: usize, osc_raw: [u8; MAX_OSC_RAW], osc_params: [(usize, usize); MAX_PARAMS], @@ -101,6 +103,8 @@ impl Parser { intermediates: [0u8; MAX_INTERMEDIATES], intermediate_idx: 0, params: [0i64; MAX_PARAMS], + param: 0, + collecting_param: false, num_params: 0, osc_raw: [0; MAX_OSC_RAW], osc_params: [(0, 0); MAX_PARAMS], @@ -286,12 +290,21 @@ impl Parser { }, Action::Unhook => performer.unhook(), Action::CsiDispatch => { + if self.collecting_param { + let idx = self.num_params; + self.params[idx] = self.param; + self.num_params += 1; + } performer.csi_dispatch( self.params(), self.intermediates(), self.ignoring, byte as char ); + + self.num_params = 0; + self.param = 0; + self.collecting_param = false; } Action::EscDispatch => { performer.esc_dispatch( @@ -312,19 +325,17 @@ impl Parser { }, Action::Param => { if byte == b';' { - // end of param; advance to next + // Completed a param + let idx = self.num_params; + self.params[idx] = self.param; + self.param = 0; self.num_params += 1; - let idx = self.num_params - 1; // borrowck - self.params[idx] = 0; + self.collecting_param = false; } else { - if self.num_params == 0 { - self.num_params = 1; - self.params[0] = 0; - } - - let idx = self.num_params - 1; - self.params[idx] *= 10; - self.params[idx] += (byte - b'0') as i64; + // Continue collecting bytes into param + self.param *= 10; + self.param += (byte - b'0') as i64; + self.collecting_param = true; } }, Action::Clear => { @@ -460,4 +471,36 @@ mod tests { // Check that flag is set and thus osc_dispatch assertions ran. assert!(dispatcher.dispatched_osc); } + + #[test] + fn parse_semi_set_underline() { + struct CsiDispatcher { + params: Vec>, + } + + impl Perform for CsiDispatcher { + fn print(&mut self, _: char) {} + fn execute(&mut self, _byte: u8) {} + fn hook(&mut self, _params: &[i64], _intermediates: &[u8], _ignore: bool) {} + fn put(&mut self, _byte: u8) {} + fn unhook(&mut self) {} + fn osc_dispatch(&mut self, _params: &[&[u8]]) { } + fn csi_dispatch(&mut self, params: &[i64], _intermediates: &[u8], _ignore: bool, _c: char) { + self.params.push(params.to_vec()); + } + fn esc_dispatch(&mut self, _params: &[i64], _intermediates: &[u8], _ignore: bool, _byte: u8) {} + } + + // Create dispatcher and check state + let mut dispatcher = CsiDispatcher { params: vec![] }; + + // Run parser using OSC_BYTES + let mut parser = Parser::new(); + for byte in b"\x1b[;4m" { + parser.advance(&mut dispatcher, *byte); + } + + // Check that flag is set and thus osc_dispatch assertions ran. + assert_eq!(dispatcher.params[0], &[0, 4]); + } } From 3b70b0d5953e8510d556e96cfb32f288d35dd705 Mon Sep 17 00:00:00 2001 From: Joe Wilm Date: Wed, 1 Mar 2017 22:03:35 -0800 Subject: [PATCH 32/99] Fix bug in OSC parsing and drop 8-bit code support OSC parsing now handles UTF-8 arguments. 8-bit code support was dropped to make supporting this easier. --- Cargo.toml | 2 +- src/lib.rs | 33 +++++++++++++++++++++++++++++---- src/table.rs | 32 ++++++++++++++++++-------------- src/table.rs.in | 14 +------------- 4 files changed, 49 insertions(+), 32 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 97411538..ad8ba16b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "vte" -version = "0.2.2" +version = "0.3.0" authors = ["Joe Wilm "] license = "Apache-2.0 OR MIT" description = "Parser for implementing terminal emulators" diff --git a/src/lib.rs b/src/lib.rs index a697b179..68eb9e42 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,6 +24,8 @@ //! //! * UTF-8 Support for Input //! * OSC Strings can be terminated by 0x07 +//! * Only supports 7-bit codes. Some 8-bit codes are still supported, but they +//! no longer work in all states. //! //! [`Parser`]: struct.Parser.html //! [`Perform`]: trait.Perform.html @@ -408,7 +410,7 @@ pub trait Perform { mod tests { use super::{Parser, Perform}; - static OSC_BYTES: &'static [u8] = &[0x9d, // Begin OSC + static OSC_BYTES: &'static [u8] = &[0x1b, 0x5d, // Begin OSC b'2', b';', b'j', b'w', b'i', b'l', b'm', b'@', b'j', b'w', b'i', b'l', b'm', b'-', b'd', b'e', b's', b'k', b':', b' ', b'~', b'/', b'c', b'o', b'd', b'e', b'/', b'a', b'l', b'a', b'c', b'r', b'i', b't', b't', b'y', @@ -452,8 +454,8 @@ mod tests { // Check that flag is set and thus osc_dispatch assertions ran. assert!(dispatcher.dispatched_osc); assert_eq!(dispatcher.params.len(), 2); - assert_eq!(dispatcher.params[0], &OSC_BYTES[1..2]); - assert_eq!(dispatcher.params[1], &OSC_BYTES[3..(OSC_BYTES.len() - 1)]); + assert_eq!(dispatcher.params[0], &OSC_BYTES[2..3]); + assert_eq!(dispatcher.params[1], &OSC_BYTES[4..(OSC_BYTES.len() - 1)]); } #[test] @@ -464,7 +466,7 @@ mod tests { // Run parser using OSC_BYTES let mut parser = Parser::new(); - for byte in &[0x9d, 0x07] { + for byte in &[0x1b, 0x5d, 0x07] { parser.advance(&mut dispatcher, *byte); } @@ -503,4 +505,27 @@ mod tests { // Check that flag is set and thus osc_dispatch assertions ran. assert_eq!(dispatcher.params[0], &[0, 4]); } + + #[test] + fn parse_osc_with_utf8_arguments() { + static INPUT: &'static [u8] = &[ + 0x0d, 0x1b, 0x5d, 0x32, 0x3b, 0x65, 0x63, 0x68, 0x6f, 0x20, 0x27, + 0xc2, 0xaf, 0x5c, 0x5f, 0x28, 0xe3, 0x83, 0x84, 0x29, 0x5f, 0x2f, + 0xc2, 0xaf, 0x27, 0x20, 0x26, 0x26, 0x20, 0x73, 0x6c, 0x65, 0x65, + 0x70, 0x20, 0x31, 0x07 + ]; + + // Create dispatcher and check state + let mut dispatcher = OscDispatcher { params: vec![], dispatched_osc: false }; + + // Run parser using OSC_BYTES + let mut parser = Parser::new(); + for byte in INPUT { + parser.advance(&mut dispatcher, *byte); + } + + // Check that flag is set and thus osc_dispatch assertions ran. + assert_eq!(dispatcher.params[0], &[b'2']); + assert_eq!(dispatcher.params[1], &INPUT[5..(INPUT.len() - 1)]); + } } diff --git a/src/table.rs b/src/table.rs index 5bb52c04..799c6d6e 100644 --- a/src/table.rs +++ b/src/table.rs @@ -31,16 +31,16 @@ pub static STATE_CHANGE: [[u8; 256]; 16] = 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 92u8, 92u8, 92u8, 92u8, 92u8, 92u8, 92u8, 92u8, 92u8, 92u8, - 92u8, 92u8, 92u8, 92u8, 92u8, 92u8, 5u8, 92u8, 92u8, 92u8, 92u8, 92u8, - 92u8, 92u8, 14u8, 92u8, 92u8, 1u8, 92u8, 13u8, 14u8, 14u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8], + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8], [80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 0u8, 80u8, 0u8, 0u8, 80u8, 80u8, 80u8, 80u8, 35u8, 35u8, 35u8, 35u8, @@ -302,16 +302,20 @@ pub static STATE_CHANGE: [[u8; 256]; 16] = 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, - 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 12u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8], + 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, + 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, + 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, + 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, + 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, + 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, + 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, + 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, + 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, + 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, + 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, + 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, + 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, + 144u8, 144u8, 144u8, 144u8, 144u8], [112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 0u8, 112u8, 0u8, 0u8, 112u8, 112u8, 112u8, diff --git a/src/table.rs.in b/src/table.rs.in index 3017e332..5593283f 100644 --- a/src/table.rs.in +++ b/src/table.rs.in @@ -7,18 +7,7 @@ pub static STATE_CHANGE: [[u8; 256]; 16] = vt_state_table! { State::Anywhere => { 0x18 => (Action::Execute, State::Ground), 0x1a => (Action::Execute, State::Ground), - 0x80...0x8f => (Action::Execute, State::Ground), - 0x91...0x97 => (Action::Execute, State::Ground), - 0x99 => (Action::Execute, State::Ground), - 0x9a => (Action::Execute, State::Ground), - 0x9c => (Action::Execute, State::Ground), 0x1b => State::Escape, - 0x98 => State::SosPmApcString, - 0x9e => State::SosPmApcString, - 0x9f => State::SosPmApcString, - 0x90 => State::DcsEntry, - 0x9d => State::OscString, - 0x9b => State::CsiEntry, }, State::Ground => { @@ -178,8 +167,7 @@ pub static STATE_CHANGE: [[u8; 256]; 16] = vt_state_table! { 0x08...0x17 => Action::Ignore, 0x19 => Action::Ignore, 0x1c...0x1f => Action::Ignore, - 0x20...0x7f => Action::OscPut, - 0x9c => State::Ground, + 0x20...0xff => Action::OscPut, } }; From 86805965e630339ee19e06ecb5fdaf8c21e711ff Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Tue, 16 May 2017 17:56:11 -0400 Subject: [PATCH 33/99] Properly handle maximum number of OSC parameters Previously, `osc_num_params` would be incremented when the final parameter finished parsing, even if it was already at `MAX_PARAMS`. This commit ensures that it is not incremented beyond `MAX_PARAMS`. --- src/lib.rs | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 68eb9e42..a5317c3a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -277,6 +277,7 @@ impl Parser { // First param is special - 0 to current byte index 0 => { self.osc_params[param_idx] = (0, idx); + self.osc_num_params += 1; }, // All other params depend on previous indexing @@ -284,10 +285,9 @@ impl Parser { let prev = self.osc_params[param_idx - 1]; let begin = prev.1; self.osc_params[param_idx] = (begin, idx); + self.osc_num_params += 1; } } - self.osc_num_params += 1; - self.osc_dispatch(performer); }, Action::Unhook => performer.unhook(), @@ -474,6 +474,31 @@ mod tests { assert!(dispatcher.dispatched_osc); } + #[test] + fn parse_osc_max_params() { + use MAX_PARAMS; + + static INPUT: &'static [u8] = b"\x1b];;;;;;;;;;;;;;;;\x1b"; + + // Create dispatcher and check state + let mut dispatcher = OscDispatcher::default(); + assert_eq!(dispatcher.dispatched_osc, false); + + // Run parser using OSC_BYTES + let mut parser = Parser::new(); + for byte in INPUT { + parser.advance(&mut dispatcher, *byte); + } + + // Check that flag is set and thus osc_dispatch assertions ran. + assert!(dispatcher.dispatched_osc); + assert_eq!(dispatcher.params.len(), MAX_PARAMS); + for param in dispatcher.params.iter() { + assert_eq!(param.len(), 0); + } + + } + #[test] fn parse_semi_set_underline() { struct CsiDispatcher { From 2910bd0cec3c1b67f8b4e052d1865bb31a626a45 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Tue, 16 May 2017 16:50:35 -0400 Subject: [PATCH 34/99] Prevent overflow when parsing CSI/DCS parameters To prevent a large CSI or DCS parameter from overflowing an i64, the value is limited to i64::MAX --- src/lib.rs | 55 ++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 37 insertions(+), 18 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index a5317c3a..97d4c4f1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -335,8 +335,8 @@ impl Parser { self.collecting_param = false; } else { // Continue collecting bytes into param - self.param *= 10; - self.param += (byte - b'0') as i64; + self.param = self.param.saturating_mul(10); + self.param = self.param.saturating_add((byte - b'0') as i64); self.collecting_param = true; } }, @@ -409,6 +409,7 @@ pub trait Perform { #[cfg(test)] mod tests { use super::{Parser, Perform}; + use std::i64; static OSC_BYTES: &'static [u8] = &[0x1b, 0x5d, // Begin OSC b'2', b';', b'j', b'w', b'i', b'l', b'm', b'@', b'j', b'w', b'i', b'l', @@ -439,6 +440,25 @@ mod tests { fn esc_dispatch(&mut self, _params: &[i64], _intermediates: &[u8], _ignore: bool, _byte: u8) {} } + #[derive(Default)] + struct CsiDispatcher { + params: Vec>, + } + + impl Perform for CsiDispatcher { + fn print(&mut self, _: char) {} + fn execute(&mut self, _byte: u8) {} + fn hook(&mut self, _params: &[i64], _intermediates: &[u8], _ignore: bool) {} + fn put(&mut self, _byte: u8) {} + fn unhook(&mut self) {} + fn osc_dispatch(&mut self, _params: &[&[u8]]) { } + fn csi_dispatch(&mut self, params: &[i64], _intermediates: &[u8], _ignore: bool, _c: char) { + self.params.push(params.to_vec()); + } + fn esc_dispatch(&mut self, _params: &[i64], _intermediates: &[u8], _ignore: bool, _byte: u8) {} + } + + #[test] fn parse_osc() { // Create dispatcher and check state @@ -501,22 +521,6 @@ mod tests { #[test] fn parse_semi_set_underline() { - struct CsiDispatcher { - params: Vec>, - } - - impl Perform for CsiDispatcher { - fn print(&mut self, _: char) {} - fn execute(&mut self, _byte: u8) {} - fn hook(&mut self, _params: &[i64], _intermediates: &[u8], _ignore: bool) {} - fn put(&mut self, _byte: u8) {} - fn unhook(&mut self) {} - fn osc_dispatch(&mut self, _params: &[&[u8]]) { } - fn csi_dispatch(&mut self, params: &[i64], _intermediates: &[u8], _ignore: bool, _c: char) { - self.params.push(params.to_vec()); - } - fn esc_dispatch(&mut self, _params: &[i64], _intermediates: &[u8], _ignore: bool, _byte: u8) {} - } // Create dispatcher and check state let mut dispatcher = CsiDispatcher { params: vec![] }; @@ -531,6 +535,21 @@ mod tests { assert_eq!(dispatcher.params[0], &[0, 4]); } + #[test] + fn parse_long_csi_param() { + // The important part is the parameter, which is (i64::MAX + 1) + static INPUT: &'static [u8] = b"\x1b[9223372036854775808m"; + + let mut dispatcher = CsiDispatcher { params: vec![] }; + + let mut parser = Parser::new(); + for byte in INPUT { + parser.advance(&mut dispatcher, *byte); + } + + assert_eq!(dispatcher.params[0], &[i64::MAX as i64]); + + } #[test] fn parse_osc_with_utf8_arguments() { static INPUT: &'static [u8] = &[ From 56f76600ff240d17ead0592ca228b655d256f769 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Mon, 29 May 2017 21:22:38 -0400 Subject: [PATCH 35/99] Properly handle maximum number of CSI params This commit ensures that 'num_params' is never incremented beyond MAX_PARAMS. Additionally, an extra parameter is added to the corresponding OSC test (17 params or MAX_PARAMS + 1) to ensure that the proper behavior is tested. --- src/lib.rs | 37 ++++++++++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 97d4c4f1..02c79968 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -329,6 +329,11 @@ impl Parser { if byte == b';' { // Completed a param let idx = self.num_params; + + if idx == MAX_PARAMS { + return; + } + self.params[idx] = self.param; self.param = 0; self.num_params += 1; @@ -442,6 +447,7 @@ mod tests { #[derive(Default)] struct CsiDispatcher { + dispatched_csi: bool, params: Vec>, } @@ -453,6 +459,7 @@ mod tests { fn unhook(&mut self) {} fn osc_dispatch(&mut self, _params: &[&[u8]]) { } fn csi_dispatch(&mut self, params: &[i64], _intermediates: &[u8], _ignore: bool, _c: char) { + self.dispatched_csi = true; self.params.push(params.to_vec()); } fn esc_dispatch(&mut self, _params: &[i64], _intermediates: &[u8], _ignore: bool, _byte: u8) {} @@ -498,7 +505,7 @@ mod tests { fn parse_osc_max_params() { use MAX_PARAMS; - static INPUT: &'static [u8] = b"\x1b];;;;;;;;;;;;;;;;\x1b"; + static INPUT: &'static [u8] = b"\x1b];;;;;;;;;;;;;;;;;\x1b"; // Create dispatcher and check state let mut dispatcher = OscDispatcher::default(); @@ -519,11 +526,35 @@ mod tests { } + #[test] + fn parse_csi_max_params() { + use MAX_PARAMS; + + static INPUT: &'static [u8] = b"\x1b[;;;;;;;;;;;;;;;;;p"; + + // Create dispatcher and check state + let mut dispatcher = CsiDispatcher::default(); + assert!(!dispatcher.dispatched_csi); + + + // Run parser using OSC_BYTES + let mut parser = Parser::new(); + for byte in INPUT { + parser.advance(&mut dispatcher, *byte); + } + + // Check that flag is set and thus csi_dispatch assertions ran. + assert!(dispatcher.dispatched_csi); + assert_eq!(dispatcher.params.len(), 1); + assert_eq!(dispatcher.params[0].len(), MAX_PARAMS); + + } + #[test] fn parse_semi_set_underline() { // Create dispatcher and check state - let mut dispatcher = CsiDispatcher { params: vec![] }; + let mut dispatcher = CsiDispatcher::default(); // Run parser using OSC_BYTES let mut parser = Parser::new(); @@ -540,7 +571,7 @@ mod tests { // The important part is the parameter, which is (i64::MAX + 1) static INPUT: &'static [u8] = b"\x1b[9223372036854775808m"; - let mut dispatcher = CsiDispatcher { params: vec![] }; + let mut dispatcher = CsiDispatcher::default(); let mut parser = Parser::new(); for byte in INPUT { From 13f3005d2772b015e54d0f43031dfb7a35403d6d Mon Sep 17 00:00:00 2001 From: Joe Wilm Date: Tue, 20 Jun 2017 07:59:56 -0700 Subject: [PATCH 36/99] Bump version for publish --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index ad8ba16b..d0db2ada 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "vte" -version = "0.3.0" +version = "0.3.1" authors = ["Joe Wilm "] license = "Apache-2.0 OR MIT" description = "Parser for implementing terminal emulators" From 2be387f7efba8871ad85b5a22fb275323efa462c Mon Sep 17 00:00:00 2001 From: Joe Wilm Date: Sat, 19 Aug 2017 11:02:07 -0700 Subject: [PATCH 37/99] Add README field to Cargo.toml This will allow the README to be rendered on crates.io. Bumped version so this can be published. --- Cargo.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index d0db2ada..fd51683d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,12 +1,13 @@ [package] name = "vte" -version = "0.3.1" +version = "0.3.2" authors = ["Joe Wilm "] license = "Apache-2.0 OR MIT" description = "Parser for implementing terminal emulators" keywords = ["ansi", "vte", "parser", "terminal"] repository = "https://github.com/jwilm/vte" documentation = "https://docs.rs/vte/" +readme = "README.md" [dependencies.utf8parse] path = "./utf8parse" From 7d71f6a02a4bbd00805c91388f257198c1173912 Mon Sep 17 00:00:00 2001 From: M Farkas-Dyck Date: Sat, 18 Nov 2017 18:38:31 -0800 Subject: [PATCH 38/99] no_std (#9) --- src/definitions.rs | 4 ++-- src/lib.rs | 6 ++++-- utf8parse/src/lib.rs | 6 +++++- utf8parse/src/types.rs | 2 +- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/definitions.rs b/src/definitions.rs index d8faf538..3cfa7de4 100644 --- a/src/definitions.rs +++ b/src/definitions.rs @@ -51,10 +51,10 @@ pub enum Action { pub fn unpack(delta: u8) -> (State, Action) { ( // State is stored in bottom 4 bits - unsafe { ::std::mem::transmute(delta & 0x0f) }, + unsafe { ::core::mem::transmute(delta & 0x0f) }, // Action is stored in top 4 bits - unsafe { ::std::mem::transmute(delta >> 4) }, + unsafe { ::core::mem::transmute(delta >> 4) }, ) } diff --git a/src/lib.rs b/src/lib.rs index 02c79968..0ec12398 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,9 +30,11 @@ //! [`Parser`]: struct.Parser.html //! [`Perform`]: trait.Perform.html //! [Paul Williams' ANSI parser state machine]: http://vt100.net/emu/dec_ansi_parser +#![no_std] + extern crate utf8parse as utf8; -use std::mem; +use core::mem; mod table; mod definitions; @@ -414,7 +416,7 @@ pub trait Perform { #[cfg(test)] mod tests { use super::{Parser, Perform}; - use std::i64; + use core::i64; static OSC_BYTES: &'static [u8] = &[0x1b, 0x5d, // Begin OSC b'2', b';', b'j', b'w', b'i', b'l', b'm', b'@', b'j', b'w', b'i', b'l', diff --git a/utf8parse/src/lib.rs b/utf8parse/src/lib.rs index e75f197a..dc4b0fa5 100644 --- a/utf8parse/src/lib.rs +++ b/utf8parse/src/lib.rs @@ -3,7 +3,9 @@ //! This module implements a table-driven UTF-8 parser which should //! theoretically contain the minimal number of branches (1). The only branch is //! on the `Action` returned from unpacking a transition. -use std::char; +#![no_std] + +use core::char; mod types; use self::types::{State, Action, unpack}; @@ -94,6 +96,8 @@ impl Parser { #[cfg(test)] mod tests { + extern crate std; + use std::io::Read; use std::fs::File; use Receiver; diff --git a/utf8parse/src/types.rs b/utf8parse/src/types.rs index 4c604f41..a5b94369 100644 --- a/utf8parse/src/types.rs +++ b/utf8parse/src/types.rs @@ -1,6 +1,6 @@ //! Types supporting the UTF-8 parser #![allow(non_camel_case_types)] -use std::mem; +use core::mem; /// States the parser can be in. /// From 3b1d5fce1da158f392f9eb0b1cd191f31a6d1a5d Mon Sep 17 00:00:00 2001 From: Nathan Lilienthal Date: Wed, 10 Jan 2018 20:32:38 -0700 Subject: [PATCH 39/99] Fix tests to run. Links against STD to allow use of Vec. --- src/lib.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 0ec12398..af353cd1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -413,8 +413,13 @@ pub trait Perform { fn esc_dispatch(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, byte: u8); } +#[cfg(test)] +#[macro_use] +extern crate std; + #[cfg(test)] mod tests { + use std::vec::Vec; use super::{Parser, Perform}; use core::i64; From eb26bbf7648891050c46770a850b1d9e90915854 Mon Sep 17 00:00:00 2001 From: Nathan Lilienthal Date: Wed, 10 Jan 2018 20:57:18 -0700 Subject: [PATCH 40/99] Fix the utf8parse tests too. --- utf8parse/src/lib.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/utf8parse/src/lib.rs b/utf8parse/src/lib.rs index dc4b0fa5..3a8ca2f9 100644 --- a/utf8parse/src/lib.rs +++ b/utf8parse/src/lib.rs @@ -95,11 +95,14 @@ impl Parser { } #[cfg(test)] -mod tests { - extern crate std; +#[macro_use] +extern crate std; +#[cfg(test)] +mod tests { use std::io::Read; use std::fs::File; + use std::string::String; use Receiver; use Parser; From 5270226c0d41457442a0d2f22038bd26cee00c1a Mon Sep 17 00:00:00 2001 From: Nathan Lilienthal Date: Wed, 10 Jan 2018 21:00:57 -0700 Subject: [PATCH 41/99] Tell travis to test the vte crate too. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 29be0546..2fe0f182 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,4 +7,4 @@ rust: - nightly script: - - cd utf8parse && cargo test + - cargo test && cd utf8parse && cargo test From 1b7126457f547cc2230e4424c4466c24bf7b70fd Mon Sep 17 00:00:00 2001 From: Nathan Lilienthal Date: Wed, 10 Jan 2018 21:07:31 -0700 Subject: [PATCH 42/99] Make the two tests look like two tests for travis. --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 2fe0f182..4d472a5e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,4 +7,5 @@ rust: - nightly script: - - cargo test && cd utf8parse && cargo test + - cargo test + - cd utf8parse && cargo test From f3d27ea95027eec8755cf0b8b6cd4150d9059a5b Mon Sep 17 00:00:00 2001 From: Ted Mielczarek Date: Wed, 6 Dec 2017 09:12:27 -0500 Subject: [PATCH 43/99] Fix links to ANSI parser state machine. http links result in a 404 now, but https links work. --- README.md | 2 +- src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9033b05e..bfaec0c5 100644 --- a/README.md +++ b/README.md @@ -21,5 +21,5 @@ If contributing to either `vte` or the `utf8parse` crate and modifying a _table.rs.in_ file, make sure to `cargo run` from the _codegen_ folder so that the compiled tables are updated. -[Paul Williams' ANSI parser state machine]: http://vt100.net/emu/dec_ansi_parser +[Paul Williams' ANSI parser state machine]: https://vt100.net/emu/dec_ansi_parser [docs]: https://docs.rs/crate/vte/ diff --git a/src/lib.rs b/src/lib.rs index af353cd1..f2a38b53 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -29,7 +29,7 @@ //! //! [`Parser`]: struct.Parser.html //! [`Perform`]: trait.Perform.html -//! [Paul Williams' ANSI parser state machine]: http://vt100.net/emu/dec_ansi_parser +//! [Paul Williams' ANSI parser state machine]: https://vt100.net/emu/dec_ansi_parser #![no_std] extern crate utf8parse as utf8; From 9603a95a8d16b62a6bd378cec5e53a868a0ac270 Mon Sep 17 00:00:00 2001 From: Nathan Lilienthal Date: Fri, 12 Jan 2018 11:45:54 -0700 Subject: [PATCH 44/99] Make this a workspace. Allows testing everything with `cargo test --all`. --- Cargo.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index fd51683d..27a028fb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,3 +12,6 @@ readme = "README.md" [dependencies.utf8parse] path = "./utf8parse" version = "0.1" + +[workspace] + From 5cf8c3380131b9d0df186eb830d18a75c88092ea Mon Sep 17 00:00:00 2001 From: Nathan Lilienthal Date: Fri, 12 Jan 2018 11:46:53 -0700 Subject: [PATCH 45/99] Use `cargo test --all` for travis. --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4d472a5e..998e56df 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,5 +7,5 @@ rust: - nightly script: - - cargo test - - cd utf8parse && cargo test + - cargo test --all + From 76ad2fa73d360a959bf4d7f0505903576514e3ec Mon Sep 17 00:00:00 2001 From: Nathan Lilienthal Date: Fri, 12 Jan 2018 11:55:32 -0700 Subject: [PATCH 46/99] Remove leading './' from utf8parse's path. This is a purely cosmetic change at the moment. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 27a028fb..93744664 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ documentation = "https://docs.rs/vte/" readme = "README.md" [dependencies.utf8parse] -path = "./utf8parse" +path = "utf8parse" version = "0.1" [workspace] From fe116505000826c42f6f0ac2e598d7fe19217588 Mon Sep 17 00:00:00 2001 From: Peter Holloway Date: Fri, 9 Mar 2018 23:48:24 +0000 Subject: [PATCH 47/99] Fix typo in parselog example osc_dispatch calls were being logged as csi_dispatch --- examples/parselog.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/parselog.rs b/examples/parselog.rs index 86751c98..a2c3b2f5 100644 --- a/examples/parselog.rs +++ b/examples/parselog.rs @@ -29,7 +29,7 @@ impl vte::Perform for Log { } fn osc_dispatch(&mut self, params: &[&[u8]]) { - println!("[csi_dispatch] params={:?}", params); + println!("[osc_dispatch] params={:?}", params); } fn csi_dispatch(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, c: char) { From b684bb8bd80637da85693daff48f3a84bb073a0c Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Sat, 11 Aug 2018 16:52:13 +0200 Subject: [PATCH 48/99] Fix off-by-one error when parsing CSI escapes The CSI escape sequences are limited to 16 parameters using the `MAX_PARAMS` constant. To make sure no more params are parsed, the CSI parser stops when the parameter index reaches `MAX_PARAMS`, however this means that it stops at index 16, which means that the number of params would be 17 since arrays start at 0. To fix this off-by-one error the CSI parser now stops when the index reaches `MAX_PARAMS - 1`, which means it will stop when the index reaches the last element in an array with `MAX_PARAMS` number of elements. This fixes jwilm/alacritty#1505. --- src/lib.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index f2a38b53..7272230f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -332,7 +332,7 @@ impl Parser { // Completed a param let idx = self.num_params; - if idx == MAX_PARAMS { + if idx == MAX_PARAMS - 1 { return; } @@ -537,7 +537,7 @@ mod tests { fn parse_csi_max_params() { use MAX_PARAMS; - static INPUT: &'static [u8] = b"\x1b[;;;;;;;;;;;;;;;;;p"; + static INPUT: &'static [u8] = b"\x1b[1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;p"; // Create dispatcher and check state let mut dispatcher = CsiDispatcher::default(); @@ -588,6 +588,7 @@ mod tests { assert_eq!(dispatcher.params[0], &[i64::MAX as i64]); } + #[test] fn parse_osc_with_utf8_arguments() { static INPUT: &'static [u8] = &[ From 416a4c7a2ed60d676dc321f0acf3e761dbeb25a5 Mon Sep 17 00:00:00 2001 From: Joe Wilm Date: Mon, 13 Aug 2018 09:03:00 -0700 Subject: [PATCH 49/99] Version 0.3.3 --- CHANGELOG.md | 5 +++++ Cargo.toml | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index af2ed8d7..9c308deb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +## 0.3.3 + +- Fix off-by-one error in CSI parsing when params list was at max length + (previously caused a panic). + ## 0.2.0 - Removes `osc_start`, `osc_put`, and `osc_end` diff --git a/Cargo.toml b/Cargo.toml index 93744664..6cae2494 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "vte" -version = "0.3.2" +version = "0.3.3" authors = ["Joe Wilm "] license = "Apache-2.0 OR MIT" description = "Parser for implementing terminal emulators" From 0f66e393abb776719747431624027a55f20e7f57 Mon Sep 17 00:00:00 2001 From: Joe Wilm Date: Mon, 13 Aug 2018 09:05:54 -0700 Subject: [PATCH 50/99] Add missing item from Version 0.3.3 changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c308deb..ba861ac5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ CHANGELOG - Fix off-by-one error in CSI parsing when params list was at max length (previously caused a panic). +- Support no_std ## 0.2.0 From af8f710149824a2772f62c007d83073f22bd8cef Mon Sep 17 00:00:00 2001 From: Joe Wilm Date: Wed, 26 Sep 2018 15:45:34 -0700 Subject: [PATCH 51/99] Add licenses to utf8parse --- utf8parse/Cargo.toml | 2 +- utf8parse/LICENSE-APACHE | 176 +++++++++++++++++++++++++++++++++++++++ utf8parse/LICENSE-MIT | 25 ++++++ 3 files changed, 202 insertions(+), 1 deletion(-) create mode 100644 utf8parse/LICENSE-APACHE create mode 100644 utf8parse/LICENSE-MIT diff --git a/utf8parse/Cargo.toml b/utf8parse/Cargo.toml index bd0946bf..1b744070 100644 --- a/utf8parse/Cargo.toml +++ b/utf8parse/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "utf8parse" -version = "0.1.0" +version = "0.1.1" authors = ["Joe Wilm "] license = "Apache-2.0 OR MIT" description = "Table-driven UTF-8 parser" diff --git a/utf8parse/LICENSE-APACHE b/utf8parse/LICENSE-APACHE new file mode 100644 index 00000000..1b5ec8b7 --- /dev/null +++ b/utf8parse/LICENSE-APACHE @@ -0,0 +1,176 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS diff --git a/utf8parse/LICENSE-MIT b/utf8parse/LICENSE-MIT new file mode 100644 index 00000000..bb419c21 --- /dev/null +++ b/utf8parse/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2016 Joe Wilm + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. From f5113133d934aa5e0cf9d48be598efd118001f83 Mon Sep 17 00:00:00 2001 From: Felix Rabe Date: Wed, 24 Apr 2019 13:54:00 +0200 Subject: [PATCH 52/99] Use correct md code fence --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 7272230f..7fa4c227 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,7 +13,7 @@ //! there simply logs all the actions [`Perform`] does. One quick thing to see it in action is to //! pipe `vim` into it //! -//! ```ignore +//! ```sh //! cargo build --release --example parselog //! vim | target/release/examples/parselog //! ``` From e2151a4ff6039aecda1eb20e38e7a8b0bb066465 Mon Sep 17 00:00:00 2001 From: VojtechStep Date: Tue, 6 Aug 2019 12:16:08 +0200 Subject: [PATCH 53/99] Add an implicit zero after trailing semicolon --- src/lib.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 7fa4c227..0813a4d0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -298,7 +298,16 @@ impl Parser { let idx = self.num_params; self.params[idx] = self.param; self.num_params += 1; + } else { + // Last character was a semicolon, add a trailing zero + + let idx = self.num_params; + if idx != MAX_PARAMS { + self.params[idx] = 0; + self.num_params += 1; + } } + performer.csi_dispatch( self.params(), self.intermediates(), @@ -557,6 +566,19 @@ mod tests { } + #[test] + fn parse_trailing_semi() { + let mut dispatcher = CsiDispatcher::default(); + let mut parser = Parser::new(); + + for byte in b"\x1b[4;m" { + parser.advance(&mut dispatcher, *byte); + } + + assert_eq!(dispatcher.params.len(), 1); + assert_eq!(dispatcher.params[0], &[4, 0]); + } + #[test] fn parse_semi_set_underline() { From bcad429a53cade02f7ec1ebf26c902e55a75acdc Mon Sep 17 00:00:00 2001 From: VojtechStep Date: Tue, 6 Aug 2019 21:38:42 +0200 Subject: [PATCH 54/99] Simplify csi dispatching --- src/lib.rs | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 0813a4d0..71ea79bd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -89,7 +89,6 @@ pub struct Parser { intermediate_idx: usize, params: [i64; MAX_PARAMS], param: i64, - collecting_param: bool, num_params: usize, osc_raw: [u8; MAX_OSC_RAW], osc_params: [(usize, usize); MAX_PARAMS], @@ -108,7 +107,6 @@ impl Parser { intermediate_idx: 0, params: [0i64; MAX_PARAMS], param: 0, - collecting_param: false, num_params: 0, osc_raw: [0; MAX_OSC_RAW], osc_params: [(0, 0); MAX_PARAMS], @@ -294,19 +292,9 @@ impl Parser { }, Action::Unhook => performer.unhook(), Action::CsiDispatch => { - if self.collecting_param { - let idx = self.num_params; - self.params[idx] = self.param; - self.num_params += 1; - } else { - // Last character was a semicolon, add a trailing zero - let idx = self.num_params; - if idx != MAX_PARAMS { - self.params[idx] = 0; - self.num_params += 1; - } - } + self.params[self.num_params] = self.param; + self.num_params += 1; performer.csi_dispatch( self.params(), @@ -317,7 +305,6 @@ impl Parser { self.num_params = 0; self.param = 0; - self.collecting_param = false; } Action::EscDispatch => { performer.esc_dispatch( @@ -348,12 +335,10 @@ impl Parser { self.params[idx] = self.param; self.param = 0; self.num_params += 1; - self.collecting_param = false; } else { // Continue collecting bytes into param self.param = self.param.saturating_mul(10); self.param = self.param.saturating_add((byte - b'0') as i64); - self.collecting_param = true; } }, Action::Clear => { From 1f9db05de259c4fb5862d449f1428d6183eadae2 Mon Sep 17 00:00:00 2001 From: VojtechStep Date: Tue, 6 Aug 2019 21:52:10 +0200 Subject: [PATCH 55/99] Address stylistic issues --- src/lib.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 71ea79bd..ba28e7cb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -292,7 +292,6 @@ impl Parser { }, Action::Unhook => performer.unhook(), Action::CsiDispatch => { - self.params[self.num_params] = self.param; self.num_params += 1; @@ -552,7 +551,7 @@ mod tests { } #[test] - fn parse_trailing_semi() { + fn parse_csi_params_trailing_semicolon() { let mut dispatcher = CsiDispatcher::default(); let mut parser = Parser::new(); From 82fc09895ec76cd07dda39f127ca5e5c21f8abf4 Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Sun, 3 Nov 2019 12:41:01 -0500 Subject: [PATCH 56/99] fix dcs handling, and add a test for it --- examples/parselog.rs | 6 ++--- src/lib.rs | 61 ++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 59 insertions(+), 8 deletions(-) diff --git a/examples/parselog.rs b/examples/parselog.rs index a2c3b2f5..acd56dc8 100644 --- a/examples/parselog.rs +++ b/examples/parselog.rs @@ -15,9 +15,9 @@ impl vte::Perform for Log { println!("[execute] {:02x}", byte); } - fn hook(&mut self, params: &[i64], intermediates: &[u8], ignore: bool) { - println!("[hook] params={:?}, intermediates={:?}, ignore={:?}", - params, intermediates, ignore); + fn hook(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, c: char) { + println!("[hook] params={:?}, intermediates={:?}, ignore={:?}, char={:?}", + params, intermediates, ignore, c); } fn put(&mut self, byte: u8) { diff --git a/src/lib.rs b/src/lib.rs index ba28e7cb..4bd5d788 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -186,13 +186,13 @@ impl Parser { state => { // Exit action for previous state let exit_action = self.state.exit_action(); - maybe_action!(exit_action, 0); + maybe_action!(exit_action, byte); // Transition action maybe_action!(action, byte); // Entry action for new state - maybe_action!(state.entry_action(), 0); + maybe_action!(state.entry_action(), byte); // Assume the new state self.state = state; @@ -223,10 +223,14 @@ impl Parser { Action::Print => performer.print(byte as char), Action::Execute => performer.execute(byte), Action::Hook => { + self.params[self.num_params] = self.param; + self.num_params += 1; + performer.hook( self.params(), self.intermediates(), self.ignoring, + byte as char, ); }, Action::Put => performer.put(byte), @@ -378,7 +382,7 @@ pub trait Perform { /// /// The `ignore` flag indicates that more than two intermediates arrived and /// subsequent characters were ignored. - fn hook(&mut self, params: &[i64], intermediates: &[u8], ignore: bool); + fn hook(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, char); /// Pass bytes as part of a device control string to the handle chosen in `hook`. C0 controls /// will also be passed to the handler. @@ -433,7 +437,7 @@ mod tests { impl Perform for OscDispatcher { fn print(&mut self, _: char) {} fn execute(&mut self, _byte: u8) {} - fn hook(&mut self, _params: &[i64], _intermediates: &[u8], _ignore: bool) {} + fn hook(&mut self, _params: &[i64], _intermediates: &[u8], _ignore: bool, _: char) {} fn put(&mut self, _byte: u8) {} fn unhook(&mut self) {} fn osc_dispatch(&mut self, params: &[&[u8]]) { @@ -454,7 +458,7 @@ mod tests { impl Perform for CsiDispatcher { fn print(&mut self, _: char) {} fn execute(&mut self, _byte: u8) {} - fn hook(&mut self, _params: &[i64], _intermediates: &[u8], _ignore: bool) {} + fn hook(&mut self, _params: &[i64], _intermediates: &[u8], _ignore: bool, _: char) {} fn put(&mut self, _byte: u8) {} fn unhook(&mut self) {} fn osc_dispatch(&mut self, _params: &[&[u8]]) { } @@ -465,6 +469,31 @@ mod tests { fn esc_dispatch(&mut self, _params: &[i64], _intermediates: &[u8], _ignore: bool, _byte: u8) {} } + #[derive(Default)] + struct DcsDispatcher { + dispatched_dcs: bool, + params: Vec, + c: Option, + s: Vec, + } + + impl Perform for DcsDispatcher { + fn print(&mut self, _: char) {} + fn execute(&mut self, _byte: u8) {} + fn hook(&mut self, params: &[i64], _intermediates: &[u8], _ignore: bool, c: char) { + self.c = Some(c); + self.params = params.to_vec(); + } + fn put(&mut self, byte: u8) { + self.s.push(byte); + } + fn unhook(&mut self) { + self.dispatched_dcs = true; + } + fn osc_dispatch(&mut self, _params: &[&[u8]]) { } + fn csi_dispatch(&mut self, _params: &[i64], _intermediates: &[u8], _ignore: bool, _c: char) {} + fn esc_dispatch(&mut self, _params: &[i64], _intermediates: &[u8], _ignore: bool, _byte: u8) {} + } #[test] fn parse_osc() { @@ -617,4 +646,26 @@ mod tests { assert_eq!(dispatcher.params[0], &[b'2']); assert_eq!(dispatcher.params[1], &INPUT[5..(INPUT.len() - 1)]); } + + #[test] + fn parse_dcs() { + static INPUT: &'static [u8] = &[ + 0x1b, 0x50, 0x30, 0x3b, 0x31, 0x7c, 0x31, 0x37, 0x2f, 0x61, 0x62, + 0x9c, + ]; + + // Create dispatcher and check state + let mut dispatcher = DcsDispatcher::default(); + + // Run parser using OSC_BYTES + let mut parser = Parser::new(); + for byte in INPUT { + parser.advance(&mut dispatcher, *byte); + } + + assert!(dispatcher.dispatched_dcs); + assert_eq!(dispatcher.params, vec![0, 1]); + assert_eq!(dispatcher.c, Some('|')); + assert_eq!(dispatcher.s, b"17/ab".to_vec()); + } } From c093a671ce3abaebef4c8e2a71a76ad8cd4670a5 Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Mon, 4 Nov 2019 17:48:06 +0100 Subject: [PATCH 57/99] Bump version to 0.4.0 --- CHANGELOG.md | 4 ++ Cargo.toml | 2 +- examples/parselog.rs | 23 ++++--- src/lib.rs | 154 +++++++++++++++++++++++++------------------ 4 files changed, 109 insertions(+), 74 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ba861ac5..443305b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ CHANGELOG ========= +## 0.4.0 + +- Fix handling of DCS escapes + ## 0.3.3 - Fix off-by-one error in CSI parsing when params list was at max length diff --git a/Cargo.toml b/Cargo.toml index 6cae2494..2d7a4577 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "vte" -version = "0.3.3" +version = "0.4.0" authors = ["Joe Wilm "] license = "Apache-2.0 OR MIT" description = "Parser for implementing terminal emulators" diff --git a/examples/parselog.rs b/examples/parselog.rs index acd56dc8..b63bcf8e 100644 --- a/examples/parselog.rs +++ b/examples/parselog.rs @@ -16,8 +16,10 @@ impl vte::Perform for Log { } fn hook(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, c: char) { - println!("[hook] params={:?}, intermediates={:?}, ignore={:?}, char={:?}", - params, intermediates, ignore, c); + println!( + "[hook] params={:?}, intermediates={:?}, ignore={:?}, char={:?}", + params, intermediates, ignore, c + ); } fn put(&mut self, byte: u8) { @@ -33,15 +35,18 @@ impl vte::Perform for Log { } fn csi_dispatch(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, c: char) { - println!("[csi_dispatch] params={:?}, intermediates={:?}, ignore={:?}, char={:?}", - params, intermediates, ignore, c); + println!( + "[csi_dispatch] params={:?}, intermediates={:?}, ignore={:?}, char={:?}", + params, intermediates, ignore, c + ); } fn esc_dispatch(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, byte: u8) { - println!("[esc_dispatch] params={:?}, intermediates={:?}, ignore={:?}, byte={:02x}", - params, intermediates, ignore, byte); + println!( + "[esc_dispatch] params={:?}, intermediates={:?}, ignore={:?}, byte={:02x}", + params, intermediates, ignore, byte + ); } - } fn main() { @@ -51,7 +56,7 @@ fn main() { let mut statemachine = vte::Parser::new(); let mut parser = Log; - let mut buf: [u8; 2048] = unsafe { std::mem::uninitialized() }; + let mut buf = [0; 2048]; loop { match handle.read(&mut buf) { @@ -60,7 +65,7 @@ fn main() { for byte in &buf[..n] { statemachine.advance(&mut parser, *byte); } - }, + } Err(err) => { println!("err: {}", err); break; diff --git a/src/lib.rs b/src/lib.rs index 4bd5d788..1b9f58c8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -34,34 +34,29 @@ extern crate utf8parse as utf8; -use core::mem; +use core::mem::{self, MaybeUninit}; -mod table; mod definitions; +mod table; -use definitions::{Action, State, unpack}; +use definitions::{unpack, Action, State}; -use table::{EXIT_ACTIONS, ENTRY_ACTIONS, STATE_CHANGE}; +use table::{ENTRY_ACTIONS, EXIT_ACTIONS, STATE_CHANGE}; impl State { /// Get exit action for this state #[inline(always)] pub fn exit_action(&self) -> Action { - unsafe { - *EXIT_ACTIONS.get_unchecked(*self as usize) - } + unsafe { *EXIT_ACTIONS.get_unchecked(*self as usize) } } /// Get entry action for this state #[inline(always)] pub fn entry_action(&self) -> Action { - unsafe { - *ENTRY_ACTIONS.get_unchecked(*self as usize) - } + unsafe { *ENTRY_ACTIONS.get_unchecked(*self as usize) } } } - const MAX_INTERMEDIATES: usize = 2; const MAX_OSC_RAW: usize = 1024; const MAX_PARAMS: usize = 16; @@ -156,7 +151,8 @@ impl Parser { #[inline] fn process_utf8

(&mut self, performer: &mut P, byte: u8) - where P: Perform + where + P: Perform, { let mut receiver = VtUtf8Receiver(performer, &mut self.state); let utf8_parser = &mut self.utf8_parser; @@ -165,7 +161,8 @@ impl Parser { #[inline] fn perform_state_change

(&mut self, performer: &mut P, state: State, action: Action, byte: u8) - where P: Perform + where + P: Perform, { macro_rules! maybe_action { ($action:expr, $arg:expr) => { @@ -173,16 +170,16 @@ impl Parser { Action::None => (), action => { self.perform_action(performer, action, $arg); - }, + } } - } + }; } match state { State::Anywhere => { // Just run the action self.perform_action(performer, action, byte); - }, + } state => { // Exit action for previous state let exit_action = self.state.exit_action(); @@ -205,16 +202,19 @@ impl Parser { /// The aliasing is needed here for multiple slices into self.osc_raw #[inline] fn osc_dispatch(&self, performer: &mut P) { - let mut slices: [&[u8]; MAX_PARAMS] = unsafe { mem::uninitialized() }; + let mut slices: [MaybeUninit<&[u8]>; MAX_PARAMS] = + unsafe { MaybeUninit::uninit().assume_init() }; for i in 0..self.osc_num_params { let indices = self.osc_params[i]; - slices[i] = &self.osc_raw[indices.0..indices.1]; + slices[i] = MaybeUninit::new(&self.osc_raw[indices.0..indices.1]); } - performer.osc_dispatch( - &slices[..self.osc_num_params], - ); + unsafe { + performer.osc_dispatch(mem::transmute::<_, &[&[u8]]>( + &slices[..self.osc_num_params], + )); + } } #[inline] @@ -232,12 +232,12 @@ impl Parser { self.ignoring, byte as char, ); - }, + } Action::Put => performer.put(byte), Action::OscStart => { self.osc_idx = 0; self.osc_num_params = 0; - }, + } Action::OscPut => { let idx = self.osc_idx; if idx == self.osc_raw.len() { @@ -254,7 +254,7 @@ impl Parser { // First param is special - 0 to current byte index 0 => { self.osc_params[param_idx] = (0, idx); - }, + } // All other params depend on previous indexing _ => { @@ -269,7 +269,7 @@ impl Parser { self.osc_raw[idx] = byte; self.osc_idx += 1; } - }, + } Action::OscEnd => { let param_idx = self.osc_num_params; let idx = self.osc_idx; @@ -282,7 +282,7 @@ impl Parser { 0 => { self.osc_params[param_idx] = (0, idx); self.osc_num_params += 1; - }, + } // All other params depend on previous indexing _ => { @@ -293,7 +293,7 @@ impl Parser { } } self.osc_dispatch(performer); - }, + } Action::Unhook => performer.unhook(), Action::CsiDispatch => { self.params[self.num_params] = self.param; @@ -303,20 +303,15 @@ impl Parser { self.params(), self.intermediates(), self.ignoring, - byte as char + byte as char, ); self.num_params = 0; self.param = 0; } Action::EscDispatch => { - performer.esc_dispatch( - self.params(), - self.intermediates(), - self.ignoring, - byte - ); - }, + performer.esc_dispatch(self.params(), self.intermediates(), self.ignoring, byte); + } Action::Ignore | Action::None => (), Action::Collect => { if self.intermediate_idx == MAX_INTERMEDIATES { @@ -325,7 +320,7 @@ impl Parser { self.intermediates[self.intermediate_idx] = byte; self.intermediate_idx += 1; } - }, + } Action::Param => { if byte == b';' { // Completed a param @@ -343,15 +338,15 @@ impl Parser { self.param = self.param.saturating_mul(10); self.param = self.param.saturating_add((byte - b'0') as i64); } - }, + } Action::Clear => { self.intermediate_idx = 0; self.num_params = 0; self.ignoring = false; - }, + } Action::BeginUtf8 => { self.process_utf8(performer, byte); - }, + } } } } @@ -416,15 +411,15 @@ extern crate std; #[cfg(test)] mod tests { - use std::vec::Vec; use super::{Parser, Perform}; use core::i64; + use std::vec::Vec; - static OSC_BYTES: &'static [u8] = &[0x1b, 0x5d, // Begin OSC - b'2', b';', b'j', b'w', b'i', b'l', b'm', b'@', b'j', b'w', b'i', b'l', - b'm', b'-', b'd', b'e', b's', b'k', b':', b' ', b'~', b'/', b'c', b'o', - b'd', b'e', b'/', b'a', b'l', b'a', b'c', b'r', b'i', b't', b't', b'y', - 0x07 // End OSC + static OSC_BYTES: &'static [u8] = &[ + 0x1b, 0x5d, // Begin OSC + b'2', b';', b'j', b'w', b'i', b'l', b'm', b'@', b'j', b'w', b'i', b'l', b'm', b'-', b'd', + b'e', b's', b'k', b':', b' ', b'~', b'/', b'c', b'o', b'd', b'e', b'/', b'a', b'l', b'a', + b'c', b'r', b'i', b't', b't', b'y', 0x07, // End OSC ]; #[derive(Default)] @@ -445,8 +440,22 @@ mod tests { self.dispatched_osc = true; self.params = params.iter().map(|p| p.to_vec()).collect(); } - fn csi_dispatch(&mut self, _params: &[i64], _intermediates: &[u8], _ignore: bool, _c: char) {} - fn esc_dispatch(&mut self, _params: &[i64], _intermediates: &[u8], _ignore: bool, _byte: u8) {} + fn csi_dispatch( + &mut self, + _params: &[i64], + _intermediates: &[u8], + _ignore: bool, + _c: char, + ) { + } + fn esc_dispatch( + &mut self, + _params: &[i64], + _intermediates: &[u8], + _ignore: bool, + _byte: u8, + ) { + } } #[derive(Default)] @@ -461,12 +470,19 @@ mod tests { fn hook(&mut self, _params: &[i64], _intermediates: &[u8], _ignore: bool, _: char) {} fn put(&mut self, _byte: u8) {} fn unhook(&mut self) {} - fn osc_dispatch(&mut self, _params: &[&[u8]]) { } + fn osc_dispatch(&mut self, _params: &[&[u8]]) {} fn csi_dispatch(&mut self, params: &[i64], _intermediates: &[u8], _ignore: bool, _c: char) { self.dispatched_csi = true; self.params.push(params.to_vec()); } - fn esc_dispatch(&mut self, _params: &[i64], _intermediates: &[u8], _ignore: bool, _byte: u8) {} + fn esc_dispatch( + &mut self, + _params: &[i64], + _intermediates: &[u8], + _ignore: bool, + _byte: u8, + ) { + } } #[derive(Default)] @@ -490,9 +506,23 @@ mod tests { fn unhook(&mut self) { self.dispatched_dcs = true; } - fn osc_dispatch(&mut self, _params: &[&[u8]]) { } - fn csi_dispatch(&mut self, _params: &[i64], _intermediates: &[u8], _ignore: bool, _c: char) {} - fn esc_dispatch(&mut self, _params: &[i64], _intermediates: &[u8], _ignore: bool, _byte: u8) {} + fn osc_dispatch(&mut self, _params: &[&[u8]]) {} + fn csi_dispatch( + &mut self, + _params: &[i64], + _intermediates: &[u8], + _ignore: bool, + _c: char, + ) { + } + fn esc_dispatch( + &mut self, + _params: &[i64], + _intermediates: &[u8], + _ignore: bool, + _byte: u8, + ) { + } } #[test] @@ -552,7 +582,6 @@ mod tests { for param in dispatcher.params.iter() { assert_eq!(param.len(), 0); } - } #[test] @@ -565,7 +594,6 @@ mod tests { let mut dispatcher = CsiDispatcher::default(); assert!(!dispatcher.dispatched_csi); - // Run parser using OSC_BYTES let mut parser = Parser::new(); for byte in INPUT { @@ -576,7 +604,6 @@ mod tests { assert!(dispatcher.dispatched_csi); assert_eq!(dispatcher.params.len(), 1); assert_eq!(dispatcher.params[0].len(), MAX_PARAMS); - } #[test] @@ -594,7 +621,6 @@ mod tests { #[test] fn parse_semi_set_underline() { - // Create dispatcher and check state let mut dispatcher = CsiDispatcher::default(); @@ -621,20 +647,21 @@ mod tests { } assert_eq!(dispatcher.params[0], &[i64::MAX as i64]); - } #[test] fn parse_osc_with_utf8_arguments() { static INPUT: &'static [u8] = &[ - 0x0d, 0x1b, 0x5d, 0x32, 0x3b, 0x65, 0x63, 0x68, 0x6f, 0x20, 0x27, - 0xc2, 0xaf, 0x5c, 0x5f, 0x28, 0xe3, 0x83, 0x84, 0x29, 0x5f, 0x2f, - 0xc2, 0xaf, 0x27, 0x20, 0x26, 0x26, 0x20, 0x73, 0x6c, 0x65, 0x65, - 0x70, 0x20, 0x31, 0x07 + 0x0d, 0x1b, 0x5d, 0x32, 0x3b, 0x65, 0x63, 0x68, 0x6f, 0x20, 0x27, 0xc2, 0xaf, 0x5c, + 0x5f, 0x28, 0xe3, 0x83, 0x84, 0x29, 0x5f, 0x2f, 0xc2, 0xaf, 0x27, 0x20, 0x26, 0x26, + 0x20, 0x73, 0x6c, 0x65, 0x65, 0x70, 0x20, 0x31, 0x07, ]; // Create dispatcher and check state - let mut dispatcher = OscDispatcher { params: vec![], dispatched_osc: false }; + let mut dispatcher = OscDispatcher { + params: vec![], + dispatched_osc: false, + }; // Run parser using OSC_BYTES let mut parser = Parser::new(); @@ -650,8 +677,7 @@ mod tests { #[test] fn parse_dcs() { static INPUT: &'static [u8] = &[ - 0x1b, 0x50, 0x30, 0x3b, 0x31, 0x7c, 0x31, 0x37, 0x2f, 0x61, 0x62, - 0x9c, + 0x1b, 0x50, 0x30, 0x3b, 0x31, 0x7c, 0x31, 0x37, 0x2f, 0x61, 0x62, 0x9c, ]; // Create dispatcher and check state From a035f334a108f4a694cf022e063edb9c8ac349ad Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Fri, 22 Nov 2019 23:24:40 +0100 Subject: [PATCH 58/99] Add dynamic buffer support --- .travis.yml | 4 +-- Cargo.toml | 11 +++---- src/lib.rs | 84 +++++++++++++++++++++++++++++++++++++++++++---------- 3 files changed, 77 insertions(+), 22 deletions(-) diff --git a/.travis.yml b/.travis.yml index 998e56df..5bd24eae 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,5 +7,5 @@ rust: - nightly script: - - cargo test --all - + - cargo test --no-default-features + - cargo test diff --git a/Cargo.toml b/Cargo.toml index 2d7a4577..f6a4b55c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,9 +9,10 @@ repository = "https://github.com/jwilm/vte" documentation = "https://docs.rs/vte/" readme = "README.md" -[dependencies.utf8parse] -path = "utf8parse" -version = "0.1" - -[workspace] +[dependencies] +arrayvec = { version = "0.5.1", default-features = false, optional = true } +utf8parse = { path = "utf8parse", version = "0.1.0" } +[features] +default = ["no_std"] +no_std = ["arrayvec"] diff --git a/src/lib.rs b/src/lib.rs index 1b9f58c8..4daeba2f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,12 +30,19 @@ //! [`Parser`]: struct.Parser.html //! [`Perform`]: trait.Perform.html //! [Paul Williams' ANSI parser state machine]: https://vt100.net/emu/dec_ansi_parser -#![no_std] +#![cfg_attr(feature = "no_std", no_std)] +#[cfg(feature = "no_std")] +extern crate arrayvec; +#[cfg(not(feature = "no_std"))] +extern crate core; extern crate utf8parse as utf8; use core::mem::{self, MaybeUninit}; +#[cfg(feature = "no_std")] +use arrayvec::ArrayVec; + mod definitions; mod table; @@ -58,6 +65,7 @@ impl State { } const MAX_INTERMEDIATES: usize = 2; +#[cfg(any(feature = "no_std", test))] const MAX_OSC_RAW: usize = 1024; const MAX_PARAMS: usize = 16; @@ -85,9 +93,11 @@ pub struct Parser { params: [i64; MAX_PARAMS], param: i64, num_params: usize, - osc_raw: [u8; MAX_OSC_RAW], + #[cfg(feature = "no_std")] + osc_raw: ArrayVec<[u8; MAX_OSC_RAW]>, + #[cfg(not(feature = "no_std"))] + osc_raw: Vec, osc_params: [(usize, usize); MAX_PARAMS], - osc_idx: usize, osc_num_params: usize, ignoring: bool, utf8_parser: utf8::Parser, @@ -103,9 +113,11 @@ impl Parser { params: [0i64; MAX_PARAMS], param: 0, num_params: 0, - osc_raw: [0; MAX_OSC_RAW], + #[cfg(feature = "no_std")] + osc_raw: ArrayVec::new(), + #[cfg(not(feature = "no_std"))] + osc_raw: Vec::new(), osc_params: [(0, 0); MAX_PARAMS], - osc_idx: 0, osc_num_params: 0, ignoring: false, utf8_parser: utf8::Parser::new(), @@ -235,15 +247,19 @@ impl Parser { } Action::Put => performer.put(byte), Action::OscStart => { - self.osc_idx = 0; + self.osc_raw.clear(); self.osc_num_params = 0; } Action::OscPut => { - let idx = self.osc_idx; - if idx == self.osc_raw.len() { - return; + #[cfg(feature = "no_std")] + { + if self.osc_raw.is_full() { + return; + } } + let idx = self.osc_raw.len(); + // Param separator if byte == b';' { let param_idx = self.osc_num_params; @@ -266,13 +282,12 @@ impl Parser { self.osc_num_params += 1; } else { - self.osc_raw[idx] = byte; - self.osc_idx += 1; + self.osc_raw.push(byte); } } Action::OscEnd => { let param_idx = self.osc_num_params; - let idx = self.osc_idx; + let idx = self.osc_raw.len(); match param_idx { // Finish last parameter if not already maxed @@ -405,15 +420,16 @@ pub trait Perform { fn esc_dispatch(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, byte: u8); } -#[cfg(test)] +#[cfg(all(test, feature = "no_std"))] #[macro_use] extern crate std; #[cfg(test)] mod tests { - use super::{Parser, Perform}; - use core::i64; + use super::*; + use std::vec::Vec; + use core::i64; static OSC_BYTES: &'static [u8] = &[ 0x1b, 0x5d, // Begin OSC @@ -694,4 +710,42 @@ mod tests { assert_eq!(dispatcher.c, Some('|')); assert_eq!(dispatcher.s, b"17/ab".to_vec()); } + + #[test] + fn exceed_max_buffer_size() { + static NUM_BYTES: usize = MAX_OSC_RAW + 100; + static INPUT_START: &'static [u8] = &[ + 0x1b, b']', b'5', b'2', b';', b's' + ]; + static INPUT_END: &'static [u8] = &[b'\x07']; + + let mut dispatcher = OscDispatcher::default(); + let mut parser = Parser::new(); + + // Create valid OSC escape + for byte in INPUT_START { + parser.advance(&mut dispatcher, *byte); + } + + // Exceed max buffer size + for _ in 0..NUM_BYTES { + parser.advance(&mut dispatcher, b'a'); + } + + // Terminate escape for dispatch + for byte in INPUT_END { + parser.advance(&mut dispatcher, *byte); + } + + assert!(dispatcher.dispatched_osc); + + assert_eq!(dispatcher.params.len(), 2); + assert_eq!(dispatcher.params[0], b"52"); + + #[cfg(not(feature = "no_std"))] + assert_eq!(dispatcher.params[1].len(), NUM_BYTES + INPUT_END.len()); + + #[cfg(feature = "no_std")] + assert_eq!(dispatcher.params[1].len(), MAX_OSC_RAW - dispatcher.params[0].len()); + } } From ea940fcb74abce67b927788e4f9f64fc63073d37 Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Sat, 23 Nov 2019 02:01:09 +0100 Subject: [PATCH 59/99] Update to Rust 2018 This moves all crates in the workspace to the latest Rust standard and resolves various style and formatting issues. Fixes #32. --- .travis.yml | 4 +- Cargo.toml | 16 +- codegen/Cargo.toml | 1 + codegen/src/ext/utf8.rs | 173 +++--- codegen/src/ext/vt.rs | 179 +++--- codegen/src/main.rs | 8 +- examples/parselog.rs | 8 +- rustfmt.toml | 13 + src/definitions.rs | 77 +-- src/lib.rs | 152 +++-- src/table.rs | 727 +++++++++++------------- utf8parse/Cargo.toml | 14 +- utf8parse/src/lib.rs | 64 +-- utf8parse/src/table.rs | 300 +++++----- utf8parse/src/types.rs | 7 +- utf8parse/{src => tests}/UTF-8-demo.txt | 0 utf8parse/tests/utf-8-demo.rs | 31 + 17 files changed, 834 insertions(+), 940 deletions(-) create mode 100644 rustfmt.toml rename utf8parse/{src => tests}/UTF-8-demo.txt (100%) create mode 100644 utf8parse/tests/utf-8-demo.rs diff --git a/.travis.yml b/.travis.yml index 5bd24eae..bc28ecea 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,5 +7,5 @@ rust: - nightly script: - - cargo test --no-default-features - - cargo test + - cargo test --workspace --no-default-features + - cargo test --workspace diff --git a/Cargo.toml b/Cargo.toml index f6a4b55c..d4c0133a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,13 +1,16 @@ [package] -name = "vte" -version = "0.4.0" -authors = ["Joe Wilm "] -license = "Apache-2.0 OR MIT" +authors = ["Joe Wilm ", "Christian Duerr "] description = "Parser for implementing terminal emulators" -keywords = ["ansi", "vte", "parser", "terminal"] repository = "https://github.com/jwilm/vte" documentation = "https://docs.rs/vte/" +keywords = ["ansi", "vte", "parser", "terminal"] +categories = ["parsing", "no-std"] +exclude = ["/.travis.yml"] readme = "README.md" +license = "Apache-2.0 OR MIT" +version = "0.4.0" +name = "vte" +edition = "2018" [dependencies] arrayvec = { version = "0.5.1", default-features = false, optional = true } @@ -16,3 +19,6 @@ utf8parse = { path = "utf8parse", version = "0.1.0" } [features] default = ["no_std"] no_std = ["arrayvec"] + +[workspace] +members = ["utf8parse", "codegen"] diff --git a/codegen/Cargo.toml b/codegen/Cargo.toml index a48de052..ec5a741d 100644 --- a/codegen/Cargo.toml +++ b/codegen/Cargo.toml @@ -2,6 +2,7 @@ name = "codegen" version = "0.1.0" authors = ["Joe Wilm "] +edition = "2018" [dependencies] syntex = "0.43.0" diff --git a/codegen/src/ext/utf8.rs b/codegen/src/ext/utf8.rs index 17ebc223..898722b0 100644 --- a/codegen/src/ext/utf8.rs +++ b/codegen/src/ext/utf8.rs @@ -3,27 +3,28 @@ use std::fmt; use syntex::Registry; -use syntex_syntax::ast::{self, ExprKind, Arm, Expr, PatKind, LitKind, Pat}; +use syntex_syntax::ast::{self, Arm, Expr, ExprKind, LitKind, Pat, PatKind}; use syntex_syntax::codemap::Span; -use syntex_syntax::ext::base::{ExtCtxt, MacEager, MacResult, DummyResult}; +use syntex_syntax::ext::base::{DummyResult, ExtCtxt, MacEager, MacResult}; use syntex_syntax::ext::build::AstBuilder; -use syntex_syntax::parse::token::{Token, DelimToken}; use syntex_syntax::parse::parser::Parser; +use syntex_syntax::parse::token::{DelimToken, Token}; use syntex_syntax::parse::PResult; use syntex_syntax::ptr::P; use syntex_syntax::tokenstream::TokenTree; -#[path="../../../utf8parse/src/types.rs"] +#[path = "../../../utf8parse/src/types.rs"] mod types; -use self::types::{State, Action, pack}; +use self::types::{pack, Action, State}; pub fn register(registry: &mut Registry) { registry.add_macro("utf8_state_table", expand_state_table); } fn state_from_str(s: &S) -> Result - where S: AsRef +where + S: AsRef, { Ok(match s.as_ref() { "State::Ground" => State::Ground, @@ -34,12 +35,13 @@ fn state_from_str(s: &S) -> Result "State::U3_2_ed" => State::U3_2_ed, "State::Utf8_4_3_f0" => State::Utf8_4_3_f0, "State::Utf8_4_3_f4" => State::Utf8_4_3_f4, - _ => return Err(()) + _ => return Err(()), }) } fn action_from_str(s: &S) -> Result - where S: AsRef +where + S: AsRef, { Ok(match s.as_ref() { "Action::InvalidSequence" => Action::InvalidSequence, @@ -50,13 +52,13 @@ fn action_from_str(s: &S) -> Result "Action::SetByte3" => Action::SetByte3, "Action::SetByte3Top" => Action::SetByte3Top, "Action::SetByte4" => Action::SetByte4, - _ => return Err(()) + _ => return Err(()), }) } fn parse_table_input_mappings<'a>(parser: &mut Parser<'a>) -> PResult<'a, Vec> { // Must start on open brace - try!(parser.expect(&Token::OpenDelim(DelimToken::Brace))); + parser.expect(&Token::OpenDelim(DelimToken::Brace))?; let mut arms: Vec = Vec::new(); while parser.token != Token::CloseDelim(DelimToken::Brace) { @@ -65,7 +67,7 @@ fn parse_table_input_mappings<'a>(parser: &mut Parser<'a>) -> PResult<'a, Vec { // Recover by skipping to the end of the block. return Err(e); - } + }, } } @@ -83,53 +85,43 @@ struct TableDefinitionExprs { fn state_from_expr(expr: P, cx: &mut ExtCtxt) -> Result { let s = match expr.node { - ExprKind::Path(ref _qself, ref path) => { - path.to_string() - }, + ExprKind::Path(ref _qself, ref path) => path.to_string(), _ => { cx.span_err(expr.span, "expected State"); - return Err(()) - } + return Err(()); + }, }; state_from_str(&s).map_err(|_| { cx.span_err(expr.span, "expected State"); - () }) } fn u8_lit_from_expr(expr: &Expr, cx: &mut ExtCtxt) -> Result { - static MSG: &'static str = "expected u8 int literal"; + static MSG: &str = "expected u8 int literal"; match expr.node { - ExprKind::Lit(ref lit) => { - match lit.node { - LitKind::Int(val, _) => { - Ok(val as u8) - }, - _ => { - cx.span_err(lit.span, MSG); - return Err(()); - } - } + ExprKind::Lit(ref lit) => match lit.node { + LitKind::Int(val, _) => Ok(val as u8), + _ => { + cx.span_err(lit.span, MSG); + Err(()) + }, }, _ => { cx.span_err(expr.span, MSG); - return Err(()); - } + Err(()) + }, } } fn input_mapping_from_arm(arm: Arm, cx: &mut ExtCtxt) -> Result { let Arm { pats, body, .. } = arm; - let input = try!(InputDefinition::from_pat(&pats[0], cx)); - let transition = try!(Transition::from_expr(&body, cx)); + let input = InputDefinition::from_pat(&pats[0], cx)?; + let transition = Transition::from_expr(&body, cx)?; - Ok(InputMapping { - input: input, - transition: transition, - }) + Ok(InputMapping { input, transition }) } /// What happens when certain input is received @@ -143,11 +135,11 @@ enum Transition { impl fmt::Debug for Transition { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - Transition::State(state) => try!(write!(f, "State({:?})", state)), - Transition::Action(action) => try!(write!(f, "Action({:?})", action)), + Transition::State(state) => write!(f, "State({:?})", state)?, + Transition::Action(action) => write!(f, "Action({:?})", action)?, Transition::StateAction(state, action) => { - try!(write!(f, "StateAction({:?}, {:?})", state, action)); - } + write!(f, "StateAction({:?}, {:?})", state, action)?; + }, } write!(f, " -> {:?}", self.pack_u8()) @@ -156,8 +148,8 @@ impl fmt::Debug for Transition { impl Transition { // State is stored in the top 4 bits - fn pack_u8(&self) -> u8 { - match *self { + fn pack_u8(self) -> u8 { + match self { Transition::State(state) => pack(state, Action::InvalidSequence), Transition::Action(action) => pack(State::Ground, action), Transition::StateAction(state, action) => pack(state, action), @@ -176,15 +168,13 @@ impl Transition { if let ExprKind::Path(_, ref path) = tup_expr.node { let path_str = path.to_string(); if path_str.starts_with('A') { - action = Some(try!(action_from_str(&path_str) - .map_err(|_| { - cx.span_err(expr.span, "invalid action"); - }))); + action = Some(action_from_str(&path_str).map_err(|_| { + cx.span_err(expr.span, "invalid action"); + })?); } else { - state = Some(try!(state_from_str(&path_str) - .map_err(|_| { - cx.span_err(expr.span, "invalid state"); - }))); + state = Some(state_from_str(&path_str).map_err(|_| { + cx.span_err(expr.span, "invalid state"); + })?); } } } @@ -196,7 +186,7 @@ impl Transition { _ => { cx.span_err(expr.span, "expected Action and/or State"); Err(()) - } + }, } }, ExprKind::Path(_, ref path) => { @@ -204,16 +194,14 @@ impl Transition { let path_str = path.to_string(); if path_str.starts_with('A') { - let action = try!(action_from_str(&path_str) - .map_err(|_| { - cx.span_err(expr.span, "invalid action"); - })); + let action = action_from_str(&path_str).map_err(|_| { + cx.span_err(expr.span, "invalid action"); + })?; Ok(Transition::Action(action)) } else { - let state = try!(state_from_str(&path_str) - .map_err(|_| { - cx.span_err(expr.span, "invalid state"); - })); + let state = state_from_str(&path_str).map_err(|_| { + cx.span_err(expr.span, "invalid state"); + })?; Ok(Transition::State(state)) } @@ -221,7 +209,7 @@ impl Transition { _ => { cx.span_err(expr.span, "expected Action and/or State"); Err(()) - } + }, } } } @@ -229,25 +217,23 @@ impl Transition { #[derive(Debug)] enum InputDefinition { Specific(u8), - Range { start: u8, end: u8 } + Range { start: u8, end: u8 }, } impl InputDefinition { fn from_pat(pat: &Pat, cx: &mut ExtCtxt) -> Result { Ok(match pat.node { PatKind::Lit(ref lit_expr) => { - InputDefinition::Specific(try!(u8_lit_from_expr(&lit_expr, cx))) + InputDefinition::Specific(u8_lit_from_expr(&lit_expr, cx)?) }, - PatKind::Range(ref start_expr, ref end_expr) => { - InputDefinition::Range { - start: try!(u8_lit_from_expr(start_expr, cx)), - end: try!(u8_lit_from_expr(end_expr, cx)), - } + PatKind::Range(ref start_expr, ref end_expr) => InputDefinition::Range { + start: u8_lit_from_expr(start_expr, cx)?, + end: u8_lit_from_expr(end_expr, cx)?, }, _ => { cx.span_err(pat.span, "expected literal or range expression"); - return Err(()) - } + return Err(()); + }, }) } } @@ -266,45 +252,39 @@ struct TableDefinition { fn parse_raw_definitions( definitions: Vec, - cx: &mut ExtCtxt + cx: &mut ExtCtxt, ) -> Result, ()> { let mut out = Vec::new(); for raw in definitions { let TableDefinitionExprs { state_expr, mapping_arms } = raw; - let state = try!(state_from_expr(state_expr, cx)); + let state = state_from_expr(state_expr, cx)?; let mut mappings = Vec::new(); for arm in mapping_arms { - mappings.push(try!(input_mapping_from_arm(arm, cx))); + mappings.push(input_mapping_from_arm(arm, cx)?); } - out.push(TableDefinition { - state: state, - mappings: mappings, - }) + out.push(TableDefinition { state, mappings }) } Ok(out) } fn parse_table_definition<'a>(parser: &mut Parser<'a>) -> PResult<'a, TableDefinitionExprs> { - let state_expr = try!(parser.parse_expr()); - try!(parser.expect(&Token::FatArrow)); - let mappings = try!(parse_table_input_mappings(parser)); + let state_expr = parser.parse_expr()?; + parser.expect(&Token::FatArrow)?; + let mappings = parse_table_input_mappings(parser)?; - Ok(TableDefinitionExprs { - state_expr: state_expr, - mapping_arms: mappings - }) + Ok(TableDefinitionExprs { state_expr, mapping_arms: mappings }) } -fn parse_table_definition_list<'a>(parser: &mut Parser<'a>) - -> PResult<'a, Vec> -{ +fn parse_table_definition_list<'a>( + parser: &mut Parser<'a>, +) -> PResult<'a, Vec> { let mut definitions = Vec::new(); while parser.token != Token::Eof { - definitions.push(try!(parse_table_definition(parser))); + definitions.push(parse_table_definition(parser)?); parser.eat(&Token::Comma); } @@ -312,7 +292,8 @@ fn parse_table_definition_list<'a>(parser: &mut Parser<'a>) } fn build_state_tables(defs: T) -> [[u8; 256]; 8] - where T: AsRef<[TableDefinition]> +where + T: AsRef<[TableDefinition]>, { let mut result = [[0u8; 256]; 8]; @@ -341,11 +322,10 @@ fn build_state_tables(defs: T) -> [[u8; 256]; 8] } fn build_table_ast(cx: &mut ExtCtxt, sp: Span, table: [[u8; 256]; 8]) -> P { - let table = table.iter() + let table = table + .iter() .map(|list| { - let exprs = list.iter() - .map(|num| cx.expr_u8(sp, *num)) - .collect(); + let exprs = list.iter().map(|num| cx.expr_u8(sp, *num)).collect(); cx.expr_vec(sp, exprs) }) .collect(); @@ -356,9 +336,8 @@ fn build_table_ast(cx: &mut ExtCtxt, sp: Span, table: [[u8; 256]; 8]) -> P( cx: &'cx mut ExtCtxt, sp: Span, - args: &[TokenTree]) - -> Box -{ + args: &[TokenTree], +) -> Box { macro_rules! ptry { ($pres:expr) => { match $pres { @@ -366,9 +345,9 @@ fn expand_state_table<'cx>( Err(mut err) => { err.emit(); return DummyResult::any(sp); - } + }, } - } + }; } // Parse the lookup spec diff --git a/codegen/src/ext/vt.rs b/codegen/src/ext/vt.rs index 3f5bcf39..aff7d68c 100644 --- a/codegen/src/ext/vt.rs +++ b/codegen/src/ext/vt.rs @@ -3,27 +3,28 @@ use std::fmt; use syntex::Registry; -use syntex_syntax::ast::{self, ExprKind, Arm, Expr, PatKind, LitKind, Pat}; +use syntex_syntax::ast::{self, Arm, Expr, ExprKind, LitKind, Pat, PatKind}; use syntex_syntax::codemap::Span; -use syntex_syntax::ext::base::{ExtCtxt, MacEager, MacResult, DummyResult}; +use syntex_syntax::ext::base::{DummyResult, ExtCtxt, MacEager, MacResult}; use syntex_syntax::ext::build::AstBuilder; -use syntex_syntax::parse::token::{Token, DelimToken}; use syntex_syntax::parse::parser::Parser; +use syntex_syntax::parse::token::{DelimToken, Token}; use syntex_syntax::parse::PResult; use syntex_syntax::ptr::P; use syntex_syntax::tokenstream::TokenTree; -#[path="../../../src/definitions.rs"] +#[path = "../../../src/definitions.rs"] mod definitions; -use self::definitions::{State, Action}; +use self::definitions::{Action, State}; pub fn register(registry: &mut Registry) { registry.add_macro("vt_state_table", expand_state_table); } fn state_from_str(s: &S) -> Result - where S: AsRef +where + S: AsRef, { Ok(match s.as_ref() { "State::Anywhere" => State::Anywhere, @@ -42,12 +43,13 @@ fn state_from_str(s: &S) -> Result "State::OscString" => State::OscString, "State::SosPmApcString" => State::SosPmApcString, "State::Utf8" => State::Utf8, - _ => return Err(()) + _ => return Err(()), }) } fn action_from_str(s: &S) -> Result - where S: AsRef +where + S: AsRef, { Ok(match s.as_ref() { "Action::None" => Action::None, @@ -66,13 +68,13 @@ fn action_from_str(s: &S) -> Result "Action::Put" => Action::Put, "Action::Unhook" => Action::Unhook, "Action::BeginUtf8" => Action::BeginUtf8, - _ => return Err(()) + _ => return Err(()), }) } fn parse_table_input_mappings<'a>(parser: &mut Parser<'a>) -> PResult<'a, Vec> { // Must start on open brace - try!(parser.expect(&Token::OpenDelim(DelimToken::Brace))); + parser.expect(&Token::OpenDelim(DelimToken::Brace))?; let mut arms: Vec = Vec::new(); while parser.token != Token::CloseDelim(DelimToken::Brace) { @@ -81,7 +83,7 @@ fn parse_table_input_mappings<'a>(parser: &mut Parser<'a>) -> PResult<'a, Vec { // Recover by skipping to the end of the block. return Err(e); - } + }, } } @@ -99,53 +101,43 @@ struct TableDefinitionExprs { fn state_from_expr(expr: P, cx: &mut ExtCtxt) -> Result { let s = match expr.node { - ExprKind::Path(ref _qself, ref path) => { - path.to_string() - }, + ExprKind::Path(ref _qself, ref path) => path.to_string(), _ => { cx.span_err(expr.span, "expected State"); - return Err(()) - } + return Err(()); + }, }; state_from_str(&s).map_err(|_| { cx.span_err(expr.span, "expected State"); - () }) } fn u8_lit_from_expr(expr: &Expr, cx: &mut ExtCtxt) -> Result { - static MSG: &'static str = "expected u8 int literal"; + static MSG: &str = "expected u8 int literal"; match expr.node { - ExprKind::Lit(ref lit) => { - match lit.node { - LitKind::Int(val, _) => { - Ok(val as u8) - }, - _ => { - cx.span_err(lit.span, MSG); - return Err(()); - } - } + ExprKind::Lit(ref lit) => match lit.node { + LitKind::Int(val, _) => Ok(val as u8), + _ => { + cx.span_err(lit.span, MSG); + Err(()) + }, }, _ => { cx.span_err(expr.span, MSG); - return Err(()); - } + Err(()) + }, } } fn input_mapping_from_arm(arm: Arm, cx: &mut ExtCtxt) -> Result { let Arm { pats, body, .. } = arm; - let input = try!(InputDefinition::from_pat(&pats[0], cx)); - let transition = try!(Transition::from_expr(&body, cx)); + let input = InputDefinition::from_pat(&pats[0], cx)?; + let transition = Transition::from_expr(&body, cx)?; - Ok(InputMapping { - input: input, - transition: transition, - }) + Ok(InputMapping { input, transition }) } /// What happens when certain input is received @@ -159,11 +151,11 @@ enum Transition { impl fmt::Debug for Transition { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - Transition::State(state) => try!(write!(f, "State({:?})", state)), - Transition::Action(action) => try!(write!(f, "Action({:?})", action)), + Transition::State(state) => write!(f, "State({:?})", state)?, + Transition::Action(action) => write!(f, "Action({:?})", action)?, Transition::StateAction(state, action) => { - try!(write!(f, "StateAction({:?}, {:?})", state, action)); - } + write!(f, "StateAction({:?}, {:?})", state, action)?; + }, } write!(f, " -> {:?}", self.pack_u8()) @@ -172,13 +164,11 @@ impl fmt::Debug for Transition { impl Transition { // State is stored in the top 4 bits - fn pack_u8(&self) -> u8 { - match *self { + fn pack_u8(self) -> u8 { + match self { Transition::State(state) => state as u8, Transition::Action(action) => (action as u8) << 4, - Transition::StateAction(state, action) => { - ((action as u8) << 4) | (state as u8) - } + Transition::StateAction(state, action) => ((action as u8) << 4) | (state as u8), } } } @@ -194,15 +184,13 @@ impl Transition { if let ExprKind::Path(_, ref path) = tup_expr.node { let path_str = path.to_string(); if path_str.starts_with('A') { - action = Some(try!(action_from_str(&path_str) - .map_err(|_| { - cx.span_err(expr.span, "invalid action"); - }))); + action = Some(action_from_str(&path_str).map_err(|_| { + cx.span_err(expr.span, "invalid action"); + })?); } else { - state = Some(try!(state_from_str(&path_str) - .map_err(|_| { - cx.span_err(expr.span, "invalid state"); - }))); + state = Some(state_from_str(&path_str).map_err(|_| { + cx.span_err(expr.span, "invalid state"); + })?); } } } @@ -214,7 +202,7 @@ impl Transition { _ => { cx.span_err(expr.span, "expected Action and/or State"); Err(()) - } + }, } }, ExprKind::Path(_, ref path) => { @@ -222,16 +210,14 @@ impl Transition { let path_str = path.to_string(); if path_str.starts_with('A') { - let action = try!(action_from_str(&path_str) - .map_err(|_| { - cx.span_err(expr.span, "invalid action"); - })); + let action = action_from_str(&path_str).map_err(|_| { + cx.span_err(expr.span, "invalid action"); + })?; Ok(Transition::Action(action)) } else { - let state = try!(state_from_str(&path_str) - .map_err(|_| { - cx.span_err(expr.span, "invalid state"); - })); + let state = state_from_str(&path_str).map_err(|_| { + cx.span_err(expr.span, "invalid state"); + })?; Ok(Transition::State(state)) } @@ -239,7 +225,7 @@ impl Transition { _ => { cx.span_err(expr.span, "expected Action and/or State"); Err(()) - } + }, } } } @@ -247,25 +233,23 @@ impl Transition { #[derive(Debug)] enum InputDefinition { Specific(u8), - Range { start: u8, end: u8 } + Range { start: u8, end: u8 }, } impl InputDefinition { fn from_pat(pat: &Pat, cx: &mut ExtCtxt) -> Result { Ok(match pat.node { PatKind::Lit(ref lit_expr) => { - InputDefinition::Specific(try!(u8_lit_from_expr(&lit_expr, cx))) + InputDefinition::Specific(u8_lit_from_expr(&lit_expr, cx)?) }, - PatKind::Range(ref start_expr, ref end_expr) => { - InputDefinition::Range { - start: try!(u8_lit_from_expr(start_expr, cx)), - end: try!(u8_lit_from_expr(end_expr, cx)), - } + PatKind::Range(ref start_expr, ref end_expr) => InputDefinition::Range { + start: u8_lit_from_expr(start_expr, cx)?, + end: u8_lit_from_expr(end_expr, cx)?, }, _ => { cx.span_err(pat.span, "expected literal or range expression"); - return Err(()) - } + return Err(()); + }, }) } } @@ -284,45 +268,39 @@ struct TableDefinition { fn parse_raw_definitions( definitions: Vec, - cx: &mut ExtCtxt + cx: &mut ExtCtxt, ) -> Result, ()> { let mut out = Vec::new(); for raw in definitions { let TableDefinitionExprs { state_expr, mapping_arms } = raw; - let state = try!(state_from_expr(state_expr, cx)); + let state = state_from_expr(state_expr, cx)?; let mut mappings = Vec::new(); for arm in mapping_arms { - mappings.push(try!(input_mapping_from_arm(arm, cx))); + mappings.push(input_mapping_from_arm(arm, cx)?); } - out.push(TableDefinition { - state: state, - mappings: mappings, - }) + out.push(TableDefinition { state, mappings }) } Ok(out) } fn parse_table_definition<'a>(parser: &mut Parser<'a>) -> PResult<'a, TableDefinitionExprs> { - let state_expr = try!(parser.parse_expr()); - try!(parser.expect(&Token::FatArrow)); - let mappings = try!(parse_table_input_mappings(parser)); + let state_expr = parser.parse_expr()?; + parser.expect(&Token::FatArrow)?; + let mappings = parse_table_input_mappings(parser)?; - Ok(TableDefinitionExprs { - state_expr: state_expr, - mapping_arms: mappings - }) + Ok(TableDefinitionExprs { state_expr, mapping_arms: mappings }) } -fn parse_table_definition_list<'a>(parser: &mut Parser<'a>) - -> PResult<'a, Vec> -{ +fn parse_table_definition_list<'a>( + parser: &mut Parser<'a>, +) -> PResult<'a, Vec> { let mut definitions = Vec::new(); while parser.token != Token::Eof { - definitions.push(try!(parse_table_definition(parser))); + definitions.push(parse_table_definition(parser)?); parser.eat(&Token::Comma); } @@ -330,7 +308,8 @@ fn parse_table_definition_list<'a>(parser: &mut Parser<'a>) } fn build_state_tables(defs: T) -> [[u8; 256]; 16] - where T: AsRef<[TableDefinition]> +where + T: AsRef<[TableDefinition]>, { let mut result = [[0u8; 256]; 16]; @@ -359,11 +338,10 @@ fn build_state_tables(defs: T) -> [[u8; 256]; 16] } fn build_table_ast(cx: &mut ExtCtxt, sp: Span, table: [[u8; 256]; 16]) -> P { - let table = table.iter() + let table = table + .iter() .map(|list| { - let exprs = list.iter() - .map(|num| cx.expr_u8(sp, *num)) - .collect(); + let exprs = list.iter().map(|num| cx.expr_u8(sp, *num)).collect(); cx.expr_vec(sp, exprs) }) .collect(); @@ -374,9 +352,8 @@ fn build_table_ast(cx: &mut ExtCtxt, sp: Span, table: [[u8; 256]; 16]) -> P( cx: &'cx mut ExtCtxt, sp: Span, - args: &[TokenTree]) - -> Box -{ + args: &[TokenTree], +) -> Box { macro_rules! ptry { ($pres:expr) => { match $pres { @@ -384,9 +361,9 @@ fn expand_state_table<'cx>( Err(mut err) => { err.emit(); return DummyResult::any(sp); - } + }, } - } + }; } // Parse the lookup spec @@ -405,7 +382,7 @@ fn expand_state_table<'cx>( #[cfg(test)] mod tests { - use definitions::{State, Action}; + use super::definitions::{Action, State}; use super::Transition; #[test] diff --git a/codegen/src/main.rs b/codegen/src/main.rs index 0d21577b..7cc6cd02 100644 --- a/codegen/src/main.rs +++ b/codegen/src/main.rs @@ -1,11 +1,11 @@ #![allow(dead_code)] -extern crate syntex; -extern crate syntex_syntax; - -mod ext; use std::path::Path; +use syntex; + +mod ext; + fn main() { // Expand VT parser state table let mut registry = syntex::Registry::new(); diff --git a/examples/parselog.rs b/examples/parselog.rs index b63bcf8e..83ba2b51 100644 --- a/examples/parselog.rs +++ b/examples/parselog.rs @@ -1,8 +1,8 @@ //! Parse input from stdin and log actions on stdout -extern crate vte; - use std::io::{self, Read}; +use vte; + /// A type implementing Perform that just logs actions struct Log; @@ -65,11 +65,11 @@ fn main() { for byte in &buf[..n] { statemachine.advance(&mut parser, *byte); } - } + }, Err(err) => { println!("err: {}", err); break; - } + }, } } } diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 00000000..9308ba98 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,13 @@ +format_code_in_doc_comments = true +match_block_trailing_comma = true +condense_wildcard_suffixes = true +use_field_init_shorthand = true +overflow_delimited_expr = true +use_small_heuristics = "Max" +normalize_comments = true +reorder_impl_items = true +use_try_shorthand = true +newline_style = "Unix" +format_strings = true +wrap_comments = true +comment_width = 100 diff --git a/src/definitions.rs b/src/definitions.rs index 3cfa7de4..375ac02c 100644 --- a/src/definitions.rs +++ b/src/definitions.rs @@ -1,43 +1,49 @@ #[allow(dead_code)] #[derive(Debug, Copy, Clone)] pub enum State { - Anywhere = 0, - CsiEntry = 1, - CsiIgnore = 2, - CsiIntermediate = 3, - CsiParam = 4, - DcsEntry = 5, - DcsIgnore = 6, - DcsIntermediate = 7, - DcsParam = 8, - DcsPassthrough = 9, - Escape = 10, - EscapeIntermediate = 11, - Ground = 12, - OscString = 13, - SosPmApcString = 14, - Utf8 = 15, + Anywhere = 0, + CsiEntry = 1, + CsiIgnore = 2, + CsiIntermediate = 3, + CsiParam = 4, + DcsEntry = 5, + DcsIgnore = 6, + DcsIntermediate = 7, + DcsParam = 8, + DcsPassthrough = 9, + Escape = 10, + EscapeIntermediate = 11, + Ground = 12, + OscString = 13, + SosPmApcString = 14, + Utf8 = 15, +} + +impl Default for State { + fn default() -> State { + State::Ground + } } #[allow(dead_code)] #[derive(Debug, Clone, Copy)] pub enum Action { - None = 0, - Clear = 1, - Collect = 2, - CsiDispatch = 3, - EscDispatch = 4, - Execute = 5, - Hook = 6, - Ignore = 7, - OscEnd = 8, - OscPut = 9, - OscStart = 10, - Param = 11, - Print = 12, - Put = 13, - Unhook = 14, - BeginUtf8 = 15, + None = 0, + Clear = 1, + Collect = 2, + CsiDispatch = 3, + EscDispatch = 4, + Execute = 5, + Hook = 6, + Ignore = 7, + OscEnd = 8, + OscPut = 9, + OscStart = 10, + Param = 11, + Print = 12, + Put = 13, + Unhook = 14, + BeginUtf8 = 15, } /// Unpack a u8 into a State and Action @@ -51,16 +57,15 @@ pub enum Action { pub fn unpack(delta: u8) -> (State, Action) { ( // State is stored in bottom 4 bits - unsafe { ::core::mem::transmute(delta & 0x0f) }, - + unsafe { core::mem::transmute(delta & 0x0f) }, // Action is stored in top 4 bits - unsafe { ::core::mem::transmute(delta >> 4) }, + unsafe { core::mem::transmute(delta >> 4) }, ) } #[cfg(test)] mod tests { - use super::{State, Action, unpack}; + use super::{unpack, Action, State}; #[test] fn unpack_state_action() { match unpack(0xee) { diff --git a/src/lib.rs b/src/lib.rs index 4daeba2f..8783d822 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,43 +24,37 @@ //! //! * UTF-8 Support for Input //! * OSC Strings can be terminated by 0x07 -//! * Only supports 7-bit codes. Some 8-bit codes are still supported, but they -//! no longer work in all states. +//! * Only supports 7-bit codes. Some 8-bit codes are still supported, but they no longer work in +//! all states. //! //! [`Parser`]: struct.Parser.html //! [`Perform`]: trait.Perform.html //! [Paul Williams' ANSI parser state machine]: https://vt100.net/emu/dec_ansi_parser #![cfg_attr(feature = "no_std", no_std)] -#[cfg(feature = "no_std")] -extern crate arrayvec; -#[cfg(not(feature = "no_std"))] -extern crate core; -extern crate utf8parse as utf8; - -use core::mem::{self, MaybeUninit}; +use core::mem::MaybeUninit; #[cfg(feature = "no_std")] use arrayvec::ArrayVec; +use utf8parse as utf8; mod definitions; mod table; use definitions::{unpack, Action, State}; - use table::{ENTRY_ACTIONS, EXIT_ACTIONS, STATE_CHANGE}; impl State { /// Get exit action for this state #[inline(always)] - pub fn exit_action(&self) -> Action { - unsafe { *EXIT_ACTIONS.get_unchecked(*self as usize) } + pub fn exit_action(self) -> Action { + unsafe { *EXIT_ACTIONS.get_unchecked(self as usize) } } /// Get entry action for this state #[inline(always)] - pub fn entry_action(&self) -> Action { - unsafe { *ENTRY_ACTIONS.get_unchecked(*self as usize) } + pub fn entry_action(self) -> Action { + unsafe { *ENTRY_ACTIONS.get_unchecked(self as usize) } } } @@ -69,7 +63,7 @@ const MAX_INTERMEDIATES: usize = 2; const MAX_OSC_RAW: usize = 1024; const MAX_PARAMS: usize = 16; -struct VtUtf8Receiver<'a, P: Perform + 'a>(&'a mut P, &'a mut State); +struct VtUtf8Receiver<'a, P: Perform>(&'a mut P, &'a mut State); impl<'a, P: Perform> utf8::Receiver for VtUtf8Receiver<'a, P> { fn codepoint(&mut self, c: char) { @@ -86,6 +80,7 @@ impl<'a, P: Perform> utf8::Receiver for VtUtf8Receiver<'a, P> { /// Parser for raw _VTE_ protocol which delegates actions to a [`Perform`] /// /// [`Perform`]: trait.Perform.html +#[derive(Default)] pub struct Parser { state: State, intermediates: [u8; MAX_INTERMEDIATES], @@ -106,22 +101,7 @@ pub struct Parser { impl Parser { /// Create a new Parser pub fn new() -> Parser { - Parser { - state: State::Ground, - intermediates: [0u8; MAX_INTERMEDIATES], - intermediate_idx: 0, - params: [0i64; MAX_PARAMS], - param: 0, - num_params: 0, - #[cfg(feature = "no_std")] - osc_raw: ArrayVec::new(), - #[cfg(not(feature = "no_std"))] - osc_raw: Vec::new(), - osc_params: [(0, 0); MAX_PARAMS], - osc_num_params: 0, - ignoring: false, - utf8_parser: utf8::Parser::new(), - } + Parser::default() } #[inline] @@ -182,7 +162,7 @@ impl Parser { Action::None => (), action => { self.perform_action(performer, action, $arg); - } + }, } }; } @@ -191,7 +171,7 @@ impl Parser { State::Anywhere => { // Just run the action self.perform_action(performer, action, byte); - } + }, state => { // Exit action for previous state let exit_action = self.state.exit_action(); @@ -205,7 +185,7 @@ impl Parser { // Assume the new state self.state = state; - } + }, } } @@ -217,15 +197,15 @@ impl Parser { let mut slices: [MaybeUninit<&[u8]>; MAX_PARAMS] = unsafe { MaybeUninit::uninit().assume_init() }; - for i in 0..self.osc_num_params { + for (i, slice) in slices.iter_mut().enumerate().take(self.osc_num_params) { let indices = self.osc_params[i]; - slices[i] = MaybeUninit::new(&self.osc_raw[indices.0..indices.1]); + *slice = MaybeUninit::new(&self.osc_raw[indices.0..indices.1]); } unsafe { - performer.osc_dispatch(mem::transmute::<_, &[&[u8]]>( - &slices[..self.osc_num_params], - )); + let num_params = self.osc_num_params; + let params = &slices[..num_params] as *const [MaybeUninit<&[u8]>] as *const [&[u8]]; + performer.osc_dispatch(&*params); } } @@ -238,18 +218,13 @@ impl Parser { self.params[self.num_params] = self.param; self.num_params += 1; - performer.hook( - self.params(), - self.intermediates(), - self.ignoring, - byte as char, - ); - } + performer.hook(self.params(), self.intermediates(), self.ignoring, byte as char); + }, Action::Put => performer.put(byte), Action::OscStart => { self.osc_raw.clear(); self.osc_num_params = 0; - } + }, Action::OscPut => { #[cfg(feature = "no_std")] { @@ -270,21 +245,21 @@ impl Parser { // First param is special - 0 to current byte index 0 => { self.osc_params[param_idx] = (0, idx); - } + }, // All other params depend on previous indexing _ => { let prev = self.osc_params[param_idx - 1]; let begin = prev.1; self.osc_params[param_idx] = (begin, idx); - } + }, } self.osc_num_params += 1; } else { self.osc_raw.push(byte); } - } + }, Action::OscEnd => { let param_idx = self.osc_num_params; let idx = self.osc_raw.len(); @@ -297,7 +272,7 @@ impl Parser { 0 => { self.osc_params[param_idx] = (0, idx); self.osc_num_params += 1; - } + }, // All other params depend on previous indexing _ => { @@ -305,10 +280,10 @@ impl Parser { let begin = prev.1; self.osc_params[param_idx] = (begin, idx); self.osc_num_params += 1; - } + }, } self.osc_dispatch(performer); - } + }, Action::Unhook => performer.unhook(), Action::CsiDispatch => { self.params[self.num_params] = self.param; @@ -323,10 +298,10 @@ impl Parser { self.num_params = 0; self.param = 0; - } + }, Action::EscDispatch => { performer.esc_dispatch(self.params(), self.intermediates(), self.ignoring, byte); - } + }, Action::Ignore | Action::None => (), Action::Collect => { if self.intermediate_idx == MAX_INTERMEDIATES { @@ -335,7 +310,7 @@ impl Parser { self.intermediates[self.intermediate_idx] = byte; self.intermediate_idx += 1; } - } + }, Action::Param => { if byte == b';' { // Completed a param @@ -353,15 +328,15 @@ impl Parser { self.param = self.param.saturating_mul(10); self.param = self.param.saturating_add((byte - b'0') as i64); } - } + }, Action::Clear => { self.intermediate_idx = 0; self.num_params = 0; self.ignoring = false; - } + }, Action::BeginUtf8 => { self.process_utf8(performer, byte); - } + }, } } } @@ -378,7 +353,7 @@ impl Parser { /// the future, consider checking archive.org. pub trait Perform { /// Draw a character to the screen and update states - fn print(&mut self, char); + fn print(&mut self, _: char); /// Execute a C0 or C1 control function fn execute(&mut self, byte: u8); @@ -392,7 +367,7 @@ pub trait Perform { /// /// The `ignore` flag indicates that more than two intermediates arrived and /// subsequent characters were ignored. - fn hook(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, char); + fn hook(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, _: char); /// Pass bytes as part of a device control string to the handle chosen in `hook`. C0 controls /// will also be passed to the handler. @@ -411,7 +386,7 @@ pub trait Perform { /// /// The `ignore` flag indicates that more than two intermediates arrived and /// subsequent characters were ignored. - fn csi_dispatch(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, char); + fn csi_dispatch(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, _: char); /// The final character of an escape sequence has arrived. /// @@ -428,10 +403,10 @@ extern crate std; mod tests { use super::*; - use std::vec::Vec; use core::i64; + use std::vec::Vec; - static OSC_BYTES: &'static [u8] = &[ + static OSC_BYTES: &[u8] = &[ 0x1b, 0x5d, // Begin OSC b'2', b';', b'j', b'w', b'i', b'l', b'm', b'@', b'j', b'w', b'i', b'l', b'm', b'-', b'd', b'e', b's', b'k', b':', b' ', b'~', b'/', b'c', b'o', b'd', b'e', b'/', b'a', b'l', b'a', @@ -447,15 +422,21 @@ mod tests { // All empty bodies except osc_dispatch impl Perform for OscDispatcher { fn print(&mut self, _: char) {} + fn execute(&mut self, _byte: u8) {} + fn hook(&mut self, _params: &[i64], _intermediates: &[u8], _ignore: bool, _: char) {} + fn put(&mut self, _byte: u8) {} + fn unhook(&mut self) {} + fn osc_dispatch(&mut self, params: &[&[u8]]) { // Set a flag so we know these assertions all run self.dispatched_osc = true; self.params = params.iter().map(|p| p.to_vec()).collect(); } + fn csi_dispatch( &mut self, _params: &[i64], @@ -464,6 +445,7 @@ mod tests { _c: char, ) { } + fn esc_dispatch( &mut self, _params: &[i64], @@ -482,15 +464,22 @@ mod tests { impl Perform for CsiDispatcher { fn print(&mut self, _: char) {} + fn execute(&mut self, _byte: u8) {} + fn hook(&mut self, _params: &[i64], _intermediates: &[u8], _ignore: bool, _: char) {} + fn put(&mut self, _byte: u8) {} + fn unhook(&mut self) {} + fn osc_dispatch(&mut self, _params: &[&[u8]]) {} + fn csi_dispatch(&mut self, params: &[i64], _intermediates: &[u8], _ignore: bool, _c: char) { self.dispatched_csi = true; self.params.push(params.to_vec()); } + fn esc_dispatch( &mut self, _params: &[i64], @@ -511,18 +500,24 @@ mod tests { impl Perform for DcsDispatcher { fn print(&mut self, _: char) {} + fn execute(&mut self, _byte: u8) {} + fn hook(&mut self, params: &[i64], _intermediates: &[u8], _ignore: bool, c: char) { self.c = Some(c); self.params = params.to_vec(); } + fn put(&mut self, byte: u8) { self.s.push(byte); } + fn unhook(&mut self) { self.dispatched_dcs = true; } + fn osc_dispatch(&mut self, _params: &[&[u8]]) {} + fn csi_dispatch( &mut self, _params: &[i64], @@ -531,6 +526,7 @@ mod tests { _c: char, ) { } + fn esc_dispatch( &mut self, _params: &[i64], @@ -578,9 +574,9 @@ mod tests { #[test] fn parse_osc_max_params() { - use MAX_PARAMS; + use crate::MAX_PARAMS; - static INPUT: &'static [u8] = b"\x1b];;;;;;;;;;;;;;;;;\x1b"; + static INPUT: &[u8] = b"\x1b];;;;;;;;;;;;;;;;;\x1b"; // Create dispatcher and check state let mut dispatcher = OscDispatcher::default(); @@ -602,9 +598,9 @@ mod tests { #[test] fn parse_csi_max_params() { - use MAX_PARAMS; + use crate::MAX_PARAMS; - static INPUT: &'static [u8] = b"\x1b[1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;p"; + static INPUT: &[u8] = b"\x1b[1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;p"; // Create dispatcher and check state let mut dispatcher = CsiDispatcher::default(); @@ -653,7 +649,7 @@ mod tests { #[test] fn parse_long_csi_param() { // The important part is the parameter, which is (i64::MAX + 1) - static INPUT: &'static [u8] = b"\x1b[9223372036854775808m"; + static INPUT: &[u8] = b"\x1b[9223372036854775808m"; let mut dispatcher = CsiDispatcher::default(); @@ -667,17 +663,14 @@ mod tests { #[test] fn parse_osc_with_utf8_arguments() { - static INPUT: &'static [u8] = &[ + static INPUT: &[u8] = &[ 0x0d, 0x1b, 0x5d, 0x32, 0x3b, 0x65, 0x63, 0x68, 0x6f, 0x20, 0x27, 0xc2, 0xaf, 0x5c, 0x5f, 0x28, 0xe3, 0x83, 0x84, 0x29, 0x5f, 0x2f, 0xc2, 0xaf, 0x27, 0x20, 0x26, 0x26, 0x20, 0x73, 0x6c, 0x65, 0x65, 0x70, 0x20, 0x31, 0x07, ]; // Create dispatcher and check state - let mut dispatcher = OscDispatcher { - params: vec![], - dispatched_osc: false, - }; + let mut dispatcher = OscDispatcher { params: vec![], dispatched_osc: false }; // Run parser using OSC_BYTES let mut parser = Parser::new(); @@ -692,9 +685,8 @@ mod tests { #[test] fn parse_dcs() { - static INPUT: &'static [u8] = &[ - 0x1b, 0x50, 0x30, 0x3b, 0x31, 0x7c, 0x31, 0x37, 0x2f, 0x61, 0x62, 0x9c, - ]; + static INPUT: &[u8] = + &[0x1b, 0x50, 0x30, 0x3b, 0x31, 0x7c, 0x31, 0x37, 0x2f, 0x61, 0x62, 0x9c]; // Create dispatcher and check state let mut dispatcher = DcsDispatcher::default(); @@ -714,10 +706,8 @@ mod tests { #[test] fn exceed_max_buffer_size() { static NUM_BYTES: usize = MAX_OSC_RAW + 100; - static INPUT_START: &'static [u8] = &[ - 0x1b, b']', b'5', b'2', b';', b's' - ]; - static INPUT_END: &'static [u8] = &[b'\x07']; + static INPUT_START: &[u8] = &[0x1b, b']', b'5', b'2', b';', b's']; + static INPUT_END: &[u8] = &[b'\x07']; let mut dispatcher = OscDispatcher::default(); let mut parser = Parser::new(); diff --git a/src/table.rs b/src/table.rs index 799c6d6e..a9569aa0 100644 --- a/src/table.rs +++ b/src/table.rs @@ -1,396 +1,343 @@ - /// This is the state change table. It's indexed first by current state and then by the next /// character in the pty stream. -use definitions::Action; +use crate::definitions::Action; -pub static STATE_CHANGE: [[u8; 256]; 16] = +pub static STATE_CHANGE: [[u8; 256]; 16] = [ + // Beginning of UTF-8 2 byte sequence + // Beginning of UTF-8 3 byte sequence + // Beginning of UTF-8 4 byte sequence [ + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 92u8, 0u8, 92u8, 10u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, + ], + [ + 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, + 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 0u8, 80u8, 0u8, 0u8, 80u8, 80u8, + 80u8, 80u8, 35u8, 35u8, 35u8, 35u8, 35u8, 35u8, 35u8, 35u8, 35u8, 35u8, 35u8, 35u8, 35u8, + 35u8, 35u8, 35u8, 180u8, 180u8, 180u8, 180u8, 180u8, 180u8, 180u8, 180u8, 180u8, 180u8, + 2u8, 180u8, 36u8, 36u8, 36u8, 36u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, + 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, + 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, + 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, + 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 112u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + ], + [ + 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, + 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 0u8, 80u8, 0u8, 0u8, 80u8, 80u8, + 80u8, 80u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, + 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, + 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, + 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, + 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, + 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, + 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 112u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + ], + [ + 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, + 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 0u8, 80u8, 0u8, 0u8, 80u8, 80u8, + 80u8, 80u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, + 32u8, 32u8, 32u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, + 2u8, 2u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, + 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, + 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, + 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, + 60u8, 60u8, 60u8, 60u8, 60u8, 112u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + ], + [ + 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, + 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 0u8, 80u8, 0u8, 0u8, 80u8, 80u8, + 80u8, 80u8, 35u8, 35u8, 35u8, 35u8, 35u8, 35u8, 35u8, 35u8, 35u8, 35u8, 35u8, 35u8, 35u8, + 35u8, 35u8, 35u8, 176u8, 176u8, 176u8, 176u8, 176u8, 176u8, 176u8, 176u8, 176u8, 176u8, + 2u8, 176u8, 2u8, 2u8, 2u8, 2u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, + 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, + 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, + 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, + 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 112u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + ], + [ + 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, + 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 0u8, 112u8, + 0u8, 0u8, 112u8, 112u8, 112u8, 112u8, 39u8, 39u8, 39u8, 39u8, 39u8, 39u8, 39u8, 39u8, 39u8, + 39u8, 39u8, 39u8, 39u8, 39u8, 39u8, 39u8, 184u8, 184u8, 184u8, 184u8, 184u8, 184u8, 184u8, + 184u8, 184u8, 184u8, 6u8, 184u8, 40u8, 40u8, 40u8, 40u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, + 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, + 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, + 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, + 9u8, 9u8, 112u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, + ], + [ + 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, + 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 0u8, 112u8, + 0u8, 0u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, + 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, + 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, + 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, + 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, + 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, + 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, + 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 12u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + ], + [ + 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, + 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 0u8, 112u8, + 0u8, 0u8, 112u8, 112u8, 112u8, 112u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, + 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 6u8, 6u8, 6u8, 6u8, 6u8, 6u8, 6u8, 6u8, 6u8, 6u8, + 6u8, 6u8, 6u8, 6u8, 6u8, 6u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, + 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, + 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, + 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 112u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + ], + [ + 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, + 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 0u8, 112u8, + 0u8, 0u8, 112u8, 112u8, 112u8, 112u8, 39u8, 39u8, 39u8, 39u8, 39u8, 39u8, 39u8, 39u8, 39u8, + 39u8, 39u8, 39u8, 39u8, 39u8, 39u8, 39u8, 176u8, 176u8, 176u8, 176u8, 176u8, 176u8, 176u8, + 176u8, 176u8, 176u8, 6u8, 176u8, 6u8, 6u8, 6u8, 6u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, + 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, + 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, + 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, + 9u8, 9u8, 112u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, + ], + [ + 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, + 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 0u8, 208u8, + 0u8, 0u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, + 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, + 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, + 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, + 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, + 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, + 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, + 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 112u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 12u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + ], + [ + 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, + 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 0u8, 80u8, 0u8, 0u8, 80u8, 80u8, + 80u8, 80u8, 43u8, 43u8, 43u8, 43u8, 43u8, 43u8, 43u8, 43u8, 43u8, 43u8, 43u8, 43u8, 43u8, + 43u8, 43u8, 43u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, + 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, + 76u8, 76u8, 76u8, 76u8, 76u8, 5u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 14u8, 76u8, + 76u8, 1u8, 76u8, 13u8, 14u8, 14u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, + 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, + 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 112u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + ], + [ + 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, + 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 0u8, 80u8, 0u8, 0u8, 80u8, 80u8, + 80u8, 80u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, + 32u8, 32u8, 32u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, + 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, + 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, + 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, + 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, + 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 112u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + ], + [ + 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, + 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 0u8, 80u8, 0u8, 0u8, 80u8, 80u8, + 80u8, 80u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, + 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, + 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, + 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, + 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, + 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, + 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, + 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, + 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 0u8, 80u8, 80u8, 80u8, 80u8, 80u8, + 80u8, 80u8, 80u8, 80u8, 80u8, 0u8, 80u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, + 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, + 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, + 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, + 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, + ], + [ + 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 12u8, 112u8, 112u8, 112u8, 112u8, 112u8, + 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 0u8, 112u8, + 0u8, 0u8, 112u8, 112u8, 112u8, 112u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, + 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, + 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, + 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, + 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, + 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, + 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, + 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, + 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, + 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, + 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, + 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, + 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, + 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, + 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, + 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, + 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, + 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, + ], + [ + 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, + 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 0u8, 112u8, + 0u8, 0u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, + 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, + 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, + 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, + 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, + 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, + 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, + 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 12u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + ], + [ + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, + ], +]; - // Beginning of UTF-8 2 byte sequence - // Beginning of UTF-8 3 byte sequence - // Beginning of UTF-8 4 byte sequence - - - - - - - - - - - - - - [0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 92u8, 0u8, 92u8, 10u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8], - [80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, - 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, - 0u8, 80u8, 0u8, 0u8, 80u8, 80u8, 80u8, 80u8, 35u8, 35u8, 35u8, 35u8, - 35u8, 35u8, 35u8, 35u8, 35u8, 35u8, 35u8, 35u8, 35u8, 35u8, 35u8, 35u8, - 180u8, 180u8, 180u8, 180u8, 180u8, 180u8, 180u8, 180u8, 180u8, 180u8, - 2u8, 180u8, 36u8, 36u8, 36u8, 36u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, - 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, - 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, - 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, - 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, - 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 112u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8], - [80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, - 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, - 0u8, 80u8, 0u8, 0u8, 80u8, 80u8, 80u8, 80u8, 112u8, 112u8, 112u8, 112u8, - 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, - 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, - 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 12u8, 12u8, - 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, - 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, - 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, - 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, - 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, - 12u8, 112u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8], - [80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, - 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, - 0u8, 80u8, 0u8, 0u8, 80u8, 80u8, 80u8, 80u8, 32u8, 32u8, 32u8, 32u8, - 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, - 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, - 2u8, 2u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, - 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, - 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, - 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, - 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, - 60u8, 60u8, 60u8, 60u8, 60u8, 112u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8], - [80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, - 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, - 0u8, 80u8, 0u8, 0u8, 80u8, 80u8, 80u8, 80u8, 35u8, 35u8, 35u8, 35u8, - 35u8, 35u8, 35u8, 35u8, 35u8, 35u8, 35u8, 35u8, 35u8, 35u8, 35u8, 35u8, - 176u8, 176u8, 176u8, 176u8, 176u8, 176u8, 176u8, 176u8, 176u8, 176u8, - 2u8, 176u8, 2u8, 2u8, 2u8, 2u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, - 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, - 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, - 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, - 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, - 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 112u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8], - [112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, - 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, - 112u8, 112u8, 112u8, 112u8, 0u8, 112u8, 0u8, 0u8, 112u8, 112u8, 112u8, - 112u8, 39u8, 39u8, 39u8, 39u8, 39u8, 39u8, 39u8, 39u8, 39u8, 39u8, 39u8, - 39u8, 39u8, 39u8, 39u8, 39u8, 184u8, 184u8, 184u8, 184u8, 184u8, 184u8, - 184u8, 184u8, 184u8, 184u8, 6u8, 184u8, 40u8, 40u8, 40u8, 40u8, 9u8, - 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, - 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, - 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, - 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, - 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 112u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8], - [112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, - 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, - 112u8, 112u8, 112u8, 112u8, 0u8, 112u8, 0u8, 0u8, 112u8, 112u8, 112u8, - 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, - 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, - 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, - 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, - 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, - 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, - 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, - 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, - 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, - 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 12u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8], - [112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, - 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, - 112u8, 112u8, 112u8, 112u8, 0u8, 112u8, 0u8, 0u8, 112u8, 112u8, 112u8, - 112u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, - 32u8, 32u8, 32u8, 32u8, 32u8, 6u8, 6u8, 6u8, 6u8, 6u8, 6u8, 6u8, 6u8, - 6u8, 6u8, 6u8, 6u8, 6u8, 6u8, 6u8, 6u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, - 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, - 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, - 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, - 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, - 9u8, 112u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8], - [112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, - 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, - 112u8, 112u8, 112u8, 112u8, 0u8, 112u8, 0u8, 0u8, 112u8, 112u8, 112u8, - 112u8, 39u8, 39u8, 39u8, 39u8, 39u8, 39u8, 39u8, 39u8, 39u8, 39u8, 39u8, - 39u8, 39u8, 39u8, 39u8, 39u8, 176u8, 176u8, 176u8, 176u8, 176u8, 176u8, - 176u8, 176u8, 176u8, 176u8, 6u8, 176u8, 6u8, 6u8, 6u8, 6u8, 9u8, 9u8, - 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, - 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, - 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, - 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, - 9u8, 9u8, 9u8, 9u8, 9u8, 112u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8], - [208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, - 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, - 208u8, 208u8, 208u8, 208u8, 0u8, 208u8, 0u8, 0u8, 208u8, 208u8, 208u8, - 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, - 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, - 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, - 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, - 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, - 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, - 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, - 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, - 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, - 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 112u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 12u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8], - [80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, - 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, - 0u8, 80u8, 0u8, 0u8, 80u8, 80u8, 80u8, 80u8, 43u8, 43u8, 43u8, 43u8, - 43u8, 43u8, 43u8, 43u8, 43u8, 43u8, 43u8, 43u8, 43u8, 43u8, 43u8, 43u8, - 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, - 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, - 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 5u8, 76u8, 76u8, 76u8, - 76u8, 76u8, 76u8, 76u8, 14u8, 76u8, 76u8, 1u8, 76u8, 13u8, 14u8, 14u8, - 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, - 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, - 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 112u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8], - [80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, - 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, - 0u8, 80u8, 0u8, 0u8, 80u8, 80u8, 80u8, 80u8, 32u8, 32u8, 32u8, 32u8, - 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, - 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, - 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, - 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, - 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, - 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, - 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, - 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 112u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8], - [80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, - 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, - 0u8, 80u8, 0u8, 0u8, 80u8, 80u8, 80u8, 80u8, 192u8, 192u8, 192u8, 192u8, - 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, - 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, - 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, - 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, - 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, - 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, - 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, - 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, - 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, - 192u8, 192u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, - 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 0u8, 80u8, 80u8, 80u8, 80u8, - 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 0u8, 80u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, - 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, - 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, - 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, - 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, - 255u8, 255u8, 255u8, 255u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8], - [112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 12u8, 112u8, 112u8, - 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, - 112u8, 112u8, 112u8, 112u8, 0u8, 112u8, 0u8, 0u8, 112u8, 112u8, 112u8, - 112u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, - 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, - 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, - 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, - 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, - 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, - 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, - 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, - 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, - 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, - 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, - 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, - 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, - 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, - 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, - 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, - 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, - 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, - 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, - 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, - 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, - 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, - 144u8, 144u8, 144u8, 144u8, 144u8], - [112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, - 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, - 112u8, 112u8, 112u8, 112u8, 0u8, 112u8, 0u8, 0u8, 112u8, 112u8, 112u8, - 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, - 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, - 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, - 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, - 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, - 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, - 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, - 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, - 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, - 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 12u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8], - [0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8]]; - -pub static ENTRY_ACTIONS: &'static [Action] = - &[Action::None, // State::Anywhere - Action::Clear, // State::CsiEntry - Action::None, // State::CsiIgnore - Action::None, // State::CsiIntermediate - Action::None, // State::CsiParam - Action::Clear, // State::DcsEntry - Action::None, // State::DcsIgnore - Action::None, // State::DcsIntermediate - Action::None, // State::DcsParam - Action::Hook, // State::DcsPassthrough - Action::Clear, // State::Escape - Action::None, // State::EscapeIntermediate - Action::None, // State::Ground - Action::OscStart, // State::OscString - Action::None, // State::SosPmApcString - Action::None]; - // State::Utf8 +pub static ENTRY_ACTIONS: &[Action] = &[ + Action::None, // State::Anywhere + Action::Clear, // State::CsiEntry + Action::None, // State::CsiIgnore + Action::None, // State::CsiIntermediate + Action::None, // State::CsiParam + Action::Clear, // State::DcsEntry + Action::None, // State::DcsIgnore + Action::None, // State::DcsIntermediate + Action::None, // State::DcsParam + Action::Hook, // State::DcsPassthrough + Action::Clear, // State::Escape + Action::None, // State::EscapeIntermediate + Action::None, // State::Ground + Action::OscStart, // State::OscString + Action::None, // State::SosPmApcString + Action::None, +]; +// State::Utf8 -pub static EXIT_ACTIONS: &'static [Action] = - &[Action::None, // State::Anywhere - Action::None, // State::CsiEntry - Action::None, // State::CsiIgnore - Action::None, // State::CsiIntermediate - Action::None, // State::CsiParam - Action::None, // State::DcsEntry - Action::None, // State::DcsIgnore - Action::None, // State::DcsIntermediate - Action::None, // State::DcsParam - Action::Unhook, // State::DcsPassthrough - Action::None, // State::Escape - Action::None, // State::EscapeIntermediate - Action::None, // State::Ground - Action::OscEnd, // State::OscString - Action::None, // State::SosPmApcString - Action::None]; // State::Utf8 +pub static EXIT_ACTIONS: &[Action] = &[ + Action::None, // State::Anywhere + Action::None, // State::CsiEntry + Action::None, // State::CsiIgnore + Action::None, // State::CsiIntermediate + Action::None, // State::CsiParam + Action::None, // State::DcsEntry + Action::None, // State::DcsIgnore + Action::None, // State::DcsIntermediate + Action::None, // State::DcsParam + Action::Unhook, // State::DcsPassthrough + Action::None, // State::Escape + Action::None, // State::EscapeIntermediate + Action::None, // State::Ground + Action::OscEnd, // State::OscString + Action::None, // State::SosPmApcString + Action::None, +]; // State::Utf8 diff --git a/utf8parse/Cargo.toml b/utf8parse/Cargo.toml index 1b744070..d8b91747 100644 --- a/utf8parse/Cargo.toml +++ b/utf8parse/Cargo.toml @@ -1,11 +1,13 @@ [package] -name = "utf8parse" -version = "0.1.1" -authors = ["Joe Wilm "] -license = "Apache-2.0 OR MIT" +authors = ["Joe Wilm ", "Christian Duerr "] description = "Table-driven UTF-8 parser" -keywords = ["utf8", "parse", "table"] -repository = "https://github.com/jwilm/vte" documentation = "https://docs.rs/utf8parse/" +repository = "https://github.com/jwilm/vte" +keywords = ["utf8", "parse", "table"] +categories = ["parsing", "no-std"] +license = "Apache-2.0 OR MIT" +version = "0.1.1" +name = "utf8parse" +edition = "2018" [dependencies] diff --git a/utf8parse/src/lib.rs b/utf8parse/src/lib.rs index 3a8ca2f9..8c866f59 100644 --- a/utf8parse/src/lib.rs +++ b/utf8parse/src/lib.rs @@ -7,16 +7,16 @@ use core::char; +mod table; mod types; -use self::types::{State, Action, unpack}; -mod table; -use self::table::TRANSITIONS; +use table::TRANSITIONS; +use types::{unpack, Action, State}; /// Handles codepoint and invalid sequence events from the parser. pub trait Receiver { /// Called whenever a codepoint is parsed successfully - fn codepoint(&mut self, char); + fn codepoint(&mut self, _: char); /// Called when an invalid_sequence is detected fn invalid_sequence(&mut self); @@ -25,6 +25,7 @@ pub trait Receiver { /// A parser for Utf8 Characters /// /// Repeatedly call `advance` with bytes to emit Utf8 characters +#[derive(Default)] pub struct Parser { point: u32, state: State, @@ -36,10 +37,7 @@ const CONTINUATION_MASK: u8 = 0b0011_1111; impl Parser { /// Create a new Parser pub fn new() -> Parser { - Parser { - point: 0, - state: State::Ground, - } + Parser { point: 0, state: State::Ground } } /// Advance the parser @@ -47,7 +45,8 @@ impl Parser { /// The provider receiver will be called whenever a codepoint is completed or an invalid /// sequence is detected. pub fn advance(&mut self, receiver: &mut R, byte: u8) - where R: Receiver + where + R: Receiver, { let cur = self.state as usize; let change = TRANSITIONS[cur][byte as usize]; @@ -58,7 +57,8 @@ impl Parser { } fn perform_action(&mut self, receiver: &mut R, byte: u8, action: Action) - where R: Receiver + where + R: Receiver, { match action { Action::InvalidSequence => { @@ -93,47 +93,3 @@ impl Parser { } } } - -#[cfg(test)] -#[macro_use] -extern crate std; - -#[cfg(test)] -mod tests { - use std::io::Read; - use std::fs::File; - use std::string::String; - use Receiver; - use Parser; - - impl Receiver for String { - fn codepoint(&mut self, c: char) { - self.push(c); - } - - fn invalid_sequence(&mut self) { - } - } - - #[test] - fn utf8parse_test() { - let mut buffer = String::new(); - let mut file = File::open("src/UTF-8-demo.txt").unwrap(); - let mut parser = Parser::new(); - - // read the file to a buffer - file.read_to_string(&mut buffer).expect("Reading file to string"); - - // standard library implementation - let expected = String::from_utf8(buffer.as_bytes().to_vec()).unwrap(); - - // utf8parse implementation - let mut actual = String::new(); - - for byte in buffer.as_bytes().to_vec() { - parser.advance(&mut actual, byte) - } - - assert_eq!(actual, expected); - } -} diff --git a/utf8parse/src/table.rs b/utf8parse/src/table.rs index 5a1292b2..04c4d34d 100644 --- a/utf8parse/src/table.rs +++ b/utf8parse/src/table.rs @@ -6,7 +6,7 @@ /// /// # UTF-8 Grammar /// -/// ```ignore +/// ```notrust /// UTF8-octets = *( UTF8-char ) /// UTF8-char = UTF8-1 / UTF8-2 / UTF8-3 / UTF8-4 /// UTF8-1 = %x00-7F @@ -24,161 +24,143 @@ /// Not specifying an action in this table is equivalent to specifying /// Action::InvalidSequence. Not specifying a state is equivalent to specifying /// state::ground. -pub static TRANSITIONS: [[u8; 256]; 8] = - [[16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, - 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, - 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, - 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, - 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, - 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, - 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, - 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, - 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, - 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, - 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 67u8, 67u8, 67u8, 67u8, 67u8, 67u8, 67u8, 67u8, - 67u8, 67u8, 67u8, 67u8, 67u8, 67u8, 67u8, 67u8, 67u8, 67u8, 67u8, 67u8, - 67u8, 67u8, 67u8, 67u8, 67u8, 67u8, 67u8, 67u8, 67u8, 67u8, 100u8, 98u8, - 98u8, 98u8, 98u8, 98u8, 98u8, 98u8, 98u8, 98u8, 98u8, 98u8, 98u8, 101u8, - 98u8, 98u8, 118u8, 113u8, 113u8, 113u8, 119u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8], - [0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, - 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, - 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, - 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, - 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, - 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8], - [0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, - 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, - 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, - 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, - 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, - 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8], - [0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, - 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, - 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, - 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, - 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, - 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8], - [0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, - 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, - 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, - 51u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8], - [0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, - 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, - 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8], - [0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, - 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, - 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, - 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, - 82u8, 82u8, 82u8, 82u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8], - [0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, - 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8]]; +pub static TRANSITIONS: [[u8; 256]; 8] = [ + [ + 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, + 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, + 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, + 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, + 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, + 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, + 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, + 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, + 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 67u8, 67u8, 67u8, 67u8, 67u8, 67u8, 67u8, 67u8, 67u8, 67u8, 67u8, 67u8, + 67u8, 67u8, 67u8, 67u8, 67u8, 67u8, 67u8, 67u8, 67u8, 67u8, 67u8, 67u8, 67u8, 67u8, 67u8, + 67u8, 67u8, 67u8, 100u8, 98u8, 98u8, 98u8, 98u8, 98u8, 98u8, 98u8, 98u8, 98u8, 98u8, 98u8, + 98u8, 101u8, 98u8, 98u8, 118u8, 113u8, 113u8, 113u8, 119u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, + ], + [ + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, + 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, + 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, + 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, + 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + ], + [ + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, + 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, + 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, + 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, + 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + ], + [ + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, + 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, + 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, + 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, + 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + ], + [ + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 51u8, 51u8, + 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, + 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + ], + [ + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, + 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, 51u8, + 51u8, 51u8, 51u8, 51u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + ], + [ + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, + 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, + 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, + 82u8, 82u8, 82u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + ], + [ + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, 82u8, + 82u8, 82u8, 82u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + ], +]; diff --git a/utf8parse/src/types.rs b/utf8parse/src/types.rs index a5b94369..93607fbd 100644 --- a/utf8parse/src/types.rs +++ b/utf8parse/src/types.rs @@ -27,6 +27,12 @@ pub enum State { Utf8_4_3_f4 = 7, } +impl Default for State { + fn default() -> State { + State::Ground + } +} + /// Action to take when receiving a byte #[allow(dead_code)] #[derive(Debug, Copy, Clone)] @@ -70,7 +76,6 @@ pub unsafe fn unpack(val: u8) -> (State, Action) { ( // State is stored in bottom 4 bits mem::transmute(val & 0x0f), - // Action is stored in top 4 bits mem::transmute(val >> 4), ) diff --git a/utf8parse/src/UTF-8-demo.txt b/utf8parse/tests/UTF-8-demo.txt similarity index 100% rename from utf8parse/src/UTF-8-demo.txt rename to utf8parse/tests/UTF-8-demo.txt diff --git a/utf8parse/tests/utf-8-demo.rs b/utf8parse/tests/utf-8-demo.rs new file mode 100644 index 00000000..e60ce22c --- /dev/null +++ b/utf8parse/tests/utf-8-demo.rs @@ -0,0 +1,31 @@ +use utf8parse::{Parser, Receiver}; + +static UTF8_DEMO: &[u8] = include_bytes!("UTF-8-demo.txt"); + +#[derive(Debug, PartialEq)] +struct StringWrapper(String); + +impl Receiver for StringWrapper { + fn codepoint(&mut self, c: char) { + self.0.push(c); + } + + fn invalid_sequence(&mut self) {} +} + +#[test] +fn utf8parse_test() { + let mut parser = Parser::new(); + + // utf8parse implementation + let mut actual = StringWrapper(String::new()); + + for byte in UTF8_DEMO { + parser.advance(&mut actual, *byte) + } + + // standard library implementation + let expected = String::from_utf8_lossy(UTF8_DEMO).to_string(); + + assert_eq!(actual.0, expected); +} From 9d37aa7a71801f3569d2a2a55dc82c37935f205a Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Tue, 10 Dec 2019 19:16:01 +0100 Subject: [PATCH 60/99] Remove table generation This completely removes the `codegen` project, which relied on outdated libraries to parse DSLs to build the utf8 and vte state tables, to make the library easier to maintain. The utf8 table could be completely removed in favor of a `match` statement, which also lead to a performance improvement with the utf8 parser. The vte table did not benefit from `match` statements at all and instead had significantly worse performance with it. To replace the old codegeneration for vte, the `generate_state_changes` crate has been created instead, which uses the language's proc_macro feature to create a `const fn` which will generate the table at compile time. --- Cargo.toml | 4 +- codegen/Cargo.toml | 9 - codegen/README.md | 11 - codegen/src/ext/mod.rs | 2 - codegen/src/ext/utf8.rs | 365 ----- codegen/src/ext/vt.rs | 393 ------ codegen/src/main.rs | 23 - generate_state_changes/Cargo.toml | 12 + generate_state_changes/src/lib.rs | 174 +++ src/definitions.rs | 63 +- src/lib.rs | 77 +- src/table.rs | 508 +++---- src/table.rs.in | 30 +- tests/demo.vte | 2052 +++++++++++++++++++++++++++++ utf8parse/Cargo.toml | 4 +- utf8parse/src/lib.rs | 50 +- utf8parse/src/table.rs | 166 --- utf8parse/src/table.rs.in | 60 - utf8parse/src/types.rs | 121 +- 19 files changed, 2660 insertions(+), 1464 deletions(-) delete mode 100644 codegen/Cargo.toml delete mode 100644 codegen/README.md delete mode 100644 codegen/src/ext/mod.rs delete mode 100644 codegen/src/ext/utf8.rs delete mode 100644 codegen/src/ext/vt.rs delete mode 100644 codegen/src/main.rs create mode 100644 generate_state_changes/Cargo.toml create mode 100644 generate_state_changes/src/lib.rs create mode 100644 tests/demo.vte delete mode 100644 utf8parse/src/table.rs delete mode 100644 utf8parse/src/table.rs.in diff --git a/Cargo.toml b/Cargo.toml index d4c0133a..73fd4b73 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,12 +13,14 @@ name = "vte" edition = "2018" [dependencies] +generate_state_changes = { version = "0.1.0", path = "generate_state_changes" } arrayvec = { version = "0.5.1", default-features = false, optional = true } utf8parse = { path = "utf8parse", version = "0.1.0" } [features] default = ["no_std"] no_std = ["arrayvec"] +nightly = ["utf8parse/nightly"] [workspace] -members = ["utf8parse", "codegen"] +members = ["utf8parse", "generate_state_changes"] diff --git a/codegen/Cargo.toml b/codegen/Cargo.toml deleted file mode 100644 index ec5a741d..00000000 --- a/codegen/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "codegen" -version = "0.1.0" -authors = ["Joe Wilm "] -edition = "2018" - -[dependencies] -syntex = "0.43.0" -syntex_syntax = "0.43.0" diff --git a/codegen/README.md b/codegen/README.md deleted file mode 100644 index d13aa5db..00000000 --- a/codegen/README.md +++ /dev/null @@ -1,11 +0,0 @@ -codegen -======= - -Depends on libsyntex and generates table.rs from table.rs.in. This code is -separate from the main vtparse crate since compiling libsyntex takes ~1 -eternity. - -## Usage - -`cargo run` in the codegen folder will process `table.rs.in` and output -`table.rs`. The latter file should be committed back into the repo. diff --git a/codegen/src/ext/mod.rs b/codegen/src/ext/mod.rs deleted file mode 100644 index c28d9f7d..00000000 --- a/codegen/src/ext/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod utf8; -pub mod vt; diff --git a/codegen/src/ext/utf8.rs b/codegen/src/ext/utf8.rs deleted file mode 100644 index 898722b0..00000000 --- a/codegen/src/ext/utf8.rs +++ /dev/null @@ -1,365 +0,0 @@ -//! Macro expansion for the utf8 parser state table -use std::fmt; - -use syntex::Registry; - -use syntex_syntax::ast::{self, Arm, Expr, ExprKind, LitKind, Pat, PatKind}; -use syntex_syntax::codemap::Span; -use syntex_syntax::ext::base::{DummyResult, ExtCtxt, MacEager, MacResult}; -use syntex_syntax::ext::build::AstBuilder; -use syntex_syntax::parse::parser::Parser; -use syntex_syntax::parse::token::{DelimToken, Token}; -use syntex_syntax::parse::PResult; -use syntex_syntax::ptr::P; -use syntex_syntax::tokenstream::TokenTree; - -#[path = "../../../utf8parse/src/types.rs"] -mod types; - -use self::types::{pack, Action, State}; - -pub fn register(registry: &mut Registry) { - registry.add_macro("utf8_state_table", expand_state_table); -} - -fn state_from_str(s: &S) -> Result -where - S: AsRef, -{ - Ok(match s.as_ref() { - "State::Ground" => State::Ground, - "State::Tail3" => State::Tail3, - "State::Tail2" => State::Tail2, - "State::Tail1" => State::Tail1, - "State::U3_2_e0" => State::U3_2_e0, - "State::U3_2_ed" => State::U3_2_ed, - "State::Utf8_4_3_f0" => State::Utf8_4_3_f0, - "State::Utf8_4_3_f4" => State::Utf8_4_3_f4, - _ => return Err(()), - }) -} - -fn action_from_str(s: &S) -> Result -where - S: AsRef, -{ - Ok(match s.as_ref() { - "Action::InvalidSequence" => Action::InvalidSequence, - "Action::EmitByte" => Action::EmitByte, - "Action::SetByte1" => Action::SetByte1, - "Action::SetByte2" => Action::SetByte2, - "Action::SetByte2Top" => Action::SetByte2Top, - "Action::SetByte3" => Action::SetByte3, - "Action::SetByte3Top" => Action::SetByte3Top, - "Action::SetByte4" => Action::SetByte4, - _ => return Err(()), - }) -} - -fn parse_table_input_mappings<'a>(parser: &mut Parser<'a>) -> PResult<'a, Vec> { - // Must start on open brace - parser.expect(&Token::OpenDelim(DelimToken::Brace))?; - - let mut arms: Vec = Vec::new(); - while parser.token != Token::CloseDelim(DelimToken::Brace) { - match parser.parse_arm() { - Ok(arm) => arms.push(arm), - Err(e) => { - // Recover by skipping to the end of the block. - return Err(e); - }, - } - } - - // Consume the closing brace - parser.bump(); - Ok(arms) -} - -/// Expressions describing state transitions and actions -#[derive(Debug)] -struct TableDefinitionExprs { - state_expr: P, - mapping_arms: Vec, -} - -fn state_from_expr(expr: P, cx: &mut ExtCtxt) -> Result { - let s = match expr.node { - ExprKind::Path(ref _qself, ref path) => path.to_string(), - _ => { - cx.span_err(expr.span, "expected State"); - return Err(()); - }, - }; - - state_from_str(&s).map_err(|_| { - cx.span_err(expr.span, "expected State"); - }) -} - -fn u8_lit_from_expr(expr: &Expr, cx: &mut ExtCtxt) -> Result { - static MSG: &str = "expected u8 int literal"; - - match expr.node { - ExprKind::Lit(ref lit) => match lit.node { - LitKind::Int(val, _) => Ok(val as u8), - _ => { - cx.span_err(lit.span, MSG); - Err(()) - }, - }, - _ => { - cx.span_err(expr.span, MSG); - Err(()) - }, - } -} - -fn input_mapping_from_arm(arm: Arm, cx: &mut ExtCtxt) -> Result { - let Arm { pats, body, .. } = arm; - - let input = InputDefinition::from_pat(&pats[0], cx)?; - let transition = Transition::from_expr(&body, cx)?; - - Ok(InputMapping { input, transition }) -} - -/// What happens when certain input is received -#[derive(Copy, Clone)] -enum Transition { - State(State), - Action(Action), - StateAction(State, Action), -} - -impl fmt::Debug for Transition { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - Transition::State(state) => write!(f, "State({:?})", state)?, - Transition::Action(action) => write!(f, "Action({:?})", action)?, - Transition::StateAction(state, action) => { - write!(f, "StateAction({:?}, {:?})", state, action)?; - }, - } - - write!(f, " -> {:?}", self.pack_u8()) - } -} - -impl Transition { - // State is stored in the top 4 bits - fn pack_u8(self) -> u8 { - match self { - Transition::State(state) => pack(state, Action::InvalidSequence), - Transition::Action(action) => pack(State::Ground, action), - Transition::StateAction(state, action) => pack(state, action), - } - } -} - -impl Transition { - fn from_expr(expr: &Expr, cx: &mut ExtCtxt) -> Result { - match expr.node { - ExprKind::Tup(ref tup_exprs) => { - let mut action = None; - let mut state = None; - - for tup_expr in tup_exprs { - if let ExprKind::Path(_, ref path) = tup_expr.node { - let path_str = path.to_string(); - if path_str.starts_with('A') { - action = Some(action_from_str(&path_str).map_err(|_| { - cx.span_err(expr.span, "invalid action"); - })?); - } else { - state = Some(state_from_str(&path_str).map_err(|_| { - cx.span_err(expr.span, "invalid state"); - })?); - } - } - } - - match (action, state) { - (Some(action), Some(state)) => Ok(Transition::StateAction(state, action)), - (None, Some(state)) => Ok(Transition::State(state)), - (Some(action), None) => Ok(Transition::Action(action)), - _ => { - cx.span_err(expr.span, "expected Action and/or State"); - Err(()) - }, - } - }, - ExprKind::Path(_, ref path) => { - // Path can be Action or State - let path_str = path.to_string(); - - if path_str.starts_with('A') { - let action = action_from_str(&path_str).map_err(|_| { - cx.span_err(expr.span, "invalid action"); - })?; - Ok(Transition::Action(action)) - } else { - let state = state_from_str(&path_str).map_err(|_| { - cx.span_err(expr.span, "invalid state"); - })?; - - Ok(Transition::State(state)) - } - }, - _ => { - cx.span_err(expr.span, "expected Action and/or State"); - Err(()) - }, - } - } -} - -#[derive(Debug)] -enum InputDefinition { - Specific(u8), - Range { start: u8, end: u8 }, -} - -impl InputDefinition { - fn from_pat(pat: &Pat, cx: &mut ExtCtxt) -> Result { - Ok(match pat.node { - PatKind::Lit(ref lit_expr) => { - InputDefinition::Specific(u8_lit_from_expr(&lit_expr, cx)?) - }, - PatKind::Range(ref start_expr, ref end_expr) => InputDefinition::Range { - start: u8_lit_from_expr(start_expr, cx)?, - end: u8_lit_from_expr(end_expr, cx)?, - }, - _ => { - cx.span_err(pat.span, "expected literal or range expression"); - return Err(()); - }, - }) - } -} - -#[derive(Debug)] -struct InputMapping { - input: InputDefinition, - transition: Transition, -} - -#[derive(Debug)] -struct TableDefinition { - state: State, - mappings: Vec, -} - -fn parse_raw_definitions( - definitions: Vec, - cx: &mut ExtCtxt, -) -> Result, ()> { - let mut out = Vec::new(); - - for raw in definitions { - let TableDefinitionExprs { state_expr, mapping_arms } = raw; - let state = state_from_expr(state_expr, cx)?; - - let mut mappings = Vec::new(); - for arm in mapping_arms { - mappings.push(input_mapping_from_arm(arm, cx)?); - } - - out.push(TableDefinition { state, mappings }) - } - - Ok(out) -} - -fn parse_table_definition<'a>(parser: &mut Parser<'a>) -> PResult<'a, TableDefinitionExprs> { - let state_expr = parser.parse_expr()?; - parser.expect(&Token::FatArrow)?; - let mappings = parse_table_input_mappings(parser)?; - - Ok(TableDefinitionExprs { state_expr, mapping_arms: mappings }) -} - -fn parse_table_definition_list<'a>( - parser: &mut Parser<'a>, -) -> PResult<'a, Vec> { - let mut definitions = Vec::new(); - while parser.token != Token::Eof { - definitions.push(parse_table_definition(parser)?); - parser.eat(&Token::Comma); - } - - Ok(definitions) -} - -fn build_state_tables(defs: T) -> [[u8; 256]; 8] -where - T: AsRef<[TableDefinition]>, -{ - let mut result = [[0u8; 256]; 8]; - - for def in defs.as_ref() { - let state = def.state; - let state = state as u8; - let transitions = &mut result[state as usize]; - - for mapping in &def.mappings { - let trans = mapping.transition.pack_u8(); - match mapping.input { - InputDefinition::Specific(idx) => { - transitions[idx as usize] = trans; - }, - InputDefinition::Range { start, end } => { - for idx in start..end { - transitions[idx as usize] = trans; - } - transitions[end as usize] = trans; - }, - } - } - } - - result -} - -fn build_table_ast(cx: &mut ExtCtxt, sp: Span, table: [[u8; 256]; 8]) -> P { - let table = table - .iter() - .map(|list| { - let exprs = list.iter().map(|num| cx.expr_u8(sp, *num)).collect(); - cx.expr_vec(sp, exprs) - }) - .collect(); - - cx.expr_vec(sp, table) -} - -fn expand_state_table<'cx>( - cx: &'cx mut ExtCtxt, - sp: Span, - args: &[TokenTree], -) -> Box { - macro_rules! ptry { - ($pres:expr) => { - match $pres { - Ok(val) => val, - Err(mut err) => { - err.emit(); - return DummyResult::any(sp); - }, - } - }; - } - - // Parse the lookup spec - let mut parser: Parser = cx.new_parser_from_tts(args); - let definitions = ptry!(parse_table_definition_list(&mut parser)); - let definitions = match parse_raw_definitions(definitions, cx) { - Ok(definitions) => definitions, - Err(_) => return DummyResult::any(sp), - }; - - let table = build_state_tables(&definitions); - let ast = build_table_ast(cx, sp, table); - - MacEager::expr(ast) -} diff --git a/codegen/src/ext/vt.rs b/codegen/src/ext/vt.rs deleted file mode 100644 index aff7d68c..00000000 --- a/codegen/src/ext/vt.rs +++ /dev/null @@ -1,393 +0,0 @@ -//! Macro expansion for the virtual terminal parser state table -use std::fmt; - -use syntex::Registry; - -use syntex_syntax::ast::{self, Arm, Expr, ExprKind, LitKind, Pat, PatKind}; -use syntex_syntax::codemap::Span; -use syntex_syntax::ext::base::{DummyResult, ExtCtxt, MacEager, MacResult}; -use syntex_syntax::ext::build::AstBuilder; -use syntex_syntax::parse::parser::Parser; -use syntex_syntax::parse::token::{DelimToken, Token}; -use syntex_syntax::parse::PResult; -use syntex_syntax::ptr::P; -use syntex_syntax::tokenstream::TokenTree; - -#[path = "../../../src/definitions.rs"] -mod definitions; - -use self::definitions::{Action, State}; - -pub fn register(registry: &mut Registry) { - registry.add_macro("vt_state_table", expand_state_table); -} - -fn state_from_str(s: &S) -> Result -where - S: AsRef, -{ - Ok(match s.as_ref() { - "State::Anywhere" => State::Anywhere, - "State::CsiEntry" => State::CsiEntry, - "State::CsiIgnore" => State::CsiIgnore, - "State::CsiIntermediate" => State::CsiIntermediate, - "State::CsiParam" => State::CsiParam, - "State::DcsEntry" => State::DcsEntry, - "State::DcsIgnore" => State::DcsIgnore, - "State::DcsIntermediate" => State::DcsIntermediate, - "State::DcsParam" => State::DcsParam, - "State::DcsPassthrough" => State::DcsPassthrough, - "State::Escape" => State::Escape, - "State::EscapeIntermediate" => State::EscapeIntermediate, - "State::Ground" => State::Ground, - "State::OscString" => State::OscString, - "State::SosPmApcString" => State::SosPmApcString, - "State::Utf8" => State::Utf8, - _ => return Err(()), - }) -} - -fn action_from_str(s: &S) -> Result -where - S: AsRef, -{ - Ok(match s.as_ref() { - "Action::None" => Action::None, - "Action::Clear" => Action::Clear, - "Action::Collect" => Action::Collect, - "Action::CsiDispatch" => Action::CsiDispatch, - "Action::EscDispatch" => Action::EscDispatch, - "Action::Execute" => Action::Execute, - "Action::Hook" => Action::Hook, - "Action::Ignore" => Action::Ignore, - "Action::OscEnd" => Action::OscEnd, - "Action::OscPut" => Action::OscPut, - "Action::OscStart" => Action::OscStart, - "Action::Param" => Action::Param, - "Action::Print" => Action::Print, - "Action::Put" => Action::Put, - "Action::Unhook" => Action::Unhook, - "Action::BeginUtf8" => Action::BeginUtf8, - _ => return Err(()), - }) -} - -fn parse_table_input_mappings<'a>(parser: &mut Parser<'a>) -> PResult<'a, Vec> { - // Must start on open brace - parser.expect(&Token::OpenDelim(DelimToken::Brace))?; - - let mut arms: Vec = Vec::new(); - while parser.token != Token::CloseDelim(DelimToken::Brace) { - match parser.parse_arm() { - Ok(arm) => arms.push(arm), - Err(e) => { - // Recover by skipping to the end of the block. - return Err(e); - }, - } - } - - // Consume the closing brace - parser.bump(); - Ok(arms) -} - -/// Expressions describing state transitions and actions -#[derive(Debug)] -struct TableDefinitionExprs { - state_expr: P, - mapping_arms: Vec, -} - -fn state_from_expr(expr: P, cx: &mut ExtCtxt) -> Result { - let s = match expr.node { - ExprKind::Path(ref _qself, ref path) => path.to_string(), - _ => { - cx.span_err(expr.span, "expected State"); - return Err(()); - }, - }; - - state_from_str(&s).map_err(|_| { - cx.span_err(expr.span, "expected State"); - }) -} - -fn u8_lit_from_expr(expr: &Expr, cx: &mut ExtCtxt) -> Result { - static MSG: &str = "expected u8 int literal"; - - match expr.node { - ExprKind::Lit(ref lit) => match lit.node { - LitKind::Int(val, _) => Ok(val as u8), - _ => { - cx.span_err(lit.span, MSG); - Err(()) - }, - }, - _ => { - cx.span_err(expr.span, MSG); - Err(()) - }, - } -} - -fn input_mapping_from_arm(arm: Arm, cx: &mut ExtCtxt) -> Result { - let Arm { pats, body, .. } = arm; - - let input = InputDefinition::from_pat(&pats[0], cx)?; - let transition = Transition::from_expr(&body, cx)?; - - Ok(InputMapping { input, transition }) -} - -/// What happens when certain input is received -#[derive(Copy, Clone)] -enum Transition { - State(State), - Action(Action), - StateAction(State, Action), -} - -impl fmt::Debug for Transition { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - Transition::State(state) => write!(f, "State({:?})", state)?, - Transition::Action(action) => write!(f, "Action({:?})", action)?, - Transition::StateAction(state, action) => { - write!(f, "StateAction({:?}, {:?})", state, action)?; - }, - } - - write!(f, " -> {:?}", self.pack_u8()) - } -} - -impl Transition { - // State is stored in the top 4 bits - fn pack_u8(self) -> u8 { - match self { - Transition::State(state) => state as u8, - Transition::Action(action) => (action as u8) << 4, - Transition::StateAction(state, action) => ((action as u8) << 4) | (state as u8), - } - } -} - -impl Transition { - fn from_expr(expr: &Expr, cx: &mut ExtCtxt) -> Result { - match expr.node { - ExprKind::Tup(ref tup_exprs) => { - let mut action = None; - let mut state = None; - - for tup_expr in tup_exprs { - if let ExprKind::Path(_, ref path) = tup_expr.node { - let path_str = path.to_string(); - if path_str.starts_with('A') { - action = Some(action_from_str(&path_str).map_err(|_| { - cx.span_err(expr.span, "invalid action"); - })?); - } else { - state = Some(state_from_str(&path_str).map_err(|_| { - cx.span_err(expr.span, "invalid state"); - })?); - } - } - } - - match (action, state) { - (Some(action), Some(state)) => Ok(Transition::StateAction(state, action)), - (None, Some(state)) => Ok(Transition::State(state)), - (Some(action), None) => Ok(Transition::Action(action)), - _ => { - cx.span_err(expr.span, "expected Action and/or State"); - Err(()) - }, - } - }, - ExprKind::Path(_, ref path) => { - // Path can be Action or State - let path_str = path.to_string(); - - if path_str.starts_with('A') { - let action = action_from_str(&path_str).map_err(|_| { - cx.span_err(expr.span, "invalid action"); - })?; - Ok(Transition::Action(action)) - } else { - let state = state_from_str(&path_str).map_err(|_| { - cx.span_err(expr.span, "invalid state"); - })?; - - Ok(Transition::State(state)) - } - }, - _ => { - cx.span_err(expr.span, "expected Action and/or State"); - Err(()) - }, - } - } -} - -#[derive(Debug)] -enum InputDefinition { - Specific(u8), - Range { start: u8, end: u8 }, -} - -impl InputDefinition { - fn from_pat(pat: &Pat, cx: &mut ExtCtxt) -> Result { - Ok(match pat.node { - PatKind::Lit(ref lit_expr) => { - InputDefinition::Specific(u8_lit_from_expr(&lit_expr, cx)?) - }, - PatKind::Range(ref start_expr, ref end_expr) => InputDefinition::Range { - start: u8_lit_from_expr(start_expr, cx)?, - end: u8_lit_from_expr(end_expr, cx)?, - }, - _ => { - cx.span_err(pat.span, "expected literal or range expression"); - return Err(()); - }, - }) - } -} - -#[derive(Debug)] -struct InputMapping { - input: InputDefinition, - transition: Transition, -} - -#[derive(Debug)] -struct TableDefinition { - state: State, - mappings: Vec, -} - -fn parse_raw_definitions( - definitions: Vec, - cx: &mut ExtCtxt, -) -> Result, ()> { - let mut out = Vec::new(); - - for raw in definitions { - let TableDefinitionExprs { state_expr, mapping_arms } = raw; - let state = state_from_expr(state_expr, cx)?; - - let mut mappings = Vec::new(); - for arm in mapping_arms { - mappings.push(input_mapping_from_arm(arm, cx)?); - } - - out.push(TableDefinition { state, mappings }) - } - - Ok(out) -} - -fn parse_table_definition<'a>(parser: &mut Parser<'a>) -> PResult<'a, TableDefinitionExprs> { - let state_expr = parser.parse_expr()?; - parser.expect(&Token::FatArrow)?; - let mappings = parse_table_input_mappings(parser)?; - - Ok(TableDefinitionExprs { state_expr, mapping_arms: mappings }) -} - -fn parse_table_definition_list<'a>( - parser: &mut Parser<'a>, -) -> PResult<'a, Vec> { - let mut definitions = Vec::new(); - while parser.token != Token::Eof { - definitions.push(parse_table_definition(parser)?); - parser.eat(&Token::Comma); - } - - Ok(definitions) -} - -fn build_state_tables(defs: T) -> [[u8; 256]; 16] -where - T: AsRef<[TableDefinition]>, -{ - let mut result = [[0u8; 256]; 16]; - - for def in defs.as_ref() { - let state = def.state; - let state = state as u8; - let transitions = &mut result[state as usize]; - - for mapping in &def.mappings { - let trans = mapping.transition.pack_u8(); - match mapping.input { - InputDefinition::Specific(idx) => { - transitions[idx as usize] = trans; - }, - InputDefinition::Range { start, end } => { - for idx in start..end { - transitions[idx as usize] = trans; - } - transitions[end as usize] = trans; - }, - } - } - } - - result -} - -fn build_table_ast(cx: &mut ExtCtxt, sp: Span, table: [[u8; 256]; 16]) -> P { - let table = table - .iter() - .map(|list| { - let exprs = list.iter().map(|num| cx.expr_u8(sp, *num)).collect(); - cx.expr_vec(sp, exprs) - }) - .collect(); - - cx.expr_vec(sp, table) -} - -fn expand_state_table<'cx>( - cx: &'cx mut ExtCtxt, - sp: Span, - args: &[TokenTree], -) -> Box { - macro_rules! ptry { - ($pres:expr) => { - match $pres { - Ok(val) => val, - Err(mut err) => { - err.emit(); - return DummyResult::any(sp); - }, - } - }; - } - - // Parse the lookup spec - let mut parser: Parser = cx.new_parser_from_tts(args); - let definitions = ptry!(parse_table_definition_list(&mut parser)); - let definitions = match parse_raw_definitions(definitions, cx) { - Ok(definitions) => definitions, - Err(_) => return DummyResult::any(sp), - }; - - let table = build_state_tables(&definitions); - let ast = build_table_ast(cx, sp, table); - - MacEager::expr(ast) -} - -#[cfg(test)] -mod tests { - use super::definitions::{Action, State}; - use super::Transition; - - #[test] - fn pack_u8() { - let transition = Transition::StateAction(State::CsiParam, Action::Collect); - assert_eq!(transition.pack_u8(), 0x24); - } -} diff --git a/codegen/src/main.rs b/codegen/src/main.rs deleted file mode 100644 index 7cc6cd02..00000000 --- a/codegen/src/main.rs +++ /dev/null @@ -1,23 +0,0 @@ -#![allow(dead_code)] - -use std::path::Path; - -use syntex; - -mod ext; - -fn main() { - // Expand VT parser state table - let mut registry = syntex::Registry::new(); - ext::vt::register(&mut registry); - let src = &Path::new("../src/table.rs.in"); - let dst = &Path::new("../src/table.rs"); - registry.expand("vt_state_table", src, dst).expect("expand vt_stable_table ok"); - - // Expand UTF8 parser state table - let mut registry = syntex::Registry::new(); - ext::utf8::register(&mut registry); - let src = &Path::new("../utf8parse/src/table.rs.in"); - let dst = &Path::new("../utf8parse/src/table.rs"); - registry.expand("utf8_state_table", src, dst).expect("expand utf8_stable_table ok"); -} diff --git a/generate_state_changes/Cargo.toml b/generate_state_changes/Cargo.toml new file mode 100644 index 00000000..efe58708 --- /dev/null +++ b/generate_state_changes/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "generate_state_changes" +version = "0.1.0" +authors = ["Christian Duerr "] +edition = "2018" + +[lib] +proc-macro = true + +[dependencies] +proc-macro2 = "1.0.6" +quote = "1.0.2" diff --git a/generate_state_changes/src/lib.rs b/generate_state_changes/src/lib.rs new file mode 100644 index 00000000..485a33e7 --- /dev/null +++ b/generate_state_changes/src/lib.rs @@ -0,0 +1,174 @@ +extern crate proc_macro; + +use std::iter::Peekable; + +use proc_macro2::TokenTree::{Group, Literal, Punct}; +use proc_macro2::{token_stream, TokenStream, TokenTree}; +use quote::quote; + +/// Create a `const fn` which will return an array with all state changes. +#[proc_macro] +pub fn generate_state_changes(item: proc_macro::TokenStream) -> proc_macro::TokenStream { + // Convert from proc_macro -> proc_macro2 + let item: TokenStream = item.into(); + let mut iter = item.into_iter().peekable(); + + // Determine output function name + let fn_name = iter.next().unwrap(); + + // Separator between name and body with state changes + expect_punct(&mut iter, ','); + + // Create token stream to assign each state change to the array + let assignments_stream = states_stream(&mut iter); + + quote!( + const fn #fn_name() -> [[u8; 256]; 16] { + let mut state_changes = [[0; 256]; 16]; + + #assignments_stream + + state_changes + } + ) + .into() +} + +/// Generate the array assignment statements for all origin states. +fn states_stream(iter: &mut impl Iterator) -> TokenStream { + let mut states_stream = next_group(iter).into_iter().peekable(); + + // Loop over all origin state entries + let mut tokens = quote!(); + while states_stream.peek().is_some() { + // Add all mappings for this state + tokens.extend(state_entry_stream(&mut states_stream)); + + // Allow trailing comma + optional_punct(&mut states_stream, ','); + } + tokens +} + +/// Generate the array assignment statements for one origin state. +fn state_entry_stream(iter: &mut Peekable) -> TokenStream { + // Origin state name + let state = iter.next().unwrap().into(); + + // Token stream with all the byte->target mappings + let mut changes_stream = next_group(iter).into_iter().peekable(); + + let mut tokens = quote!(); + while changes_stream.peek().is_some() { + // Add next mapping for this state + tokens.extend(change_stream(&mut changes_stream, &state)); + + // Allow trailing comma + optional_punct(&mut changes_stream, ','); + } + tokens +} + +/// Generate the array assignment statement for a single byte->target mapping for one state. +fn change_stream(iter: &mut Peekable, state: &TokenTree) -> TokenStream { + // Start of input byte range + let start = next_usize(iter); + + // End of input byte range + let end = if optional_punct(iter, '.') { + // Read inclusive end of range + expect_punct(iter, '.'); + expect_punct(iter, '='); + next_usize(iter) + } else { + // Without range, end is equal to start + start + }; + + // Separator between byte input range and output state + expect_punct(iter, '='); + expect_punct(iter, '>'); + + // Token stream with target state and action + let mut target_change_stream = next_group(iter).into_iter().peekable(); + + let mut tokens = quote!(); + while target_change_stream.peek().is_some() { + // Target state/action for all bytes in the range + let (target_state, target_action) = target_change(&mut target_change_stream); + + // Create a new entry for every byte in the range + for byte in start..=end { + // TODO: Force adding `State::` and `Action::`? + // TODO: Should we really use `pack` here without import? + tokens.extend(quote!( + state_changes[State::#state as usize][#byte] = + pack(State::#target_state, Action::#target_action); + )); + } + } + tokens +} + +/// Get next target state and action. +fn target_change(iter: &mut Peekable) -> (TokenTree, TokenTree) { + let target_state = iter.next().unwrap(); + + // Separator between state and action + expect_punct(iter, ','); + + let target_action = iter.next().unwrap(); + + (target_state, target_action) +} + +/// Check if next token matches specific punctuation. +fn optional_punct(iter: &mut Peekable, c: char) -> bool { + match iter.peek() { + Some(Punct(punct)) if punct.as_char() == c => iter.next().is_some(), + _ => false, + } +} + +/// Ensure next token matches specific punctuation. +/// +/// # Panics +/// +/// Panics if the punctuation does not match. +fn expect_punct(iter: &mut impl Iterator, c: char) { + match iter.next() { + Some(Punct(punct)) if punct.as_char() == c => (), + token => panic!("Expected punctuation '{}', but got {:?}", c, token), + } +} + +/// Get next token as [`usize`]. +/// +/// # Panics +/// +/// Panics if the next token is not a [`usize`] in hex or decimal literal format. +fn next_usize(iter: &mut impl Iterator) -> usize { + match iter.next() { + Some(Literal(literal)) => { + let literal = literal.to_string(); + if literal.starts_with("0x") { + usize::from_str_radix(&literal[2..], 16).unwrap() + } else { + usize::from_str_radix(&literal, 10).unwrap() + } + }, + token => panic!("Expected literal, but got {:?}", token), + } +} + +/// Get next token as [`Group`]. +/// +/// # Panics +/// +/// Panics if the next token is not a [`Group`]. +fn next_group(iter: &mut impl Iterator) -> TokenStream { + match iter.next() { + Some(Group(group)) => group.stream(), + token => panic!("Expected group, but got {:?}", token), + } +} diff --git a/src/definitions.rs b/src/definitions.rs index 375ac02c..568eb41f 100644 --- a/src/definitions.rs +++ b/src/definitions.rs @@ -1,3 +1,5 @@ +use core::mem; + #[allow(dead_code)] #[derive(Debug, Copy, Clone)] pub enum State { @@ -46,6 +48,27 @@ pub enum Action { BeginUtf8 = 15, } +impl State { + #[inline] + pub fn entry_action(&self) -> Action { + match self { + State::CsiEntry | State::DcsEntry | State::Escape => Action::Clear, + State::DcsPassthrough => Action::Hook, + State::OscString => Action::OscStart, + _ => Action::None, + } + } + + #[inline] + pub fn exit_action(&self) -> Action { + match self { + State::DcsPassthrough => Action::Unhook, + State::OscString => Action::OscEnd, + _ => Action::None, + } + } +} + /// Unpack a u8 into a State and Action /// /// The implementation of this assumes that there are *precisely* 16 variants for both Action and @@ -55,17 +78,25 @@ pub enum Action { /// Bad things will happen if those invariants are violated. #[inline(always)] pub fn unpack(delta: u8) -> (State, Action) { - ( - // State is stored in bottom 4 bits - unsafe { core::mem::transmute(delta & 0x0f) }, - // Action is stored in top 4 bits - unsafe { core::mem::transmute(delta >> 4) }, - ) + unsafe { + ( + // State is stored in bottom 4 bits + mem::transmute(delta & 0x0f), + // Action is stored in top 4 bits + mem::transmute(delta >> 4), + ) + } +} + +#[inline(always)] +pub const fn pack(state: State, action: Action) -> u8 { + (action as u8) << 4 | state as u8 } #[cfg(test)] mod tests { - use super::{unpack, Action, State}; + use super::*; + #[test] fn unpack_state_action() { match unpack(0xee) { @@ -83,4 +114,22 @@ mod tests { _ => panic!("unpack failed"), } } + + #[test] + fn pack_state_action() { + match unpack(0xee) { + (State::SosPmApcString, Action::Unhook) => (), + _ => panic!("unpack failed"), + } + + match unpack(0x0f) { + (State::Utf8, Action::None) => (), + _ => panic!("unpack failed"), + } + + match unpack(0xff) { + (State::Utf8, Action::BeginUtf8) => (), + _ => panic!("unpack failed"), + } + } } diff --git a/src/lib.rs b/src/lib.rs index 8783d822..50eddb88 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,6 +30,7 @@ //! [`Parser`]: struct.Parser.html //! [`Perform`]: trait.Perform.html //! [Paul Williams' ANSI parser state machine]: https://vt100.net/emu/dec_ansi_parser +#![cfg_attr(all(feature = "nightly", test), feature(test))] #![cfg_attr(feature = "no_std", no_std)] use core::mem::MaybeUninit; @@ -42,21 +43,6 @@ mod definitions; mod table; use definitions::{unpack, Action, State}; -use table::{ENTRY_ACTIONS, EXIT_ACTIONS, STATE_CHANGE}; - -impl State { - /// Get exit action for this state - #[inline(always)] - pub fn exit_action(self) -> Action { - unsafe { *EXIT_ACTIONS.get_unchecked(self as usize) } - } - - /// Get entry action for this state - #[inline(always)] - pub fn entry_action(self) -> Action { - unsafe { *ENTRY_ACTIONS.get_unchecked(self as usize) } - } -} const MAX_INTERMEDIATES: usize = 2; #[cfg(any(feature = "no_std", test))] @@ -129,10 +115,10 @@ impl Parser { // Handle state changes in the anywhere state before evaluating changes // for current state. - let mut change = STATE_CHANGE[State::Anywhere as usize][byte as usize]; + let mut change = table::STATE_CHANGES[State::Anywhere as usize][byte as usize]; if change == 0 { - change = STATE_CHANGE[self.state as usize][byte as usize]; + change = table::STATE_CHANGES[self.state as usize][byte as usize]; } // Unpack into a state and action @@ -739,3 +725,60 @@ mod tests { assert_eq!(dispatcher.params[1].len(), MAX_OSC_RAW - dispatcher.params[0].len()); } } + +#[cfg(all(feature = "nightly", test))] +mod bench { + extern crate std; + extern crate test; + + use super::*; + + use test::{black_box, Bencher}; + + static VTE_DEMO: &[u8] = include_bytes!("../tests/demo.vte"); + + struct BenchDispatcher; + impl Perform for BenchDispatcher { + fn print(&mut self, c: char) { + black_box(c); + } + + fn execute(&mut self, byte: u8) { + black_box(byte); + } + + fn hook(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, c: char) { + black_box((params, intermediates, ignore, c)); + } + + fn put(&mut self, byte: u8) { + black_box(byte); + } + + fn unhook(&mut self) {} + + fn osc_dispatch(&mut self, params: &[&[u8]]) { + black_box(params); + } + + fn csi_dispatch(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, c: char) { + black_box((params, intermediates, ignore, c)); + } + + fn esc_dispatch(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, byte: u8) { + black_box((params, intermediates, ignore, byte)); + } + } + + #[bench] + fn testfile(b: &mut Bencher) { + b.iter(|| { + let mut dispatcher = BenchDispatcher; + let mut parser = Parser::new(); + + for byte in VTE_DEMO { + parser.advance(&mut dispatcher, *byte); + } + }); + } +} diff --git a/src/table.rs b/src/table.rs index a9569aa0..f5a90ee9 100644 --- a/src/table.rs +++ b/src/table.rs @@ -1,343 +1,175 @@ /// This is the state change table. It's indexed first by current state and then by the next /// character in the pty stream. -use crate::definitions::Action; +use crate::definitions::{pack, Action, State}; -pub static STATE_CHANGE: [[u8; 256]; 16] = [ - // Beginning of UTF-8 2 byte sequence - // Beginning of UTF-8 3 byte sequence - // Beginning of UTF-8 4 byte sequence - [ - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 92u8, 0u8, 92u8, 10u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, - ], - [ - 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, - 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 0u8, 80u8, 0u8, 0u8, 80u8, 80u8, - 80u8, 80u8, 35u8, 35u8, 35u8, 35u8, 35u8, 35u8, 35u8, 35u8, 35u8, 35u8, 35u8, 35u8, 35u8, - 35u8, 35u8, 35u8, 180u8, 180u8, 180u8, 180u8, 180u8, 180u8, 180u8, 180u8, 180u8, 180u8, - 2u8, 180u8, 36u8, 36u8, 36u8, 36u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, - 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, - 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, - 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, - 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 112u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - ], - [ - 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, - 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 0u8, 80u8, 0u8, 0u8, 80u8, 80u8, - 80u8, 80u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, - 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, - 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, - 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, - 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, - 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, - 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 12u8, 112u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - ], - [ - 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, - 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 0u8, 80u8, 0u8, 0u8, 80u8, 80u8, - 80u8, 80u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, - 32u8, 32u8, 32u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, 2u8, - 2u8, 2u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, - 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, - 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, - 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, - 60u8, 60u8, 60u8, 60u8, 60u8, 112u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - ], - [ - 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, - 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 0u8, 80u8, 0u8, 0u8, 80u8, 80u8, - 80u8, 80u8, 35u8, 35u8, 35u8, 35u8, 35u8, 35u8, 35u8, 35u8, 35u8, 35u8, 35u8, 35u8, 35u8, - 35u8, 35u8, 35u8, 176u8, 176u8, 176u8, 176u8, 176u8, 176u8, 176u8, 176u8, 176u8, 176u8, - 2u8, 176u8, 2u8, 2u8, 2u8, 2u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, - 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, - 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, - 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, - 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 60u8, 112u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - ], - [ - 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, - 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 0u8, 112u8, - 0u8, 0u8, 112u8, 112u8, 112u8, 112u8, 39u8, 39u8, 39u8, 39u8, 39u8, 39u8, 39u8, 39u8, 39u8, - 39u8, 39u8, 39u8, 39u8, 39u8, 39u8, 39u8, 184u8, 184u8, 184u8, 184u8, 184u8, 184u8, 184u8, - 184u8, 184u8, 184u8, 6u8, 184u8, 40u8, 40u8, 40u8, 40u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, - 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, - 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, - 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, - 9u8, 9u8, 112u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, - ], - [ - 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, - 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 0u8, 112u8, - 0u8, 0u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, - 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, - 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, - 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, - 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, - 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, - 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, - 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 12u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - ], - [ - 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, - 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 0u8, 112u8, - 0u8, 0u8, 112u8, 112u8, 112u8, 112u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, - 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 6u8, 6u8, 6u8, 6u8, 6u8, 6u8, 6u8, 6u8, 6u8, 6u8, - 6u8, 6u8, 6u8, 6u8, 6u8, 6u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, - 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, - 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, - 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 112u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - ], - [ - 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, - 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 0u8, 112u8, - 0u8, 0u8, 112u8, 112u8, 112u8, 112u8, 39u8, 39u8, 39u8, 39u8, 39u8, 39u8, 39u8, 39u8, 39u8, - 39u8, 39u8, 39u8, 39u8, 39u8, 39u8, 39u8, 176u8, 176u8, 176u8, 176u8, 176u8, 176u8, 176u8, - 176u8, 176u8, 176u8, 6u8, 176u8, 6u8, 6u8, 6u8, 6u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, - 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, - 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, - 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, 9u8, - 9u8, 9u8, 112u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, - ], - [ - 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, - 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 0u8, 208u8, - 0u8, 0u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, - 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, - 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, - 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, - 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, - 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, - 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, - 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 208u8, 112u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 12u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - ], - [ - 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, - 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 0u8, 80u8, 0u8, 0u8, 80u8, 80u8, - 80u8, 80u8, 43u8, 43u8, 43u8, 43u8, 43u8, 43u8, 43u8, 43u8, 43u8, 43u8, 43u8, 43u8, 43u8, - 43u8, 43u8, 43u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, - 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, - 76u8, 76u8, 76u8, 76u8, 76u8, 5u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 14u8, 76u8, - 76u8, 1u8, 76u8, 13u8, 14u8, 14u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, - 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, - 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 112u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - ], - [ - 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, - 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 0u8, 80u8, 0u8, 0u8, 80u8, 80u8, - 80u8, 80u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, 32u8, - 32u8, 32u8, 32u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, - 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, - 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, - 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, - 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, - 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 76u8, 112u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - ], - [ - 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, - 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 0u8, 80u8, 0u8, 0u8, 80u8, 80u8, - 80u8, 80u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, - 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, - 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, - 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, - 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, - 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, - 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, - 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 192u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, - 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 80u8, 0u8, 80u8, 80u8, 80u8, 80u8, 80u8, - 80u8, 80u8, 80u8, 80u8, 80u8, 0u8, 80u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, - 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, - 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, - 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, - 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, - ], - [ - 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 12u8, 112u8, 112u8, 112u8, 112u8, 112u8, - 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 0u8, 112u8, - 0u8, 0u8, 112u8, 112u8, 112u8, 112u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, - 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, - 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, - 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, - 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, - 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, - 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, - 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, - 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, - 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, - 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, - 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, - 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, - 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, - 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, - 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, - 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, - 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, 144u8, - ], - [ - 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, - 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 0u8, 112u8, - 0u8, 0u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, - 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, - 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, - 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, - 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, - 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, - 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, - 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 112u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 12u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - ], - [ - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, - ], -]; +use generate_state_changes::generate_state_changes; -pub static ENTRY_ACTIONS: &[Action] = &[ - Action::None, // State::Anywhere - Action::Clear, // State::CsiEntry - Action::None, // State::CsiIgnore - Action::None, // State::CsiIntermediate - Action::None, // State::CsiParam - Action::Clear, // State::DcsEntry - Action::None, // State::DcsIgnore - Action::None, // State::DcsIntermediate - Action::None, // State::DcsParam - Action::Hook, // State::DcsPassthrough - Action::Clear, // State::Escape - Action::None, // State::EscapeIntermediate - Action::None, // State::Ground - Action::OscStart, // State::OscString - Action::None, // State::SosPmApcString - Action::None, -]; -// State::Utf8 +// Generate state changes at compile-time +pub static STATE_CHANGES: [[u8; 256]; 16] = state_changes(); +generate_state_changes!(state_changes, { + Anywhere { + 0x18 => (Ground, Execute), + 0x1a => (Ground, Execute), + 0x1b => (Escape, None), + }, -pub static EXIT_ACTIONS: &[Action] = &[ - Action::None, // State::Anywhere - Action::None, // State::CsiEntry - Action::None, // State::CsiIgnore - Action::None, // State::CsiIntermediate - Action::None, // State::CsiParam - Action::None, // State::DcsEntry - Action::None, // State::DcsIgnore - Action::None, // State::DcsIntermediate - Action::None, // State::DcsParam - Action::Unhook, // State::DcsPassthrough - Action::None, // State::Escape - Action::None, // State::EscapeIntermediate - Action::None, // State::Ground - Action::OscEnd, // State::OscString - Action::None, // State::SosPmApcString - Action::None, -]; // State::Utf8 + Ground { + 0x00..=0x17 => (Anywhere, Execute), + 0x19 => (Anywhere, Execute), + 0x1c..=0x1f => (Anywhere, Execute), + 0x20..=0x7f => (Anywhere, Print), + 0x80..=0x8f => (Anywhere, Execute), + 0x91..=0x9a => (Anywhere, Execute), + 0x9c => (Anywhere, Execute), + // Beginning of UTF-8 2 byte sequence + 0xc2..=0xdf => (Utf8, BeginUtf8), + // Beginning of UTF-8 3 byte sequence + 0xe0..=0xef => (Utf8, BeginUtf8), + // Beginning of UTF-8 4 byte sequence + 0xf0..=0xf4 => (Utf8, BeginUtf8), + }, + + Escape { + 0x00..=0x17 => (Anywhere, Execute), + 0x19 => (Anywhere, Execute), + 0x1c..=0x1f => (Anywhere, Execute), + 0x7f => (Anywhere, Ignore), + 0x20..=0x2f => (EscapeIntermediate, Collect), + 0x30..=0x4f => (Ground, EscDispatch), + 0x51..=0x57 => (Ground, EscDispatch), + 0x59 => (Ground, EscDispatch), + 0x5a => (Ground, EscDispatch), + 0x5c => (Ground, EscDispatch), + 0x60..=0x7e => (Ground, EscDispatch), + 0x5b => (CsiEntry, None), + 0x5d => (OscString, None), + 0x50 => (DcsEntry, None), + 0x58 => (SosPmApcString, None), + 0x5e => (SosPmApcString, None), + 0x5f => (SosPmApcString, None), + }, + + EscapeIntermediate { + 0x00..=0x17 => (Anywhere, Execute), + 0x19 => (Anywhere, Execute), + 0x1c..=0x1f => (Anywhere, Execute), + 0x20..=0x2f => (Anywhere, Collect), + 0x7f => (Anywhere, Ignore), + 0x30..=0x7e => (Ground, EscDispatch), + }, + + CsiEntry { + 0x00..=0x17 => (Anywhere, Execute), + 0x19 => (Anywhere, Execute), + 0x1c..=0x1f => (Anywhere, Execute), + 0x7f => (Anywhere, Ignore), + 0x20..=0x2f => (CsiIntermediate, Collect), + 0x3a => (CsiIgnore, None), + 0x30..=0x39 => (CsiParam, Param), + 0x3b => (CsiParam, Param), + 0x3c..=0x3f => (CsiParam, Collect), + 0x40..=0x7e => (Ground, CsiDispatch), + }, + + CsiIgnore { + 0x00..=0x17 => (Anywhere, Execute), + 0x19 => (Anywhere, Execute), + 0x1c..=0x1f => (Anywhere, Execute), + 0x20..=0x3f => (Anywhere, Ignore), + 0x7f => (Anywhere, Ignore), + 0x40..=0x7e => (Ground, None), + }, + + CsiParam { + 0x00..=0x17 => (Anywhere, Execute), + 0x19 => (Anywhere, Execute), + 0x1c..=0x1f => (Anywhere, Execute), + 0x30..=0x39 => (Anywhere, Param), + 0x3b => (Anywhere, Param), + 0x7f => (Anywhere, Ignore), + 0x3a => (CsiIgnore, None), + 0x3c..=0x3f => (CsiIgnore, None), + 0x20..=0x2f => (CsiIntermediate, Collect), + 0x40..=0x7e => (Ground, CsiDispatch), + }, + + CsiIntermediate { + 0x00..=0x17 => (Anywhere, Execute), + 0x19 => (Anywhere, Execute), + 0x1c..=0x1f => (Anywhere, Execute), + 0x20..=0x2f => (Anywhere, Collect), + 0x7f => (Anywhere, Ignore), + 0x30..=0x3f => (CsiIgnore, None), + 0x40..=0x7e => (Ground, CsiDispatch), + }, + + DcsEntry { + 0x00..=0x17 => (Anywhere, Ignore), + 0x19 => (Anywhere, Ignore), + 0x1c..=0x1f => (Anywhere, Ignore), + 0x7f => (Anywhere, Ignore), + 0x3a => (DcsIgnore, None), + 0x20..=0x2f => (DcsIntermediate, Collect), + 0x30..=0x39 => (DcsParam, Param), + 0x3b => (DcsParam, Param), + 0x3c..=0x3f => (DcsParam, Collect), + 0x40..=0x7e => (DcsPassthrough, None), + }, + + DcsIntermediate { + 0x00..=0x17 => (Anywhere, Ignore), + 0x19 => (Anywhere, Ignore), + 0x1c..=0x1f => (Anywhere, Ignore), + 0x20..=0x2f => (Anywhere, Collect), + 0x7f => (Anywhere, Ignore), + 0x30..=0x3f => (DcsIgnore, None), + 0x40..=0x7e => (DcsPassthrough, None), + }, + + DcsIgnore { + 0x00..=0x17 => (Anywhere, Ignore), + 0x19 => (Anywhere, Ignore), + 0x1c..=0x1f => (Anywhere, Ignore), + 0x20..=0x7f => (Anywhere, Ignore), + 0x9c => (Ground, None), + }, + + DcsParam { + 0x00..=0x17 => (Anywhere, Ignore), + 0x19 => (Anywhere, Ignore), + 0x1c..=0x1f => (Anywhere, Ignore), + 0x30..=0x39 => (Anywhere, Param), + 0x3b => (Anywhere, Param), + 0x7f => (Anywhere, Ignore), + 0x3a => (DcsIgnore, None), + 0x3c..=0x3f => (DcsIgnore, None), + 0x20..=0x2f => (DcsIntermediate, Collect), + 0x40..=0x7e => (DcsPassthrough, None), + }, + + DcsPassthrough { + 0x00..=0x17 => (Anywhere, Put), + 0x19 => (Anywhere, Put), + 0x1c..=0x1f => (Anywhere, Put), + 0x20..=0x7e => (Anywhere, Put), + 0x7f => (Anywhere, Ignore), + 0x9c => (Ground, None), + }, + + SosPmApcString { + 0x00..=0x17 => (Anywhere, Ignore), + 0x19 => (Anywhere, Ignore), + 0x1c..=0x1f => (Anywhere, Ignore), + 0x20..=0x7f => (Anywhere, Ignore), + 0x9c => (Ground, None), + }, + + OscString { + 0x00..=0x06 => (Anywhere, Ignore), + 0x07 => (Ground, None), + 0x08..=0x17 => (Anywhere, Ignore), + 0x19 => (Anywhere, Ignore), + 0x1c..=0x1f => (Anywhere, Ignore), + 0x20..=0xff => (Anywhere, OscPut), + } +}); diff --git a/src/table.rs.in b/src/table.rs.in index 5593283f..0245af7d 100644 --- a/src/table.rs.in +++ b/src/table.rs.in @@ -4,13 +4,13 @@ use definitions::Action; pub static STATE_CHANGE: [[u8; 256]; 16] = vt_state_table! { - State::Anywhere => { + Anywhere { 0x18 => (Action::Execute, State::Ground), 0x1a => (Action::Execute, State::Ground), 0x1b => State::Escape, }, - State::Ground => { + Ground { 0x00...0x17 => Action::Execute, 0x19 => Action::Execute, 0x1c...0x1f => Action::Execute, @@ -26,7 +26,7 @@ pub static STATE_CHANGE: [[u8; 256]; 16] = vt_state_table! { 0xf0...0xf4 => (State::Utf8, Action::BeginUtf8), }, - State::Escape => { + Escape { 0x00...0x17 => Action::Execute, 0x19 => Action::Execute, 0x1c...0x1f => Action::Execute, @@ -46,7 +46,7 @@ pub static STATE_CHANGE: [[u8; 256]; 16] = vt_state_table! { 0x5f => State::SosPmApcString, }, - State::EscapeIntermediate => { + EscapeIntermediate { 0x00...0x17 => Action::Execute, 0x19 => Action::Execute, 0x1c...0x1f => Action::Execute, @@ -55,7 +55,7 @@ pub static STATE_CHANGE: [[u8; 256]; 16] = vt_state_table! { 0x30...0x7e => (Action::EscDispatch, State::Ground) }, - State::CsiEntry => { + CsiEntry { 0x00...0x17 => Action::Execute, 0x19 => Action::Execute, 0x1c...0x1f => Action::Execute, @@ -68,7 +68,7 @@ pub static STATE_CHANGE: [[u8; 256]; 16] = vt_state_table! { 0x40...0x7e => (Action::CsiDispatch, State::Ground) }, - State::CsiIgnore => { + CsiIgnore { 0x00...0x17 => Action::Execute, 0x19 => Action::Execute, 0x1c...0x1f => Action::Execute, @@ -77,7 +77,7 @@ pub static STATE_CHANGE: [[u8; 256]; 16] = vt_state_table! { 0x40...0x7e => State::Ground, }, - State::CsiParam => { + CsiParam { 0x00...0x17 => Action::Execute, 0x19 => Action::Execute, 0x1c...0x1f => Action::Execute, @@ -90,7 +90,7 @@ pub static STATE_CHANGE: [[u8; 256]; 16] = vt_state_table! { 0x40...0x7e => (Action::CsiDispatch, State::Ground) }, - State::CsiIntermediate => { + CsiIntermediate { 0x00...0x17 => Action::Execute, 0x19 => Action::Execute, 0x1c...0x1f => Action::Execute, @@ -100,7 +100,7 @@ pub static STATE_CHANGE: [[u8; 256]; 16] = vt_state_table! { 0x40...0x7e => (Action::CsiDispatch, State::Ground), }, - State::DcsEntry => { + DcsEntry { 0x00...0x17 => Action::Ignore, 0x19 => Action::Ignore, 0x1c...0x1f => Action::Ignore, @@ -113,7 +113,7 @@ pub static STATE_CHANGE: [[u8; 256]; 16] = vt_state_table! { 0x40...0x7e => State::DcsPassthrough }, - State::DcsIntermediate => { + DcsIntermediate { 0x00...0x17 => Action::Ignore, 0x19 => Action::Ignore, 0x1c...0x1f => Action::Ignore, @@ -123,7 +123,7 @@ pub static STATE_CHANGE: [[u8; 256]; 16] = vt_state_table! { 0x40...0x7e => State::DcsPassthrough }, - State::DcsIgnore => { + DcsIgnore { 0x00...0x17 => Action::Ignore, 0x19 => Action::Ignore, 0x1c...0x1f => Action::Ignore, @@ -131,7 +131,7 @@ pub static STATE_CHANGE: [[u8; 256]; 16] = vt_state_table! { 0x9c => State::Ground }, - State::DcsParam => { + DcsParam { 0x00...0x17 => Action::Ignore, 0x19 => Action::Ignore, 0x1c...0x1f => Action::Ignore, @@ -144,7 +144,7 @@ pub static STATE_CHANGE: [[u8; 256]; 16] = vt_state_table! { 0x40...0x7e => State::DcsPassthrough }, - State::DcsPassthrough => { + DcsPassthrough { 0x00...0x17 => Action::Put, 0x19 => Action::Put, 0x1c...0x1f => Action::Put, @@ -153,7 +153,7 @@ pub static STATE_CHANGE: [[u8; 256]; 16] = vt_state_table! { 0x9c => State::Ground, }, - State::SosPmApcString => { + SosPmApcString { 0x00...0x17 => Action::Ignore, 0x19 => Action::Ignore, 0x1c...0x1f => Action::Ignore, @@ -161,7 +161,7 @@ pub static STATE_CHANGE: [[u8; 256]; 16] = vt_state_table! { 0x9c => State::Ground }, - State::OscString => { + OscString { 0x00...0x06 => Action::Ignore, 0x07 => State::Ground, 0x08...0x17 => Action::Ignore, diff --git a/tests/demo.vte b/tests/demo.vte new file mode 100644 index 00000000..ed62b355 --- /dev/null +++ b/tests/demo.vte @@ -0,0 +1,2052 @@ +Test +RED ON GREEN +]52;c;Y2xpcGJvYXJkIHRlc3Q=];;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;some random text;  what + + +P0;1|17/ab + ]2;echo '¯\_(ツ)_/¯' && sleep 1 +REEEEEED +Test +RED ON GREEN +]52;c;Y2xpcGJvYXJkIHRlc3Q=];;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;some random text;  what + + +P0;1|17/ab + ]2;echo '¯\_(ツ)_/¯' && sleep 1 +REEEEEEEEEEEEED +[6 q +[0 q + + + +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288 +289 +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300 +301 +302 +303 +304 +305 +306 +307 +308 +309 +310 +311 +312 +313 +314 +315 +316 +317 +318 +319 +320 +321 +322 +323 +324 +325 +326 +327 +328 +329 +330 +331 +332 +333 +334 +335 +336 +337 +338 +339 +340 +341 +342 +343 +344 +345 +346 +347 +348 +349 +350 +351 +352 +353 +354 +355 +356 +357 +358 +359 +360 +361 +362 +363 +364 +365 +366 +367 +368 +369 +370 +371 +372 +373 +374 +375 +376 +377 +378 +379 +380 +381 +382 +383 +384 +385 +386 +387 +388 +389 +390 +391 +392 +393 +394 +395 +396 +397 +398 +399 +400 +401 +402 +403 +404 +405 +406 +407 +408 +409 +410 +411 +412 +413 +414 +415 +416 +417 +418 +419 +420 +421 +422 +423 +424 +425 +426 +427 +428 +429 +430 +431 +432 +433 +434 +435 +436 +437 +438 +439 +440 +441 +442 +443 +444 +445 +446 +447 +448 +449 +450 +451 +452 +453 +454 +455 +456 +457 +458 +459 +460 +461 +462 +463 +464 +465 +466 +467 +468 +469 +470 +471 +472 +473 +474 +475 +476 +477 +478 +479 +480 +481 +482 +483 +484 +485 +486 +487 +488 +489 +490 +491 +492 +493 +494 +495 +496 +497 +498 +499 +500 +501 +502 +503 +504 +505 +506 +507 +508 +509 +510 +511 +512 +513 +514 +515 +516 +517 +518 +519 +520 +521 +522 +523 +524 +525 +526 +527 +528 +529 +530 +531 +532 +533 +534 +535 +536 +537 +538 +539 +540 +541 +542 +543 +544 +545 +546 +547 +548 +549 +550 +551 +552 +553 +554 +555 +556 +557 +558 +559 +560 +561 +562 +563 +564 +565 +566 +567 +568 +569 +570 +571 +572 +573 +574 +575 +576 +577 +578 +579 +580 +581 +582 +583 +584 +585 +586 +587 +588 +589 +590 +591 +592 +593 +594 +595 +596 +597 +598 +599 +600 +601 +602 +603 +604 +605 +606 +607 +608 +609 +610 +611 +612 +613 +614 +615 +616 +617 +618 +619 +620 +621 +622 +623 +624 +625 +626 +627 +628 +629 +630 +631 +632 +633 +634 +635 +636 +637 +638 +639 +640 +641 +642 +643 +644 +645 +646 +647 +648 +649 +650 +651 +652 +653 +654 +655 +656 +657 +658 +659 +660 +661 +662 +663 +664 +665 +666 +667 +668 +669 +670 +671 +672 +673 +674 +675 +676 +677 +678 +679 +680 +681 +682 +683 +684 +685 +686 +687 +688 +689 +690 +691 +692 +693 +694 +695 +696 +697 +698 +699 +700 +701 +702 +703 +704 +705 +706 +707 +708 +709 +710 +711 +712 +713 +714 +715 +716 +717 +718 +719 +720 +721 +722 +723 +724 +725 +726 +727 +728 +729 +730 +731 +732 +733 +734 +735 +736 +737 +738 +739 +740 +741 +742 +743 +744 +745 +746 +747 +748 +749 +750 +751 +752 +753 +754 +755 +756 +757 +758 +759 +760 +761 +762 +763 +764 +765 +766 +767 +768 +769 +770 +771 +772 +773 +774 +775 +776 +777 +778 +779 +780 +781 +782 +783 +784 +785 +786 +787 +788 +789 +790 +791 +792 +793 +794 +795 +796 +797 +798 +799 +800 +801 +802 +803 +804 +805 +806 +807 +808 +809 +810 +811 +812 +813 +814 +815 +816 +817 +818 +819 +820 +821 +822 +823 +824 +825 +826 +827 +828 +829 +830 +831 +832 +833 +834 +835 +836 +837 +838 +839 +840 +841 +842 +843 +844 +845 +846 +847 +848 +849 +850 +851 +852 +853 +854 +855 +856 +857 +858 +859 +860 +861 +862 +863 +864 +865 +866 +867 +868 +869 +870 +871 +872 +873 +874 +875 +876 +877 +878 +879 +880 +881 +882 +883 +884 +885 +886 +887 +888 +889 +890 +891 +892 +893 +894 +895 +896 +897 +898 +899 +900 +901 +902 +903 +904 +905 +906 +907 +908 +909 +910 +911 +912 +913 +914 +915 +916 +917 +918 +919 +920 +921 +922 +923 +924 +925 +926 +927 +928 +929 +930 +931 +932 +933 +934 +935 +936 +937 +938 +939 +940 +941 +942 +943 +944 +945 +946 +947 +948 +949 +950 +951 +952 +953 +954 +955 +956 +957 +958 +959 +960 +961 +962 +963 +964 +965 +966 +967 +968 +969 +970 +971 +972 +973 +974 +975 +976 +977 +978 +979 +980 +981 +982 +983 +984 +985 +986 +987 +988 +989 +990 +991 +992 +993 +994 +995 +996 +997 +998 +999 +1000 + +[0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288 +289 +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300 +301 +302 +303 +304 +305 +306 +307 +308 +309 +310 +311 +312 +313 +314 +315 +316 +317 +318 +319 +320 +321 +322 +323 +324 +325 +326 +327 +328 +329 +330 +331 +332 +333 +334 +335 +336 +337 +338 +339 +340 +341 +342 +343 +344 +345 +346 +347 +348 +349 +350 +351 +352 +353 +354 +355 +356 +357 +358 +359 +360 +361 +362 +363 +364 +365 +366 +367 +368 +369 +370 +371 +372 +373 +374 +375 +376 +377 +378 +379 +380 +381 +382 +383 +384 +385 +386 +387 +388 +389 +390 +391 +392 +393 +394 +395 +396 +397 +398 +399 +400 +401 +402 +403 +404 +405 +406 +407 +408 +409 +410 +411 +412 +413 +414 +415 +416 +417 +418 +419 +420 +421 +422 +423 +424 +425 +426 +427 +428 +429 +430 +431 +432 +433 +434 +435 +436 +437 +438 +439 +440 +441 +442 +443 +444 +445 +446 +447 +448 +449 +450 +451 +452 +453 +454 +455 +456 +457 +458 +459 +460 +461 +462 +463 +464 +465 +466 +467 +468 +469 +470 +471 +472 +473 +474 +475 +476 +477 +478 +479 +480 +481 +482 +483 +484 +485 +486 +487 +488 +489 +490 +491 +492 +493 +494 +495 +496 +497 +498 +499 +500 +501 +502 +503 +504 +505 +506 +507 +508 +509 +510 +511 +512 +513 +514 +515 +516 +517 +518 +519 +520 +521 +522 +523 +524 +525 +526 +527 +528 +529 +530 +531 +532 +533 +534 +535 +536 +537 +538 +539 +540 +541 +542 +543 +544 +545 +546 +547 +548 +549 +550 +551 +552 +553 +554 +555 +556 +557 +558 +559 +560 +561 +562 +563 +564 +565 +566 +567 +568 +569 +570 +571 +572 +573 +574 +575 +576 +577 +578 +579 +580 +581 +582 +583 +584 +585 +586 +587 +588 +589 +590 +591 +592 +593 +594 +595 +596 +597 +598 +599 +600 +601 +602 +603 +604 +605 +606 +607 +608 +609 +610 +611 +612 +613 +614 +615 +616 +617 +618 +619 +620 +621 +622 +623 +624 +625 +626 +627 +628 +629 +630 +631 +632 +633 +634 +635 +636 +637 +638 +639 +640 +641 +642 +643 +644 +645 +646 +647 +648 +649 +650 +651 +652 +653 +654 +655 +656 +657 +658 +659 +660 +661 +662 +663 +664 +665 +666 +667 +668 +669 +670 +671 +672 +673 +674 +675 +676 +677 +678 +679 +680 +681 +682 +683 +684 +685 +686 +687 +688 +689 +690 +691 +692 +693 +694 +695 +696 +697 +698 +699 +700 +701 +702 +703 +704 +705 +706 +707 +708 +709 +710 +711 +712 +713 +714 +715 +716 +717 +718 +719 +720 +721 +722 +723 +724 +725 +726 +727 +728 +729 +730 +731 +732 +733 +734 +735 +736 +737 +738 +739 +740 +741 +742 +743 +744 +745 +746 +747 +748 +749 +750 +751 +752 +753 +754 +755 +756 +757 +758 +759 +760 +761 +762 +763 +764 +765 +766 +767 +768 +769 +770 +771 +772 +773 +774 +775 +776 +777 +778 +779 +780 +781 +782 +783 +784 +785 +786 +787 +788 +789 +790 +791 +792 +793 +794 +795 +796 +797 +798 +799 +800 +801 +802 +803 +804 +805 +806 +807 +808 +809 +810 +811 +812 +813 +814 +815 +816 +817 +818 +819 +820 +821 +822 +823 +824 +825 +826 +827 +828 +829 +830 +831 +832 +833 +834 +835 +836 +837 +838 +839 +840 +841 +842 +843 +844 +845 +846 +847 +848 +849 +850 +851 +852 +853 +854 +855 +856 +857 +858 +859 +860 +861 +862 +863 +864 +865 +866 +867 +868 +869 +870 +871 +872 +873 +874 +875 +876 +877 +878 +879 +880 +881 +882 +883 +884 +885 +886 +887 +888 +889 +890 +891 +892 +893 +894 +895 +896 +897 +898 +899 +900 +901 +902 +903 +904 +905 +906 +907 +908 +909 +910 +911 +912 +913 +914 +915 +916 +917 +918 +919 +920 +921 +922 +923 +924 +925 +926 +927 +928 +929 +930 +931 +932 +933 +934 +935 +936 +937 +938 +939 +940 +941 +942 +943 +944 +945 +946 +947 +948 +949 +950 +951 +952 +953 +954 +955 +956 +957 +958 +959 +960 +961 +962 +963 +964 +965 +966 +967 +968 +969 +970 +971 +972 +973 +974 +975 +976 +977 +978 +979 +980 +981 +982 +983 +984 +985 +986 +987 +988 +989 +990 +991 +992 +993 +994 +995 +996 +997 +998 +999 +1000 + +Hello, World +Oops +Z +汉字漢字汉字漢字汉字漢字汉字漢字汉字漢字汉字漢字汉字漢字汉字漢字 + + + +-[ \eAAAAAAABBBBBBBBBBBBCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDDDDDDDDEEEEEEEEEFFFFFFFFFGGGGGGG +SA8SyD4+ĜPVLx yij)]9VmbЮ+~=K.tI zep+dۨX120;#r=:Bʾ>voxY̊曮Bk.l&=^"hl 9˖(ɇzXRV50x>%1]/L6ޔ݄ /:ɀ$%|H6'^oդqE(pop(4qwRfpl5<#y^N伸l HQ&VPYƃ" +`TuhM +%=D̹]iTYn`w{b{ד`^ WhCT ŀ6|>4|huﴯU-:aу_'rUu8p35 sjm79GCG8 ܘ ޮM!8 ]w!tTrRh ks>XجIy'\\Z0:lwkI4Jg`Mb$p;gj ՙ`!vb$1~'V+W=(sfB +g !EI#߉kۘ7"BV|ؽ=]K试7)H{Q a2B7YI|"w]mwNJb ],p gԍ@rB$3zSDKqZEr"BgM+9EQ䑽'&'mν||"4ガB4kY$?8\G,BNӢl^{3ʻ1\=6vn%q"A6A aw0ۂFA .<(+ʙ pAsQERĤ2tZܣ&CϾ\}#5"5Hp-X'B4Tm.nG-;f}ʕ ɸJhW #Z/)xx+J*##p{ +r^ƮxJEM>vF?D +O}wEqoYtAZ X{JN JcZ!= ߎ񇻨b8 +D/!IK` >B(HL؃ FEO: +LA/ u:|ۆ5& FMΏsa ֎Å,\8m/yaݟ}3(dןf͵␗uJ\9Q ^QIo8fuڀG~YeA>b@amKk=VyNR芫x܊8Qf^&c}k+{%@b)tj jkPoŎ.2?t\})C>`D I',Wّ6?At6WdGi*~H଺V }p3dw<Ҝo=DT=F Mwحnԃ54wbdw(IJRNv fD֪Vљ4ѧ]c"/Eg,~m afE@;V]S<-L"raE4"Joo@te"0c>FV 70z RMQ;t開C [P5ȏ[nx}O#I d!lW +]oC#Mux*ۘ8_)p6B3L mìO1 +Iw@qR)Ue@V2VzDzӃ>~r$ȸπW7דJ;jd"~J;^G91(<]ayh-PSg(6BD 3O7laU%& :>+ )L؞xeS6o}/ =5EM7'*j/wp'ED"E; xm`},ovJi=D$ҼNqA?њ h:?'_-+>2[A!č~p+F˚Z}Ir:Q`CIT{+6`\gEeY7{j:!~>ybնAMH#We[]Rt;%Na1Ā 4UcOnh0hVVE\D:J`nO HzX45,>pd!^'hOw.K @ ׁ;o"˼"bj)!EJ7D댩cjVn(3@QLn:rR Ma_~Қ7?BH{Q'k s<3o[x瘘Fo׊rl偞ջ p`3uY %?eJ?`ܛ=QW+ۘ*k<[ř;s0#tgH<43HJg'dc8_SW5LBϚ1Zo?| ИDW9_lx_/Hyb0;ϫO,eͦ8gG]8;j拱g,uH'rU[YPͣEp.9WMs)řmfΧ͍Va>D"h { - 0x00...0x7f => (State::Ground, Action::EmitByte), - 0xc2...0xdf => (State::Tail1, Action::SetByte2Top), - 0xe0 => (State::U3_2_e0, Action::SetByte3Top), - 0xe1...0xec => (State::Tail2, Action::SetByte3Top), - 0xed => (State::U3_2_ed, Action::SetByte3Top), - 0xee...0xef => (State::Tail2, Action::SetByte3Top), - 0xf0 => (State::Utf8_4_3_f0, Action::SetByte4), - 0xf1...0xf3 => (State::Tail3, Action::SetByte4), - 0xf4 => (State::Utf8_4_3_f4, Action::SetByte4), - }, - State::U3_2_e0 => { - 0xa0...0xbf => (State::Tail1, Action::SetByte2), - }, - State::U3_2_ed => { - 0x80...0x9f => (State::Tail1, Action::SetByte2), - }, - State::Utf8_4_3_f0 => { - 0x90...0xbf => (State::Tail2, Action::SetByte3), - }, - State::Utf8_4_3_f4 => { - 0x80...0x8f => (State::Tail2, Action::SetByte3), - }, - State::Tail3 => { - 0x80...0xbf => (State::Tail2, Action::SetByte3), - }, - State::Tail2 => { - 0x80...0xbf => (State::Tail1, Action::SetByte2), - }, - State::Tail1 => { - 0x80...0xbf => (State::Ground, Action::SetByte1), - }, -}; diff --git a/utf8parse/src/types.rs b/utf8parse/src/types.rs index 93607fbd..5a70b3c1 100644 --- a/utf8parse/src/types.rs +++ b/utf8parse/src/types.rs @@ -1,12 +1,31 @@ //! Types supporting the UTF-8 parser -#![allow(non_camel_case_types)] -use core::mem; + +/// Action to take when receiving a byte +#[derive(Debug, Copy, Clone)] +pub enum Action { + /// Unexpected byte; sequence is invalid + InvalidSequence = 0, + /// Received valid 7-bit ASCII byte which can be directly emitted. + EmitByte = 1, + /// Set the bottom continuation byte + SetByte1 = 2, + /// Set the 2nd-from-last continuation byte + SetByte2 = 3, + /// Set the 2nd-from-last byte which is part of a two byte sequence + SetByte2Top = 4, + /// Set the 3rd-from-last continuation byte + SetByte3 = 5, + /// Set the 3rd-from-last byte which is part of a three byte sequence + SetByte3Top = 6, + /// Set the top byte of a four byte sequence. + SetByte4 = 7, +} /// States the parser can be in. /// /// There is a state for each initial input of the 3 and 4 byte sequences since /// the following bytes are subject to different conditions than a tail byte. -#[allow(dead_code)] +#[allow(non_camel_case_types)] #[derive(Debug, Copy, Clone)] pub enum State { /// Ground state; expect anything @@ -33,50 +52,54 @@ impl Default for State { } } -/// Action to take when receiving a byte -#[allow(dead_code)] -#[derive(Debug, Copy, Clone)] -pub enum Action { - /// Unexpected byte; sequence is invalid - InvalidSequence = 0, - /// Received valid 7-bit ASCII byte which can be directly emitted. - EmitByte = 1, - /// Set the bottom continuation byte - SetByte1 = 2, - /// Set the 2nd-from-last continuation byte - SetByte2 = 3, - /// Set the 2nd-from-last byte which is part of a two byte sequence - SetByte2Top = 4, - /// Set the 3rd-from-last continuation byte - SetByte3 = 5, - /// Set the 3rd-from-last byte which is part of a three byte sequence - SetByte3Top = 6, - /// Set the top byte of a four byte sequence. - SetByte4 = 7, -} - -/// Convert a state and action to a u8 -/// -/// State will be the bottom 4 bits and action the top 4 -#[inline] -#[allow(dead_code)] -pub fn pack(state: State, action: Action) -> u8 { - ((action as u8) << 4) | (state as u8) -} - -/// Convert a u8 to a state and action -/// -/// # Unsafety -/// -/// If this function is called with a byte that wasn't encoded with the `pack` -/// function in this module, there is no guarantee that a valid state and action -/// can be produced. -#[inline] -pub unsafe fn unpack(val: u8) -> (State, Action) { - ( - // State is stored in bottom 4 bits - mem::transmute(val & 0x0f), - // Action is stored in top 4 bits - mem::transmute(val >> 4), - ) +impl State { + /// Advance the parser state. + /// + /// This takes the current state and input byte into consideration, to determine the next state + /// and any action that should be taken. + #[inline] + pub fn advance(&self, byte: u8) -> (State, Action) { + match self { + State::Ground => match byte { + 0x00..=0x7f => (State::Ground, Action::EmitByte), + 0xc2..=0xdf => (State::Tail1, Action::SetByte2Top), + 0xe0 => (State::U3_2_e0, Action::SetByte3Top), + 0xe1..=0xec => (State::Tail2, Action::SetByte3Top), + 0xed => (State::U3_2_ed, Action::SetByte3Top), + 0xee..=0xef => (State::Tail2, Action::SetByte3Top), + 0xf0 => (State::Utf8_4_3_f0, Action::SetByte4), + 0xf1..=0xf3 => (State::Tail3, Action::SetByte4), + 0xf4 => (State::Utf8_4_3_f4, Action::SetByte4), + _ => (State::Ground, Action::InvalidSequence), + }, + State::U3_2_e0 => match byte { + 0xa0..=0xbf => (State::Tail1, Action::SetByte2), + _ => (State::Ground, Action::InvalidSequence), + }, + State::U3_2_ed => match byte { + 0x80..=0x9f => (State::Tail1, Action::SetByte2), + _ => (State::Ground, Action::InvalidSequence), + }, + State::Utf8_4_3_f0 => match byte { + 0x90..=0xbf => (State::Tail2, Action::SetByte3), + _ => (State::Ground, Action::InvalidSequence), + }, + State::Utf8_4_3_f4 => match byte { + 0x80..=0x8f => (State::Tail2, Action::SetByte3), + _ => (State::Ground, Action::InvalidSequence), + }, + State::Tail3 => match byte { + 0x80..=0xbf => (State::Tail2, Action::SetByte3), + _ => (State::Ground, Action::InvalidSequence), + }, + State::Tail2 => match byte { + 0x80..=0xbf => (State::Tail1, Action::SetByte2), + _ => (State::Ground, Action::InvalidSequence), + }, + State::Tail1 => match byte { + 0x80..=0xbf => (State::Ground, Action::SetByte1), + _ => (State::Ground, Action::InvalidSequence), + }, + } + } } From 5e5d7de9c8054f837a2d34d0d9a8c3791ab15bf8 Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Tue, 10 Dec 2019 20:58:39 +0100 Subject: [PATCH 61/99] Bump utf8parse to 0.2.0 --- Cargo.toml | 2 +- utf8parse/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 73fd4b73..0eef1a80 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,7 @@ edition = "2018" [dependencies] generate_state_changes = { version = "0.1.0", path = "generate_state_changes" } arrayvec = { version = "0.5.1", default-features = false, optional = true } -utf8parse = { path = "utf8parse", version = "0.1.0" } +utf8parse = { path = "utf8parse", version = "0.2.0" } [features] default = ["no_std"] diff --git a/utf8parse/Cargo.toml b/utf8parse/Cargo.toml index 8c8c8df4..7aeafbeb 100644 --- a/utf8parse/Cargo.toml +++ b/utf8parse/Cargo.toml @@ -6,7 +6,7 @@ repository = "https://github.com/jwilm/vte" keywords = ["utf8", "parse", "table"] categories = ["parsing", "no-std"] license = "Apache-2.0 OR MIT" -version = "0.1.1" +version = "0.2.0" name = "utf8parse" edition = "2018" From 89ea6d665a11bb9f5d2561593c30e3737f6eaf9b Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Tue, 10 Dec 2019 20:59:31 +0100 Subject: [PATCH 62/99] Bump version to 0.5.0 --- CHANGELOG.md | 6 ++++++ Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 443305b0..c96d04ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ CHANGELOG ========= +## 0.5.0 + +- Support for dynamically sized escape buffers without feature `no_std` +- Improved UTF8 parser performance +- Migrate to Rust 2018 + ## 0.4.0 - Fix handling of DCS escapes diff --git a/Cargo.toml b/Cargo.toml index 0eef1a80..1425fb6b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ categories = ["parsing", "no-std"] exclude = ["/.travis.yml"] readme = "README.md" license = "Apache-2.0 OR MIT" -version = "0.4.0" +version = "0.5.0" name = "vte" edition = "2018" From 92f7b13d96f6a708c4b5a1a5d7cfa3bb59fd7cbc Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Tue, 10 Dec 2019 21:04:10 +0100 Subject: [PATCH 63/99] Rename generate_state_changes proc macro This renames the generate_state_changes proc macro to include the `vte_` prefix, since it's not useful to anyone other than our `vte` crate. --- Cargo.toml | 6 +++--- src/table.rs | 2 +- .../Cargo.toml | 7 +++++-- .../src/lib.rs | 0 4 files changed, 9 insertions(+), 6 deletions(-) rename {generate_state_changes => vte_generate_state_changes}/Cargo.toml (51%) rename {generate_state_changes => vte_generate_state_changes}/src/lib.rs (100%) diff --git a/Cargo.toml b/Cargo.toml index 1425fb6b..f67878c9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,9 +13,9 @@ name = "vte" edition = "2018" [dependencies] -generate_state_changes = { version = "0.1.0", path = "generate_state_changes" } +vte_generate_state_changes = { version = "0.1.0", path = "vte_generate_state_changes" } arrayvec = { version = "0.5.1", default-features = false, optional = true } -utf8parse = { path = "utf8parse", version = "0.2.0" } +utf8parse = { version = "0.2.0", path = "utf8parse" } [features] default = ["no_std"] @@ -23,4 +23,4 @@ no_std = ["arrayvec"] nightly = ["utf8parse/nightly"] [workspace] -members = ["utf8parse", "generate_state_changes"] +members = ["utf8parse", "vte_generate_state_changes"] diff --git a/src/table.rs b/src/table.rs index f5a90ee9..c19e4abb 100644 --- a/src/table.rs +++ b/src/table.rs @@ -2,7 +2,7 @@ /// character in the pty stream. use crate::definitions::{pack, Action, State}; -use generate_state_changes::generate_state_changes; +use vte_generate_state_changes::generate_state_changes; // Generate state changes at compile-time pub static STATE_CHANGES: [[u8; 256]; 16] = state_changes(); diff --git a/generate_state_changes/Cargo.toml b/vte_generate_state_changes/Cargo.toml similarity index 51% rename from generate_state_changes/Cargo.toml rename to vte_generate_state_changes/Cargo.toml index efe58708..1a4bb171 100644 --- a/generate_state_changes/Cargo.toml +++ b/vte_generate_state_changes/Cargo.toml @@ -1,7 +1,10 @@ [package] -name = "generate_state_changes" -version = "0.1.0" authors = ["Christian Duerr "] +description = "Proc macro for generating VTE state changes" +repository = "https://github.com/jwilm/vte" +name = "vte_generate_state_changes" +license = "Apache-2.0 OR MIT" +version = "0.1.0" edition = "2018" [lib] diff --git a/generate_state_changes/src/lib.rs b/vte_generate_state_changes/src/lib.rs similarity index 100% rename from generate_state_changes/src/lib.rs rename to vte_generate_state_changes/src/lib.rs From fb2430ef10e5fc0b6b4fb73a6422abebf9bd2070 Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Mon, 16 Dec 2019 02:00:06 +0100 Subject: [PATCH 64/99] Remove outdated table.rs.in file --- src/table.rs.in | 210 ------------------------------------------------ 1 file changed, 210 deletions(-) delete mode 100644 src/table.rs.in diff --git a/src/table.rs.in b/src/table.rs.in deleted file mode 100644 index 0245af7d..00000000 --- a/src/table.rs.in +++ /dev/null @@ -1,210 +0,0 @@ -/// This is the state change table. It's indexed first by current state and then by the next -/// character in the pty stream. - -use definitions::Action; - -pub static STATE_CHANGE: [[u8; 256]; 16] = vt_state_table! { - Anywhere { - 0x18 => (Action::Execute, State::Ground), - 0x1a => (Action::Execute, State::Ground), - 0x1b => State::Escape, - }, - - Ground { - 0x00...0x17 => Action::Execute, - 0x19 => Action::Execute, - 0x1c...0x1f => Action::Execute, - 0x20...0x7f => Action::Print, - 0x80...0x8f => Action::Execute, - 0x91...0x9a => Action::Execute, - 0x9c => Action::Execute, - // Beginning of UTF-8 2 byte sequence - 0xc2...0xdf => (State::Utf8, Action::BeginUtf8), - // Beginning of UTF-8 3 byte sequence - 0xe0...0xef => (State::Utf8, Action::BeginUtf8), - // Beginning of UTF-8 4 byte sequence - 0xf0...0xf4 => (State::Utf8, Action::BeginUtf8), - }, - - Escape { - 0x00...0x17 => Action::Execute, - 0x19 => Action::Execute, - 0x1c...0x1f => Action::Execute, - 0x7f => Action::Ignore, - 0x20...0x2f => (Action::Collect, State::EscapeIntermediate), - 0x30...0x4f => (Action::EscDispatch, State::Ground), - 0x51...0x57 => (Action::EscDispatch, State::Ground), - 0x59 => (Action::EscDispatch, State::Ground), - 0x5a => (Action::EscDispatch, State::Ground), - 0x5c => (Action::EscDispatch, State::Ground), - 0x60...0x7e => (Action::EscDispatch, State::Ground), - 0x5b => State::CsiEntry, - 0x5d => State::OscString, - 0x50 => State::DcsEntry, - 0x58 => State::SosPmApcString, - 0x5e => State::SosPmApcString, - 0x5f => State::SosPmApcString, - }, - - EscapeIntermediate { - 0x00...0x17 => Action::Execute, - 0x19 => Action::Execute, - 0x1c...0x1f => Action::Execute, - 0x20...0x2f => Action::Collect, - 0x7f => Action::Ignore, - 0x30...0x7e => (Action::EscDispatch, State::Ground) - }, - - CsiEntry { - 0x00...0x17 => Action::Execute, - 0x19 => Action::Execute, - 0x1c...0x1f => Action::Execute, - 0x7f => Action::Ignore, - 0x20...0x2f => (Action::Collect, State::CsiIntermediate), - 0x3a => State::CsiIgnore, - 0x30...0x39 => (Action::Param, State::CsiParam), - 0x3b => (Action::Param, State::CsiParam), - 0x3c...0x3f => (Action::Collect, State::CsiParam), - 0x40...0x7e => (Action::CsiDispatch, State::Ground) - }, - - CsiIgnore { - 0x00...0x17 => Action::Execute, - 0x19 => Action::Execute, - 0x1c...0x1f => Action::Execute, - 0x20...0x3f => Action::Ignore, - 0x7f => Action::Ignore, - 0x40...0x7e => State::Ground, - }, - - CsiParam { - 0x00...0x17 => Action::Execute, - 0x19 => Action::Execute, - 0x1c...0x1f => Action::Execute, - 0x30...0x39 => Action::Param, - 0x3b => Action::Param, - 0x7f => Action::Ignore, - 0x3a => State::CsiIgnore, - 0x3c...0x3f => State::CsiIgnore, - 0x20...0x2f => (Action::Collect, State::CsiIntermediate), - 0x40...0x7e => (Action::CsiDispatch, State::Ground) - }, - - CsiIntermediate { - 0x00...0x17 => Action::Execute, - 0x19 => Action::Execute, - 0x1c...0x1f => Action::Execute, - 0x20...0x2f => Action::Collect, - 0x7f => Action::Ignore, - 0x30...0x3f => State::CsiIgnore, - 0x40...0x7e => (Action::CsiDispatch, State::Ground), - }, - - DcsEntry { - 0x00...0x17 => Action::Ignore, - 0x19 => Action::Ignore, - 0x1c...0x1f => Action::Ignore, - 0x7f => Action::Ignore, - 0x3a => State::DcsIgnore, - 0x20...0x2f => (Action::Collect, State::DcsIntermediate), - 0x30...0x39 => (Action::Param, State::DcsParam), - 0x3b => (Action::Param, State::DcsParam), - 0x3c...0x3f => (Action::Collect, State::DcsParam), - 0x40...0x7e => State::DcsPassthrough - }, - - DcsIntermediate { - 0x00...0x17 => Action::Ignore, - 0x19 => Action::Ignore, - 0x1c...0x1f => Action::Ignore, - 0x20...0x2f => Action::Collect, - 0x7f => Action::Ignore, - 0x30...0x3f => State::DcsIgnore, - 0x40...0x7e => State::DcsPassthrough - }, - - DcsIgnore { - 0x00...0x17 => Action::Ignore, - 0x19 => Action::Ignore, - 0x1c...0x1f => Action::Ignore, - 0x20...0x7f => Action::Ignore, - 0x9c => State::Ground - }, - - DcsParam { - 0x00...0x17 => Action::Ignore, - 0x19 => Action::Ignore, - 0x1c...0x1f => Action::Ignore, - 0x30...0x39 => Action::Param, - 0x3b => Action::Param, - 0x7f => Action::Ignore, - 0x3a => State::DcsIgnore, - 0x3c...0x3f => State::DcsIgnore, - 0x20...0x2f => (Action::Collect, State::DcsIntermediate), - 0x40...0x7e => State::DcsPassthrough - }, - - DcsPassthrough { - 0x00...0x17 => Action::Put, - 0x19 => Action::Put, - 0x1c...0x1f => Action::Put, - 0x20...0x7e => Action::Put, - 0x7f => Action::Ignore, - 0x9c => State::Ground, - }, - - SosPmApcString { - 0x00...0x17 => Action::Ignore, - 0x19 => Action::Ignore, - 0x1c...0x1f => Action::Ignore, - 0x20...0x7f => Action::Ignore, - 0x9c => State::Ground - }, - - OscString { - 0x00...0x06 => Action::Ignore, - 0x07 => State::Ground, - 0x08...0x17 => Action::Ignore, - 0x19 => Action::Ignore, - 0x1c...0x1f => Action::Ignore, - 0x20...0xff => Action::OscPut, - } -}; - -pub static ENTRY_ACTIONS: &'static [Action] = &[ - Action::None, // State::Anywhere - Action::Clear, // State::CsiEntry - Action::None, // State::CsiIgnore - Action::None, // State::CsiIntermediate - Action::None, // State::CsiParam - Action::Clear, // State::DcsEntry - Action::None, // State::DcsIgnore - Action::None, // State::DcsIntermediate - Action::None, // State::DcsParam - Action::Hook, // State::DcsPassthrough - Action::Clear, // State::Escape - Action::None, // State::EscapeIntermediate - Action::None, // State::Ground - Action::OscStart, // State::OscString - Action::None, // State::SosPmApcString - Action::None, // State::Utf8 -]; - -pub static EXIT_ACTIONS: &'static [Action] = &[ - Action::None, // State::Anywhere - Action::None, // State::CsiEntry - Action::None, // State::CsiIgnore - Action::None, // State::CsiIntermediate - Action::None, // State::CsiParam - Action::None, // State::DcsEntry - Action::None, // State::DcsIgnore - Action::None, // State::DcsIntermediate - Action::None, // State::DcsParam - Action::Unhook, // State::DcsPassthrough - Action::None, // State::Escape - Action::None, // State::EscapeIntermediate - Action::None, // State::Ground - Action::OscEnd, // State::OscString - Action::None, // State::SosPmApcString - Action::None, // State::Utf8 -]; From b844c38d5d4b8eff5db07b1d4d5a14d626411698 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vojt=C4=9Bch=20=C5=A0t=C4=9Bpan=C4=8D=C3=ADk?= Date: Sat, 28 Dec 2019 22:49:48 +0100 Subject: [PATCH 65/99] Discard CSI sequences with too many parameters Fixes #24. --- src/lib.rs | 71 ++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 53 insertions(+), 18 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 50eddb88..e0f43311 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -272,8 +272,12 @@ impl Parser { }, Action::Unhook => performer.unhook(), Action::CsiDispatch => { - self.params[self.num_params] = self.param; - self.num_params += 1; + if self.num_params == MAX_PARAMS { + self.ignoring = true; + } else { + self.params[self.num_params] = self.param; + self.num_params += 1; + } performer.csi_dispatch( self.params(), @@ -298,14 +302,15 @@ impl Parser { } }, Action::Param => { - if byte == b';' { - // Completed a param - let idx = self.num_params; + // Completed a param + let idx = self.num_params; - if idx == MAX_PARAMS - 1 { - return; - } + if idx == MAX_PARAMS { + self.ignoring = true; + return; + } + if byte == b';' { self.params[idx] = self.param; self.param = 0; self.num_params += 1; @@ -370,8 +375,9 @@ pub trait Perform { /// A final character has arrived for a CSI sequence /// - /// The `ignore` flag indicates that more than two intermediates arrived and - /// subsequent characters were ignored. + /// The `ignore` flag indicates that either more than two intermediates arrived + /// or the number of parameters exceeded the maximum supported length, + /// and subsequent characters were ignored. fn csi_dispatch(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, _: char); /// The final character of an escape sequence has arrived. @@ -390,6 +396,7 @@ mod tests { use super::*; use core::i64; + use std::string::String; use std::vec::Vec; static OSC_BYTES: &[u8] = &[ @@ -445,6 +452,7 @@ mod tests { #[derive(Default)] struct CsiDispatcher { dispatched_csi: bool, + ignore: bool, params: Vec>, } @@ -461,8 +469,9 @@ mod tests { fn osc_dispatch(&mut self, _params: &[&[u8]]) {} - fn csi_dispatch(&mut self, params: &[i64], _intermediates: &[u8], _ignore: bool, _c: char) { + fn csi_dispatch(&mut self, params: &[i64], _intermediates: &[u8], ignore: bool, _c: char) { self.dispatched_csi = true; + self.ignore = ignore; self.params.push(params.to_vec()); } @@ -560,8 +569,6 @@ mod tests { #[test] fn parse_osc_max_params() { - use crate::MAX_PARAMS; - static INPUT: &[u8] = b"\x1b];;;;;;;;;;;;;;;;;\x1b"; // Create dispatcher and check state @@ -584,24 +591,52 @@ mod tests { #[test] fn parse_csi_max_params() { - use crate::MAX_PARAMS; + // This will build a list of repeating '1;'s + // The length is MAX_PARAMS - 1 because the last semicolon is interpreted + // as an implicit zero, making the total number of parameters MAX_PARAMS + let params = std::iter::repeat("1;").take(MAX_PARAMS - 1).collect::(); + let input = format!("\x1b[{}p", ¶ms[..]).into_bytes(); + + // Create dispatcher and check state + let mut dispatcher = CsiDispatcher::default(); + assert!(!dispatcher.dispatched_csi); + + // Run parser using INPUT + let mut parser = Parser::new(); + for byte in input { + parser.advance(&mut dispatcher, byte); + } + + // Check that flag is set and thus csi_dispatch assertions ran. + assert!(dispatcher.dispatched_csi); + assert_eq!(dispatcher.params.len(), 1); + assert_eq!(dispatcher.params[0].len(), MAX_PARAMS); + assert!(!dispatcher.ignore); + } - static INPUT: &[u8] = b"\x1b[1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;p"; + #[test] + fn parse_csi_params_ignore_long_params() { + // This will build a list of repeating '1;'s + // The length is MAX_PARAMS because the last semicolon is interpreted + // as an implicit zero, making the total number of parameters MAX_PARAMS + 1 + let params = std::iter::repeat("1;").take(MAX_PARAMS).collect::(); + let input = format!("\x1b[{}p", ¶ms[..]).into_bytes(); // Create dispatcher and check state let mut dispatcher = CsiDispatcher::default(); assert!(!dispatcher.dispatched_csi); - // Run parser using OSC_BYTES + // Run parser using INPUT let mut parser = Parser::new(); - for byte in INPUT { - parser.advance(&mut dispatcher, *byte); + for byte in input { + parser.advance(&mut dispatcher, byte); } // Check that flag is set and thus csi_dispatch assertions ran. assert!(dispatcher.dispatched_csi); assert_eq!(dispatcher.params.len(), 1); assert_eq!(dispatcher.params[0].len(), MAX_PARAMS); + assert!(dispatcher.ignore); } #[test] From 59e13856269f5da22b3b0714545851247126d6ba Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Sun, 12 Jan 2020 16:33:19 +0100 Subject: [PATCH 66/99] Move to Alacritty org travis setup This replaces the existing travis setup with the default for the Alacritty organization. This includes making it a requirement to build on 1.36.0. --- .travis.yml | 54 +++++++++++++++++++++++++++++++++++++++++++++++---- ci/install.sh | 11 +++++++++++ ci/script.sh | 16 +++++++++++++++ 3 files changed, 77 insertions(+), 4 deletions(-) create mode 100755 ci/install.sh create mode 100755 ci/script.sh diff --git a/.travis.yml b/.travis.yml index bc28ecea..a401da4b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,11 +1,57 @@ language: rust -cache: cargo +addons: + apt: + packages: + - libxcb-xfixes0-dev + +git: + depth: 1 + +os: + - linux + - osx rust: + - 1.36.0 - stable - nightly -script: - - cargo test --workspace --no-default-features - - cargo test --workspace +matrix: + fast_finish: true + include: + - if: tag IS present + os: linux + rust: stable + env: ARCH=i386 + - name: "Clippy Linux" + os: linux + env: CLIPPY=true + rust: stable + - name: "Clippy OSX" + os: osx + env: CLIPPY=true + rust: stable + - name: "Clippy Windows" + os: windows + env: CLIPPY=true + rust: stable-x86_64-pc-windows-msvc + - name: "Rustfmt" + os: linux + env: RUSTFMT=true + rust: nightly + - name: "Windows 1.36.0" + os: windows + rust: 1.36.0-x86_64-pc-windows-msvc + - name: "Windows Stable" + os: windows + rust: stable-x86_64-pc-windows-msvc + - name: "Windows Nightly" + os: windows + rust: nightly-x86_64-pc-windows-msvc + allow_failures: + - rust: nightly + - rust: nightly-x86_64-pc-windows-msvc + +install: ci/install.sh +script: ci/script.sh diff --git a/ci/install.sh b/ci/install.sh new file mode 100755 index 00000000..ccbe3728 --- /dev/null +++ b/ci/install.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +# Add clippy for lint validation +if [ "$CLIPPY" == "true" ]; then + rustup component add clippy +fi + +# Add rustfmt for format validation +if [ "$RUSTFMT" == "true" ]; then + rustup component add rustfmt +fi diff --git a/ci/script.sh b/ci/script.sh new file mode 100755 index 00000000..e601d34c --- /dev/null +++ b/ci/script.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +# Run clippy checks +if [ "$CLIPPY" == "true" ]; then + cargo clippy --all-targets + exit +fi + +# Run clippy rustfmt +if [ "$RUSTFMT" == "true" ]; then + cargo fmt -- --check + exit +fi + +# Run tests +cargo test From a0b8c325e1bbfa9d403fa279a4914348282d366c Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Sun, 12 Jan 2020 16:47:26 +0100 Subject: [PATCH 67/99] Fix 1.36.0 build failure --- :wq | 29 +++++++++++++++++++++++++++ CHANGELOG.md | 4 ++++ vte_generate_state_changes/src/lib.rs | 2 +- 3 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 :wq diff --git a/:wq b/:wq new file mode 100644 index 00000000..f0765545 --- /dev/null +++ b/:wq @@ -0,0 +1,29 @@ +CHANGELOG +========= + +## Unreleased + +- Fix build failure on Rust 1.36.0 + +## 0.5.0 + +- Support for dynamically sized escape buffers without feature `no_std` +- Improved UTF8 parser performance +- Migrate to Rust 2018 + +## 0.4.0 + +- Fix handling of DCS escapes + +## 0.3.3 + +- Fix off-by-one error in CSI parsing when params list was at max length + (previously caused a panic). +- Support no_std + +## 0.2.0 + +- Removes `osc_start`, `osc_put`, and `osc_end` +- Adds `osc_dispatch` which simply receives a list of parameters +- Removes `byte: u8` parameter from `hook` and `unhook` because it's always + zero. diff --git a/CHANGELOG.md b/CHANGELOG.md index c96d04ff..f0765545 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ CHANGELOG ========= +## Unreleased + +- Fix build failure on Rust 1.36.0 + ## 0.5.0 - Support for dynamically sized escape buffers without feature `no_std` diff --git a/vte_generate_state_changes/src/lib.rs b/vte_generate_state_changes/src/lib.rs index 485a33e7..5cfb3acf 100644 --- a/vte_generate_state_changes/src/lib.rs +++ b/vte_generate_state_changes/src/lib.rs @@ -137,7 +137,7 @@ fn optional_punct(iter: &mut Peekable, c: char) -> bool /// Panics if the punctuation does not match. fn expect_punct(iter: &mut impl Iterator, c: char) { match iter.next() { - Some(Punct(punct)) if punct.as_char() == c => (), + Some(Punct(ref punct)) if punct.as_char() == c => (), token => panic!("Expected punctuation '{}', but got {:?}", c, token), } } From 1712405055f5d97f6dc7b6156885c940982ec20d Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Sun, 12 Jan 2020 16:57:00 +0100 Subject: [PATCH 68/99] Bump vte_generate_state_changes version to 0.1.1 --- vte_generate_state_changes/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vte_generate_state_changes/Cargo.toml b/vte_generate_state_changes/Cargo.toml index 1a4bb171..9bdfb64b 100644 --- a/vte_generate_state_changes/Cargo.toml +++ b/vte_generate_state_changes/Cargo.toml @@ -4,7 +4,7 @@ description = "Proc macro for generating VTE state changes" repository = "https://github.com/jwilm/vte" name = "vte_generate_state_changes" license = "Apache-2.0 OR MIT" -version = "0.1.0" +version = "0.1.1" edition = "2018" [lib] From 618a1e784a368e4a7122a02a034eaaee67616176 Mon Sep 17 00:00:00 2001 From: Kirill Chibisov Date: Tue, 21 Jan 2020 01:13:08 +0300 Subject: [PATCH 69/99] Remove vim artifact --- :wq | 29 ----------------------------- 1 file changed, 29 deletions(-) delete mode 100644 :wq diff --git a/:wq b/:wq deleted file mode 100644 index f0765545..00000000 --- a/:wq +++ /dev/null @@ -1,29 +0,0 @@ -CHANGELOG -========= - -## Unreleased - -- Fix build failure on Rust 1.36.0 - -## 0.5.0 - -- Support for dynamically sized escape buffers without feature `no_std` -- Improved UTF8 parser performance -- Migrate to Rust 2018 - -## 0.4.0 - -- Fix handling of DCS escapes - -## 0.3.3 - -- Fix off-by-one error in CSI parsing when params list was at max length - (previously caused a panic). -- Support no_std - -## 0.2.0 - -- Removes `osc_start`, `osc_put`, and `osc_end` -- Adds `osc_dispatch` which simply receives a list of parameters -- Removes `byte: u8` parameter from `hook` and `unhook` because it's always - zero. From 7399615d1f94676b99defff0ebe9a385e26d7199 Mon Sep 17 00:00:00 2001 From: Alex Touchet Date: Mon, 20 Jan 2020 14:45:09 -0800 Subject: [PATCH 70/99] Fix outdated URLs --- Cargo.toml | 2 +- README.md | 2 +- utf8parse/Cargo.toml | 2 +- vte_generate_state_changes/Cargo.toml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f67878c9..dc776694 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Joe Wilm ", "Christian Duerr "] description = "Parser for implementing terminal emulators" -repository = "https://github.com/jwilm/vte" +repository = "https://github.com/alacritty/vte" documentation = "https://docs.rs/vte/" keywords = ["ansi", "vte", "parser", "terminal"] categories = ["parsing", "no-std"] diff --git a/README.md b/README.md index bfaec0c5..014795f2 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ vte === -[![Build Status](https://travis-ci.org/jwilm/vte.svg?branch=master)](https://travis-ci.org/jwilm/vte) +[![Build Status](https://travis-ci.org/alacritty/vte.svg?branch=master)](https://travis-ci.org/alacritty/vte) [![Crates.io Version](https://img.shields.io/crates/v/vte.svg)](https://crates.io/crates/vte/) Parser for implementing virtual terminal emulators in Rust. diff --git a/utf8parse/Cargo.toml b/utf8parse/Cargo.toml index 7aeafbeb..f2709758 100644 --- a/utf8parse/Cargo.toml +++ b/utf8parse/Cargo.toml @@ -2,7 +2,7 @@ authors = ["Joe Wilm ", "Christian Duerr "] description = "Table-driven UTF-8 parser" documentation = "https://docs.rs/utf8parse/" -repository = "https://github.com/jwilm/vte" +repository = "https://github.com/alacritty/vte" keywords = ["utf8", "parse", "table"] categories = ["parsing", "no-std"] license = "Apache-2.0 OR MIT" diff --git a/vte_generate_state_changes/Cargo.toml b/vte_generate_state_changes/Cargo.toml index 9bdfb64b..3f540f1e 100644 --- a/vte_generate_state_changes/Cargo.toml +++ b/vte_generate_state_changes/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Christian Duerr "] description = "Proc macro for generating VTE state changes" -repository = "https://github.com/jwilm/vte" +repository = "https://github.com/alacritty/vte" name = "vte_generate_state_changes" license = "Apache-2.0 OR MIT" version = "0.1.1" From e61e9652241a8e85ffdbb6dc6e48375e30ea9d40 Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Wed, 29 Jan 2020 15:57:04 +0000 Subject: [PATCH 71/99] Pass terminator to osc dispatcher Even though the ST terminator is the only officially supported terminator, some applications still rely on BEL to work properly. Both have been supported historically, however there was no way for the terminal to tell which terminator was used. Since OSC escapes frequently offer the `?` parameter to query for the current format, some applications expect the response terminator to match the request terminator. To make it possible to support this, the osc_dispatcher is now informed when the BEL terminator was used. Since the C1 ST terminator was not yet supported for OSC escapes, support for it has also been added. --- examples/parselog.rs | 4 +- src/definitions.rs | 4 +- src/lib.rs | 121 +++++++++++++++----------- src/table.rs | 4 +- utf8parse/src/lib.rs | 1 + utf8parse/src/types.rs | 2 +- vte_generate_state_changes/src/lib.rs | 4 +- 7 files changed, 83 insertions(+), 57 deletions(-) diff --git a/examples/parselog.rs b/examples/parselog.rs index 83ba2b51..331a003d 100644 --- a/examples/parselog.rs +++ b/examples/parselog.rs @@ -30,8 +30,8 @@ impl vte::Perform for Log { println!("[unhook]"); } - fn osc_dispatch(&mut self, params: &[&[u8]]) { - println!("[osc_dispatch] params={:?}", params); + fn osc_dispatch(&mut self, params: &[&[u8]], bell_terminated: bool) { + println!("[osc_dispatch] params={:?} bell_terminated={}", params, bell_terminated); } fn csi_dispatch(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, c: char) { diff --git a/src/definitions.rs b/src/definitions.rs index 568eb41f..5d016236 100644 --- a/src/definitions.rs +++ b/src/definitions.rs @@ -50,7 +50,7 @@ pub enum Action { impl State { #[inline] - pub fn entry_action(&self) -> Action { + pub fn entry_action(self) -> Action { match self { State::CsiEntry | State::DcsEntry | State::Escape => Action::Clear, State::DcsPassthrough => Action::Hook, @@ -60,7 +60,7 @@ impl State { } #[inline] - pub fn exit_action(&self) -> Action { + pub fn exit_action(self) -> Action { match self { State::DcsPassthrough => Action::Unhook, State::OscString => Action::OscEnd, diff --git a/src/lib.rs b/src/lib.rs index e0f43311..14021080 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,6 +30,7 @@ //! [`Parser`]: struct.Parser.html //! [`Perform`]: trait.Perform.html //! [Paul Williams' ANSI parser state machine]: https://vt100.net/emu/dec_ansi_parser +#![deny(clippy::all, clippy::if_not_else, clippy::enum_glob_use, clippy::wrong_pub_self_convention)] #![cfg_attr(all(feature = "nightly", test), feature(test))] #![cfg_attr(feature = "no_std", no_std)] @@ -179,7 +180,7 @@ impl Parser { /// /// The aliasing is needed here for multiple slices into self.osc_raw #[inline] - fn osc_dispatch(&self, performer: &mut P) { + fn osc_dispatch(&self, performer: &mut P, byte: u8) { let mut slices: [MaybeUninit<&[u8]>; MAX_PARAMS] = unsafe { MaybeUninit::uninit().assume_init() }; @@ -191,7 +192,7 @@ impl Parser { unsafe { let num_params = self.osc_num_params; let params = &slices[..num_params] as *const [MaybeUninit<&[u8]>] as *const [&[u8]]; - performer.osc_dispatch(&*params); + performer.osc_dispatch(&*params, byte == 0x07); } } @@ -268,7 +269,7 @@ impl Parser { self.osc_num_params += 1; }, } - self.osc_dispatch(performer); + self.osc_dispatch(performer, byte); }, Action::Unhook => performer.unhook(), Action::CsiDispatch => { @@ -343,13 +344,13 @@ impl Parser { /// referenced if something isn't clear. If the site disappears at some point in /// the future, consider checking archive.org. pub trait Perform { - /// Draw a character to the screen and update states + /// Draw a character to the screen and update states. fn print(&mut self, _: char); - /// Execute a C0 or C1 control function + /// Execute a C0 or C1 control function. fn execute(&mut self, byte: u8); - /// Invoked when a final character arrives in first part of device control string + /// Invoked when a final character arrives in first part of device control string. /// /// The control function should be determined from the private marker, final character, and /// execute with a parameter list. A handler should be selected for remaining characters in the @@ -358,27 +359,27 @@ pub trait Perform { /// /// The `ignore` flag indicates that more than two intermediates arrived and /// subsequent characters were ignored. - fn hook(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, _: char); + fn hook(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, action: char); /// Pass bytes as part of a device control string to the handle chosen in `hook`. C0 controls /// will also be passed to the handler. fn put(&mut self, byte: u8); - /// Called when a device control string is terminated + /// Called when a device control string is terminated. /// /// The previously selected handler should be notified that the DCS has /// terminated. fn unhook(&mut self); - /// Dispatch an operating system command - fn osc_dispatch(&mut self, params: &[&[u8]]); + /// Dispatch an operating system command. + fn osc_dispatch(&mut self, params: &[&[u8]], bell_terminated: bool); /// A final character has arrived for a CSI sequence /// /// The `ignore` flag indicates that either more than two intermediates arrived /// or the number of parameters exceeded the maximum supported length, /// and subsequent characters were ignored. - fn csi_dispatch(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, _: char); + fn csi_dispatch(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, action: char); /// The final character of an escape sequence has arrived. /// @@ -409,6 +410,7 @@ mod tests { #[derive(Default)] struct OscDispatcher { dispatched_osc: bool, + bell_terminated: bool, params: Vec>, } @@ -424,9 +426,10 @@ mod tests { fn unhook(&mut self) {} - fn osc_dispatch(&mut self, params: &[&[u8]]) { + fn osc_dispatch(&mut self, params: &[&[u8]], bell_terminated: bool) { // Set a flag so we know these assertions all run self.dispatched_osc = true; + self.bell_terminated = bell_terminated; self.params = params.iter().map(|p| p.to_vec()).collect(); } @@ -467,7 +470,7 @@ mod tests { fn unhook(&mut self) {} - fn osc_dispatch(&mut self, _params: &[&[u8]]) {} + fn osc_dispatch(&mut self, _params: &[&[u8]], _bell_terminated: bool) {} fn csi_dispatch(&mut self, params: &[i64], _intermediates: &[u8], ignore: bool, _c: char) { self.dispatched_csi = true; @@ -511,7 +514,7 @@ mod tests { self.dispatched_dcs = true; } - fn osc_dispatch(&mut self, _params: &[&[u8]]) {} + fn osc_dispatch(&mut self, _params: &[&[u8]], _bell_terminated: bool) {} fn csi_dispatch( &mut self, @@ -534,12 +537,9 @@ mod tests { #[test] fn parse_osc() { - // Create dispatcher and check state let mut dispatcher = OscDispatcher::default(); - assert_eq!(dispatcher.dispatched_osc, false); - - // Run parser using OSC_BYTES let mut parser = Parser::new(); + for byte in OSC_BYTES { parser.advance(&mut dispatcher, *byte); } @@ -553,12 +553,9 @@ mod tests { #[test] fn parse_empty_osc() { - // Create dispatcher and check state let mut dispatcher = OscDispatcher::default(); - assert_eq!(dispatcher.dispatched_osc, false); - - // Run parser using OSC_BYTES let mut parser = Parser::new(); + for byte in &[0x1b, 0x5d, 0x07] { parser.advance(&mut dispatcher, *byte); } @@ -570,13 +567,9 @@ mod tests { #[test] fn parse_osc_max_params() { static INPUT: &[u8] = b"\x1b];;;;;;;;;;;;;;;;;\x1b"; - - // Create dispatcher and check state let mut dispatcher = OscDispatcher::default(); - assert_eq!(dispatcher.dispatched_osc, false); - - // Run parser using OSC_BYTES let mut parser = Parser::new(); + for byte in INPUT { parser.advance(&mut dispatcher, *byte); } @@ -589,6 +582,48 @@ mod tests { } } + #[test] + fn osc_bell_terminated() { + static INPUT: &[u8] = b"\x1b]11;ff/00/ff\x07"; + let mut dispatcher = OscDispatcher::default(); + let mut parser = Parser::new(); + + for byte in INPUT { + parser.advance(&mut dispatcher, *byte); + } + + assert!(dispatcher.dispatched_osc); + assert!(dispatcher.bell_terminated); + } + + #[test] + fn osc_c1_st_terminated() { + static INPUT: &[u8] = b"\x1b]11;ff/00/ff\x9c"; + let mut dispatcher = OscDispatcher::default(); + let mut parser = Parser::new(); + + for byte in INPUT { + parser.advance(&mut dispatcher, *byte); + } + + assert!(dispatcher.dispatched_osc); + assert!(!dispatcher.bell_terminated); + } + + #[test] + fn osc_c0_st_terminated() { + static INPUT: &[u8] = b"\x1b]11;ff/00/ff\x1b\\"; + let mut dispatcher = OscDispatcher::default(); + let mut parser = Parser::new(); + + for byte in INPUT { + parser.advance(&mut dispatcher, *byte); + } + + assert!(dispatcher.dispatched_osc); + assert!(!dispatcher.bell_terminated); + } + #[test] fn parse_csi_max_params() { // This will build a list of repeating '1;'s @@ -597,12 +632,9 @@ mod tests { let params = std::iter::repeat("1;").take(MAX_PARAMS - 1).collect::(); let input = format!("\x1b[{}p", ¶ms[..]).into_bytes(); - // Create dispatcher and check state let mut dispatcher = CsiDispatcher::default(); - assert!(!dispatcher.dispatched_csi); - - // Run parser using INPUT let mut parser = Parser::new(); + for byte in input { parser.advance(&mut dispatcher, byte); } @@ -622,12 +654,9 @@ mod tests { let params = std::iter::repeat("1;").take(MAX_PARAMS).collect::(); let input = format!("\x1b[{}p", ¶ms[..]).into_bytes(); - // Create dispatcher and check state let mut dispatcher = CsiDispatcher::default(); - assert!(!dispatcher.dispatched_csi); - - // Run parser using INPUT let mut parser = Parser::new(); + for byte in input { parser.advance(&mut dispatcher, byte); } @@ -656,9 +685,8 @@ mod tests { fn parse_semi_set_underline() { // Create dispatcher and check state let mut dispatcher = CsiDispatcher::default(); - - // Run parser using OSC_BYTES let mut parser = Parser::new(); + for byte in b"\x1b[;4m" { parser.advance(&mut dispatcher, *byte); } @@ -671,10 +699,9 @@ mod tests { fn parse_long_csi_param() { // The important part is the parameter, which is (i64::MAX + 1) static INPUT: &[u8] = b"\x1b[9223372036854775808m"; - let mut dispatcher = CsiDispatcher::default(); - let mut parser = Parser::new(); + for byte in INPUT { parser.advance(&mut dispatcher, *byte); } @@ -689,12 +716,9 @@ mod tests { 0x5f, 0x28, 0xe3, 0x83, 0x84, 0x29, 0x5f, 0x2f, 0xc2, 0xaf, 0x27, 0x20, 0x26, 0x26, 0x20, 0x73, 0x6c, 0x65, 0x65, 0x70, 0x20, 0x31, 0x07, ]; - - // Create dispatcher and check state - let mut dispatcher = OscDispatcher { params: vec![], dispatched_osc: false }; - - // Run parser using OSC_BYTES + let mut dispatcher = OscDispatcher::default(); let mut parser = Parser::new(); + for byte in INPUT { parser.advance(&mut dispatcher, *byte); } @@ -708,12 +732,9 @@ mod tests { fn parse_dcs() { static INPUT: &[u8] = &[0x1b, 0x50, 0x30, 0x3b, 0x31, 0x7c, 0x31, 0x37, 0x2f, 0x61, 0x62, 0x9c]; - - // Create dispatcher and check state let mut dispatcher = DcsDispatcher::default(); - - // Run parser using OSC_BYTES let mut parser = Parser::new(); + for byte in INPUT { parser.advance(&mut dispatcher, *byte); } @@ -792,8 +813,8 @@ mod bench { fn unhook(&mut self) {} - fn osc_dispatch(&mut self, params: &[&[u8]]) { - black_box(params); + fn osc_dispatch(&mut self, params: &[&[u8]], bell_terminated: bool) { + black_box((params, bell_terminated)); } fn csi_dispatch(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, c: char) { diff --git a/src/table.rs b/src/table.rs index c19e4abb..392cf052 100644 --- a/src/table.rs +++ b/src/table.rs @@ -170,6 +170,8 @@ generate_state_changes!(state_changes, { 0x08..=0x17 => (Anywhere, Ignore), 0x19 => (Anywhere, Ignore), 0x1c..=0x1f => (Anywhere, Ignore), - 0x20..=0xff => (Anywhere, OscPut), + 0x20..=0x9b => (Anywhere, OscPut), + 0x9c => (Ground, None), + 0x9d..=0xff => (Anywhere, OscPut), } }); diff --git a/utf8parse/src/lib.rs b/utf8parse/src/lib.rs index c092647a..6168e2e4 100644 --- a/utf8parse/src/lib.rs +++ b/utf8parse/src/lib.rs @@ -3,6 +3,7 @@ //! This module implements a table-driven UTF-8 parser which should //! theoretically contain the minimal number of branches (1). The only branch is //! on the `Action` returned from unpacking a transition. +#![deny(clippy::all, clippy::if_not_else, clippy::enum_glob_use, clippy::wrong_pub_self_convention)] #![cfg_attr(all(feature = "nightly", test), feature(test))] #![no_std] diff --git a/utf8parse/src/types.rs b/utf8parse/src/types.rs index 5a70b3c1..77a79cc1 100644 --- a/utf8parse/src/types.rs +++ b/utf8parse/src/types.rs @@ -58,7 +58,7 @@ impl State { /// This takes the current state and input byte into consideration, to determine the next state /// and any action that should be taken. #[inline] - pub fn advance(&self, byte: u8) -> (State, Action) { + pub fn advance(self, byte: u8) -> (State, Action) { match self { State::Ground => match byte { 0x00..=0x7f => (State::Ground, Action::EmitByte), diff --git a/vte_generate_state_changes/src/lib.rs b/vte_generate_state_changes/src/lib.rs index 5cfb3acf..cae8f65a 100644 --- a/vte_generate_state_changes/src/lib.rs +++ b/vte_generate_state_changes/src/lib.rs @@ -1,3 +1,5 @@ +#![deny(clippy::all, clippy::if_not_else, clippy::enum_glob_use, clippy::wrong_pub_self_convention)] + extern crate proc_macro; use std::iter::Peekable; @@ -53,7 +55,7 @@ fn states_stream(iter: &mut impl Iterator) -> TokenStream { /// Generate the array assignment statements for one origin state. fn state_entry_stream(iter: &mut Peekable) -> TokenStream { // Origin state name - let state = iter.next().unwrap().into(); + let state = iter.next().unwrap(); // Token stream with all the byte->target mappings let mut changes_stream = next_group(iter).into_iter().peekable(); From 3ccf275e5dd438fc0aeaa000d49a50eb8e4edaa0 Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Thu, 30 Jan 2020 19:57:50 +0000 Subject: [PATCH 72/99] Bump version to 0.6.0 --- CHANGELOG.md | 3 ++- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f0765545..ffea20cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,10 @@ CHANGELOG ========= -## Unreleased +## 0.6.0 - Fix build failure on Rust 1.36.0 +- Add `bool_terminated` parameter to osc dispatch ## 0.5.0 diff --git a/Cargo.toml b/Cargo.toml index dc776694..0a66fb33 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ categories = ["parsing", "no-std"] exclude = ["/.travis.yml"] readme = "README.md" license = "Apache-2.0 OR MIT" -version = "0.5.0" +version = "0.6.0" name = "vte" edition = "2018" From 035c47fb362cc97fb42712e0138c55a7a4d318e4 Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Fri, 31 Jan 2020 22:22:09 +0000 Subject: [PATCH 73/99] Fix param not resetting between escapes Fixes #46. --- CHANGELOG.md | 4 ++++ src/lib.rs | 39 ++++++++++++++++++++++++++++++++------- 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ffea20cd..ffce24eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ CHANGELOG ========= +## [Unreleased] + +- Fix params reset between escapes + ## 0.6.0 - Fix build failure on Rust 1.36.0 diff --git a/src/lib.rs b/src/lib.rs index 14021080..011b6a17 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -286,9 +286,6 @@ impl Parser { self.ignoring, byte as char, ); - - self.num_params = 0; - self.param = 0; }, Action::EscDispatch => { performer.esc_dispatch(self.params(), self.intermediates(), self.ignoring, byte); @@ -322,13 +319,13 @@ impl Parser { } }, Action::Clear => { + // Reset everything on ESC/CSI/DCS entry self.intermediate_idx = 0; - self.num_params = 0; self.ignoring = false; + self.num_params = 0; + self.param = 0; }, - Action::BeginUtf8 => { - self.process_utf8(performer, byte); - }, + Action::BeginUtf8 => self.process_utf8(performer, byte), } } } @@ -709,6 +706,34 @@ mod tests { assert_eq!(dispatcher.params[0], &[i64::MAX as i64]); } + #[test] + fn csi_reset() { + static INPUT: &[u8] = b"\x1b[3;1\x1b[2J"; + let mut dispatcher = CsiDispatcher::default(); + let mut parser = Parser::new(); + + for byte in INPUT { + parser.advance(&mut dispatcher, *byte); + } + + assert_eq!(dispatcher.params.len(), 1); + assert_eq!(dispatcher.params[0], &[2]); + } + + #[test] + fn dcs_reset() { + static INPUT: &[u8] = b"\x1bP1X\x9c\x1b[31mH"; + let mut dispatcher = CsiDispatcher::default(); + let mut parser = Parser::new(); + + for byte in INPUT { + parser.advance(&mut dispatcher, *byte); + } + + assert_eq!(dispatcher.params.len(), 1); + assert_eq!(dispatcher.params[0], &[31]); + } + #[test] fn parse_osc_with_utf8_arguments() { static INPUT: &[u8] = &[ From cad136272a95c2f17bb6e25b2df02509bb7b86bf Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Sat, 1 Feb 2020 00:03:42 +0000 Subject: [PATCH 74/99] Remove ESC params Since ESC escapes cannot have parameters, they have been removed from the `esc_dispatch` function. --- CHANGELOG.md | 1 + examples/parselog.rs | 6 +- src/lib.rs | 165 ++++++++++++++++++++++++------------------- 3 files changed, 96 insertions(+), 76 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ffce24eb..c46b31d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ CHANGELOG ## [Unreleased] - Fix params reset between escapes +- Removed unused parameter from `esc_dispatch` ## 0.6.0 diff --git a/examples/parselog.rs b/examples/parselog.rs index 331a003d..4878f347 100644 --- a/examples/parselog.rs +++ b/examples/parselog.rs @@ -41,10 +41,10 @@ impl vte::Perform for Log { ); } - fn esc_dispatch(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, byte: u8) { + fn esc_dispatch(&mut self, intermediates: &[u8], ignore: bool, byte: u8) { println!( - "[esc_dispatch] params={:?}, intermediates={:?}, ignore={:?}, byte={:02x}", - params, intermediates, ignore, byte + "[esc_dispatch] intermediates={:?}, ignore={:?}, byte={:02x}", + intermediates, ignore, byte ); } } diff --git a/src/lib.rs b/src/lib.rs index 011b6a17..af1682ee 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -288,7 +288,7 @@ impl Parser { ); }, Action::EscDispatch => { - performer.esc_dispatch(self.params(), self.intermediates(), self.ignoring, byte); + performer.esc_dispatch(self.intermediates(), self.ignoring, byte) }, Action::Ignore | Action::None => (), Action::Collect => { @@ -382,7 +382,7 @@ pub trait Perform { /// /// The `ignore` flag indicates that more than two intermediates arrived and /// subsequent characters were ignored. - fn esc_dispatch(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, byte: u8); + fn esc_dispatch(&mut self, intermediates: &[u8], ignore: bool, byte: u8); } #[cfg(all(test, feature = "no_std"))] @@ -415,11 +415,11 @@ mod tests { impl Perform for OscDispatcher { fn print(&mut self, _: char) {} - fn execute(&mut self, _byte: u8) {} + fn execute(&mut self, _: u8) {} - fn hook(&mut self, _params: &[i64], _intermediates: &[u8], _ignore: bool, _: char) {} + fn hook(&mut self, _: &[i64], _: &[u8], _: bool, _: char) {} - fn put(&mut self, _byte: u8) {} + fn put(&mut self, _: u8) {} fn unhook(&mut self) {} @@ -430,65 +430,48 @@ mod tests { self.params = params.iter().map(|p| p.to_vec()).collect(); } - fn csi_dispatch( - &mut self, - _params: &[i64], - _intermediates: &[u8], - _ignore: bool, - _c: char, - ) { - } + fn csi_dispatch(&mut self, _: &[i64], _: &[u8], _: bool, _: char) {} - fn esc_dispatch( - &mut self, - _params: &[i64], - _intermediates: &[u8], - _ignore: bool, - _byte: u8, - ) { - } + fn esc_dispatch(&mut self, _: &[u8], _: bool, _: u8) {} } #[derive(Default)] struct CsiDispatcher { dispatched_csi: bool, ignore: bool, - params: Vec>, + params: Vec, + intermediates: Vec, } impl Perform for CsiDispatcher { fn print(&mut self, _: char) {} - fn execute(&mut self, _byte: u8) {} + fn execute(&mut self, _: u8) {} - fn hook(&mut self, _params: &[i64], _intermediates: &[u8], _ignore: bool, _: char) {} + fn hook(&mut self, _: &[i64], _: &[u8], _: bool, _: char) {} - fn put(&mut self, _byte: u8) {} + fn put(&mut self, _: u8) {} fn unhook(&mut self) {} - fn osc_dispatch(&mut self, _params: &[&[u8]], _bell_terminated: bool) {} + fn osc_dispatch(&mut self, _: &[&[u8]], _: bool) {} - fn csi_dispatch(&mut self, params: &[i64], _intermediates: &[u8], ignore: bool, _c: char) { - self.dispatched_csi = true; + fn csi_dispatch(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, _: char) { + self.intermediates = intermediates.to_vec(); + self.params = params.to_vec(); self.ignore = ignore; - self.params.push(params.to_vec()); + self.dispatched_csi = true; } - fn esc_dispatch( - &mut self, - _params: &[i64], - _intermediates: &[u8], - _ignore: bool, - _byte: u8, - ) { - } + fn esc_dispatch(&mut self, _: &[u8], _: bool, _: u8) {} } #[derive(Default)] struct DcsDispatcher { dispatched_dcs: bool, + intermediates: Vec, params: Vec, + ignore: bool, c: Option, s: Vec, } @@ -496,11 +479,14 @@ mod tests { impl Perform for DcsDispatcher { fn print(&mut self, _: char) {} - fn execute(&mut self, _byte: u8) {} + fn execute(&mut self, _: u8) {} - fn hook(&mut self, params: &[i64], _intermediates: &[u8], _ignore: bool, c: char) { - self.c = Some(c); + fn hook(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, c: char) { + self.intermediates = intermediates.to_vec(); self.params = params.to_vec(); + self.ignore = ignore; + self.c = Some(c); + self.dispatched_dcs = true; } fn put(&mut self, byte: u8) { @@ -511,24 +497,41 @@ mod tests { self.dispatched_dcs = true; } - fn osc_dispatch(&mut self, _params: &[&[u8]], _bell_terminated: bool) {} + fn osc_dispatch(&mut self, _: &[&[u8]], _: bool) {} - fn csi_dispatch( - &mut self, - _params: &[i64], - _intermediates: &[u8], - _ignore: bool, - _c: char, - ) { - } + fn csi_dispatch(&mut self, _: &[i64], _: &[u8], _: bool, _: char) {} + + fn esc_dispatch(&mut self, _: &[u8], _: bool, _: u8) {} + } + + #[derive(Default)] + struct EscDispatcher { + dispatched_esc: bool, + intermediates: Vec, + ignore: bool, + byte: u8, + } + + impl Perform for EscDispatcher { + fn print(&mut self, _: char) {} + + fn execute(&mut self, _: u8) {} + + fn hook(&mut self, _: &[i64], _: &[u8], _: bool, _: char) {} - fn esc_dispatch( - &mut self, - _params: &[i64], - _intermediates: &[u8], - _ignore: bool, - _byte: u8, - ) { + fn put(&mut self, _: u8) {} + + fn unhook(&mut self) {} + + fn osc_dispatch(&mut self, _: &[&[u8]], _: bool) {} + + fn csi_dispatch(&mut self, _: &[i64], _: &[u8], _: bool, _: char) {} + + fn esc_dispatch(&mut self, intermediates: &[u8], ignore: bool, byte: u8) { + self.intermediates = intermediates.to_vec(); + self.ignore = ignore; + self.byte = byte; + self.dispatched_esc = true; } } @@ -638,8 +641,7 @@ mod tests { // Check that flag is set and thus csi_dispatch assertions ran. assert!(dispatcher.dispatched_csi); - assert_eq!(dispatcher.params.len(), 1); - assert_eq!(dispatcher.params[0].len(), MAX_PARAMS); + assert_eq!(dispatcher.params.len(), MAX_PARAMS); assert!(!dispatcher.ignore); } @@ -660,8 +662,7 @@ mod tests { // Check that flag is set and thus csi_dispatch assertions ran. assert!(dispatcher.dispatched_csi); - assert_eq!(dispatcher.params.len(), 1); - assert_eq!(dispatcher.params[0].len(), MAX_PARAMS); + assert_eq!(dispatcher.params.len(), MAX_PARAMS); assert!(dispatcher.ignore); } @@ -674,8 +675,7 @@ mod tests { parser.advance(&mut dispatcher, *byte); } - assert_eq!(dispatcher.params.len(), 1); - assert_eq!(dispatcher.params[0], &[4, 0]); + assert_eq!(dispatcher.params, &[4, 0]); } #[test] @@ -689,7 +689,7 @@ mod tests { } // Check that flag is set and thus osc_dispatch assertions ran. - assert_eq!(dispatcher.params[0], &[0, 4]); + assert_eq!(dispatcher.params, &[0, 4]); } #[test] @@ -703,12 +703,12 @@ mod tests { parser.advance(&mut dispatcher, *byte); } - assert_eq!(dispatcher.params[0], &[i64::MAX as i64]); + assert_eq!(dispatcher.params, &[i64::MAX as i64]); } #[test] fn csi_reset() { - static INPUT: &[u8] = b"\x1b[3;1\x1b[2J"; + static INPUT: &[u8] = b"\x1b[3;1\x1b[?1049h"; let mut dispatcher = CsiDispatcher::default(); let mut parser = Parser::new(); @@ -716,22 +716,41 @@ mod tests { parser.advance(&mut dispatcher, *byte); } - assert_eq!(dispatcher.params.len(), 1); - assert_eq!(dispatcher.params[0], &[2]); + assert!(dispatcher.dispatched_csi); + assert!(!dispatcher.ignore); + assert_eq!(dispatcher.intermediates, &[b'?']); + assert_eq!(dispatcher.params, &[1049]); } #[test] fn dcs_reset() { - static INPUT: &[u8] = b"\x1bP1X\x9c\x1b[31mH"; - let mut dispatcher = CsiDispatcher::default(); + static INPUT: &[u8] = b"\x1b[3;1\x1bP1$tx\x9c"; + let mut dispatcher = DcsDispatcher::default(); let mut parser = Parser::new(); for byte in INPUT { parser.advance(&mut dispatcher, *byte); } - assert_eq!(dispatcher.params.len(), 1); - assert_eq!(dispatcher.params[0], &[31]); + assert!(dispatcher.dispatched_dcs); + assert!(!dispatcher.ignore); + assert_eq!(dispatcher.intermediates, &[b'$']); + assert_eq!(dispatcher.params, &[1]); + } + + #[test] + fn esc_reset() { + static INPUT: &[u8] = b"\x1b[3;1\x1b(A"; + let mut dispatcher = EscDispatcher::default(); + let mut parser = Parser::new(); + + for byte in INPUT { + parser.advance(&mut dispatcher, *byte); + } + + assert!(dispatcher.dispatched_esc); + assert!(!dispatcher.ignore); + assert_eq!(dispatcher.intermediates, &[b'(']); } #[test] @@ -846,8 +865,8 @@ mod bench { black_box((params, intermediates, ignore, c)); } - fn esc_dispatch(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, byte: u8) { - black_box((params, intermediates, ignore, byte)); + fn esc_dispatch(&mut self, intermediates: &[u8], ignore: bool, byte: u8) { + black_box((intermediates, ignore, byte)); } } From 9e2fc2f4cd2db13f4f751fa7f21cf13629f9df32 Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Tue, 11 Feb 2020 19:59:45 +0000 Subject: [PATCH 75/99] Bump version to 0.7.0 --- CHANGELOG.md | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c46b31d6..8b3e5dc0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ CHANGELOG ========= -## [Unreleased] +## 0.7.0 - Fix params reset between escapes - Removed unused parameter from `esc_dispatch` diff --git a/Cargo.toml b/Cargo.toml index 0a66fb33..5aa171e1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ categories = ["parsing", "no-std"] exclude = ["/.travis.yml"] readme = "README.md" license = "Apache-2.0 OR MIT" -version = "0.6.0" +version = "0.7.0" name = "vte" edition = "2018" From cb3b717258d97fd05cd8be2676ad87bbf12b7511 Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Sun, 1 Mar 2020 23:25:37 +0000 Subject: [PATCH 76/99] Fix OOB in DCS parser This resolves an issue with parsing of DCS escapes, where it would try to write parameters beyond the maximum parameter count limit. Fixes #50. --- CHANGELOG.md | 4 ++++ src/lib.rs | 27 +++++++++++++++++++++++++-- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b3e5dc0..212b2ff8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ CHANGELOG ========= +## [Unreleased] + +- Out of bounds when parsing a DCS with more than 16 parameters + ## 0.7.0 - Fix params reset between escapes diff --git a/src/lib.rs b/src/lib.rs index af1682ee..30708ca4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -202,8 +202,12 @@ impl Parser { Action::Print => performer.print(byte as char), Action::Execute => performer.execute(byte), Action::Hook => { - self.params[self.num_params] = self.param; - self.num_params += 1; + if self.num_params == MAX_PARAMS { + self.ignoring = true; + } else { + self.params[self.num_params] = self.param; + self.num_params += 1; + } performer.hook(self.params(), self.intermediates(), self.ignoring, byte as char); }, @@ -582,6 +586,25 @@ mod tests { } } + #[test] + fn parse_dcs_max_params() { + static INPUT: &[u8] = b"\x1bP1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;p\x1b"; + let mut dispatcher = DcsDispatcher::default(); + let mut parser = Parser::new(); + + for byte in INPUT { + parser.advance(&mut dispatcher, *byte); + } + + // Check that flag is set and thus osc_dispatch assertions ran. + assert!(dispatcher.ignore); + assert!(dispatcher.dispatched_dcs); + assert_eq!(dispatcher.params.len(), MAX_PARAMS); + for param in dispatcher.params.iter() { + assert_eq!(*param, 1); + } + } + #[test] fn osc_bell_terminated() { static INPUT: &[u8] = b"\x1b]11;ff/00/ff\x07"; From 204893a1becc1f1eba6c8f8c954ec3023978963b Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Mon, 2 Mar 2020 00:12:52 +0000 Subject: [PATCH 77/99] Bump version to 0.7.1 --- CHANGELOG.md | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 212b2ff8..71cac4b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ CHANGELOG ========= -## [Unreleased] +## 0.7.1 - Out of bounds when parsing a DCS with more than 16 parameters diff --git a/Cargo.toml b/Cargo.toml index 5aa171e1..351327d8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ categories = ["parsing", "no-std"] exclude = ["/.travis.yml"] readme = "README.md" license = "Apache-2.0 OR MIT" -version = "0.7.0" +version = "0.7.1" name = "vte" edition = "2018" From c8454b7f186cbbaee31a43ab2e49960f0fb92794 Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Wed, 15 Apr 2020 03:50:56 +0000 Subject: [PATCH 78/99] Remove C1 ST support from OSCs --- CHANGELOG.md | 4 ++++ src/lib.rs | 27 +++++++++++++-------------- src/table.rs | 4 +--- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 71cac4b4..ebc37077 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ CHANGELOG ========= +## Unreleased + +- Remove C1 ST support in OSCs, fixing OSCs with ST in the payload + ## 0.7.1 - Out of bounds when parsing a DCS with more than 16 parameters diff --git a/src/lib.rs b/src/lib.rs index 30708ca4..62349012 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -619,20 +619,6 @@ mod tests { assert!(dispatcher.bell_terminated); } - #[test] - fn osc_c1_st_terminated() { - static INPUT: &[u8] = b"\x1b]11;ff/00/ff\x9c"; - let mut dispatcher = OscDispatcher::default(); - let mut parser = Parser::new(); - - for byte in INPUT { - parser.advance(&mut dispatcher, *byte); - } - - assert!(dispatcher.dispatched_osc); - assert!(!dispatcher.bell_terminated); - } - #[test] fn osc_c0_st_terminated() { static INPUT: &[u8] = b"\x1b]11;ff/00/ff\x1b\\"; @@ -795,6 +781,19 @@ mod tests { assert_eq!(dispatcher.params[1], &INPUT[5..(INPUT.len() - 1)]); } + #[test] + fn osc_containing_string_terminator() { + static INPUT: &[u8] = b"\x1b]2;\xe6\x9c\xab\x1b\\"; + let mut dispatcher = OscDispatcher::default(); + let mut parser = Parser::new(); + + for byte in INPUT { + parser.advance(&mut dispatcher, *byte); + } + + assert_eq!(dispatcher.params[1], &INPUT[4..(INPUT.len() - 2)]); + } + #[test] fn parse_dcs() { static INPUT: &[u8] = diff --git a/src/table.rs b/src/table.rs index 392cf052..c19e4abb 100644 --- a/src/table.rs +++ b/src/table.rs @@ -170,8 +170,6 @@ generate_state_changes!(state_changes, { 0x08..=0x17 => (Anywhere, Ignore), 0x19 => (Anywhere, Ignore), 0x1c..=0x1f => (Anywhere, Ignore), - 0x20..=0x9b => (Anywhere, OscPut), - 0x9c => (Ground, None), - 0x9d..=0xff => (Anywhere, OscPut), + 0x20..=0xff => (Anywhere, OscPut), } }); From 2a92abe675bf903c7837fe91d36a440b6b389e09 Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Wed, 13 May 2020 09:14:55 +0000 Subject: [PATCH 79/99] Bump version to 0.8.0 --- CHANGELOG.md | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ebc37077..02a1e0a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ CHANGELOG ========= -## Unreleased +## 0.8.0 - Remove C1 ST support in OSCs, fixing OSCs with ST in the payload diff --git a/Cargo.toml b/Cargo.toml index 351327d8..3619eb34 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ categories = ["parsing", "no-std"] exclude = ["/.travis.yml"] readme = "README.md" license = "Apache-2.0 OR MIT" -version = "0.7.1" +version = "0.8.0" name = "vte" edition = "2018" From 582731cf9d3bdb4ba453e189fb114583f0b8f0f0 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Mon, 15 Jun 2020 09:04:32 -0700 Subject: [PATCH 80/99] Remove redundant `.to_string()` --- utf8parse/tests/utf-8-demo.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utf8parse/tests/utf-8-demo.rs b/utf8parse/tests/utf-8-demo.rs index e60ce22c..51df4927 100644 --- a/utf8parse/tests/utf-8-demo.rs +++ b/utf8parse/tests/utf-8-demo.rs @@ -25,7 +25,7 @@ fn utf8parse_test() { } // standard library implementation - let expected = String::from_utf8_lossy(UTF8_DEMO).to_string(); + let expected = String::from_utf8_lossy(UTF8_DEMO); assert_eq!(actual.0, expected); } From 408b1584646338e9e1e8e4fd7e2d127aef8ebd0a Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Mon, 15 Jun 2020 10:30:44 -0700 Subject: [PATCH 81/99] Rename example variable to match trait --- examples/parselog.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/parselog.rs b/examples/parselog.rs index 4878f347..c3101820 100644 --- a/examples/parselog.rs +++ b/examples/parselog.rs @@ -54,7 +54,7 @@ fn main() { let mut handle = input.lock(); let mut statemachine = vte::Parser::new(); - let mut parser = Log; + let mut performer = Log; let mut buf = [0; 2048]; @@ -63,7 +63,7 @@ fn main() { Ok(0) => break, Ok(n) => { for byte in &buf[..n] { - statemachine.advance(&mut parser, *byte); + statemachine.advance(&mut performer, *byte); } }, Err(err) => { From 335aaf364cf8435fb9e3aa8d6cef2c2287776ad7 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Mon, 15 Jun 2020 16:01:18 -0700 Subject: [PATCH 82/99] Remove outdated documentation --- README.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/README.md b/README.md index 014795f2..a9c016a1 100644 --- a/README.md +++ b/README.md @@ -15,11 +15,5 @@ useful with the parsed data. The `Parser` handles the book keeping, and the See the [docs] for more info. -## Developer Notes - -If contributing to either `vte` or the `utf8parse` crate and modifying a -_table.rs.in_ file, make sure to `cargo run` from the _codegen_ folder so that -the compiled tables are updated. - [Paul Williams' ANSI parser state machine]: https://vt100.net/emu/dec_ansi_parser [docs]: https://docs.rs/crate/vte/ From f53d1b7dcfb9a1101b297437fb135667dd908628 Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Sat, 18 Jul 2020 19:02:15 +0000 Subject: [PATCH 83/99] Move CI to sourcehut --- .builds/linux.yml | 21 +++++++++++++++++ .travis.yml | 57 ----------------------------------------------- ci/install.sh | 11 --------- ci/script.sh | 16 ------------- 4 files changed, 21 insertions(+), 84 deletions(-) create mode 100644 .builds/linux.yml delete mode 100644 .travis.yml delete mode 100755 ci/install.sh delete mode 100755 ci/script.sh diff --git a/.builds/linux.yml b/.builds/linux.yml new file mode 100644 index 00000000..7430c526 --- /dev/null +++ b/.builds/linux.yml @@ -0,0 +1,21 @@ +image: archlinux +sources: + - https://github.com/alacritty/vte +tasks: + - rustup: | + curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain stable --profile minimal -c clippy + - stable: | + cd vte + $HOME/.cargo/bin/cargo +stable test + - clippy: | + cd vte + $HOME/.cargo/bin/cargo +stable clippy + - rustfmt: | + $HOME/.cargo/bin/rustup toolchain install nightly -c rustfmt + cd vte + $HOME/.cargo/bin/cargo +nightly fmt -- --check + - 1-36-0: | + $HOME/.cargo/bin/rustup toolchain install --profile minimal 1.36.0 + cd vte + rm Cargo.lock + $HOME/.cargo/bin/cargo +1.36.0 test diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index a401da4b..00000000 --- a/.travis.yml +++ /dev/null @@ -1,57 +0,0 @@ -language: rust - -addons: - apt: - packages: - - libxcb-xfixes0-dev - -git: - depth: 1 - -os: - - linux - - osx - -rust: - - 1.36.0 - - stable - - nightly - -matrix: - fast_finish: true - include: - - if: tag IS present - os: linux - rust: stable - env: ARCH=i386 - - name: "Clippy Linux" - os: linux - env: CLIPPY=true - rust: stable - - name: "Clippy OSX" - os: osx - env: CLIPPY=true - rust: stable - - name: "Clippy Windows" - os: windows - env: CLIPPY=true - rust: stable-x86_64-pc-windows-msvc - - name: "Rustfmt" - os: linux - env: RUSTFMT=true - rust: nightly - - name: "Windows 1.36.0" - os: windows - rust: 1.36.0-x86_64-pc-windows-msvc - - name: "Windows Stable" - os: windows - rust: stable-x86_64-pc-windows-msvc - - name: "Windows Nightly" - os: windows - rust: nightly-x86_64-pc-windows-msvc - allow_failures: - - rust: nightly - - rust: nightly-x86_64-pc-windows-msvc - -install: ci/install.sh -script: ci/script.sh diff --git a/ci/install.sh b/ci/install.sh deleted file mode 100755 index ccbe3728..00000000 --- a/ci/install.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -# Add clippy for lint validation -if [ "$CLIPPY" == "true" ]; then - rustup component add clippy -fi - -# Add rustfmt for format validation -if [ "$RUSTFMT" == "true" ]; then - rustup component add rustfmt -fi diff --git a/ci/script.sh b/ci/script.sh deleted file mode 100755 index e601d34c..00000000 --- a/ci/script.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash - -# Run clippy checks -if [ "$CLIPPY" == "true" ]; then - cargo clippy --all-targets - exit -fi - -# Run clippy rustfmt -if [ "$RUSTFMT" == "true" ]; then - cargo fmt -- --check - exit -fi - -# Run tests -cargo test From 0310be12d3007e32be614c5df94653d29fcc1a8b Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Mon, 27 Jul 2020 22:37:20 +0000 Subject: [PATCH 84/99] Improve parser performance --- src/definitions.rs | 21 ------------------ src/lib.rs | 53 +++++++++++++++++++++++++++++++++++++--------- 2 files changed, 43 insertions(+), 31 deletions(-) diff --git a/src/definitions.rs b/src/definitions.rs index 5d016236..fe7952d4 100644 --- a/src/definitions.rs +++ b/src/definitions.rs @@ -48,27 +48,6 @@ pub enum Action { BeginUtf8 = 15, } -impl State { - #[inline] - pub fn entry_action(self) -> Action { - match self { - State::CsiEntry | State::DcsEntry | State::Escape => Action::Clear, - State::DcsPassthrough => Action::Hook, - State::OscString => Action::OscStart, - _ => Action::None, - } - } - - #[inline] - pub fn exit_action(self) -> Action { - match self { - State::DcsPassthrough => Action::Unhook, - State::OscString => Action::OscEnd, - _ => Action::None, - } - } -} - /// Unpack a u8 into a State and Action /// /// The implementation of this assumes that there are *precisely* 16 variants for both Action and diff --git a/src/lib.rs b/src/lib.rs index 62349012..a99638a2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -160,15 +160,32 @@ impl Parser { self.perform_action(performer, action, byte); }, state => { - // Exit action for previous state - let exit_action = self.state.exit_action(); - maybe_action!(exit_action, byte); - - // Transition action - maybe_action!(action, byte); - - // Entry action for new state - maybe_action!(state.entry_action(), byte); + match self.state { + State::DcsPassthrough => { + self.perform_action(performer, Action::Unhook, byte); + maybe_action!(action, byte); + }, + State::OscString => { + self.perform_action(performer, Action::OscEnd, byte); + maybe_action!(action, byte); + }, + _ => { + maybe_action!(action, byte); + + match state { + State::CsiEntry | State::DcsEntry | State::Escape => { + self.perform_action(performer, Action::Clear, byte); + }, + State::DcsPassthrough => { + self.perform_action(performer, Action::Hook, byte); + }, + State::OscString => { + self.perform_action(performer, Action::OscStart, byte); + }, + _ => (), + } + }, + } // Assume the new state self.state = state; @@ -294,7 +311,6 @@ impl Parser { Action::EscDispatch => { performer.esc_dispatch(self.intermediates(), self.ignoring, byte) }, - Action::Ignore | Action::None => (), Action::Collect => { if self.intermediate_idx == MAX_INTERMEDIATES { self.ignoring = true; @@ -330,6 +346,8 @@ impl Parser { self.param = 0; }, Action::BeginUtf8 => self.process_utf8(performer, byte), + Action::Ignore => (), + Action::None => (), } } } @@ -903,4 +921,19 @@ mod bench { } }); } + + #[bench] + fn state_changes(b: &mut Bencher) { + let input = b"\x1b]2;X\x1b\\ \x1b[0m \x1bP0@\x1b\\"; + b.iter(|| { + let mut dispatcher = BenchDispatcher; + let mut parser = Parser::new(); + + for _ in 0..1_000 { + for byte in input { + parser.advance(&mut dispatcher, *byte); + } + } + }); + } } From 4f44023dab081f7da74fee14bc53b10ee8f96a1e Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Wed, 5 Aug 2020 00:36:41 +0000 Subject: [PATCH 85/99] Add CSI subparameter support This adds support for CSI subparameters like `\x1b[38:2:255:0:255m`, which allows the combination of truecolor SGR commands together with other SGR parameters like bold text, without any ambiguity. This implements subparameters by storing them in a list together with all other parameters and having a separate slice to indicate which parameter is a subparameter and how long the subparameter list is. This allows for static memory allocation and good performance while still having the option for dynamic sizing of the parameters. Since the subparameters are now also counted as parameters, the number of allowed parameters has been increased from `16` to `32`. Since the existing structures combine the handling of parameters for CSI and DCS escape sequences, it is now also possible for DCS parameters to have subparameters, even though that is currently never used. Considering that DCS is rarely supported by terminal emulators, handling these separately would likely just cause unnecessary issues. The performance should also be better by using this existing subparam structure rather than having two separate structures for DCS and CSI parameters. The only API provided for accessing the list of parameters is using an iterator, this is intentional to make the internal structure clear and allow for easy optimizations downstream. Since it makes little sense to access parameters out of order, this limitation should not have any negative effects on performance. The main drawback is that direct access to the first parameter while ignoring all other subparameters is less efficient, since it requires indexing a slice after iterating to the element. However while this is often useful, it's mostly done for the first few parameters which significantly reduces the overhead to a negligible amount. At the same time this forces people to support subparameters or at least consider their existence, which should make it more difficult to implement things improperly downstream. Fixes #22. --- examples/parselog.rs | 12 ++-- src/lib.rs | 128 +++++++++++++++++++++----------------- src/params.rs | 142 +++++++++++++++++++++++++++++++++++++++++++ src/table.rs | 12 ++-- 4 files changed, 225 insertions(+), 69 deletions(-) create mode 100644 src/params.rs diff --git a/examples/parselog.rs b/examples/parselog.rs index c3101820..dfd0aee9 100644 --- a/examples/parselog.rs +++ b/examples/parselog.rs @@ -1,12 +1,12 @@ //! Parse input from stdin and log actions on stdout use std::io::{self, Read}; -use vte; +use vte::{Params, Parser, Perform}; /// A type implementing Perform that just logs actions struct Log; -impl vte::Perform for Log { +impl Perform for Log { fn print(&mut self, c: char) { println!("[print] {:?}", c); } @@ -15,7 +15,7 @@ impl vte::Perform for Log { println!("[execute] {:02x}", byte); } - fn hook(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, c: char) { + fn hook(&mut self, params: &Params, intermediates: &[u8], ignore: bool, c: char) { println!( "[hook] params={:?}, intermediates={:?}, ignore={:?}, char={:?}", params, intermediates, ignore, c @@ -34,9 +34,9 @@ impl vte::Perform for Log { println!("[osc_dispatch] params={:?} bell_terminated={}", params, bell_terminated); } - fn csi_dispatch(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, c: char) { + fn csi_dispatch(&mut self, params: &Params, intermediates: &[u8], ignore: bool, c: char) { println!( - "[csi_dispatch] params={:?}, intermediates={:?}, ignore={:?}, char={:?}", + "[csi_dispatch] params={:#?}, intermediates={:?}, ignore={:?}, char={:?}", params, intermediates, ignore, c ); } @@ -53,7 +53,7 @@ fn main() { let input = io::stdin(); let mut handle = input.lock(); - let mut statemachine = vte::Parser::new(); + let mut statemachine = Parser::new(); let mut performer = Log; let mut buf = [0; 2048]; diff --git a/src/lib.rs b/src/lib.rs index a99638a2..749dd218 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -41,14 +41,17 @@ use arrayvec::ArrayVec; use utf8parse as utf8; mod definitions; +mod params; mod table; +pub use params::{Params, ParamsIter}; + use definitions::{unpack, Action, State}; const MAX_INTERMEDIATES: usize = 2; +const MAX_OSC_PARAMS: usize = 16; #[cfg(any(feature = "no_std", test))] const MAX_OSC_RAW: usize = 1024; -const MAX_PARAMS: usize = 16; struct VtUtf8Receiver<'a, P: Perform>(&'a mut P, &'a mut State); @@ -72,14 +75,13 @@ pub struct Parser { state: State, intermediates: [u8; MAX_INTERMEDIATES], intermediate_idx: usize, - params: [i64; MAX_PARAMS], + params: Params, param: i64, - num_params: usize, #[cfg(feature = "no_std")] osc_raw: ArrayVec<[u8; MAX_OSC_RAW]>, #[cfg(not(feature = "no_std"))] osc_raw: Vec, - osc_params: [(usize, usize); MAX_PARAMS], + osc_params: [(usize, usize); MAX_OSC_PARAMS], osc_num_params: usize, ignoring: bool, utf8_parser: utf8::Parser, @@ -92,8 +94,8 @@ impl Parser { } #[inline] - fn params(&self) -> &[i64] { - &self.params[..self.num_params] + fn params(&self) -> &Params { + &self.params } #[inline] @@ -198,7 +200,7 @@ impl Parser { /// The aliasing is needed here for multiple slices into self.osc_raw #[inline] fn osc_dispatch(&self, performer: &mut P, byte: u8) { - let mut slices: [MaybeUninit<&[u8]>; MAX_PARAMS] = + let mut slices: [MaybeUninit<&[u8]>; MAX_OSC_PARAMS] = unsafe { MaybeUninit::uninit().assume_init() }; for (i, slice) in slices.iter_mut().enumerate().take(self.osc_num_params) { @@ -219,11 +221,10 @@ impl Parser { Action::Print => performer.print(byte as char), Action::Execute => performer.execute(byte), Action::Hook => { - if self.num_params == MAX_PARAMS { + if self.params.is_full() { self.ignoring = true; } else { - self.params[self.num_params] = self.param; - self.num_params += 1; + self.params.push(self.param); } performer.hook(self.params(), self.intermediates(), self.ignoring, byte as char); @@ -247,8 +248,8 @@ impl Parser { if byte == b';' { let param_idx = self.osc_num_params; match param_idx { - // Only process up to MAX_PARAMS - MAX_PARAMS => return, + // Only process up to MAX_OSC_PARAMS + MAX_OSC_PARAMS => return, // First param is special - 0 to current byte index 0 => { @@ -274,7 +275,7 @@ impl Parser { match param_idx { // Finish last parameter if not already maxed - MAX_PARAMS => (), + MAX_OSC_PARAMS => (), // First param is special - 0 to current byte index 0 => { @@ -294,11 +295,10 @@ impl Parser { }, Action::Unhook => performer.unhook(), Action::CsiDispatch => { - if self.num_params == MAX_PARAMS { + if self.params.is_full() { self.ignoring = true; } else { - self.params[self.num_params] = self.param; - self.num_params += 1; + self.params.push(self.param); } performer.csi_dispatch( @@ -320,18 +320,17 @@ impl Parser { } }, Action::Param => { - // Completed a param - let idx = self.num_params; - - if idx == MAX_PARAMS { + if self.params.is_full() { self.ignoring = true; return; } if byte == b';' { - self.params[idx] = self.param; + self.params.push(self.param); + self.param = 0; + } else if byte == b':' { + self.params.extend(self.param); self.param = 0; - self.num_params += 1; } else { // Continue collecting bytes into param self.param = self.param.saturating_mul(10); @@ -342,8 +341,9 @@ impl Parser { // Reset everything on ESC/CSI/DCS entry self.intermediate_idx = 0; self.ignoring = false; - self.num_params = 0; self.param = 0; + + self.params.clear(); }, Action::BeginUtf8 => self.process_utf8(performer, byte), Action::Ignore => (), @@ -378,7 +378,7 @@ pub trait Perform { /// /// The `ignore` flag indicates that more than two intermediates arrived and /// subsequent characters were ignored. - fn hook(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, action: char); + fn hook(&mut self, params: &Params, intermediates: &[u8], ignore: bool, action: char); /// Pass bytes as part of a device control string to the handle chosen in `hook`. C0 controls /// will also be passed to the handler. @@ -398,7 +398,7 @@ pub trait Perform { /// The `ignore` flag indicates that either more than two intermediates arrived /// or the number of parameters exceeded the maximum supported length, /// and subsequent characters were ignored. - fn csi_dispatch(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, action: char); + fn csi_dispatch(&mut self, params: &Params, intermediates: &[u8], ignore: bool, action: char); /// The final character of an escape sequence has arrived. /// @@ -439,7 +439,7 @@ mod tests { fn execute(&mut self, _: u8) {} - fn hook(&mut self, _: &[i64], _: &[u8], _: bool, _: char) {} + fn hook(&mut self, _: &Params, _: &[u8], _: bool, _: char) {} fn put(&mut self, _: u8) {} @@ -452,7 +452,7 @@ mod tests { self.params = params.iter().map(|p| p.to_vec()).collect(); } - fn csi_dispatch(&mut self, _: &[i64], _: &[u8], _: bool, _: char) {} + fn csi_dispatch(&mut self, _: &Params, _: &[u8], _: bool, _: char) {} fn esc_dispatch(&mut self, _: &[u8], _: bool, _: u8) {} } @@ -461,7 +461,7 @@ mod tests { struct CsiDispatcher { dispatched_csi: bool, ignore: bool, - params: Vec, + params: Vec>, intermediates: Vec, } @@ -470,7 +470,7 @@ mod tests { fn execute(&mut self, _: u8) {} - fn hook(&mut self, _: &[i64], _: &[u8], _: bool, _: char) {} + fn hook(&mut self, _: &Params, _: &[u8], _: bool, _: char) {} fn put(&mut self, _: u8) {} @@ -478,11 +478,11 @@ mod tests { fn osc_dispatch(&mut self, _: &[&[u8]], _: bool) {} - fn csi_dispatch(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, _: char) { + fn csi_dispatch(&mut self, params: &Params, intermediates: &[u8], ignore: bool, _: char) { self.intermediates = intermediates.to_vec(); - self.params = params.to_vec(); - self.ignore = ignore; self.dispatched_csi = true; + self.params = params.iter().map(|subparam| subparam.to_vec()).collect(); + self.ignore = ignore; } fn esc_dispatch(&mut self, _: &[u8], _: bool, _: u8) {} @@ -503,9 +503,9 @@ mod tests { fn execute(&mut self, _: u8) {} - fn hook(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, c: char) { + fn hook(&mut self, params: &Params, intermediates: &[u8], ignore: bool, c: char) { self.intermediates = intermediates.to_vec(); - self.params = params.to_vec(); + self.params = params.iter().map(|x| x.to_vec()).flatten().collect(); self.ignore = ignore; self.c = Some(c); self.dispatched_dcs = true; @@ -521,7 +521,7 @@ mod tests { fn osc_dispatch(&mut self, _: &[&[u8]], _: bool) {} - fn csi_dispatch(&mut self, _: &[i64], _: &[u8], _: bool, _: char) {} + fn csi_dispatch(&mut self, _: &Params, _: &[u8], _: bool, _: char) {} fn esc_dispatch(&mut self, _: &[u8], _: bool, _: u8) {} } @@ -539,7 +539,7 @@ mod tests { fn execute(&mut self, _: u8) {} - fn hook(&mut self, _: &[i64], _: &[u8], _: bool, _: char) {} + fn hook(&mut self, _: &Params, _: &[u8], _: bool, _: char) {} fn put(&mut self, _: u8) {} @@ -547,7 +547,7 @@ mod tests { fn osc_dispatch(&mut self, _: &[&[u8]], _: bool) {} - fn csi_dispatch(&mut self, _: &[i64], _: &[u8], _: bool, _: char) {} + fn csi_dispatch(&mut self, _: &Params, _: &[u8], _: bool, _: char) {} fn esc_dispatch(&mut self, intermediates: &[u8], ignore: bool, byte: u8) { self.intermediates = intermediates.to_vec(); @@ -588,17 +588,18 @@ mod tests { #[test] fn parse_osc_max_params() { - static INPUT: &[u8] = b"\x1b];;;;;;;;;;;;;;;;;\x1b"; + let params = std::iter::repeat(";").take(params::MAX_PARAMS + 1).collect::(); + let input = format!("\x1b]{}\x1b", ¶ms[..]).into_bytes(); let mut dispatcher = OscDispatcher::default(); let mut parser = Parser::new(); - for byte in INPUT { - parser.advance(&mut dispatcher, *byte); + for byte in input { + parser.advance(&mut dispatcher, byte); } // Check that flag is set and thus osc_dispatch assertions ran. assert!(dispatcher.dispatched_osc); - assert_eq!(dispatcher.params.len(), MAX_PARAMS); + assert_eq!(dispatcher.params.len(), MAX_OSC_PARAMS); for param in dispatcher.params.iter() { assert_eq!(param.len(), 0); } @@ -606,18 +607,19 @@ mod tests { #[test] fn parse_dcs_max_params() { - static INPUT: &[u8] = b"\x1bP1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;p\x1b"; + let params = std::iter::repeat("1;").take(params::MAX_PARAMS + 1).collect::(); + let input = format!("\x1bP{}p", ¶ms[..]).into_bytes(); let mut dispatcher = DcsDispatcher::default(); let mut parser = Parser::new(); - for byte in INPUT { - parser.advance(&mut dispatcher, *byte); + for byte in input { + parser.advance(&mut dispatcher, byte); } // Check that flag is set and thus osc_dispatch assertions ran. assert!(dispatcher.ignore); assert!(dispatcher.dispatched_dcs); - assert_eq!(dispatcher.params.len(), MAX_PARAMS); + assert_eq!(dispatcher.params.len(), params::MAX_PARAMS); for param in dispatcher.params.iter() { assert_eq!(*param, 1); } @@ -656,7 +658,7 @@ mod tests { // This will build a list of repeating '1;'s // The length is MAX_PARAMS - 1 because the last semicolon is interpreted // as an implicit zero, making the total number of parameters MAX_PARAMS - let params = std::iter::repeat("1;").take(MAX_PARAMS - 1).collect::(); + let params = std::iter::repeat("1;").take(params::MAX_PARAMS - 1).collect::(); let input = format!("\x1b[{}p", ¶ms[..]).into_bytes(); let mut dispatcher = CsiDispatcher::default(); @@ -668,7 +670,7 @@ mod tests { // Check that flag is set and thus csi_dispatch assertions ran. assert!(dispatcher.dispatched_csi); - assert_eq!(dispatcher.params.len(), MAX_PARAMS); + assert_eq!(dispatcher.params.len(), params::MAX_PARAMS); assert!(!dispatcher.ignore); } @@ -677,7 +679,7 @@ mod tests { // This will build a list of repeating '1;'s // The length is MAX_PARAMS because the last semicolon is interpreted // as an implicit zero, making the total number of parameters MAX_PARAMS + 1 - let params = std::iter::repeat("1;").take(MAX_PARAMS).collect::(); + let params = std::iter::repeat("1;").take(params::MAX_PARAMS).collect::(); let input = format!("\x1b[{}p", ¶ms[..]).into_bytes(); let mut dispatcher = CsiDispatcher::default(); @@ -689,7 +691,7 @@ mod tests { // Check that flag is set and thus csi_dispatch assertions ran. assert!(dispatcher.dispatched_csi); - assert_eq!(dispatcher.params.len(), MAX_PARAMS); + assert_eq!(dispatcher.params.len(), params::MAX_PARAMS); assert!(dispatcher.ignore); } @@ -702,7 +704,7 @@ mod tests { parser.advance(&mut dispatcher, *byte); } - assert_eq!(dispatcher.params, &[4, 0]); + assert_eq!(dispatcher.params, &[[4], [0]]); } #[test] @@ -716,7 +718,7 @@ mod tests { } // Check that flag is set and thus osc_dispatch assertions ran. - assert_eq!(dispatcher.params, &[0, 4]); + assert_eq!(dispatcher.params, &[[0], [4]]); } #[test] @@ -730,7 +732,7 @@ mod tests { parser.advance(&mut dispatcher, *byte); } - assert_eq!(dispatcher.params, &[i64::MAX as i64]); + assert_eq!(dispatcher.params, &[[i64::MAX as i64]]); } #[test] @@ -746,7 +748,23 @@ mod tests { assert!(dispatcher.dispatched_csi); assert!(!dispatcher.ignore); assert_eq!(dispatcher.intermediates, &[b'?']); - assert_eq!(dispatcher.params, &[1049]); + assert_eq!(dispatcher.params, &[[1049]]); + } + + #[test] + fn csi_subparameters() { + static INPUT: &[u8] = b"\x1b[38:2:255:0:255;1m"; + let mut dispatcher = CsiDispatcher::default(); + let mut parser = Parser::new(); + + for byte in INPUT { + parser.advance(&mut dispatcher, *byte); + } + + assert!(dispatcher.dispatched_csi); + assert!(!dispatcher.ignore); + assert_eq!(dispatcher.intermediates, &[]); + assert_eq!(dispatcher.params, &[vec![38, 2, 255, 0, 255], vec![1]]); } #[test] @@ -887,7 +905,7 @@ mod bench { black_box(byte); } - fn hook(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, c: char) { + fn hook(&mut self, params: &Params, intermediates: &[u8], ignore: bool, c: char) { black_box((params, intermediates, ignore, c)); } @@ -901,7 +919,7 @@ mod bench { black_box((params, bell_terminated)); } - fn csi_dispatch(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, c: char) { + fn csi_dispatch(&mut self, params: &Params, intermediates: &[u8], ignore: bool, c: char) { black_box((params, intermediates, ignore, c)); } diff --git a/src/params.rs b/src/params.rs new file mode 100644 index 00000000..efa24cb3 --- /dev/null +++ b/src/params.rs @@ -0,0 +1,142 @@ +//! Fixed size parameters list with optional subparameters. + +use core::fmt::{self, Debug, Formatter}; + +pub(crate) const MAX_PARAMS: usize = 32; + +#[derive(Default)] +pub struct Params { + /// Number of subparameters for each parameter. + /// + /// For each entry in the `params` slice, this stores the length of the param as number of + /// subparams at the same index as the param in the `params` slice. + /// + /// At the subparam positions the length will always be `0`. + subparams: [u8; MAX_PARAMS], + + /// All parameters and subparameters. + params: [i64; MAX_PARAMS], + + /// Number of suparameters in the current parameter. + current_subparams: u8, + + /// Total number of parameters and subparameters. + len: usize, +} + +impl Params { + /// Returns the number of parameters. + #[inline] + pub fn len(&self) -> usize { + self.len + } + + /// Returns `true` if there are no parameters present. + #[inline] + pub fn is_empty(&self) -> bool { + self.len == 0 + } + + /// Returns an iterator over all parameters and subparameters. + #[inline] + pub fn iter(&self) -> ParamsIter<'_> { + ParamsIter::new(self) + } + + /// Returns `true` if there is no more space for additional parameters. + #[inline] + pub(crate) fn is_full(&self) -> bool { + self.len == MAX_PARAMS + } + + /// Clear all parameters. + #[inline] + pub(crate) fn clear(&mut self) { + self.current_subparams = 0; + self.len = 0; + } + + /// Add an additional parameter. + #[inline] + pub(crate) fn push(&mut self, item: i64) { + self.subparams[self.len - self.current_subparams as usize] = self.current_subparams + 1; + self.params[self.len] = item; + self.current_subparams = 0; + self.len += 1; + } + + /// Add an additional subparameter to the current parameter. + #[inline] + pub(crate) fn extend(&mut self, item: i64) { + self.params[self.len] = item; + self.current_subparams += 1; + self.len += 1; + } +} + +impl<'a> IntoIterator for &'a Params { + type IntoIter = ParamsIter<'a>; + type Item = &'a [i64]; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +/// Immutable subparameter iterator. +pub struct ParamsIter<'a> { + params: &'a Params, + index: usize, +} + +impl<'a> ParamsIter<'a> { + fn new(params: &'a Params) -> Self { + Self { params, index: 0 } + } +} + +impl<'a> Iterator for ParamsIter<'a> { + type Item = &'a [i64]; + + fn next(&mut self) -> Option { + if self.index >= self.params.len() { + return None; + } + + // Get all subparameters for the current parameter. + let num_subparams = self.params.subparams[self.index]; + let param = &self.params.params[self.index..self.index + num_subparams as usize]; + + // Jump to the next parameter. + self.index += num_subparams as usize; + + Some(param) + } + + fn size_hint(&self) -> (usize, Option) { + let remaining = self.params.len() - self.index; + (remaining, Some(remaining)) + } +} + +impl Debug for Params { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "[")?; + + for (i, param) in self.iter().enumerate() { + if i != 0 { + write!(f, ";")?; + } + + for (i, subparam) in param.iter().enumerate() { + if i != 0 { + write!(f, ":")?; + } + + subparam.fmt(f)?; + } + } + + write!(f, "]") + } +} diff --git a/src/table.rs b/src/table.rs index c19e4abb..f2c01058 100644 --- a/src/table.rs +++ b/src/table.rs @@ -64,9 +64,8 @@ generate_state_changes!(state_changes, { 0x1c..=0x1f => (Anywhere, Execute), 0x7f => (Anywhere, Ignore), 0x20..=0x2f => (CsiIntermediate, Collect), - 0x3a => (CsiIgnore, None), 0x30..=0x39 => (CsiParam, Param), - 0x3b => (CsiParam, Param), + 0x3a..=0x3b => (CsiParam, Param), 0x3c..=0x3f => (CsiParam, Collect), 0x40..=0x7e => (Ground, CsiDispatch), }, @@ -85,9 +84,8 @@ generate_state_changes!(state_changes, { 0x19 => (Anywhere, Execute), 0x1c..=0x1f => (Anywhere, Execute), 0x30..=0x39 => (Anywhere, Param), - 0x3b => (Anywhere, Param), + 0x3a..=0x3b => (Anywhere, Param), 0x7f => (Anywhere, Ignore), - 0x3a => (CsiIgnore, None), 0x3c..=0x3f => (CsiIgnore, None), 0x20..=0x2f => (CsiIntermediate, Collect), 0x40..=0x7e => (Ground, CsiDispatch), @@ -108,10 +106,9 @@ generate_state_changes!(state_changes, { 0x19 => (Anywhere, Ignore), 0x1c..=0x1f => (Anywhere, Ignore), 0x7f => (Anywhere, Ignore), - 0x3a => (DcsIgnore, None), 0x20..=0x2f => (DcsIntermediate, Collect), 0x30..=0x39 => (DcsParam, Param), - 0x3b => (DcsParam, Param), + 0x3a..=0x3b => (DcsParam, Param), 0x3c..=0x3f => (DcsParam, Collect), 0x40..=0x7e => (DcsPassthrough, None), }, @@ -139,9 +136,8 @@ generate_state_changes!(state_changes, { 0x19 => (Anywhere, Ignore), 0x1c..=0x1f => (Anywhere, Ignore), 0x30..=0x39 => (Anywhere, Param), - 0x3b => (Anywhere, Param), + 0x3a..=0x3b => (Anywhere, Param), 0x7f => (Anywhere, Ignore), - 0x3a => (DcsIgnore, None), 0x3c..=0x3f => (DcsIgnore, None), 0x20..=0x2f => (DcsIntermediate, Collect), 0x40..=0x7e => (DcsPassthrough, None), From 3cafbadd7e2544b484b75588d8759c9a6081fad8 Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Fri, 13 Nov 2020 18:26:37 +0000 Subject: [PATCH 86/99] Bump version to 0.9.0 --- CHANGELOG.md | 5 +++++ Cargo.toml | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 02a1e0a3..32a6453a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +## 0.9.0 + +- Added CSI subparameter support; required changes can be seen in Alacritty: + https://github.com/alacritty/alacritty/commit/576252294d09c1f52ec73bde03652349bdf5a529#diff-49ac9e6f6e6a855312bfcd393201f18ca53e6148c4a22a3a4949f1f9d1d137a8 + ## 0.8.0 - Remove C1 ST support in OSCs, fixing OSCs with ST in the payload diff --git a/Cargo.toml b/Cargo.toml index 3619eb34..c13e69e2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ categories = ["parsing", "no-std"] exclude = ["/.travis.yml"] readme = "README.md" license = "Apache-2.0 OR MIT" -version = "0.8.0" +version = "0.9.0" name = "vte" edition = "2018" From 86603075dc8fdb481a0c475a740c00fb25c97771 Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Thu, 26 Nov 2020 00:00:35 +0000 Subject: [PATCH 87/99] Reduce the maximum value of CSI parameters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since limits CSI parameters to be within range of `u16`, rather than `i64`. This should effectively prevent downstream users from running into DoS problems with excessively big escape sequence requests. An example of a problematic escape would be `CSI Ps b` (repeat char). According to https://vt100.net/emu/dec_ansi_parser, the smallest possible size limit would be `16383`: > The VT500 Programmer Information is inconsistent regarding the maximum > value that a parameter can take. In section 4.3.3.2 of EK-VT520-RM it > says that “any parameter greater than 9999 (decimal) is set to 9999 > (decimal)”. However, in the description of DECSR (Secure Reset), its > parameter is allowed to range from 0 to 16383. Because individual > control functions need to make sure that numeric parameters are within > specific limits, the supported maximum is not critical, but it must be > at least 16383. --- CHANGELOG.md | 4 ++++ src/lib.rs | 11 +++++------ src/params.rs | 10 +++++----- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 32a6453a..fff0880c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ CHANGELOG ========= +## Unreleased + +- Changed the type of CSI parameters from i64 to u16 + ## 0.9.0 - Added CSI subparameter support; required changes can be seen in Alacritty: diff --git a/src/lib.rs b/src/lib.rs index 749dd218..db02c07c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -76,7 +76,7 @@ pub struct Parser { intermediates: [u8; MAX_INTERMEDIATES], intermediate_idx: usize, params: Params, - param: i64, + param: u16, #[cfg(feature = "no_std")] osc_raw: ArrayVec<[u8; MAX_OSC_RAW]>, #[cfg(not(feature = "no_std"))] @@ -334,7 +334,7 @@ impl Parser { } else { // Continue collecting bytes into param self.param = self.param.saturating_mul(10); - self.param = self.param.saturating_add((byte - b'0') as i64); + self.param = self.param.saturating_add((byte - b'0') as u16); } }, Action::Clear => { @@ -415,7 +415,6 @@ extern crate std; mod tests { use super::*; - use core::i64; use std::string::String; use std::vec::Vec; @@ -461,7 +460,7 @@ mod tests { struct CsiDispatcher { dispatched_csi: bool, ignore: bool, - params: Vec>, + params: Vec>, intermediates: Vec, } @@ -492,7 +491,7 @@ mod tests { struct DcsDispatcher { dispatched_dcs: bool, intermediates: Vec, - params: Vec, + params: Vec, ignore: bool, c: Option, s: Vec, @@ -732,7 +731,7 @@ mod tests { parser.advance(&mut dispatcher, *byte); } - assert_eq!(dispatcher.params, &[[i64::MAX as i64]]); + assert_eq!(dispatcher.params, &[[std::u16::MAX as u16]]); } #[test] diff --git a/src/params.rs b/src/params.rs index efa24cb3..ca6ba480 100644 --- a/src/params.rs +++ b/src/params.rs @@ -15,7 +15,7 @@ pub struct Params { subparams: [u8; MAX_PARAMS], /// All parameters and subparameters. - params: [i64; MAX_PARAMS], + params: [u16; MAX_PARAMS], /// Number of suparameters in the current parameter. current_subparams: u8, @@ -58,7 +58,7 @@ impl Params { /// Add an additional parameter. #[inline] - pub(crate) fn push(&mut self, item: i64) { + pub(crate) fn push(&mut self, item: u16) { self.subparams[self.len - self.current_subparams as usize] = self.current_subparams + 1; self.params[self.len] = item; self.current_subparams = 0; @@ -67,7 +67,7 @@ impl Params { /// Add an additional subparameter to the current parameter. #[inline] - pub(crate) fn extend(&mut self, item: i64) { + pub(crate) fn extend(&mut self, item: u16) { self.params[self.len] = item; self.current_subparams += 1; self.len += 1; @@ -76,7 +76,7 @@ impl Params { impl<'a> IntoIterator for &'a Params { type IntoIter = ParamsIter<'a>; - type Item = &'a [i64]; + type Item = &'a [u16]; fn into_iter(self) -> Self::IntoIter { self.iter() @@ -96,7 +96,7 @@ impl<'a> ParamsIter<'a> { } impl<'a> Iterator for ParamsIter<'a> { - type Item = &'a [i64]; + type Item = &'a [u16]; fn next(&mut self) -> Option { if self.index >= self.params.len() { From b4b08a6de09ebecc6a4c14c81435418fd5a4e8a8 Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Fri, 27 Nov 2020 04:59:45 +0000 Subject: [PATCH 88/99] Make all methods of the trait `Perform` optional I've noticed while playing around with vte in a personal project, that I didn't need all of the methods of the `Perform` trait. In Alacritty we also don't react to everything and other crates like `strip-ansi-escapes` basically doesn't respond to anything. Of course it's always easy to just copy/paste the entire trait and move on, but I think it's probably worth making the life of downstream easier by not enforcing this. --- CHANGELOG.md | 1 + src/lib.rs | 77 ++++++++++------------------------------------------ 2 files changed, 16 insertions(+), 62 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fff0880c..9256d195 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ CHANGELOG ## Unreleased - Changed the type of CSI parameters from i64 to u16 +- All methods of the `Perform` trait are now optional ## 0.9.0 diff --git a/src/lib.rs b/src/lib.rs index db02c07c..b6d2658f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -364,10 +364,10 @@ impl Parser { /// the future, consider checking archive.org. pub trait Perform { /// Draw a character to the screen and update states. - fn print(&mut self, _: char); + fn print(&mut self, _c: char) {} /// Execute a C0 or C1 control function. - fn execute(&mut self, byte: u8); + fn execute(&mut self, _byte: u8) {} /// Invoked when a final character arrives in first part of device control string. /// @@ -378,33 +378,40 @@ pub trait Perform { /// /// The `ignore` flag indicates that more than two intermediates arrived and /// subsequent characters were ignored. - fn hook(&mut self, params: &Params, intermediates: &[u8], ignore: bool, action: char); + fn hook(&mut self, _params: &Params, _intermediates: &[u8], _ignore: bool, _action: char) {} /// Pass bytes as part of a device control string to the handle chosen in `hook`. C0 controls /// will also be passed to the handler. - fn put(&mut self, byte: u8); + fn put(&mut self, _byte: u8) {} /// Called when a device control string is terminated. /// /// The previously selected handler should be notified that the DCS has /// terminated. - fn unhook(&mut self); + fn unhook(&mut self) {} /// Dispatch an operating system command. - fn osc_dispatch(&mut self, params: &[&[u8]], bell_terminated: bool); + fn osc_dispatch(&mut self, _params: &[&[u8]], _bell_terminated: bool) {} /// A final character has arrived for a CSI sequence /// /// The `ignore` flag indicates that either more than two intermediates arrived /// or the number of parameters exceeded the maximum supported length, /// and subsequent characters were ignored. - fn csi_dispatch(&mut self, params: &Params, intermediates: &[u8], ignore: bool, action: char); + fn csi_dispatch( + &mut self, + _params: &Params, + _intermediates: &[u8], + _ignore: bool, + _action: char, + ) { + } /// The final character of an escape sequence has arrived. /// /// The `ignore` flag indicates that more than two intermediates arrived and /// subsequent characters were ignored. - fn esc_dispatch(&mut self, intermediates: &[u8], ignore: bool, byte: u8); + fn esc_dispatch(&mut self, _intermediates: &[u8], _ignore: bool, _byte: u8) {} } #[cfg(all(test, feature = "no_std"))] @@ -434,26 +441,12 @@ mod tests { // All empty bodies except osc_dispatch impl Perform for OscDispatcher { - fn print(&mut self, _: char) {} - - fn execute(&mut self, _: u8) {} - - fn hook(&mut self, _: &Params, _: &[u8], _: bool, _: char) {} - - fn put(&mut self, _: u8) {} - - fn unhook(&mut self) {} - fn osc_dispatch(&mut self, params: &[&[u8]], bell_terminated: bool) { // Set a flag so we know these assertions all run self.dispatched_osc = true; self.bell_terminated = bell_terminated; self.params = params.iter().map(|p| p.to_vec()).collect(); } - - fn csi_dispatch(&mut self, _: &Params, _: &[u8], _: bool, _: char) {} - - fn esc_dispatch(&mut self, _: &[u8], _: bool, _: u8) {} } #[derive(Default)] @@ -465,26 +458,12 @@ mod tests { } impl Perform for CsiDispatcher { - fn print(&mut self, _: char) {} - - fn execute(&mut self, _: u8) {} - - fn hook(&mut self, _: &Params, _: &[u8], _: bool, _: char) {} - - fn put(&mut self, _: u8) {} - - fn unhook(&mut self) {} - - fn osc_dispatch(&mut self, _: &[&[u8]], _: bool) {} - fn csi_dispatch(&mut self, params: &Params, intermediates: &[u8], ignore: bool, _: char) { self.intermediates = intermediates.to_vec(); self.dispatched_csi = true; self.params = params.iter().map(|subparam| subparam.to_vec()).collect(); self.ignore = ignore; } - - fn esc_dispatch(&mut self, _: &[u8], _: bool, _: u8) {} } #[derive(Default)] @@ -498,10 +477,6 @@ mod tests { } impl Perform for DcsDispatcher { - fn print(&mut self, _: char) {} - - fn execute(&mut self, _: u8) {} - fn hook(&mut self, params: &Params, intermediates: &[u8], ignore: bool, c: char) { self.intermediates = intermediates.to_vec(); self.params = params.iter().map(|x| x.to_vec()).flatten().collect(); @@ -517,12 +492,6 @@ mod tests { fn unhook(&mut self) { self.dispatched_dcs = true; } - - fn osc_dispatch(&mut self, _: &[&[u8]], _: bool) {} - - fn csi_dispatch(&mut self, _: &Params, _: &[u8], _: bool, _: char) {} - - fn esc_dispatch(&mut self, _: &[u8], _: bool, _: u8) {} } #[derive(Default)] @@ -534,20 +503,6 @@ mod tests { } impl Perform for EscDispatcher { - fn print(&mut self, _: char) {} - - fn execute(&mut self, _: u8) {} - - fn hook(&mut self, _: &Params, _: &[u8], _: bool, _: char) {} - - fn put(&mut self, _: u8) {} - - fn unhook(&mut self) {} - - fn osc_dispatch(&mut self, _: &[&[u8]], _: bool) {} - - fn csi_dispatch(&mut self, _: &Params, _: &[u8], _: bool, _: char) {} - fn esc_dispatch(&mut self, intermediates: &[u8], ignore: bool, byte: u8) { self.intermediates = intermediates.to_vec(); self.ignore = ignore; @@ -912,8 +867,6 @@ mod bench { black_box(byte); } - fn unhook(&mut self) {} - fn osc_dispatch(&mut self, params: &[&[u8]], bell_terminated: bool) { black_box((params, bell_terminated)); } From 8a0c57bbc0dd648f7a3cb80e48e8e2387641bbb8 Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Sun, 3 Jan 2021 10:47:01 +0000 Subject: [PATCH 89/99] Bump version to 0.10.0 --- CHANGELOG.md | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9256d195..1c00ca8a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ CHANGELOG ========= -## Unreleased +## 0.10.0 - Changed the type of CSI parameters from i64 to u16 - All methods of the `Perform` trait are now optional diff --git a/Cargo.toml b/Cargo.toml index c13e69e2..75bdb96c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ categories = ["parsing", "no-std"] exclude = ["/.travis.yml"] readme = "README.md" license = "Apache-2.0 OR MIT" -version = "0.9.0" +version = "0.10.0" name = "vte" edition = "2018" From 59bb331d5e702a4cb608636d4b8b534a3903f7bb Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Sun, 21 Feb 2021 20:57:02 +0100 Subject: [PATCH 90/99] Fix intermediate reset when going from DCS to ESC This resolves a bug when transitioning between DCS and ESC sequences, which would cause the intermediates of the ESC dispatch to contain data from the DCS sequence. --- src/lib.rs | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index b6d2658f..9d7931f1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -165,28 +165,26 @@ impl Parser { match self.state { State::DcsPassthrough => { self.perform_action(performer, Action::Unhook, byte); - maybe_action!(action, byte); }, State::OscString => { self.perform_action(performer, Action::OscEnd, byte); - maybe_action!(action, byte); }, - _ => { - maybe_action!(action, byte); - - match state { - State::CsiEntry | State::DcsEntry | State::Escape => { - self.perform_action(performer, Action::Clear, byte); - }, - State::DcsPassthrough => { - self.perform_action(performer, Action::Hook, byte); - }, - State::OscString => { - self.perform_action(performer, Action::OscStart, byte); - }, - _ => (), - } + _ => (), + } + + maybe_action!(action, byte); + + match state { + State::CsiEntry | State::DcsEntry | State::Escape => { + self.perform_action(performer, Action::Clear, byte); + }, + State::DcsPassthrough => { + self.perform_action(performer, Action::Hook, byte); + }, + State::OscString => { + self.perform_action(performer, Action::OscStart, byte); }, + _ => (), } // Assume the new state From 1f1a92938e0d8f5b54c89a76c34c628727c9c0bf Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Sun, 21 Feb 2021 20:58:20 +0100 Subject: [PATCH 91/99] Refactor test code This changes the test code to use only a single dispatcher instead of having a dispatcher for every single type of escape sequence. This makes it trivial to test transitions between the two separate escape sequence types. --- src/lib.rs | 460 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 263 insertions(+), 197 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 9d7931f1..157392a4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -431,178 +431,224 @@ mod tests { ]; #[derive(Default)] - struct OscDispatcher { - dispatched_osc: bool, - bell_terminated: bool, - params: Vec>, + struct Dispatcher { + dispatched: Vec, } - // All empty bodies except osc_dispatch - impl Perform for OscDispatcher { - fn osc_dispatch(&mut self, params: &[&[u8]], bell_terminated: bool) { - // Set a flag so we know these assertions all run - self.dispatched_osc = true; - self.bell_terminated = bell_terminated; - self.params = params.iter().map(|p| p.to_vec()).collect(); - } + #[derive(Debug, PartialEq, Eq)] + enum Sequence { + Osc(Vec>, bool), + Csi(Vec>, Vec, bool, char), + Esc(Vec, bool, u8), + DcsHook(Vec>, Vec, bool, char), + DcsPut(u8), + DcsUnhook, } - #[derive(Default)] - struct CsiDispatcher { - dispatched_csi: bool, - ignore: bool, - params: Vec>, - intermediates: Vec, - } + impl Perform for Dispatcher { + fn osc_dispatch(&mut self, params: &[&[u8]], bell_terminated: bool) { + let params = params.iter().map(|p| p.to_vec()).collect(); + self.dispatched.push(Sequence::Osc(params, bell_terminated)); + } - impl Perform for CsiDispatcher { - fn csi_dispatch(&mut self, params: &Params, intermediates: &[u8], ignore: bool, _: char) { - self.intermediates = intermediates.to_vec(); - self.dispatched_csi = true; - self.params = params.iter().map(|subparam| subparam.to_vec()).collect(); - self.ignore = ignore; + fn csi_dispatch(&mut self, params: &Params, intermediates: &[u8], ignore: bool, c: char) { + let params = params.iter().map(|subparam| subparam.to_vec()).collect(); + let intermediates = intermediates.to_vec(); + self.dispatched.push(Sequence::Csi(params, intermediates, ignore, c)); } - } - #[derive(Default)] - struct DcsDispatcher { - dispatched_dcs: bool, - intermediates: Vec, - params: Vec, - ignore: bool, - c: Option, - s: Vec, - } + fn esc_dispatch(&mut self, intermediates: &[u8], ignore: bool, byte: u8) { + let intermediates = intermediates.to_vec(); + self.dispatched.push(Sequence::Esc(intermediates, ignore, byte)); + } - impl Perform for DcsDispatcher { fn hook(&mut self, params: &Params, intermediates: &[u8], ignore: bool, c: char) { - self.intermediates = intermediates.to_vec(); - self.params = params.iter().map(|x| x.to_vec()).flatten().collect(); - self.ignore = ignore; - self.c = Some(c); - self.dispatched_dcs = true; + let params = params.iter().map(|subparam| subparam.to_vec()).collect(); + let intermediates = intermediates.to_vec(); + self.dispatched.push(Sequence::DcsHook(params, intermediates, ignore, c)); } fn put(&mut self, byte: u8) { - self.s.push(byte); + self.dispatched.push(Sequence::DcsPut(byte)); } fn unhook(&mut self) { - self.dispatched_dcs = true; - } - } - - #[derive(Default)] - struct EscDispatcher { - dispatched_esc: bool, - intermediates: Vec, - ignore: bool, - byte: u8, - } - - impl Perform for EscDispatcher { - fn esc_dispatch(&mut self, intermediates: &[u8], ignore: bool, byte: u8) { - self.intermediates = intermediates.to_vec(); - self.ignore = ignore; - self.byte = byte; - self.dispatched_esc = true; + self.dispatched.push(Sequence::DcsUnhook); } } #[test] fn parse_osc() { - let mut dispatcher = OscDispatcher::default(); + let mut dispatcher = Dispatcher::default(); let mut parser = Parser::new(); for byte in OSC_BYTES { parser.advance(&mut dispatcher, *byte); } - // Check that flag is set and thus osc_dispatch assertions ran. - assert!(dispatcher.dispatched_osc); - assert_eq!(dispatcher.params.len(), 2); - assert_eq!(dispatcher.params[0], &OSC_BYTES[2..3]); - assert_eq!(dispatcher.params[1], &OSC_BYTES[4..(OSC_BYTES.len() - 1)]); + assert_eq!(dispatcher.dispatched.len(), 1); + match &dispatcher.dispatched[0] { + Sequence::Osc(params, _) => { + assert_eq!(params.len(), 2); + assert_eq!(params[0], &OSC_BYTES[2..3]); + assert_eq!(params[1], &OSC_BYTES[4..(OSC_BYTES.len() - 1)]); + }, + _ => panic!("expected osc sequence"), + } } #[test] fn parse_empty_osc() { - let mut dispatcher = OscDispatcher::default(); + let mut dispatcher = Dispatcher::default(); let mut parser = Parser::new(); for byte in &[0x1b, 0x5d, 0x07] { parser.advance(&mut dispatcher, *byte); } - // Check that flag is set and thus osc_dispatch assertions ran. - assert!(dispatcher.dispatched_osc); + assert_eq!(dispatcher.dispatched.len(), 1); + match &dispatcher.dispatched[0] { + Sequence::Osc(..) => (), + _ => panic!("expected osc sequence"), + } } #[test] fn parse_osc_max_params() { let params = std::iter::repeat(";").take(params::MAX_PARAMS + 1).collect::(); let input = format!("\x1b]{}\x1b", ¶ms[..]).into_bytes(); - let mut dispatcher = OscDispatcher::default(); + let mut dispatcher = Dispatcher::default(); let mut parser = Parser::new(); for byte in input { parser.advance(&mut dispatcher, byte); } - // Check that flag is set and thus osc_dispatch assertions ran. - assert!(dispatcher.dispatched_osc); - assert_eq!(dispatcher.params.len(), MAX_OSC_PARAMS); - for param in dispatcher.params.iter() { - assert_eq!(param.len(), 0); + assert_eq!(dispatcher.dispatched.len(), 1); + match &dispatcher.dispatched[0] { + Sequence::Osc(params, _) => { + assert_eq!(params.len(), MAX_OSC_PARAMS); + assert!(params.iter().all(Vec::is_empty)); + }, + _ => panic!("expected osc sequence"), } } #[test] - fn parse_dcs_max_params() { - let params = std::iter::repeat("1;").take(params::MAX_PARAMS + 1).collect::(); - let input = format!("\x1bP{}p", ¶ms[..]).into_bytes(); - let mut dispatcher = DcsDispatcher::default(); + fn osc_bell_terminated() { + static INPUT: &[u8] = b"\x1b]11;ff/00/ff\x07"; + let mut dispatcher = Dispatcher::default(); let mut parser = Parser::new(); - for byte in input { - parser.advance(&mut dispatcher, byte); + for byte in INPUT { + parser.advance(&mut dispatcher, *byte); } - // Check that flag is set and thus osc_dispatch assertions ran. - assert!(dispatcher.ignore); - assert!(dispatcher.dispatched_dcs); - assert_eq!(dispatcher.params.len(), params::MAX_PARAMS); - for param in dispatcher.params.iter() { - assert_eq!(*param, 1); + assert_eq!(dispatcher.dispatched.len(), 1); + match &dispatcher.dispatched[0] { + Sequence::Osc(_, true) => (), + _ => panic!("expected osc with bell terminator"), } } #[test] - fn osc_bell_terminated() { - static INPUT: &[u8] = b"\x1b]11;ff/00/ff\x07"; - let mut dispatcher = OscDispatcher::default(); + fn osc_c0_st_terminated() { + static INPUT: &[u8] = b"\x1b]11;ff/00/ff\x1b\\"; + let mut dispatcher = Dispatcher::default(); let mut parser = Parser::new(); for byte in INPUT { parser.advance(&mut dispatcher, *byte); } - assert!(dispatcher.dispatched_osc); - assert!(dispatcher.bell_terminated); + assert_eq!(dispatcher.dispatched.len(), 2); + match &dispatcher.dispatched[0] { + Sequence::Osc(_, false) => (), + _ => panic!("expected osc with ST terminator"), + } } #[test] - fn osc_c0_st_terminated() { - static INPUT: &[u8] = b"\x1b]11;ff/00/ff\x1b\\"; - let mut dispatcher = OscDispatcher::default(); + fn parse_osc_with_utf8_arguments() { + static INPUT: &[u8] = &[ + 0x0d, 0x1b, 0x5d, 0x32, 0x3b, 0x65, 0x63, 0x68, 0x6f, 0x20, 0x27, 0xc2, 0xaf, 0x5c, + 0x5f, 0x28, 0xe3, 0x83, 0x84, 0x29, 0x5f, 0x2f, 0xc2, 0xaf, 0x27, 0x20, 0x26, 0x26, + 0x20, 0x73, 0x6c, 0x65, 0x65, 0x70, 0x20, 0x31, 0x07, + ]; + let mut dispatcher = Dispatcher::default(); + let mut parser = Parser::new(); + + for byte in INPUT { + parser.advance(&mut dispatcher, *byte); + } + + assert_eq!(dispatcher.dispatched.len(), 1); + match &dispatcher.dispatched[0] { + Sequence::Osc(params, _) => { + assert_eq!(params[0], &[b'2']); + assert_eq!(params[1], &INPUT[5..(INPUT.len() - 1)]); + }, + _ => panic!("expected osc sequence"), + } + } + + #[test] + fn osc_containing_string_terminator() { + static INPUT: &[u8] = b"\x1b]2;\xe6\x9c\xab\x1b\\"; + let mut dispatcher = Dispatcher::default(); let mut parser = Parser::new(); for byte in INPUT { parser.advance(&mut dispatcher, *byte); } - assert!(dispatcher.dispatched_osc); - assert!(!dispatcher.bell_terminated); + assert_eq!(dispatcher.dispatched.len(), 2); + match &dispatcher.dispatched[0] { + Sequence::Osc(params, _) => { + assert_eq!(params[1], &INPUT[4..(INPUT.len() - 2)]); + }, + _ => panic!("expected osc sequence"), + } + } + + #[test] + fn exceed_max_buffer_size() { + static NUM_BYTES: usize = MAX_OSC_RAW + 100; + static INPUT_START: &[u8] = &[0x1b, b']', b'5', b'2', b';', b's']; + static INPUT_END: &[u8] = &[b'\x07']; + + let mut dispatcher = Dispatcher::default(); + let mut parser = Parser::new(); + + // Create valid OSC escape + for byte in INPUT_START { + parser.advance(&mut dispatcher, *byte); + } + + // Exceed max buffer size + for _ in 0..NUM_BYTES { + parser.advance(&mut dispatcher, b'a'); + } + + // Terminate escape for dispatch + for byte in INPUT_END { + parser.advance(&mut dispatcher, *byte); + } + + assert_eq!(dispatcher.dispatched.len(), 1); + match &dispatcher.dispatched[0] { + Sequence::Osc(params, _) => { + assert_eq!(params.len(), 2); + assert_eq!(params[0], b"52"); + + #[cfg(not(feature = "no_std"))] + assert_eq!(params[1].len(), NUM_BYTES + INPUT_END.len()); + + #[cfg(feature = "no_std")] + assert_eq!(params[1].len(), MAX_OSC_RAW - params[0].len()); + }, + _ => panic!("expected osc sequence"), + } } #[test] @@ -613,17 +659,21 @@ mod tests { let params = std::iter::repeat("1;").take(params::MAX_PARAMS - 1).collect::(); let input = format!("\x1b[{}p", ¶ms[..]).into_bytes(); - let mut dispatcher = CsiDispatcher::default(); + let mut dispatcher = Dispatcher::default(); let mut parser = Parser::new(); for byte in input { parser.advance(&mut dispatcher, byte); } - // Check that flag is set and thus csi_dispatch assertions ran. - assert!(dispatcher.dispatched_csi); - assert_eq!(dispatcher.params.len(), params::MAX_PARAMS); - assert!(!dispatcher.ignore); + assert_eq!(dispatcher.dispatched.len(), 1); + match &dispatcher.dispatched[0] { + Sequence::Csi(params, _, ignore, _) => { + assert_eq!(params.len(), params::MAX_PARAMS); + assert!(!ignore); + }, + _ => panic!("expected csi sequence"), + } } #[test] @@ -634,205 +684,221 @@ mod tests { let params = std::iter::repeat("1;").take(params::MAX_PARAMS).collect::(); let input = format!("\x1b[{}p", ¶ms[..]).into_bytes(); - let mut dispatcher = CsiDispatcher::default(); + let mut dispatcher = Dispatcher::default(); let mut parser = Parser::new(); for byte in input { parser.advance(&mut dispatcher, byte); } - // Check that flag is set and thus csi_dispatch assertions ran. - assert!(dispatcher.dispatched_csi); - assert_eq!(dispatcher.params.len(), params::MAX_PARAMS); - assert!(dispatcher.ignore); + assert_eq!(dispatcher.dispatched.len(), 1); + match &dispatcher.dispatched[0] { + Sequence::Csi(params, _, ignore, _) => { + assert_eq!(params.len(), params::MAX_PARAMS); + assert!(ignore); + }, + _ => panic!("expected csi sequence"), + } } #[test] fn parse_csi_params_trailing_semicolon() { - let mut dispatcher = CsiDispatcher::default(); + let mut dispatcher = Dispatcher::default(); let mut parser = Parser::new(); for byte in b"\x1b[4;m" { parser.advance(&mut dispatcher, *byte); } - assert_eq!(dispatcher.params, &[[4], [0]]); + assert_eq!(dispatcher.dispatched.len(), 1); + match &dispatcher.dispatched[0] { + Sequence::Csi(params, ..) => assert_eq!(params, &[[4], [0]]), + _ => panic!("expected csi sequence"), + } } #[test] - fn parse_semi_set_underline() { + fn parse_csi_params_leading_semicolon() { // Create dispatcher and check state - let mut dispatcher = CsiDispatcher::default(); + let mut dispatcher = Dispatcher::default(); let mut parser = Parser::new(); for byte in b"\x1b[;4m" { parser.advance(&mut dispatcher, *byte); } - // Check that flag is set and thus osc_dispatch assertions ran. - assert_eq!(dispatcher.params, &[[0], [4]]); + assert_eq!(dispatcher.dispatched.len(), 1); + match &dispatcher.dispatched[0] { + Sequence::Csi(params, ..) => assert_eq!(params, &[[0], [4]]), + _ => panic!("expected csi sequence"), + } } #[test] fn parse_long_csi_param() { // The important part is the parameter, which is (i64::MAX + 1) static INPUT: &[u8] = b"\x1b[9223372036854775808m"; - let mut dispatcher = CsiDispatcher::default(); + let mut dispatcher = Dispatcher::default(); let mut parser = Parser::new(); for byte in INPUT { parser.advance(&mut dispatcher, *byte); } - assert_eq!(dispatcher.params, &[[std::u16::MAX as u16]]); + assert_eq!(dispatcher.dispatched.len(), 1); + match &dispatcher.dispatched[0] { + Sequence::Csi(params, ..) => assert_eq!(params, &[[std::u16::MAX as u16]]), + _ => panic!("expected csi sequence"), + } } #[test] fn csi_reset() { static INPUT: &[u8] = b"\x1b[3;1\x1b[?1049h"; - let mut dispatcher = CsiDispatcher::default(); + let mut dispatcher = Dispatcher::default(); let mut parser = Parser::new(); for byte in INPUT { parser.advance(&mut dispatcher, *byte); } - assert!(dispatcher.dispatched_csi); - assert!(!dispatcher.ignore); - assert_eq!(dispatcher.intermediates, &[b'?']); - assert_eq!(dispatcher.params, &[[1049]]); + assert_eq!(dispatcher.dispatched.len(), 1); + match &dispatcher.dispatched[0] { + Sequence::Csi(params, intermediates, ignore, _) => { + assert_eq!(intermediates, &[b'?']); + assert_eq!(params, &[[1049]]); + assert!(!ignore); + }, + _ => panic!("expected csi sequence"), + } } #[test] fn csi_subparameters() { static INPUT: &[u8] = b"\x1b[38:2:255:0:255;1m"; - let mut dispatcher = CsiDispatcher::default(); + let mut dispatcher = Dispatcher::default(); let mut parser = Parser::new(); for byte in INPUT { parser.advance(&mut dispatcher, *byte); } - assert!(dispatcher.dispatched_csi); - assert!(!dispatcher.ignore); - assert_eq!(dispatcher.intermediates, &[]); - assert_eq!(dispatcher.params, &[vec![38, 2, 255, 0, 255], vec![1]]); - } - - #[test] - fn dcs_reset() { - static INPUT: &[u8] = b"\x1b[3;1\x1bP1$tx\x9c"; - let mut dispatcher = DcsDispatcher::default(); - let mut parser = Parser::new(); - - for byte in INPUT { - parser.advance(&mut dispatcher, *byte); + assert_eq!(dispatcher.dispatched.len(), 1); + match &dispatcher.dispatched[0] { + Sequence::Csi(params, intermediates, ignore, _) => { + assert_eq!(params, &[vec![38, 2, 255, 0, 255], vec![1]]); + assert_eq!(intermediates, &[]); + assert!(!ignore); + }, + _ => panic!("expected csi sequence"), } - - assert!(dispatcher.dispatched_dcs); - assert!(!dispatcher.ignore); - assert_eq!(dispatcher.intermediates, &[b'$']); - assert_eq!(dispatcher.params, &[1]); } #[test] - fn esc_reset() { - static INPUT: &[u8] = b"\x1b[3;1\x1b(A"; - let mut dispatcher = EscDispatcher::default(); + fn parse_dcs_max_params() { + let params = std::iter::repeat("1;").take(params::MAX_PARAMS + 1).collect::(); + let input = format!("\x1bP{}p", ¶ms[..]).into_bytes(); + let mut dispatcher = Dispatcher::default(); let mut parser = Parser::new(); - for byte in INPUT { - parser.advance(&mut dispatcher, *byte); + for byte in input { + parser.advance(&mut dispatcher, byte); } - assert!(dispatcher.dispatched_esc); - assert!(!dispatcher.ignore); - assert_eq!(dispatcher.intermediates, &[b'(']); + assert_eq!(dispatcher.dispatched.len(), 1); + match &dispatcher.dispatched[0] { + Sequence::DcsHook(params, _, ignore, _) => { + assert_eq!(params.len(), params::MAX_PARAMS); + assert!(params.iter().all(|param| param == &[1])); + assert!(ignore); + }, + _ => panic!("expected dcs sequence"), + } } #[test] - fn parse_osc_with_utf8_arguments() { - static INPUT: &[u8] = &[ - 0x0d, 0x1b, 0x5d, 0x32, 0x3b, 0x65, 0x63, 0x68, 0x6f, 0x20, 0x27, 0xc2, 0xaf, 0x5c, - 0x5f, 0x28, 0xe3, 0x83, 0x84, 0x29, 0x5f, 0x2f, 0xc2, 0xaf, 0x27, 0x20, 0x26, 0x26, - 0x20, 0x73, 0x6c, 0x65, 0x65, 0x70, 0x20, 0x31, 0x07, - ]; - let mut dispatcher = OscDispatcher::default(); + fn dcs_reset() { + static INPUT: &[u8] = b"\x1b[3;1\x1bP1$tx\x9c"; + let mut dispatcher = Dispatcher::default(); let mut parser = Parser::new(); for byte in INPUT { parser.advance(&mut dispatcher, *byte); } - // Check that flag is set and thus osc_dispatch assertions ran. - assert_eq!(dispatcher.params[0], &[b'2']); - assert_eq!(dispatcher.params[1], &INPUT[5..(INPUT.len() - 1)]); + assert_eq!(dispatcher.dispatched.len(), 3); + match &dispatcher.dispatched[0] { + Sequence::DcsHook(params, intermediates, ignore, _) => { + assert_eq!(intermediates, &[b'$']); + assert_eq!(params, &[[1]]); + assert!(!ignore); + }, + _ => panic!("expected dcs sequence"), + } + assert_eq!(dispatcher.dispatched[1], Sequence::DcsPut(b'x')); + assert_eq!(dispatcher.dispatched[2], Sequence::DcsUnhook); } #[test] - fn osc_containing_string_terminator() { - static INPUT: &[u8] = b"\x1b]2;\xe6\x9c\xab\x1b\\"; - let mut dispatcher = OscDispatcher::default(); + fn parse_dcs() { + static INPUT: &[u8] = b"\x1bP0;1|17/ab\x9c"; + let mut dispatcher = Dispatcher::default(); let mut parser = Parser::new(); for byte in INPUT { parser.advance(&mut dispatcher, *byte); } - assert_eq!(dispatcher.params[1], &INPUT[4..(INPUT.len() - 2)]); + assert_eq!(dispatcher.dispatched.len(), 7); + match &dispatcher.dispatched[0] { + Sequence::DcsHook(params, _, _, c) => { + assert_eq!(params, &[[0], [1]]); + assert_eq!(c, &'|'); + }, + _ => panic!("expected dcs sequence"), + } + for (i, byte) in b"17/ab".iter().enumerate() { + assert_eq!(dispatcher.dispatched[1 + i], Sequence::DcsPut(*byte)); + } + assert_eq!(dispatcher.dispatched[6], Sequence::DcsUnhook); } #[test] - fn parse_dcs() { - static INPUT: &[u8] = - &[0x1b, 0x50, 0x30, 0x3b, 0x31, 0x7c, 0x31, 0x37, 0x2f, 0x61, 0x62, 0x9c]; - let mut dispatcher = DcsDispatcher::default(); + fn intermediate_reset_on_dcs_exit() { + static INPUT: &[u8] = b"\x1bP=1sZZZ\x1b+\x5c"; + let mut dispatcher = Dispatcher::default(); let mut parser = Parser::new(); for byte in INPUT { parser.advance(&mut dispatcher, *byte); } - assert!(dispatcher.dispatched_dcs); - assert_eq!(dispatcher.params, vec![0, 1]); - assert_eq!(dispatcher.c, Some('|')); - assert_eq!(dispatcher.s, b"17/ab".to_vec()); + assert_eq!(dispatcher.dispatched.len(), 6); + match &dispatcher.dispatched[5] { + Sequence::Esc(intermediates, ..) => assert_eq!(intermediates, &[b'+']), + _ => panic!("expected esc sequence"), + } } #[test] - fn exceed_max_buffer_size() { - static NUM_BYTES: usize = MAX_OSC_RAW + 100; - static INPUT_START: &[u8] = &[0x1b, b']', b'5', b'2', b';', b's']; - static INPUT_END: &[u8] = &[b'\x07']; - - let mut dispatcher = OscDispatcher::default(); + fn esc_reset() { + static INPUT: &[u8] = b"\x1b[3;1\x1b(A"; + let mut dispatcher = Dispatcher::default(); let mut parser = Parser::new(); - // Create valid OSC escape - for byte in INPUT_START { + for byte in INPUT { parser.advance(&mut dispatcher, *byte); } - // Exceed max buffer size - for _ in 0..NUM_BYTES { - parser.advance(&mut dispatcher, b'a'); - } - - // Terminate escape for dispatch - for byte in INPUT_END { - parser.advance(&mut dispatcher, *byte); + assert_eq!(dispatcher.dispatched.len(), 1); + match &dispatcher.dispatched[0] { + Sequence::Esc(intermediates, ignore, byte) => { + assert_eq!(intermediates, &[b'(']); + assert_eq!(*byte, b'A'); + assert!(!ignore); + }, + _ => panic!("expected esc sequence"), } - - assert!(dispatcher.dispatched_osc); - - assert_eq!(dispatcher.params.len(), 2); - assert_eq!(dispatcher.params[0], b"52"); - - #[cfg(not(feature = "no_std"))] - assert_eq!(dispatcher.params[1].len(), NUM_BYTES + INPUT_END.len()); - - #[cfg(feature = "no_std")] - assert_eq!(dispatcher.params[1].len(), MAX_OSC_RAW - dispatcher.params[0].len()); } } From fe1022f6e6d6012652554e1964601d2827d7048f Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Sat, 17 Apr 2021 02:57:00 +0200 Subject: [PATCH 92/99] Bump version to 0.10.1 --- CHANGELOG.md | 4 ++++ Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c00ca8a..f094a895 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ CHANGELOG ========= +## 0.10.1 + +- Fixed invalid intermediates when transitioning from DCS to ESC + ## 0.10.0 - Changed the type of CSI parameters from i64 to u16 diff --git a/Cargo.toml b/Cargo.toml index 75bdb96c..9d91d6bf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ categories = ["parsing", "no-std"] exclude = ["/.travis.yml"] readme = "README.md" license = "Apache-2.0 OR MIT" -version = "0.10.0" +version = "0.10.1" name = "vte" edition = "2018" From dfac57ef3fdd5ddc884ce7d7559137c5123bae3e Mon Sep 17 00:00:00 2001 From: Kirill Chibisov Date: Sun, 16 Jan 2022 09:34:22 +0300 Subject: [PATCH 93/99] Migrate to 2021 edition --- .builds/linux.yml | 6 +++--- CHANGELOG.md | 4 ++++ Cargo.toml | 3 ++- src/lib.rs | 11 +++++------ utf8parse/src/lib.rs | 2 +- vte_generate_state_changes/src/lib.rs | 8 ++++---- 6 files changed, 19 insertions(+), 15 deletions(-) diff --git a/.builds/linux.yml b/.builds/linux.yml index 7430c526..a574963d 100644 --- a/.builds/linux.yml +++ b/.builds/linux.yml @@ -14,8 +14,8 @@ tasks: $HOME/.cargo/bin/rustup toolchain install nightly -c rustfmt cd vte $HOME/.cargo/bin/cargo +nightly fmt -- --check - - 1-36-0: | - $HOME/.cargo/bin/rustup toolchain install --profile minimal 1.36.0 + - 1-56-0: | + $HOME/.cargo/bin/rustup toolchain install --profile minimal 1.56.0 cd vte rm Cargo.lock - $HOME/.cargo/bin/cargo +1.36.0 test + $HOME/.cargo/bin/cargo +1.56.0 test diff --git a/CHANGELOG.md b/CHANGELOG.md index f094a895..df9e8f0d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ CHANGELOG ========= +## Unreleased + +- Minimum rust version has been bumped to 1.56.0 + ## 0.10.1 - Fixed invalid intermediates when transitioning from DCS to ESC diff --git a/Cargo.toml b/Cargo.toml index 9d91d6bf..2b1e1840 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,8 @@ readme = "README.md" license = "Apache-2.0 OR MIT" version = "0.10.1" name = "vte" -edition = "2018" +edition = "2021" +rust-version = "1.56.0" [dependencies] vte_generate_state_changes = { version = "0.1.0", path = "vte_generate_state_changes" } diff --git a/src/lib.rs b/src/lib.rs index 157392a4..c9886bf8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,7 +30,7 @@ //! [`Parser`]: struct.Parser.html //! [`Perform`]: trait.Perform.html //! [Paul Williams' ANSI parser state machine]: https://vt100.net/emu/dec_ansi_parser -#![deny(clippy::all, clippy::if_not_else, clippy::enum_glob_use, clippy::wrong_pub_self_convention)] +#![deny(clippy::all, clippy::if_not_else, clippy::enum_glob_use)] #![cfg_attr(all(feature = "nightly", test), feature(test))] #![cfg_attr(feature = "no_std", no_std)] @@ -420,7 +420,6 @@ extern crate std; mod tests { use super::*; - use std::string::String; use std::vec::Vec; static OSC_BYTES: &[u8] = &[ @@ -515,7 +514,7 @@ mod tests { #[test] fn parse_osc_max_params() { - let params = std::iter::repeat(";").take(params::MAX_PARAMS + 1).collect::(); + let params = ";".repeat(params::MAX_PARAMS + 1); let input = format!("\x1b]{}\x1b", ¶ms[..]).into_bytes(); let mut dispatcher = Dispatcher::default(); let mut parser = Parser::new(); @@ -656,7 +655,7 @@ mod tests { // This will build a list of repeating '1;'s // The length is MAX_PARAMS - 1 because the last semicolon is interpreted // as an implicit zero, making the total number of parameters MAX_PARAMS - let params = std::iter::repeat("1;").take(params::MAX_PARAMS - 1).collect::(); + let params = "1;".repeat(params::MAX_PARAMS - 1); let input = format!("\x1b[{}p", ¶ms[..]).into_bytes(); let mut dispatcher = Dispatcher::default(); @@ -681,7 +680,7 @@ mod tests { // This will build a list of repeating '1;'s // The length is MAX_PARAMS because the last semicolon is interpreted // as an implicit zero, making the total number of parameters MAX_PARAMS + 1 - let params = std::iter::repeat("1;").take(params::MAX_PARAMS).collect::(); + let params = "1;".repeat(params::MAX_PARAMS); let input = format!("\x1b[{}p", ¶ms[..]).into_bytes(); let mut dispatcher = Dispatcher::default(); @@ -796,7 +795,7 @@ mod tests { #[test] fn parse_dcs_max_params() { - let params = std::iter::repeat("1;").take(params::MAX_PARAMS + 1).collect::(); + let params = "1;".repeat(params::MAX_PARAMS + 1); let input = format!("\x1bP{}p", ¶ms[..]).into_bytes(); let mut dispatcher = Dispatcher::default(); let mut parser = Parser::new(); diff --git a/utf8parse/src/lib.rs b/utf8parse/src/lib.rs index 6168e2e4..947a0aa0 100644 --- a/utf8parse/src/lib.rs +++ b/utf8parse/src/lib.rs @@ -3,7 +3,7 @@ //! This module implements a table-driven UTF-8 parser which should //! theoretically contain the minimal number of branches (1). The only branch is //! on the `Action` returned from unpacking a transition. -#![deny(clippy::all, clippy::if_not_else, clippy::enum_glob_use, clippy::wrong_pub_self_convention)] +#![deny(clippy::all, clippy::if_not_else, clippy::enum_glob_use)] #![cfg_attr(all(feature = "nightly", test), feature(test))] #![no_std] diff --git a/vte_generate_state_changes/src/lib.rs b/vte_generate_state_changes/src/lib.rs index cae8f65a..b016518b 100644 --- a/vte_generate_state_changes/src/lib.rs +++ b/vte_generate_state_changes/src/lib.rs @@ -1,4 +1,4 @@ -#![deny(clippy::all, clippy::if_not_else, clippy::enum_glob_use, clippy::wrong_pub_self_convention)] +#![deny(clippy::all, clippy::if_not_else, clippy::enum_glob_use)] extern crate proc_macro; @@ -153,10 +153,10 @@ fn next_usize(iter: &mut impl Iterator) -> usize { match iter.next() { Some(Literal(literal)) => { let literal = literal.to_string(); - if literal.starts_with("0x") { - usize::from_str_radix(&literal[2..], 16).unwrap() + if let Some(prefix) = literal.strip_prefix("0x") { + usize::from_str_radix(prefix, 16).unwrap() } else { - usize::from_str_radix(&literal, 10).unwrap() + literal.parse::().unwrap() } }, token => panic!("Expected literal, but got {:?}", token), From 586a5fee5a1dd578dae857a45689aece7f03edeb Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Wed, 18 May 2022 01:58:09 +0200 Subject: [PATCH 94/99] Fix filled params list ending with subparam When the params list for the CSI/DCS escapes is filled with all 32 parameters but ends in a subparameter, it would not properly stage the length of the added subparameters causing the param iterator to get stuck in place. To ensure we always update the subparameter length even when no parameter is staged after it, the length of subparameters is now updated immediately while the subparameters itself are added. Fixes #77. --- CHANGELOG.md | 1 + src/lib.rs | 24 +++++++++++++++++++++++- src/params.rs | 1 + 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index df9e8f0d..b658cb3e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ CHANGELOG ## Unreleased - Minimum rust version has been bumped to 1.56.0 +- Fixed infinite loop in `Params` iterator when 32nd parameter is a subparameter ## 0.10.1 diff --git a/src/lib.rs b/src/lib.rs index c9886bf8..4860fcc5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -307,7 +307,7 @@ impl Parser { ); }, Action::EscDispatch => { - performer.esc_dispatch(self.intermediates(), self.ignoring, byte) + performer.esc_dispatch(self.intermediates(), self.ignoring, byte); }, Action::Collect => { if self.intermediate_idx == MAX_INTERMEDIATES { @@ -899,6 +899,28 @@ mod tests { _ => panic!("expected esc sequence"), } } + + #[test] + fn params_buffer_filled_with_subparam() { + static INPUT: &[u8] = b"\x1b[::::::::::::::::::::::::::::::::x\x1b"; + let mut dispatcher = Dispatcher::default(); + let mut parser = Parser::new(); + + for byte in INPUT { + parser.advance(&mut dispatcher, *byte); + } + + assert_eq!(dispatcher.dispatched.len(), 1); + match &dispatcher.dispatched[0] { + Sequence::Csi(params, intermediates, ignore, c) => { + assert_eq!(intermediates, &[]); + assert_eq!(params, &[[0; 32]]); + assert_eq!(c, &'x'); + assert!(ignore); + }, + _ => panic!("expected csi sequence"), + } + } } #[cfg(all(feature = "nightly", test))] diff --git a/src/params.rs b/src/params.rs index ca6ba480..608c0409 100644 --- a/src/params.rs +++ b/src/params.rs @@ -68,6 +68,7 @@ impl Params { /// Add an additional subparameter to the current parameter. #[inline] pub(crate) fn extend(&mut self, item: u16) { + self.subparams[self.len - self.current_subparams as usize] = self.current_subparams + 1; self.params[self.len] = item; self.current_subparams += 1; self.len += 1; From 45670c47cebd7af050def2f80a307bdeec7caba3 Mon Sep 17 00:00:00 2001 From: Nikhil Benesch Date: Sun, 17 Jul 2022 23:18:30 -0400 Subject: [PATCH 95/99] Bump arrayvec to 0.7.2 --- Cargo.toml | 2 +- src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 2b1e1840..2b0a1fb7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,7 @@ rust-version = "1.56.0" [dependencies] vte_generate_state_changes = { version = "0.1.0", path = "vte_generate_state_changes" } -arrayvec = { version = "0.5.1", default-features = false, optional = true } +arrayvec = { version = "0.7.2", default-features = false, optional = true } utf8parse = { version = "0.2.0", path = "utf8parse" } [features] diff --git a/src/lib.rs b/src/lib.rs index 4860fcc5..f8292082 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -78,7 +78,7 @@ pub struct Parser { params: Params, param: u16, #[cfg(feature = "no_std")] - osc_raw: ArrayVec<[u8; MAX_OSC_RAW]>, + osc_raw: ArrayVec, #[cfg(not(feature = "no_std"))] osc_raw: Vec, osc_params: [(usize, usize); MAX_OSC_PARAMS], From dc861b1dae166183c66848fcbd47b8e81a43d972 Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Wed, 20 Jul 2022 13:42:26 +0000 Subject: [PATCH 96/99] Bump version to 0.11.0 --- CHANGELOG.md | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b658cb3e..b19cc664 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ CHANGELOG ========= -## Unreleased +## 0.11.0 - Minimum rust version has been bumped to 1.56.0 - Fixed infinite loop in `Params` iterator when 32nd parameter is a subparameter diff --git a/Cargo.toml b/Cargo.toml index 2b0a1fb7..04076f2d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ categories = ["parsing", "no-std"] exclude = ["/.travis.yml"] readme = "README.md" license = "Apache-2.0 OR MIT" -version = "0.10.1" +version = "0.11.0" name = "vte" edition = "2021" rust-version = "1.56.0" From 89039f82d66581d3720d4ed1a8c9872ef77b221a Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 27 Feb 2023 17:36:51 -0600 Subject: [PATCH 97/99] chore: Remove utf8parse / vte_generate_state_changes --- Cargo.toml | 7 +- utf8parse/Cargo.toml | 15 -- utf8parse/LICENSE-APACHE | 176 --------------------- utf8parse/LICENSE-MIT | 25 --- utf8parse/src/lib.rs | 132 ---------------- utf8parse/src/types.rs | 105 ------------- utf8parse/tests/UTF-8-demo.txt | 212 -------------------------- utf8parse/tests/utf-8-demo.rs | 31 ---- vte_generate_state_changes/Cargo.toml | 15 -- vte_generate_state_changes/src/lib.rs | 176 --------------------- 10 files changed, 2 insertions(+), 892 deletions(-) delete mode 100644 utf8parse/Cargo.toml delete mode 100644 utf8parse/LICENSE-APACHE delete mode 100644 utf8parse/LICENSE-MIT delete mode 100644 utf8parse/src/lib.rs delete mode 100644 utf8parse/src/types.rs delete mode 100644 utf8parse/tests/UTF-8-demo.txt delete mode 100644 utf8parse/tests/utf-8-demo.rs delete mode 100644 vte_generate_state_changes/Cargo.toml delete mode 100644 vte_generate_state_changes/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index 04076f2d..3742e995 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,14 +14,11 @@ edition = "2021" rust-version = "1.56.0" [dependencies] -vte_generate_state_changes = { version = "0.1.0", path = "vte_generate_state_changes" } +vte_generate_state_changes = { version = "0.1.0" } arrayvec = { version = "0.7.2", default-features = false, optional = true } -utf8parse = { version = "0.2.0", path = "utf8parse" } +utf8parse = { version = "0.2.0" } [features] default = ["no_std"] no_std = ["arrayvec"] nightly = ["utf8parse/nightly"] - -[workspace] -members = ["utf8parse", "vte_generate_state_changes"] diff --git a/utf8parse/Cargo.toml b/utf8parse/Cargo.toml deleted file mode 100644 index f2709758..00000000 --- a/utf8parse/Cargo.toml +++ /dev/null @@ -1,15 +0,0 @@ -[package] -authors = ["Joe Wilm ", "Christian Duerr "] -description = "Table-driven UTF-8 parser" -documentation = "https://docs.rs/utf8parse/" -repository = "https://github.com/alacritty/vte" -keywords = ["utf8", "parse", "table"] -categories = ["parsing", "no-std"] -license = "Apache-2.0 OR MIT" -version = "0.2.0" -name = "utf8parse" -edition = "2018" - -[features] -nightly = [] -default = [] diff --git a/utf8parse/LICENSE-APACHE b/utf8parse/LICENSE-APACHE deleted file mode 100644 index 1b5ec8b7..00000000 --- a/utf8parse/LICENSE-APACHE +++ /dev/null @@ -1,176 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS diff --git a/utf8parse/LICENSE-MIT b/utf8parse/LICENSE-MIT deleted file mode 100644 index bb419c21..00000000 --- a/utf8parse/LICENSE-MIT +++ /dev/null @@ -1,25 +0,0 @@ -Copyright (c) 2016 Joe Wilm - -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/utf8parse/src/lib.rs b/utf8parse/src/lib.rs deleted file mode 100644 index 947a0aa0..00000000 --- a/utf8parse/src/lib.rs +++ /dev/null @@ -1,132 +0,0 @@ -//! A table-driven UTF-8 Parser -//! -//! This module implements a table-driven UTF-8 parser which should -//! theoretically contain the minimal number of branches (1). The only branch is -//! on the `Action` returned from unpacking a transition. -#![deny(clippy::all, clippy::if_not_else, clippy::enum_glob_use)] -#![cfg_attr(all(feature = "nightly", test), feature(test))] -#![no_std] - -use core::char; - -mod types; - -use types::{Action, State}; - -/// Handles codepoint and invalid sequence events from the parser. -pub trait Receiver { - /// Called whenever a codepoint is parsed successfully - fn codepoint(&mut self, _: char); - - /// Called when an invalid_sequence is detected - fn invalid_sequence(&mut self); -} - -/// A parser for Utf8 Characters -/// -/// Repeatedly call `advance` with bytes to emit Utf8 characters -#[derive(Default)] -pub struct Parser { - point: u32, - state: State, -} - -/// Continuation bytes are masked with this value. -const CONTINUATION_MASK: u8 = 0b0011_1111; - -impl Parser { - /// Create a new Parser - pub fn new() -> Parser { - Parser { point: 0, state: State::Ground } - } - - /// Advance the parser - /// - /// The provider receiver will be called whenever a codepoint is completed or an invalid - /// sequence is detected. - pub fn advance(&mut self, receiver: &mut R, byte: u8) - where - R: Receiver, - { - let (state, action) = self.state.advance(byte); - self.perform_action(receiver, byte, action); - self.state = state; - } - - fn perform_action(&mut self, receiver: &mut R, byte: u8, action: Action) - where - R: Receiver, - { - match action { - Action::InvalidSequence => { - self.point = 0; - receiver.invalid_sequence(); - }, - Action::EmitByte => { - receiver.codepoint(byte as char); - }, - Action::SetByte1 => { - let point = self.point | ((byte & CONTINUATION_MASK) as u32); - let c = unsafe { char::from_u32_unchecked(point) }; - self.point = 0; - - receiver.codepoint(c); - }, - Action::SetByte2 => { - self.point |= ((byte & CONTINUATION_MASK) as u32) << 6; - }, - Action::SetByte2Top => { - self.point |= ((byte & 0b0001_1111) as u32) << 6; - }, - Action::SetByte3 => { - self.point |= ((byte & CONTINUATION_MASK) as u32) << 12; - }, - Action::SetByte3Top => { - self.point |= ((byte & 0b0000_1111) as u32) << 12; - }, - Action::SetByte4 => { - self.point |= ((byte & 0b0000_0111) as u32) << 18; - }, - } - } -} - -#[cfg(all(feature = "nightly", test))] -mod benches { - extern crate std; - extern crate test; - - use super::{Parser, Receiver}; - - use self::test::{black_box, Bencher}; - - static UTF8_DEMO: &[u8] = include_bytes!("../tests/UTF-8-demo.txt"); - - impl Receiver for () { - fn codepoint(&mut self, c: char) { - black_box(c); - } - - fn invalid_sequence(&mut self) {} - } - - #[bench] - fn parse_bench_utf8_demo(b: &mut Bencher) { - let mut parser = Parser::new(); - - b.iter(|| { - for byte in UTF8_DEMO { - parser.advance(&mut (), *byte); - } - }) - } - - #[bench] - fn std_string_parse_utf8(b: &mut Bencher) { - b.iter(|| { - for c in std::str::from_utf8(UTF8_DEMO).unwrap().chars() { - black_box(c); - } - }); - } -} diff --git a/utf8parse/src/types.rs b/utf8parse/src/types.rs deleted file mode 100644 index 77a79cc1..00000000 --- a/utf8parse/src/types.rs +++ /dev/null @@ -1,105 +0,0 @@ -//! Types supporting the UTF-8 parser - -/// Action to take when receiving a byte -#[derive(Debug, Copy, Clone)] -pub enum Action { - /// Unexpected byte; sequence is invalid - InvalidSequence = 0, - /// Received valid 7-bit ASCII byte which can be directly emitted. - EmitByte = 1, - /// Set the bottom continuation byte - SetByte1 = 2, - /// Set the 2nd-from-last continuation byte - SetByte2 = 3, - /// Set the 2nd-from-last byte which is part of a two byte sequence - SetByte2Top = 4, - /// Set the 3rd-from-last continuation byte - SetByte3 = 5, - /// Set the 3rd-from-last byte which is part of a three byte sequence - SetByte3Top = 6, - /// Set the top byte of a four byte sequence. - SetByte4 = 7, -} - -/// States the parser can be in. -/// -/// There is a state for each initial input of the 3 and 4 byte sequences since -/// the following bytes are subject to different conditions than a tail byte. -#[allow(non_camel_case_types)] -#[derive(Debug, Copy, Clone)] -pub enum State { - /// Ground state; expect anything - Ground = 0, - /// 3 tail bytes - Tail3 = 1, - /// 2 tail bytes - Tail2 = 2, - /// 1 tail byte - Tail1 = 3, - /// UTF8-3 starting with E0 - U3_2_e0 = 4, - /// UTF8-3 starting with ED - U3_2_ed = 5, - /// UTF8-4 starting with F0 - Utf8_4_3_f0 = 6, - /// UTF8-4 starting with F4 - Utf8_4_3_f4 = 7, -} - -impl Default for State { - fn default() -> State { - State::Ground - } -} - -impl State { - /// Advance the parser state. - /// - /// This takes the current state and input byte into consideration, to determine the next state - /// and any action that should be taken. - #[inline] - pub fn advance(self, byte: u8) -> (State, Action) { - match self { - State::Ground => match byte { - 0x00..=0x7f => (State::Ground, Action::EmitByte), - 0xc2..=0xdf => (State::Tail1, Action::SetByte2Top), - 0xe0 => (State::U3_2_e0, Action::SetByte3Top), - 0xe1..=0xec => (State::Tail2, Action::SetByte3Top), - 0xed => (State::U3_2_ed, Action::SetByte3Top), - 0xee..=0xef => (State::Tail2, Action::SetByte3Top), - 0xf0 => (State::Utf8_4_3_f0, Action::SetByte4), - 0xf1..=0xf3 => (State::Tail3, Action::SetByte4), - 0xf4 => (State::Utf8_4_3_f4, Action::SetByte4), - _ => (State::Ground, Action::InvalidSequence), - }, - State::U3_2_e0 => match byte { - 0xa0..=0xbf => (State::Tail1, Action::SetByte2), - _ => (State::Ground, Action::InvalidSequence), - }, - State::U3_2_ed => match byte { - 0x80..=0x9f => (State::Tail1, Action::SetByte2), - _ => (State::Ground, Action::InvalidSequence), - }, - State::Utf8_4_3_f0 => match byte { - 0x90..=0xbf => (State::Tail2, Action::SetByte3), - _ => (State::Ground, Action::InvalidSequence), - }, - State::Utf8_4_3_f4 => match byte { - 0x80..=0x8f => (State::Tail2, Action::SetByte3), - _ => (State::Ground, Action::InvalidSequence), - }, - State::Tail3 => match byte { - 0x80..=0xbf => (State::Tail2, Action::SetByte3), - _ => (State::Ground, Action::InvalidSequence), - }, - State::Tail2 => match byte { - 0x80..=0xbf => (State::Tail1, Action::SetByte2), - _ => (State::Ground, Action::InvalidSequence), - }, - State::Tail1 => match byte { - 0x80..=0xbf => (State::Ground, Action::SetByte1), - _ => (State::Ground, Action::InvalidSequence), - }, - } - } -} diff --git a/utf8parse/tests/UTF-8-demo.txt b/utf8parse/tests/UTF-8-demo.txt deleted file mode 100644 index 4363f27b..00000000 --- a/utf8parse/tests/UTF-8-demo.txt +++ /dev/null @@ -1,212 +0,0 @@ - -UTF-8 encoded sample plain-text file -‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾ - -Markus Kuhn [ˈmaʳkʊs kuːn] — 2002-07-25 - - -The ASCII compatible UTF-8 encoding used in this plain-text file -is defined in Unicode, ISO 10646-1, and RFC 2279. - - -Using Unicode/UTF-8, you can write in emails and source code things such as - -Mathematics and sciences: - - ∮ E⋅da = Q, n → ∞, ∑ f(i) = ∏ g(i), ⎧⎡⎛┌─────┐⎞⎤⎫ - ⎪⎢⎜│a²+b³ ⎟⎥⎪ - ∀x∈ℝ: ⌈x⌉ = −⌊−x⌋, α ∧ ¬β = ¬(¬α ∨ β), ⎪⎢⎜│───── ⎟⎥⎪ - ⎪⎢⎜⎷ c₈ ⎟⎥⎪ - ℕ ⊆ ℕ₀ ⊂ ℤ ⊂ ℚ ⊂ ℝ ⊂ ℂ, ⎨⎢⎜ ⎟⎥⎬ - ⎪⎢⎜ ∞ ⎟⎥⎪ - ⊥ < a ≠ b ≡ c ≤ d ≪ ⊤ ⇒ (⟦A⟧ ⇔ ⟪B⟫), ⎪⎢⎜ ⎲ ⎟⎥⎪ - ⎪⎢⎜ ⎳aⁱ-bⁱ⎟⎥⎪ - 2H₂ + O₂ ⇌ 2H₂O, R = 4.7 kΩ, ⌀ 200 mm ⎩⎣⎝i=1 ⎠⎦⎭ - -Linguistics and dictionaries: - - ði ıntəˈnæʃənəl fəˈnɛtık əsoʊsiˈeıʃn - Y [ˈʏpsilɔn], Yen [jɛn], Yoga [ˈjoːgɑ] - -APL: - - ((V⍳V)=⍳⍴V)/V←,V ⌷←⍳→⍴∆∇⊃‾⍎⍕⌈ - -Nicer typography in plain text files: - - ╔══════════════════════════════════════════╗ - ║ ║ - ║ • ‘single’ and “double” quotes ║ - ║ ║ - ║ • Curly apostrophes: “We’ve been here” ║ - ║ ║ - ║ • Latin-1 apostrophe and accents: '´` ║ - ║ ║ - ║ • ‚deutsche‘ „Anführungszeichen“ ║ - ║ ║ - ║ • †, ‡, ‰, •, 3–4, —, −5/+5, ™, … ║ - ║ ║ - ║ • ASCII safety test: 1lI|, 0OD, 8B ║ - ║ ╭─────────╮ ║ - ║ • the euro symbol: │ 14.95 € │ ║ - ║ ╰─────────╯ ║ - ╚══════════════════════════════════════════╝ - -Combining characters: - - STARGΛ̊TE SG-1, a = v̇ = r̈, a⃑ ⊥ b⃑ - -Greek (in Polytonic): - - The Greek anthem: - - Σὲ γνωρίζω ἀπὸ τὴν κόψη - τοῦ σπαθιοῦ τὴν τρομερή, - σὲ γνωρίζω ἀπὸ τὴν ὄψη - ποὺ μὲ βία μετράει τὴ γῆ. - - ᾿Απ᾿ τὰ κόκκαλα βγαλμένη - τῶν ῾Ελλήνων τὰ ἱερά - καὶ σὰν πρῶτα ἀνδρειωμένη - χαῖρε, ὦ χαῖρε, ᾿Ελευθεριά! - - From a speech of Demosthenes in the 4th century BC: - - Οὐχὶ ταὐτὰ παρίσταταί μοι γιγνώσκειν, ὦ ἄνδρες ᾿Αθηναῖοι, - ὅταν τ᾿ εἰς τὰ πράγματα ἀποβλέψω καὶ ὅταν πρὸς τοὺς - λόγους οὓς ἀκούω· τοὺς μὲν γὰρ λόγους περὶ τοῦ - τιμωρήσασθαι Φίλιππον ὁρῶ γιγνομένους, τὰ δὲ πράγματ᾿ - εἰς τοῦτο προήκοντα, ὥσθ᾿ ὅπως μὴ πεισόμεθ᾿ αὐτοὶ - πρότερον κακῶς σκέψασθαι δέον. οὐδέν οὖν ἄλλο μοι δοκοῦσιν - οἱ τὰ τοιαῦτα λέγοντες ἢ τὴν ὑπόθεσιν, περὶ ἧς βουλεύεσθαι, - οὐχὶ τὴν οὖσαν παριστάντες ὑμῖν ἁμαρτάνειν. ἐγὼ δέ, ὅτι μέν - ποτ᾿ ἐξῆν τῇ πόλει καὶ τὰ αὑτῆς ἔχειν ἀσφαλῶς καὶ Φίλιππον - τιμωρήσασθαι, καὶ μάλ᾿ ἀκριβῶς οἶδα· ἐπ᾿ ἐμοῦ γάρ, οὐ πάλαι - γέγονεν ταῦτ᾿ ἀμφότερα· νῦν μέντοι πέπεισμαι τοῦθ᾿ ἱκανὸν - προλαβεῖν ἡμῖν εἶναι τὴν πρώτην, ὅπως τοὺς συμμάχους - σώσομεν. ἐὰν γὰρ τοῦτο βεβαίως ὑπάρξῃ, τότε καὶ περὶ τοῦ - τίνα τιμωρήσεταί τις καὶ ὃν τρόπον ἐξέσται σκοπεῖν· πρὶν δὲ - τὴν ἀρχὴν ὀρθῶς ὑποθέσθαι, μάταιον ἡγοῦμαι περὶ τῆς - τελευτῆς ὁντινοῦν ποιεῖσθαι λόγον. - - Δημοσθένους, Γ´ ᾿Ολυνθιακὸς - -Georgian: - - From a Unicode conference invitation: - - გთხოვთ ახლავე გაიაროთ რეგისტრაცია Unicode-ის მეათე საერთაშორისო - კონფერენციაზე დასასწრებად, რომელიც გაიმართება 10-12 მარტს, - ქ. მაინცში, გერმანიაში. კონფერენცია შეჰკრებს ერთად მსოფლიოს - ექსპერტებს ისეთ დარგებში როგორიცაა ინტერნეტი და Unicode-ი, - ინტერნაციონალიზაცია და ლოკალიზაცია, Unicode-ის გამოყენება - ოპერაციულ სისტემებსა, და გამოყენებით პროგრამებში, შრიფტებში, - ტექსტების დამუშავებასა და მრავალენოვან კომპიუტერულ სისტემებში. - -Russian: - - From a Unicode conference invitation: - - Зарегистрируйтесь сейчас на Десятую Международную Конференцию по - Unicode, которая состоится 10-12 марта 1997 года в Майнце в Германии. - Конференция соберет широкий круг экспертов по вопросам глобального - Интернета и Unicode, локализации и интернационализации, воплощению и - применению Unicode в различных операционных системах и программных - приложениях, шрифтах, верстке и многоязычных компьютерных системах. - -Thai (UCS Level 2): - - Excerpt from a poetry on The Romance of The Three Kingdoms (a Chinese - classic 'San Gua'): - - [----------------------------|------------------------] - ๏ แผ่นดินฮั่นเสื่อมโทรมแสนสังเวช พระปกเกศกองบู๊กู้ขึ้นใหม่ - สิบสองกษัตริย์ก่อนหน้าแลถัดไป สององค์ไซร้โง่เขลาเบาปัญญา - ทรงนับถือขันทีเป็นที่พึ่ง บ้านเมืองจึงวิปริตเป็นนักหนา - โฮจิ๋นเรียกทัพทั่วหัวเมืองมา หมายจะฆ่ามดชั่วตัวสำคัญ - เหมือนขับไสไล่เสือจากเคหา รับหมาป่าเข้ามาเลยอาสัญ - ฝ่ายอ้องอุ้นยุแยกให้แตกกัน ใช้สาวนั้นเป็นชนวนชื่นชวนใจ - พลันลิฉุยกุยกีกลับก่อเหตุ ช่างอาเพศจริงหนาฟ้าร้องไห้ - ต้องรบราฆ่าฟันจนบรรลัย ฤๅหาใครค้ำชูกู้บรรลังก์ ฯ - - (The above is a two-column text. If combining characters are handled - correctly, the lines of the second column should be aligned with the - | character above.) - -Ethiopian: - - Proverbs in the Amharic language: - - ሰማይ አይታረስ ንጉሥ አይከሰስ። - ብላ ካለኝ እንደአባቴ በቆመጠኝ። - ጌጥ ያለቤቱ ቁምጥና ነው። - ደሀ በሕልሙ ቅቤ ባይጠጣ ንጣት በገደለው። - የአፍ ወለምታ በቅቤ አይታሽም። - አይጥ በበላ ዳዋ ተመታ። - ሲተረጉሙ ይደረግሙ። - ቀስ በቀስ፥ ዕንቁላል በእግሩ ይሄዳል። - ድር ቢያብር አንበሳ ያስር። - ሰው እንደቤቱ እንጅ እንደ ጉረቤቱ አይተዳደርም። - እግዜር የከፈተውን ጉሮሮ ሳይዘጋው አይድርም። - የጎረቤት ሌባ፥ ቢያዩት ይስቅ ባያዩት ያጠልቅ። - ሥራ ከመፍታት ልጄን ላፋታት። - ዓባይ ማደሪያ የለው፥ ግንድ ይዞ ይዞራል። - የእስላም አገሩ መካ የአሞራ አገሩ ዋርካ። - ተንጋሎ ቢተፉ ተመልሶ ባፉ። - ወዳጅህ ማር ቢሆን ጨርስህ አትላሰው። - እግርህን በፍራሽህ ልክ ዘርጋ። - -Runes: - - ᚻᛖ ᚳᚹᚫᚦ ᚦᚫᛏ ᚻᛖ ᛒᚢᛞᛖ ᚩᚾ ᚦᚫᛗ ᛚᚪᚾᛞᛖ ᚾᚩᚱᚦᚹᛖᚪᚱᛞᚢᛗ ᚹᛁᚦ ᚦᚪ ᚹᛖᛥᚫ - - (Old English, which transcribed into Latin reads 'He cwaeth that he - bude thaem lande northweardum with tha Westsae.' and means 'He said - that he lived in the northern land near the Western Sea.') - -Braille: - - ⡌⠁⠧⠑ ⠼⠁⠒ ⡍⠜⠇⠑⠹⠰⠎ ⡣⠕⠌ - - ⡍⠜⠇⠑⠹ ⠺⠁⠎ ⠙⠑⠁⠙⠒ ⠞⠕ ⠃⠑⠛⠔ ⠺⠊⠹⠲ ⡹⠻⠑ ⠊⠎ ⠝⠕ ⠙⠳⠃⠞ - ⠱⠁⠞⠑⠧⠻ ⠁⠃⠳⠞ ⠹⠁⠞⠲ ⡹⠑ ⠗⠑⠛⠊⠌⠻ ⠕⠋ ⠙⠊⠎ ⠃⠥⠗⠊⠁⠇ ⠺⠁⠎ - ⠎⠊⠛⠝⠫ ⠃⠹ ⠹⠑ ⠊⠇⠻⠛⠹⠍⠁⠝⠂ ⠹⠑ ⠊⠇⠻⠅⠂ ⠹⠑ ⠥⠝⠙⠻⠞⠁⠅⠻⠂ - ⠁⠝⠙ ⠹⠑ ⠡⠊⠑⠋ ⠍⠳⠗⠝⠻⠲ ⡎⠊⠗⠕⠕⠛⠑ ⠎⠊⠛⠝⠫ ⠊⠞⠲ ⡁⠝⠙ - ⡎⠊⠗⠕⠕⠛⠑⠰⠎ ⠝⠁⠍⠑ ⠺⠁⠎ ⠛⠕⠕⠙ ⠥⠏⠕⠝ ⠰⡡⠁⠝⠛⠑⠂ ⠋⠕⠗ ⠁⠝⠹⠹⠔⠛ ⠙⠑ - ⠡⠕⠎⠑ ⠞⠕ ⠏⠥⠞ ⠙⠊⠎ ⠙⠁⠝⠙ ⠞⠕⠲ - - ⡕⠇⠙ ⡍⠜⠇⠑⠹ ⠺⠁⠎ ⠁⠎ ⠙⠑⠁⠙ ⠁⠎ ⠁ ⠙⠕⠕⠗⠤⠝⠁⠊⠇⠲ - - ⡍⠔⠙⠖ ⡊ ⠙⠕⠝⠰⠞ ⠍⠑⠁⠝ ⠞⠕ ⠎⠁⠹ ⠹⠁⠞ ⡊ ⠅⠝⠪⠂ ⠕⠋ ⠍⠹ - ⠪⠝ ⠅⠝⠪⠇⠫⠛⠑⠂ ⠱⠁⠞ ⠹⠻⠑ ⠊⠎ ⠏⠜⠞⠊⠊⠥⠇⠜⠇⠹ ⠙⠑⠁⠙ ⠁⠃⠳⠞ - ⠁ ⠙⠕⠕⠗⠤⠝⠁⠊⠇⠲ ⡊ ⠍⠊⠣⠞ ⠙⠁⠧⠑ ⠃⠑⠲ ⠔⠊⠇⠔⠫⠂ ⠍⠹⠎⠑⠇⠋⠂ ⠞⠕ - ⠗⠑⠛⠜⠙ ⠁ ⠊⠕⠋⠋⠔⠤⠝⠁⠊⠇ ⠁⠎ ⠹⠑ ⠙⠑⠁⠙⠑⠌ ⠏⠊⠑⠊⠑ ⠕⠋ ⠊⠗⠕⠝⠍⠕⠝⠛⠻⠹ - ⠔ ⠹⠑ ⠞⠗⠁⠙⠑⠲ ⡃⠥⠞ ⠹⠑ ⠺⠊⠎⠙⠕⠍ ⠕⠋ ⠳⠗ ⠁⠝⠊⠑⠌⠕⠗⠎ - ⠊⠎ ⠔ ⠹⠑ ⠎⠊⠍⠊⠇⠑⠆ ⠁⠝⠙ ⠍⠹ ⠥⠝⠙⠁⠇⠇⠪⠫ ⠙⠁⠝⠙⠎ - ⠩⠁⠇⠇ ⠝⠕⠞ ⠙⠊⠌⠥⠗⠃ ⠊⠞⠂ ⠕⠗ ⠹⠑ ⡊⠳⠝⠞⠗⠹⠰⠎ ⠙⠕⠝⠑ ⠋⠕⠗⠲ ⡹⠳ - ⠺⠊⠇⠇ ⠹⠻⠑⠋⠕⠗⠑ ⠏⠻⠍⠊⠞ ⠍⠑ ⠞⠕ ⠗⠑⠏⠑⠁⠞⠂ ⠑⠍⠏⠙⠁⠞⠊⠊⠁⠇⠇⠹⠂ ⠹⠁⠞ - ⡍⠜⠇⠑⠹ ⠺⠁⠎ ⠁⠎ ⠙⠑⠁⠙ ⠁⠎ ⠁ ⠙⠕⠕⠗⠤⠝⠁⠊⠇⠲ - - (The first couple of paragraphs of "A Christmas Carol" by Dickens) - -Compact font selection example text: - - ABCDEFGHIJKLMNOPQRSTUVWXYZ /0123456789 - abcdefghijklmnopqrstuvwxyz £©µÀÆÖÞßéöÿ - –—‘“”„†•…‰™œŠŸž€ ΑΒΓΔΩαβγδω АБВГДабвгд - ∀∂∈ℝ∧∪≡∞ ↑↗↨↻⇣ ┐┼╔╘░►☺♀ fi�⑀₂ἠḂӥẄɐː⍎אԱა - -Greetings in various languages: - - Hello world, Καλημέρα κόσμε, コンニチハ - -Box drawing alignment tests: █ - ▉ - ╔══╦══╗ ┌──┬──┐ ╭──┬──╮ ╭──┬──╮ ┏━━┳━━┓ ┎┒┏┑ ╷ ╻ ┏┯┓ ┌┰┐ ▊ ╱╲╱╲╳╳╳ - ║┌─╨─┐║ │╔═╧═╗│ │╒═╪═╕│ │╓─╁─╖│ ┃┌─╂─┐┃ ┗╃╄┙ ╶┼╴╺╋╸┠┼┨ ┝╋┥ ▋ ╲╱╲╱╳╳╳ - ║│╲ ╱│║ │║ ║│ ││ │ ││ │║ ┃ ║│ ┃│ ╿ │┃ ┍╅╆┓ ╵ ╹ ┗┷┛ └┸┘ ▌ ╱╲╱╲╳╳╳ - ╠╡ ╳ ╞╣ ├╢ ╟┤ ├┼─┼─┼┤ ├╫─╂─╫┤ ┣┿╾┼╼┿┫ ┕┛┖┚ ┌┄┄┐ ╎ ┏┅┅┓ ┋ ▍ ╲╱╲╱╳╳╳ - ║│╱ ╲│║ │║ ║│ ││ │ ││ │║ ┃ ║│ ┃│ ╽ │┃ ░░▒▒▓▓██ ┊ ┆ ╎ ╏ ┇ ┋ ▎ - ║└─╥─┘║ │╚═╤═╝│ │╘═╪═╛│ │╙─╀─╜│ ┃└─╂─┘┃ ░░▒▒▓▓██ ┊ ┆ ╎ ╏ ┇ ┋ ▏ - ╚══╩══╝ └──┴──┘ ╰──┴──╯ ╰──┴──╯ ┗━━┻━━┛ ▗▄▖▛▀▜ └╌╌┘ ╎ ┗╍╍┛ ┋ ▁▂▃▄▅▆▇█ - ▝▀▘▙▄▟ diff --git a/utf8parse/tests/utf-8-demo.rs b/utf8parse/tests/utf-8-demo.rs deleted file mode 100644 index 51df4927..00000000 --- a/utf8parse/tests/utf-8-demo.rs +++ /dev/null @@ -1,31 +0,0 @@ -use utf8parse::{Parser, Receiver}; - -static UTF8_DEMO: &[u8] = include_bytes!("UTF-8-demo.txt"); - -#[derive(Debug, PartialEq)] -struct StringWrapper(String); - -impl Receiver for StringWrapper { - fn codepoint(&mut self, c: char) { - self.0.push(c); - } - - fn invalid_sequence(&mut self) {} -} - -#[test] -fn utf8parse_test() { - let mut parser = Parser::new(); - - // utf8parse implementation - let mut actual = StringWrapper(String::new()); - - for byte in UTF8_DEMO { - parser.advance(&mut actual, *byte) - } - - // standard library implementation - let expected = String::from_utf8_lossy(UTF8_DEMO); - - assert_eq!(actual.0, expected); -} diff --git a/vte_generate_state_changes/Cargo.toml b/vte_generate_state_changes/Cargo.toml deleted file mode 100644 index 3f540f1e..00000000 --- a/vte_generate_state_changes/Cargo.toml +++ /dev/null @@ -1,15 +0,0 @@ -[package] -authors = ["Christian Duerr "] -description = "Proc macro for generating VTE state changes" -repository = "https://github.com/alacritty/vte" -name = "vte_generate_state_changes" -license = "Apache-2.0 OR MIT" -version = "0.1.1" -edition = "2018" - -[lib] -proc-macro = true - -[dependencies] -proc-macro2 = "1.0.6" -quote = "1.0.2" diff --git a/vte_generate_state_changes/src/lib.rs b/vte_generate_state_changes/src/lib.rs deleted file mode 100644 index b016518b..00000000 --- a/vte_generate_state_changes/src/lib.rs +++ /dev/null @@ -1,176 +0,0 @@ -#![deny(clippy::all, clippy::if_not_else, clippy::enum_glob_use)] - -extern crate proc_macro; - -use std::iter::Peekable; - -use proc_macro2::TokenTree::{Group, Literal, Punct}; -use proc_macro2::{token_stream, TokenStream, TokenTree}; -use quote::quote; - -/// Create a `const fn` which will return an array with all state changes. -#[proc_macro] -pub fn generate_state_changes(item: proc_macro::TokenStream) -> proc_macro::TokenStream { - // Convert from proc_macro -> proc_macro2 - let item: TokenStream = item.into(); - let mut iter = item.into_iter().peekable(); - - // Determine output function name - let fn_name = iter.next().unwrap(); - - // Separator between name and body with state changes - expect_punct(&mut iter, ','); - - // Create token stream to assign each state change to the array - let assignments_stream = states_stream(&mut iter); - - quote!( - const fn #fn_name() -> [[u8; 256]; 16] { - let mut state_changes = [[0; 256]; 16]; - - #assignments_stream - - state_changes - } - ) - .into() -} - -/// Generate the array assignment statements for all origin states. -fn states_stream(iter: &mut impl Iterator) -> TokenStream { - let mut states_stream = next_group(iter).into_iter().peekable(); - - // Loop over all origin state entries - let mut tokens = quote!(); - while states_stream.peek().is_some() { - // Add all mappings for this state - tokens.extend(state_entry_stream(&mut states_stream)); - - // Allow trailing comma - optional_punct(&mut states_stream, ','); - } - tokens -} - -/// Generate the array assignment statements for one origin state. -fn state_entry_stream(iter: &mut Peekable) -> TokenStream { - // Origin state name - let state = iter.next().unwrap(); - - // Token stream with all the byte->target mappings - let mut changes_stream = next_group(iter).into_iter().peekable(); - - let mut tokens = quote!(); - while changes_stream.peek().is_some() { - // Add next mapping for this state - tokens.extend(change_stream(&mut changes_stream, &state)); - - // Allow trailing comma - optional_punct(&mut changes_stream, ','); - } - tokens -} - -/// Generate the array assignment statement for a single byte->target mapping for one state. -fn change_stream(iter: &mut Peekable, state: &TokenTree) -> TokenStream { - // Start of input byte range - let start = next_usize(iter); - - // End of input byte range - let end = if optional_punct(iter, '.') { - // Read inclusive end of range - expect_punct(iter, '.'); - expect_punct(iter, '='); - next_usize(iter) - } else { - // Without range, end is equal to start - start - }; - - // Separator between byte input range and output state - expect_punct(iter, '='); - expect_punct(iter, '>'); - - // Token stream with target state and action - let mut target_change_stream = next_group(iter).into_iter().peekable(); - - let mut tokens = quote!(); - while target_change_stream.peek().is_some() { - // Target state/action for all bytes in the range - let (target_state, target_action) = target_change(&mut target_change_stream); - - // Create a new entry for every byte in the range - for byte in start..=end { - // TODO: Force adding `State::` and `Action::`? - // TODO: Should we really use `pack` here without import? - tokens.extend(quote!( - state_changes[State::#state as usize][#byte] = - pack(State::#target_state, Action::#target_action); - )); - } - } - tokens -} - -/// Get next target state and action. -fn target_change(iter: &mut Peekable) -> (TokenTree, TokenTree) { - let target_state = iter.next().unwrap(); - - // Separator between state and action - expect_punct(iter, ','); - - let target_action = iter.next().unwrap(); - - (target_state, target_action) -} - -/// Check if next token matches specific punctuation. -fn optional_punct(iter: &mut Peekable, c: char) -> bool { - match iter.peek() { - Some(Punct(punct)) if punct.as_char() == c => iter.next().is_some(), - _ => false, - } -} - -/// Ensure next token matches specific punctuation. -/// -/// # Panics -/// -/// Panics if the punctuation does not match. -fn expect_punct(iter: &mut impl Iterator, c: char) { - match iter.next() { - Some(Punct(ref punct)) if punct.as_char() == c => (), - token => panic!("Expected punctuation '{}', but got {:?}", c, token), - } -} - -/// Get next token as [`usize`]. -/// -/// # Panics -/// -/// Panics if the next token is not a [`usize`] in hex or decimal literal format. -fn next_usize(iter: &mut impl Iterator) -> usize { - match iter.next() { - Some(Literal(literal)) => { - let literal = literal.to_string(); - if let Some(prefix) = literal.strip_prefix("0x") { - usize::from_str_radix(prefix, 16).unwrap() - } else { - literal.parse::().unwrap() - } - }, - token => panic!("Expected literal, but got {:?}", token), - } -} - -/// Get next token as [`Group`]. -/// -/// # Panics -/// -/// Panics if the next token is not a [`Group`]. -fn next_group(iter: &mut impl Iterator) -> TokenStream { - match iter.next() { - Some(Group(group)) => group.stream(), - token => panic!("Expected group, but got {:?}", token), - } -} From a55df30cbd18ae106fbf33e075874cd84267d4c7 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 27 Feb 2023 17:37:54 -0600 Subject: [PATCH 98/99] style: Use default fmt --- examples/parselog.rs | 9 +++-- rustfmt.toml | 13 ------- src/lib.rs | 86 ++++++++++++++++++++++++-------------------- 3 files changed, 53 insertions(+), 55 deletions(-) delete mode 100644 rustfmt.toml diff --git a/examples/parselog.rs b/examples/parselog.rs index dfd0aee9..c28ffc61 100644 --- a/examples/parselog.rs +++ b/examples/parselog.rs @@ -31,7 +31,10 @@ impl Perform for Log { } fn osc_dispatch(&mut self, params: &[&[u8]], bell_terminated: bool) { - println!("[osc_dispatch] params={:?} bell_terminated={}", params, bell_terminated); + println!( + "[osc_dispatch] params={:?} bell_terminated={}", + params, bell_terminated + ); } fn csi_dispatch(&mut self, params: &Params, intermediates: &[u8], ignore: bool, c: char) { @@ -65,11 +68,11 @@ fn main() { for byte in &buf[..n] { statemachine.advance(&mut performer, *byte); } - }, + } Err(err) => { println!("err: {}", err); break; - }, + } } } } diff --git a/rustfmt.toml b/rustfmt.toml deleted file mode 100644 index 9308ba98..00000000 --- a/rustfmt.toml +++ /dev/null @@ -1,13 +0,0 @@ -format_code_in_doc_comments = true -match_block_trailing_comma = true -condense_wildcard_suffixes = true -use_field_init_shorthand = true -overflow_delimited_expr = true -use_small_heuristics = "Max" -normalize_comments = true -reorder_impl_items = true -use_try_shorthand = true -newline_style = "Unix" -format_strings = true -wrap_comments = true -comment_width = 100 diff --git a/src/lib.rs b/src/lib.rs index f8292082..8cf6592d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -151,7 +151,7 @@ impl Parser { Action::None => (), action => { self.perform_action(performer, action, $arg); - }, + } } }; } @@ -160,15 +160,15 @@ impl Parser { State::Anywhere => { // Just run the action self.perform_action(performer, action, byte); - }, + } state => { match self.state { State::DcsPassthrough => { self.perform_action(performer, Action::Unhook, byte); - }, + } State::OscString => { self.perform_action(performer, Action::OscEnd, byte); - }, + } _ => (), } @@ -177,19 +177,19 @@ impl Parser { match state { State::CsiEntry | State::DcsEntry | State::Escape => { self.perform_action(performer, Action::Clear, byte); - }, + } State::DcsPassthrough => { self.perform_action(performer, Action::Hook, byte); - }, + } State::OscString => { self.perform_action(performer, Action::OscStart, byte); - }, + } _ => (), } // Assume the new state self.state = state; - }, + } } } @@ -225,13 +225,18 @@ impl Parser { self.params.push(self.param); } - performer.hook(self.params(), self.intermediates(), self.ignoring, byte as char); - }, + performer.hook( + self.params(), + self.intermediates(), + self.ignoring, + byte as char, + ); + } Action::Put => performer.put(byte), Action::OscStart => { self.osc_raw.clear(); self.osc_num_params = 0; - }, + } Action::OscPut => { #[cfg(feature = "no_std")] { @@ -252,21 +257,21 @@ impl Parser { // First param is special - 0 to current byte index 0 => { self.osc_params[param_idx] = (0, idx); - }, + } // All other params depend on previous indexing _ => { let prev = self.osc_params[param_idx - 1]; let begin = prev.1; self.osc_params[param_idx] = (begin, idx); - }, + } } self.osc_num_params += 1; } else { self.osc_raw.push(byte); } - }, + } Action::OscEnd => { let param_idx = self.osc_num_params; let idx = self.osc_raw.len(); @@ -279,7 +284,7 @@ impl Parser { 0 => { self.osc_params[param_idx] = (0, idx); self.osc_num_params += 1; - }, + } // All other params depend on previous indexing _ => { @@ -287,10 +292,10 @@ impl Parser { let begin = prev.1; self.osc_params[param_idx] = (begin, idx); self.osc_num_params += 1; - }, + } } self.osc_dispatch(performer, byte); - }, + } Action::Unhook => performer.unhook(), Action::CsiDispatch => { if self.params.is_full() { @@ -305,10 +310,10 @@ impl Parser { self.ignoring, byte as char, ); - }, + } Action::EscDispatch => { performer.esc_dispatch(self.intermediates(), self.ignoring, byte); - }, + } Action::Collect => { if self.intermediate_idx == MAX_INTERMEDIATES { self.ignoring = true; @@ -316,7 +321,7 @@ impl Parser { self.intermediates[self.intermediate_idx] = byte; self.intermediate_idx += 1; } - }, + } Action::Param => { if self.params.is_full() { self.ignoring = true; @@ -334,7 +339,7 @@ impl Parser { self.param = self.param.saturating_mul(10); self.param = self.param.saturating_add((byte - b'0') as u16); } - }, + } Action::Clear => { // Reset everything on ESC/CSI/DCS entry self.intermediate_idx = 0; @@ -342,7 +347,7 @@ impl Parser { self.param = 0; self.params.clear(); - }, + } Action::BeginUtf8 => self.process_utf8(performer, byte), Action::Ignore => (), Action::None => (), @@ -453,18 +458,21 @@ mod tests { fn csi_dispatch(&mut self, params: &Params, intermediates: &[u8], ignore: bool, c: char) { let params = params.iter().map(|subparam| subparam.to_vec()).collect(); let intermediates = intermediates.to_vec(); - self.dispatched.push(Sequence::Csi(params, intermediates, ignore, c)); + self.dispatched + .push(Sequence::Csi(params, intermediates, ignore, c)); } fn esc_dispatch(&mut self, intermediates: &[u8], ignore: bool, byte: u8) { let intermediates = intermediates.to_vec(); - self.dispatched.push(Sequence::Esc(intermediates, ignore, byte)); + self.dispatched + .push(Sequence::Esc(intermediates, ignore, byte)); } fn hook(&mut self, params: &Params, intermediates: &[u8], ignore: bool, c: char) { let params = params.iter().map(|subparam| subparam.to_vec()).collect(); let intermediates = intermediates.to_vec(); - self.dispatched.push(Sequence::DcsHook(params, intermediates, ignore, c)); + self.dispatched + .push(Sequence::DcsHook(params, intermediates, ignore, c)); } fn put(&mut self, byte: u8) { @@ -491,7 +499,7 @@ mod tests { assert_eq!(params.len(), 2); assert_eq!(params[0], &OSC_BYTES[2..3]); assert_eq!(params[1], &OSC_BYTES[4..(OSC_BYTES.len() - 1)]); - }, + } _ => panic!("expected osc sequence"), } } @@ -528,7 +536,7 @@ mod tests { Sequence::Osc(params, _) => { assert_eq!(params.len(), MAX_OSC_PARAMS); assert!(params.iter().all(Vec::is_empty)); - }, + } _ => panic!("expected osc sequence"), } } @@ -586,7 +594,7 @@ mod tests { Sequence::Osc(params, _) => { assert_eq!(params[0], &[b'2']); assert_eq!(params[1], &INPUT[5..(INPUT.len() - 1)]); - }, + } _ => panic!("expected osc sequence"), } } @@ -605,7 +613,7 @@ mod tests { match &dispatcher.dispatched[0] { Sequence::Osc(params, _) => { assert_eq!(params[1], &INPUT[4..(INPUT.len() - 2)]); - }, + } _ => panic!("expected osc sequence"), } } @@ -645,7 +653,7 @@ mod tests { #[cfg(feature = "no_std")] assert_eq!(params[1].len(), MAX_OSC_RAW - params[0].len()); - }, + } _ => panic!("expected osc sequence"), } } @@ -670,7 +678,7 @@ mod tests { Sequence::Csi(params, _, ignore, _) => { assert_eq!(params.len(), params::MAX_PARAMS); assert!(!ignore); - }, + } _ => panic!("expected csi sequence"), } } @@ -695,7 +703,7 @@ mod tests { Sequence::Csi(params, _, ignore, _) => { assert_eq!(params.len(), params::MAX_PARAMS); assert!(ignore); - }, + } _ => panic!("expected csi sequence"), } } @@ -767,7 +775,7 @@ mod tests { assert_eq!(intermediates, &[b'?']); assert_eq!(params, &[[1049]]); assert!(!ignore); - }, + } _ => panic!("expected csi sequence"), } } @@ -788,7 +796,7 @@ mod tests { assert_eq!(params, &[vec![38, 2, 255, 0, 255], vec![1]]); assert_eq!(intermediates, &[]); assert!(!ignore); - }, + } _ => panic!("expected csi sequence"), } } @@ -810,7 +818,7 @@ mod tests { assert_eq!(params.len(), params::MAX_PARAMS); assert!(params.iter().all(|param| param == &[1])); assert!(ignore); - }, + } _ => panic!("expected dcs sequence"), } } @@ -831,7 +839,7 @@ mod tests { assert_eq!(intermediates, &[b'$']); assert_eq!(params, &[[1]]); assert!(!ignore); - }, + } _ => panic!("expected dcs sequence"), } assert_eq!(dispatcher.dispatched[1], Sequence::DcsPut(b'x')); @@ -853,7 +861,7 @@ mod tests { Sequence::DcsHook(params, _, _, c) => { assert_eq!(params, &[[0], [1]]); assert_eq!(c, &'|'); - }, + } _ => panic!("expected dcs sequence"), } for (i, byte) in b"17/ab".iter().enumerate() { @@ -895,7 +903,7 @@ mod tests { assert_eq!(intermediates, &[b'(']); assert_eq!(*byte, b'A'); assert!(!ignore); - }, + } _ => panic!("expected esc sequence"), } } @@ -917,7 +925,7 @@ mod tests { assert_eq!(params, &[[0; 32]]); assert_eq!(c, &'x'); assert!(ignore); - }, + } _ => panic!("expected csi sequence"), } } From f1e65aa7c409a49efcc15cb50809a75e551f633a Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 27 Feb 2023 17:43:59 -0600 Subject: [PATCH 99/99] chore: Move files into place --- .builds/linux.yml | 21 ------------------- .gitignore | 2 -- .../anstyle-parse/CHANGELOG.md | 0 Cargo.toml => crates/anstyle-parse/Cargo.toml | 0 .../anstyle-parse/LICENSE-APACHE | 0 .../anstyle-parse/LICENSE-MIT | 0 README.md => crates/anstyle-parse/README.md | 0 .../anstyle-parse/examples}/parselog.rs | 0 .../anstyle-parse/src}/definitions.rs | 0 {src => crates/anstyle-parse/src}/lib.rs | 0 {src => crates/anstyle-parse/src}/params.rs | 0 {src => crates/anstyle-parse/src}/table.rs | 0 .../anstyle-parse/tests}/demo.vte | 0 13 files changed, 23 deletions(-) delete mode 100644 .builds/linux.yml delete mode 100644 .gitignore rename CHANGELOG.md => crates/anstyle-parse/CHANGELOG.md (100%) rename Cargo.toml => crates/anstyle-parse/Cargo.toml (100%) rename LICENSE-APACHE => crates/anstyle-parse/LICENSE-APACHE (100%) rename LICENSE-MIT => crates/anstyle-parse/LICENSE-MIT (100%) rename README.md => crates/anstyle-parse/README.md (100%) rename {examples => crates/anstyle-parse/examples}/parselog.rs (100%) rename {src => crates/anstyle-parse/src}/definitions.rs (100%) rename {src => crates/anstyle-parse/src}/lib.rs (100%) rename {src => crates/anstyle-parse/src}/params.rs (100%) rename {src => crates/anstyle-parse/src}/table.rs (100%) rename {tests => crates/anstyle-parse/tests}/demo.vte (100%) diff --git a/.builds/linux.yml b/.builds/linux.yml deleted file mode 100644 index a574963d..00000000 --- a/.builds/linux.yml +++ /dev/null @@ -1,21 +0,0 @@ -image: archlinux -sources: - - https://github.com/alacritty/vte -tasks: - - rustup: | - curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain stable --profile minimal -c clippy - - stable: | - cd vte - $HOME/.cargo/bin/cargo +stable test - - clippy: | - cd vte - $HOME/.cargo/bin/cargo +stable clippy - - rustfmt: | - $HOME/.cargo/bin/rustup toolchain install nightly -c rustfmt - cd vte - $HOME/.cargo/bin/cargo +nightly fmt -- --check - - 1-56-0: | - $HOME/.cargo/bin/rustup toolchain install --profile minimal 1.56.0 - cd vte - rm Cargo.lock - $HOME/.cargo/bin/cargo +1.56.0 test diff --git a/.gitignore b/.gitignore deleted file mode 100644 index a9d37c56..00000000 --- a/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -target -Cargo.lock diff --git a/CHANGELOG.md b/crates/anstyle-parse/CHANGELOG.md similarity index 100% rename from CHANGELOG.md rename to crates/anstyle-parse/CHANGELOG.md diff --git a/Cargo.toml b/crates/anstyle-parse/Cargo.toml similarity index 100% rename from Cargo.toml rename to crates/anstyle-parse/Cargo.toml diff --git a/LICENSE-APACHE b/crates/anstyle-parse/LICENSE-APACHE similarity index 100% rename from LICENSE-APACHE rename to crates/anstyle-parse/LICENSE-APACHE diff --git a/LICENSE-MIT b/crates/anstyle-parse/LICENSE-MIT similarity index 100% rename from LICENSE-MIT rename to crates/anstyle-parse/LICENSE-MIT diff --git a/README.md b/crates/anstyle-parse/README.md similarity index 100% rename from README.md rename to crates/anstyle-parse/README.md diff --git a/examples/parselog.rs b/crates/anstyle-parse/examples/parselog.rs similarity index 100% rename from examples/parselog.rs rename to crates/anstyle-parse/examples/parselog.rs diff --git a/src/definitions.rs b/crates/anstyle-parse/src/definitions.rs similarity index 100% rename from src/definitions.rs rename to crates/anstyle-parse/src/definitions.rs diff --git a/src/lib.rs b/crates/anstyle-parse/src/lib.rs similarity index 100% rename from src/lib.rs rename to crates/anstyle-parse/src/lib.rs diff --git a/src/params.rs b/crates/anstyle-parse/src/params.rs similarity index 100% rename from src/params.rs rename to crates/anstyle-parse/src/params.rs diff --git a/src/table.rs b/crates/anstyle-parse/src/table.rs similarity index 100% rename from src/table.rs rename to crates/anstyle-parse/src/table.rs diff --git a/tests/demo.vte b/crates/anstyle-parse/tests/demo.vte similarity index 100% rename from tests/demo.vte rename to crates/anstyle-parse/tests/demo.vte