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