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