1 | #![allow (non_upper_case_globals, missing_docs)] |
2 | |
3 | //! ncurses-compatible compiled terminfo format parsing (term(5)) |
4 | |
5 | use super::super::TermInfo; |
6 | use std::collections::HashMap; |
7 | use std::io; |
8 | use std::io::prelude::*; |
9 | |
10 | #[cfg (test)] |
11 | mod tests; |
12 | |
13 | // These are the orders ncurses uses in its compiled format (as of 5.9). Not sure if portable. |
14 | |
15 | #[rustfmt::skip] |
16 | pub(crate) static boolfnames: &[&str] = &["auto_left_margin" , "auto_right_margin" , |
17 | "no_esc_ctlc" , "ceol_standout_glitch" , "eat_newline_glitch" , "erase_overstrike" , "generic_type" , |
18 | "hard_copy" , "has_meta_key" , "has_status_line" , "insert_null_glitch" , "memory_above" , |
19 | "memory_below" , "move_insert_mode" , "move_standout_mode" , "over_strike" , "status_line_esc_ok" , |
20 | "dest_tabs_magic_smso" , "tilde_glitch" , "transparent_underline" , "xon_xoff" , "needs_xon_xoff" , |
21 | "prtr_silent" , "hard_cursor" , "non_rev_rmcup" , "no_pad_char" , "non_dest_scroll_region" , |
22 | "can_change" , "back_color_erase" , "hue_lightness_saturation" , "col_addr_glitch" , |
23 | "cr_cancels_micro_mode" , "has_print_wheel" , "row_addr_glitch" , "semi_auto_right_margin" , |
24 | "cpi_changes_res" , "lpi_changes_res" , "backspaces_with_bs" , "crt_no_scrolling" , |
25 | "no_correctly_working_cr" , "gnu_has_meta_key" , "linefeed_is_newline" , "has_hardware_tabs" , |
26 | "return_does_clr_eol" ]; |
27 | |
28 | #[rustfmt::skip] |
29 | pub(crate) static boolnames: &[&str] = &["bw" , "am" , "xsb" , "xhp" , "xenl" , "eo" , |
30 | "gn" , "hc" , "km" , "hs" , "in" , "db" , "da" , "mir" , "msgr" , "os" , "eslok" , "xt" , "hz" , "ul" , "xon" , |
31 | "nxon" , "mc5i" , "chts" , "nrrmc" , "npc" , "ndscr" , "ccc" , "bce" , "hls" , "xhpa" , "crxm" , "daisy" , |
32 | "xvpa" , "sam" , "cpix" , "lpix" , "OTbs" , "OTns" , "OTnc" , "OTMT" , "OTNL" , "OTpt" , "OTxr" ]; |
33 | |
34 | #[rustfmt::skip] |
35 | pub(crate) static numfnames: &[&str] = &[ "columns" , "init_tabs" , "lines" , |
36 | "lines_of_memory" , "magic_cookie_glitch" , "padding_baud_rate" , "virtual_terminal" , |
37 | "width_status_line" , "num_labels" , "label_height" , "label_width" , "max_attributes" , |
38 | "maximum_windows" , "max_colors" , "max_pairs" , "no_color_video" , "buffer_capacity" , |
39 | "dot_vert_spacing" , "dot_horz_spacing" , "max_micro_address" , "max_micro_jump" , "micro_col_size" , |
40 | "micro_line_size" , "number_of_pins" , "output_res_char" , "output_res_line" , |
41 | "output_res_horz_inch" , "output_res_vert_inch" , "print_rate" , "wide_char_size" , "buttons" , |
42 | "bit_image_entwining" , "bit_image_type" , "magic_cookie_glitch_ul" , "carriage_return_delay" , |
43 | "new_line_delay" , "backspace_delay" , "horizontal_tab_delay" , "number_of_function_keys" ]; |
44 | |
45 | #[rustfmt::skip] |
46 | pub(crate) static numnames: &[&str] = &[ "cols" , "it" , "lines" , "lm" , "xmc" , "pb" , |
47 | "vt" , "wsl" , "nlab" , "lh" , "lw" , "ma" , "wnum" , "colors" , "pairs" , "ncv" , "bufsz" , "spinv" , |
48 | "spinh" , "maddr" , "mjump" , "mcs" , "mls" , "npins" , "orc" , "orl" , "orhi" , "orvi" , "cps" , "widcs" , |
49 | "btns" , "bitwin" , "bitype" , "UTug" , "OTdC" , "OTdN" , "OTdB" , "OTdT" , "OTkn" ]; |
50 | |
51 | #[rustfmt::skip] |
52 | pub(crate) static stringfnames: &[&str] = &[ "back_tab" , "bell" , "carriage_return" , |
53 | "change_scroll_region" , "clear_all_tabs" , "clear_screen" , "clr_eol" , "clr_eos" , |
54 | "column_address" , "command_character" , "cursor_address" , "cursor_down" , "cursor_home" , |
55 | "cursor_invisible" , "cursor_left" , "cursor_mem_address" , "cursor_normal" , "cursor_right" , |
56 | "cursor_to_ll" , "cursor_up" , "cursor_visible" , "delete_character" , "delete_line" , |
57 | "dis_status_line" , "down_half_line" , "enter_alt_charset_mode" , "enter_blink_mode" , |
58 | "enter_bold_mode" , "enter_ca_mode" , "enter_delete_mode" , "enter_dim_mode" , "enter_insert_mode" , |
59 | "enter_secure_mode" , "enter_protected_mode" , "enter_reverse_mode" , "enter_standout_mode" , |
60 | "enter_underline_mode" , "erase_chars" , "exit_alt_charset_mode" , "exit_attribute_mode" , |
61 | "exit_ca_mode" , "exit_delete_mode" , "exit_insert_mode" , "exit_standout_mode" , |
62 | "exit_underline_mode" , "flash_screen" , "form_feed" , "from_status_line" , "init_1string" , |
63 | "init_2string" , "init_3string" , "init_file" , "insert_character" , "insert_line" , |
64 | "insert_padding" , "key_backspace" , "key_catab" , "key_clear" , "key_ctab" , "key_dc" , "key_dl" , |
65 | "key_down" , "key_eic" , "key_eol" , "key_eos" , "key_f0" , "key_f1" , "key_f10" , "key_f2" , "key_f3" , |
66 | "key_f4" , "key_f5" , "key_f6" , "key_f7" , "key_f8" , "key_f9" , "key_home" , "key_ic" , "key_il" , |
67 | "key_left" , "key_ll" , "key_npage" , "key_ppage" , "key_right" , "key_sf" , "key_sr" , "key_stab" , |
68 | "key_up" , "keypad_local" , "keypad_xmit" , "lab_f0" , "lab_f1" , "lab_f10" , "lab_f2" , "lab_f3" , |
69 | "lab_f4" , "lab_f5" , "lab_f6" , "lab_f7" , "lab_f8" , "lab_f9" , "meta_off" , "meta_on" , "newline" , |
70 | "pad_char" , "parm_dch" , "parm_delete_line" , "parm_down_cursor" , "parm_ich" , "parm_index" , |
71 | "parm_insert_line" , "parm_left_cursor" , "parm_right_cursor" , "parm_rindex" , "parm_up_cursor" , |
72 | "pkey_key" , "pkey_local" , "pkey_xmit" , "print_screen" , "prtr_off" , "prtr_on" , "repeat_char" , |
73 | "reset_1string" , "reset_2string" , "reset_3string" , "reset_file" , "restore_cursor" , |
74 | "row_address" , "save_cursor" , "scroll_forward" , "scroll_reverse" , "set_attributes" , "set_tab" , |
75 | "set_window" , "tab" , "to_status_line" , "underline_char" , "up_half_line" , "init_prog" , "key_a1" , |
76 | "key_a3" , "key_b2" , "key_c1" , "key_c3" , "prtr_non" , "char_padding" , "acs_chars" , "plab_norm" , |
77 | "key_btab" , "enter_xon_mode" , "exit_xon_mode" , "enter_am_mode" , "exit_am_mode" , "xon_character" , |
78 | "xoff_character" , "ena_acs" , "label_on" , "label_off" , "key_beg" , "key_cancel" , "key_close" , |
79 | "key_command" , "key_copy" , "key_create" , "key_end" , "key_enter" , "key_exit" , "key_find" , |
80 | "key_help" , "key_mark" , "key_message" , "key_move" , "key_next" , "key_open" , "key_options" , |
81 | "key_previous" , "key_print" , "key_redo" , "key_reference" , "key_refresh" , "key_replace" , |
82 | "key_restart" , "key_resume" , "key_save" , "key_suspend" , "key_undo" , "key_sbeg" , "key_scancel" , |
83 | "key_scommand" , "key_scopy" , "key_screate" , "key_sdc" , "key_sdl" , "key_select" , "key_send" , |
84 | "key_seol" , "key_sexit" , "key_sfind" , "key_shelp" , "key_shome" , "key_sic" , "key_sleft" , |
85 | "key_smessage" , "key_smove" , "key_snext" , "key_soptions" , "key_sprevious" , "key_sprint" , |
86 | "key_sredo" , "key_sreplace" , "key_sright" , "key_srsume" , "key_ssave" , "key_ssuspend" , |
87 | "key_sundo" , "req_for_input" , "key_f11" , "key_f12" , "key_f13" , "key_f14" , "key_f15" , "key_f16" , |
88 | "key_f17" , "key_f18" , "key_f19" , "key_f20" , "key_f21" , "key_f22" , "key_f23" , "key_f24" , |
89 | "key_f25" , "key_f26" , "key_f27" , "key_f28" , "key_f29" , "key_f30" , "key_f31" , "key_f32" , |
90 | "key_f33" , "key_f34" , "key_f35" , "key_f36" , "key_f37" , "key_f38" , "key_f39" , "key_f40" , |
91 | "key_f41" , "key_f42" , "key_f43" , "key_f44" , "key_f45" , "key_f46" , "key_f47" , "key_f48" , |
92 | "key_f49" , "key_f50" , "key_f51" , "key_f52" , "key_f53" , "key_f54" , "key_f55" , "key_f56" , |
93 | "key_f57" , "key_f58" , "key_f59" , "key_f60" , "key_f61" , "key_f62" , "key_f63" , "clr_bol" , |
94 | "clear_margins" , "set_left_margin" , "set_right_margin" , "label_format" , "set_clock" , |
95 | "display_clock" , "remove_clock" , "create_window" , "goto_window" , "hangup" , "dial_phone" , |
96 | "quick_dial" , "tone" , "pulse" , "flash_hook" , "fixed_pause" , "wait_tone" , "user0" , "user1" , |
97 | "user2" , "user3" , "user4" , "user5" , "user6" , "user7" , "user8" , "user9" , "orig_pair" , |
98 | "orig_colors" , "initialize_color" , "initialize_pair" , "set_color_pair" , "set_foreground" , |
99 | "set_background" , "change_char_pitch" , "change_line_pitch" , "change_res_horz" , |
100 | "change_res_vert" , "define_char" , "enter_doublewide_mode" , "enter_draft_quality" , |
101 | "enter_italics_mode" , "enter_leftward_mode" , "enter_micro_mode" , "enter_near_letter_quality" , |
102 | "enter_normal_quality" , "enter_shadow_mode" , "enter_subscript_mode" , "enter_superscript_mode" , |
103 | "enter_upward_mode" , "exit_doublewide_mode" , "exit_italics_mode" , "exit_leftward_mode" , |
104 | "exit_micro_mode" , "exit_shadow_mode" , "exit_subscript_mode" , "exit_superscript_mode" , |
105 | "exit_upward_mode" , "micro_column_address" , "micro_down" , "micro_left" , "micro_right" , |
106 | "micro_row_address" , "micro_up" , "order_of_pins" , "parm_down_micro" , "parm_left_micro" , |
107 | "parm_right_micro" , "parm_up_micro" , "select_char_set" , "set_bottom_margin" , |
108 | "set_bottom_margin_parm" , "set_left_margin_parm" , "set_right_margin_parm" , "set_top_margin" , |
109 | "set_top_margin_parm" , "start_bit_image" , "start_char_set_def" , "stop_bit_image" , |
110 | "stop_char_set_def" , "subscript_characters" , "superscript_characters" , "these_cause_cr" , |
111 | "zero_motion" , "char_set_names" , "key_mouse" , "mouse_info" , "req_mouse_pos" , "get_mouse" , |
112 | "set_a_foreground" , "set_a_background" , "pkey_plab" , "device_type" , "code_set_init" , |
113 | "set0_des_seq" , "set1_des_seq" , "set2_des_seq" , "set3_des_seq" , "set_lr_margin" , |
114 | "set_tb_margin" , "bit_image_repeat" , "bit_image_newline" , "bit_image_carriage_return" , |
115 | "color_names" , "define_bit_image_region" , "end_bit_image_region" , "set_color_band" , |
116 | "set_page_length" , "display_pc_char" , "enter_pc_charset_mode" , "exit_pc_charset_mode" , |
117 | "enter_scancode_mode" , "exit_scancode_mode" , "pc_term_options" , "scancode_escape" , |
118 | "alt_scancode_esc" , "enter_horizontal_hl_mode" , "enter_left_hl_mode" , "enter_low_hl_mode" , |
119 | "enter_right_hl_mode" , "enter_top_hl_mode" , "enter_vertical_hl_mode" , "set_a_attributes" , |
120 | "set_pglen_inch" , "termcap_init2" , "termcap_reset" , "linefeed_if_not_lf" , "backspace_if_not_bs" , |
121 | "other_non_function_keys" , "arrow_key_map" , "acs_ulcorner" , "acs_llcorner" , "acs_urcorner" , |
122 | "acs_lrcorner" , "acs_ltee" , "acs_rtee" , "acs_btee" , "acs_ttee" , "acs_hline" , "acs_vline" , |
123 | "acs_plus" , "memory_lock" , "memory_unlock" , "box_chars_1" ]; |
124 | |
125 | #[rustfmt::skip] |
126 | pub(crate) static stringnames: &[&str] = &[ "cbt" , "_" , "cr" , "csr" , "tbc" , "clear" , |
127 | "_" , "_" , "hpa" , "cmdch" , "cup" , "cud1" , "home" , "civis" , "cub1" , "mrcup" , "cnorm" , "cuf1" , |
128 | "ll" , "cuu1" , "cvvis" , "dch1" , "dl1" , "dsl" , "hd" , "smacs" , "blink" , "bold" , "smcup" , "smdc" , |
129 | "dim" , "smir" , "invis" , "prot" , "rev" , "smso" , "smul" , "ech" , "rmacs" , "sgr0" , "rmcup" , "rmdc" , |
130 | "rmir" , "rmso" , "rmul" , "flash" , "ff" , "fsl" , "is1" , "is2" , "is3" , "if" , "ich1" , "il1" , "ip" , |
131 | "kbs" , "ktbc" , "kclr" , "kctab" , "_" , "_" , "kcud1" , "_" , "_" , "_" , "_" , "_" , "_" , "_" , "_" , "_" , |
132 | "_" , "_" , "_" , "_" , "_" , "khome" , "_" , "_" , "kcub1" , "_" , "knp" , "kpp" , "kcuf1" , "_" , "_" , |
133 | "khts" , "_" , "rmkx" , "smkx" , "_" , "_" , "_" , "_" , "_" , "_" , "_" , "_" , "_" , "_" , "_" , "rmm" , "_" , |
134 | "_" , "pad" , "dch" , "dl" , "cud" , "ich" , "indn" , "il" , "cub" , "cuf" , "rin" , "cuu" , "pfkey" , |
135 | "pfloc" , "pfx" , "mc0" , "mc4" , "_" , "rep" , "rs1" , "rs2" , "rs3" , "rf" , "rc" , "vpa" , "sc" , "ind" , |
136 | "ri" , "sgr" , "_" , "wind" , "_" , "tsl" , "uc" , "hu" , "iprog" , "_" , "_" , "_" , "_" , "_" , "mc5p" , |
137 | "rmp" , "acsc" , "pln" , "kcbt" , "smxon" , "rmxon" , "smam" , "rmam" , "xonc" , "xoffc" , "_" , "smln" , |
138 | "rmln" , "_" , "kcan" , "kclo" , "kcmd" , "kcpy" , "kcrt" , "_" , "kent" , "kext" , "kfnd" , "khlp" , |
139 | "kmrk" , "kmsg" , "kmov" , "knxt" , "kopn" , "kopt" , "kprv" , "kprt" , "krdo" , "kref" , "krfr" , "krpl" , |
140 | "krst" , "kres" , "ksav" , "kspd" , "kund" , "kBEG" , "kCAN" , "kCMD" , "kCPY" , "kCRT" , "_" , "_" , |
141 | "kslt" , "kEND" , "kEOL" , "kEXT" , "kFND" , "kHLP" , "kHOM" , "_" , "kLFT" , "kMSG" , "kMOV" , "kNXT" , |
142 | "kOPT" , "kPRV" , "kPRT" , "kRDO" , "kRPL" , "kRIT" , "kRES" , "kSAV" , "kSPD" , "kUND" , "rfi" , "_" , "_" , |
143 | "_" , "_" , "_" , "_" , "_" , "_" , "_" , "_" , "_" , "_" , "_" , "_" , "_" , "_" , "_" , "_" , "_" , "_" , "_" , |
144 | "_" , "_" , "_" , "_" , "_" , "_" , "_" , "_" , "_" , "_" , "_" , "_" , "_" , "_" , "_" , "_" , "_" , "_" , "_" , |
145 | "_" , "_" , "_" , "_" , "_" , "_" , "_" , "_" , "_" , "_" , "_" , "_" , "_" , "_" , "_" , "_" , "_" , "_" , "_" , |
146 | "dclk" , "rmclk" , "cwin" , "wingo" , "_" , "dial" , "qdial" , "_" , "_" , "hook" , "pause" , "wait" , "_" , |
147 | "_" , "_" , "_" , "_" , "_" , "_" , "_" , "_" , "_" , "op" , "oc" , "initc" , "initp" , "scp" , "setf" , |
148 | "setb" , "cpi" , "lpi" , "chr" , "cvr" , "defc" , "swidm" , "sdrfq" , "sitm" , "slm" , "smicm" , "snlq" , |
149 | "snrmq" , "sshm" , "ssubm" , "ssupm" , "sum" , "rwidm" , "ritm" , "rlm" , "rmicm" , "rshm" , "rsubm" , |
150 | "rsupm" , "rum" , "mhpa" , "mcud1" , "mcub1" , "mcuf1" , "mvpa" , "mcuu1" , "porder" , "mcud" , "mcub" , |
151 | "mcuf" , "mcuu" , "scs" , "smgb" , "smgbp" , "smglp" , "smgrp" , "smgt" , "smgtp" , "sbim" , "scsd" , |
152 | "rbim" , "rcsd" , "subcs" , "supcs" , "docr" , "zerom" , "csnm" , "kmous" , "minfo" , "reqmp" , "getm" , |
153 | "setaf" , "setab" , "pfxl" , "devt" , "csin" , "s0ds" , "s1ds" , "s2ds" , "s3ds" , "smglr" , "smgtb" , |
154 | "birep" , "binel" , "bicr" , "colornm" , "defbi" , "endbi" , "setcolor" , "slines" , "dispc" , "smpch" , |
155 | "rmpch" , "smsc" , "rmsc" , "pctrm" , "scesc" , "scesa" , "ehhlm" , "elhlm" , "elohlm" , "erhlm" , |
156 | "ethlm" , "evhlm" , "sgr1" , "slength" , "OTi2" , "OTrs" , "OTnl" , "OTbs" , "OTko" , "OTma" , "OTG2" , |
157 | "OTG3" , "OTG1" , "OTG4" , "OTGR" , "OTGL" , "OTGU" , "OTGD" , "OTGH" , "OTGV" , "OTGC" , "meml" , "memu" , |
158 | "box1" ]; |
159 | |
160 | fn read_le_u16(r: &mut dyn io::Read) -> io::Result<u16> { |
161 | let mut b: [i32; 2] = [0; 2]; |
162 | r.read_exact(&mut b)?; |
163 | Ok((b[0] as u16) | ((b[1] as u16) << 8)) |
164 | } |
165 | |
166 | fn read_le_u32(r: &mut dyn io::Read) -> io::Result<u32> { |
167 | let mut b: [i32; 4] = [0; 4]; |
168 | r.read_exact(&mut b)?; |
169 | Ok((b[0] as u32) | ((b[1] as u32) << 8) | ((b[2] as u32) << 16) | ((b[3] as u32) << 24)) |
170 | } |
171 | |
172 | fn read_byte(r: &mut dyn io::Read) -> io::Result<u8> { |
173 | match r.bytes().next() { |
174 | Some(s) => s, |
175 | None => Err(io::Error::new(io::ErrorKind::Other, "end of file" )), |
176 | } |
177 | } |
178 | |
179 | /// Parse a compiled terminfo entry, using long capability names if `longnames` |
180 | /// is true |
181 | pub(crate) fn parse(file: &mut dyn io::Read, longnames: bool) -> Result<TermInfo, String> { |
182 | macro_rules! t( ($e:expr) => ( |
183 | match $e { |
184 | Ok(e) => e, |
185 | Err(e) => return Err(e.to_string()) |
186 | } |
187 | ) ); |
188 | |
189 | let (bnames, snames, nnames) = if longnames { |
190 | (boolfnames, stringfnames, numfnames) |
191 | } else { |
192 | (boolnames, stringnames, numnames) |
193 | }; |
194 | |
195 | // Check magic number |
196 | let magic = t!(read_le_u16(file)); |
197 | |
198 | let extended = match magic { |
199 | 0o0432 => false, |
200 | 0o01036 => true, |
201 | _ => return Err(format!("invalid magic number, found {magic:o}" )), |
202 | }; |
203 | |
204 | // According to the spec, these fields must be >= -1 where -1 means that the feature is not |
205 | // supported. Using 0 instead of -1 works because we skip sections with length 0. |
206 | macro_rules! read_nonneg { |
207 | () => {{ |
208 | match t!(read_le_u16(file)) as i16 { |
209 | n if n >= 0 => n as usize, |
210 | -1 => 0, |
211 | _ => return Err("incompatible file: length fields must be >= -1" .to_string()), |
212 | } |
213 | }}; |
214 | } |
215 | |
216 | let names_bytes = read_nonneg!(); |
217 | let bools_bytes = read_nonneg!(); |
218 | let numbers_count = read_nonneg!(); |
219 | let string_offsets_count = read_nonneg!(); |
220 | let string_table_bytes = read_nonneg!(); |
221 | |
222 | if names_bytes == 0 { |
223 | return Err("incompatible file: names field must be at least 1 byte wide" .to_string()); |
224 | } |
225 | |
226 | if bools_bytes > boolnames.len() { |
227 | return Err("incompatible file: more booleans than expected" .to_string()); |
228 | } |
229 | |
230 | if numbers_count > numnames.len() { |
231 | return Err("incompatible file: more numbers than expected" .to_string()); |
232 | } |
233 | |
234 | if string_offsets_count > stringnames.len() { |
235 | return Err("incompatible file: more string offsets than expected" .to_string()); |
236 | } |
237 | |
238 | // don't read NUL |
239 | let mut bytes = Vec::new(); |
240 | t!(file.take((names_bytes - 1) as u64).read_to_end(&mut bytes)); |
241 | let names_str = match String::from_utf8(bytes) { |
242 | Ok(s) => s, |
243 | Err(_) => return Err("input not utf-8" .to_string()), |
244 | }; |
245 | |
246 | let term_names: Vec<String> = names_str.split('|' ).map(|s| s.to_string()).collect(); |
247 | // consume NUL |
248 | if t!(read_byte(file)) != b' \0' { |
249 | return Err("incompatible file: missing null terminator for names section" .to_string()); |
250 | } |
251 | |
252 | let bools_map: HashMap<String, bool> = t! { |
253 | (0..bools_bytes).filter_map(|i| match read_byte(file) { |
254 | Err(e) => Some(Err(e)), |
255 | Ok(1) => Some(Ok((bnames[i].to_string(), true))), |
256 | Ok(_) => None |
257 | }).collect() |
258 | }; |
259 | |
260 | if (bools_bytes + names_bytes) % 2 == 1 { |
261 | t!(read_byte(file)); // compensate for padding |
262 | } |
263 | |
264 | let numbers_map: HashMap<String, u32> = t! { |
265 | (0..numbers_count).filter_map(|i| { |
266 | let number = if extended { read_le_u32(file) } else { read_le_u16(file).map(Into::into) }; |
267 | |
268 | match number { |
269 | Ok(0xFFFF) => None, |
270 | Ok(n) => Some(Ok((nnames[i].to_string(), n))), |
271 | Err(e) => Some(Err(e)) |
272 | } |
273 | }).collect() |
274 | }; |
275 | |
276 | let string_map: HashMap<String, Vec<u8>> = if string_offsets_count > 0 { |
277 | let string_offsets: Vec<u16> = |
278 | t!((0..string_offsets_count).map(|_| read_le_u16(file)).collect()); |
279 | |
280 | let mut string_table = Vec::new(); |
281 | t!(file.take(string_table_bytes as u64).read_to_end(&mut string_table)); |
282 | |
283 | t!(string_offsets |
284 | .into_iter() |
285 | .enumerate() |
286 | .filter(|&(_, offset)| { |
287 | // non-entry |
288 | offset != 0xFFFF |
289 | }) |
290 | .map(|(i, offset)| { |
291 | let offset = offset as usize; |
292 | |
293 | let name = if snames[i] == "_" { stringfnames[i] } else { snames[i] }; |
294 | |
295 | if offset == 0xFFFE { |
296 | // undocumented: FFFE indicates cap@, which means the capability is not present |
297 | // unsure if the handling for this is correct |
298 | return Ok((name.to_string(), Vec::new())); |
299 | } |
300 | |
301 | // Find the offset of the NUL we want to go to |
302 | let nulpos = string_table[offset..string_table_bytes].iter().position(|&b| b == 0); |
303 | match nulpos { |
304 | Some(len) => { |
305 | Ok((name.to_string(), string_table[offset..offset + len].to_vec())) |
306 | } |
307 | None => Err("invalid file: missing NUL in string_table" .to_string()), |
308 | } |
309 | }) |
310 | .collect()) |
311 | } else { |
312 | HashMap::new() |
313 | }; |
314 | |
315 | // And that's all there is to it |
316 | Ok(TermInfo { names: term_names, bools: bools_map, numbers: numbers_map, strings: string_map }) |
317 | } |
318 | |
319 | /// Creates a dummy TermInfo struct for msys terminals |
320 | pub(crate) fn msys_terminfo() -> TermInfo { |
321 | let mut strings = HashMap::new(); |
322 | strings.insert("sgr0" .to_string(), b" \x1B[0m" .to_vec()); |
323 | strings.insert("bold" .to_string(), b" \x1B[1m" .to_vec()); |
324 | strings.insert("setaf" .to_string(), b" \x1B[3%p1%dm" .to_vec()); |
325 | strings.insert("setab" .to_string(), b" \x1B[4%p1%dm" .to_vec()); |
326 | |
327 | let mut numbers = HashMap::new(); |
328 | numbers.insert("colors" .to_string(), 8); |
329 | |
330 | TermInfo { |
331 | names: vec!["cygwin" .to_string()], // msys is a fork of an older cygwin version |
332 | bools: HashMap::new(), |
333 | numbers, |
334 | strings, |
335 | } |
336 | } |
337 | |