(index<- ) ./libextra/terminfo/parser/compiled.rs
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
11 #[allow(non_uppercase_statics)];
12
13 /// ncurses-compatible compiled terminfo format parsing (term(5))
14
15
16 use std::{vec, str};
17 use std::io::Reader;
18 use std::hashmap::HashMap;
19 use super::super::TermInfo;
20
21 // These are the orders ncurses uses in its compiled format (as of 5.9). Not sure if portable.
22
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"];
34
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"];
39
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"];
49
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"];
54
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"];
127
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",
160 "box1"];
161
162 /// Parse a compiled terminfo entry, using long capability names if `longnames` is true
163 pub fn parse(file: @Reader, longnames: bool) -> Result<~TermInfo, ~str> {
164 let bnames;
165 let snames;
166 let nnames;
167
168 if longnames {
169 bnames = boolfnames;
170 snames = stringfnames;
171 nnames = numfnames;
172 } else {
173 bnames = boolnames;
174 snames = stringnames;
175 nnames = numnames;
176 }
177
178 // Check magic number
179 let magic = file.read_le_u16();
180 if (magic != 0x011A) {
181 return Err(fmt!("invalid magic number: expected %x but found %x", 0x011A, magic as uint));
182 }
183
184 let names_bytes = file.read_le_i16() as int;
185 let bools_bytes = file.read_le_i16() as int;
186 let numbers_count = file.read_le_i16() as int;
187 let string_offsets_count = file.read_le_i16() as int;
188 let string_table_bytes = file.read_le_i16() as int;
189
190 assert!(names_bytes > 0);
191
192 debug!("names_bytes = %?", names_bytes);
193 debug!("bools_bytes = %?", bools_bytes);
194 debug!("numbers_count = %?", numbers_count);
195 debug!("string_offsets_count = %?", string_offsets_count);
196 debug!("string_table_bytes = %?", string_table_bytes);
197
198 if (bools_bytes as uint) > boolnames.len() {
199 error!("expected bools_bytes to be less than %? but found %?", boolnames.len(),
200 bools_bytes);
201 return Err(~"incompatible file: more booleans than expected");
202 }
203
204 if (numbers_count as uint) > numnames.len() {
205 error!("expected numbers_count to be less than %? but found %?", numnames.len(),
206 numbers_count);
207 return Err(~"incompatible file: more numbers than expected");
208 }
209
210 if (string_offsets_count as uint) > stringnames.len() {
211 error!("expected string_offsets_count to be less than %? but found %?", stringnames.len(),
212 string_offsets_count);
213 return Err(~"incompatible file: more string offsets than expected");
214 }
215
216 let names_str = str::from_utf8(file.read_bytes(names_bytes as uint - 1)); // don't read NUL
217 let term_names: ~[~str] = names_str.split_iter('|').map(|s| s.to_owned()).collect();
218
219 file.read_byte(); // consume NUL
220
221 debug!("term names: %?", term_names);
222
223 let mut bools_map = HashMap::new();
224 if bools_bytes != 0 {
225 for i in range(0, bools_bytes) {
226 let b = file.read_byte();
227 if b < 0 {
228 error!("EOF reading bools after %? entries", i);
229 return Err(~"error: expected more bools but hit EOF");
230 } else if b == 1 {
231 debug!("%s set", bnames[i]);
232 bools_map.insert(bnames[i].to_owned(), true);
233 }
234 }
235 }
236
237 debug!("bools: %?", bools_map);
238
239 if (bools_bytes + names_bytes) % 2 == 1 {
240 debug!("adjusting for padding between bools and numbers");
241 file.read_byte(); // compensate for padding
242 }
243
244 let mut numbers_map = HashMap::new();
245 if numbers_count != 0 {
246 for i in range(0, numbers_count) {
247 let n = file.read_le_u16();
248 if n != 0xFFFF {
249 debug!("%s#%?", nnames[i], n);
250 numbers_map.insert(nnames[i].to_owned(), n);
251 }
252 }
253 }
254
255 debug!("numbers: %?", numbers_map);
256
257 let mut string_map = HashMap::new();
258
259 if string_offsets_count != 0 {
260 let mut string_offsets = vec::with_capacity(10);
261 for _ in range(0, string_offsets_count) {
262 string_offsets.push(file.read_le_u16());
263 }
264
265 debug!("offsets: %?", string_offsets);
266
267 let string_table = file.read_bytes(string_table_bytes as uint);
268
269 if string_table.len() != string_table_bytes as uint {
270 error!("EOF reading string table after %? bytes, wanted %?", string_table.len(),
271 string_table_bytes);
272 return Err(~"error: hit EOF before end of string table");
273 }
274
275 for (i, v) in string_offsets.iter().enumerate() {
276 let offset = *v;
277 if offset == 0xFFFF { // non-entry
278 loop;
279 }
280
281 let name = if snames[i] == "_" {
282 stringfnames[i]
283 } else {
284 snames[i]
285 };
286
287 if offset == 0xFFFE {
288 // undocumented: FFFE indicates cap@, which means the capability is not present
289 // unsure if the handling for this is correct
290 string_map.insert(name.to_owned(), ~[]);
291 loop;
292 }
293
294
295 // Find the offset of the NUL we want to go to
296 let nulpos = string_table.slice(offset as uint, string_table_bytes as uint)
297 .iter().position(|&b| b == 0);
298 match nulpos {
299 Some(len) => {
300 string_map.insert(name.to_owned(),
301 string_table.slice(offset as uint,
302 offset as uint + len).to_owned())
303 },
304 None => {
305 return Err(~"invalid file: missing NUL in string_table");
306 }
307 };
308 }
309 }
310
311 // And that's all there is to it
312 Ok(~TermInfo {names: term_names, bools: bools_map, numbers: numbers_map, strings: string_map })
313 }
314
315 #[cfg(test)]
316 mod test {
317 use super::*;
318
319 #[test]
320 fn test_veclens() {
321 assert_eq!(boolfnames.len(), boolnames.len());
322 assert_eq!(numfnames.len(), numnames.len());
323 assert_eq!(stringfnames.len(), stringnames.len());
324 }
325
326 #[test]
327 #[ignore(reason = "no ncurses on buildbots, needs a bundled terminfo file to test against")]
328 fn test_parse() {
329 // FIXME #6870: Distribute a compiled file in src/tests and test there
330 // parse(io::file_reader(&p("/usr/share/terminfo/r/rxvt-256color")).unwrap(), false);
331 }
332 }