Skip to content

Commit 36efacd

Browse files
author
Eric Sessoms
committed
Include script to regenerate lookup tables
script/generate_rfc3454.rs can be used to recreate src/rfc3454.rs from the specification at script/rfc3454.txt. This can be done on an as-needed basis and is not part of the build.
1 parent 0b883c7 commit 36efacd

File tree

4 files changed

+5246
-40
lines changed

4 files changed

+5246
-40
lines changed

script/generate_rfc3454.rs

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
extern crate regex;
2+
3+
use regex::Regex;
4+
5+
use std::env;
6+
use std::fs::File;
7+
use std::io::prelude::*;
8+
use std::io::{BufReader, BufWriter};
9+
use std::path::Path;
10+
11+
// Generate character mapping tables directly from the specification.
12+
fn main() {
13+
// Input from the RFC.
14+
let in_file = File::open("rfc3454.txt").unwrap();
15+
let mut reader = BufReader::new(in_file);
16+
17+
// Output to a Rust source file.
18+
let out_dir = env::var("OUT_DIR").unwrap();
19+
let dest_path = Path::new(&out_dir).join("rfc3454.rs");
20+
let out_file = File::create(&dest_path).unwrap();
21+
let mut writer = BufWriter::new(out_file);
22+
23+
// Generate tables.
24+
include_table(&mut writer, &mut reader, "A.1");
25+
include_table(&mut writer, &mut reader, "B.2");
26+
}
27+
28+
// Generate code for the named mapping table.
29+
fn include_table<R: Read, W: Write>(writer: &mut BufWriter<W>, reader: &mut BufReader<R>, tablename: &str) {
30+
// Scan to start of table.
31+
loop {
32+
let mut line = String::new();
33+
reader.read_line(&mut line).unwrap();
34+
if line.contains("Start Table") && line.contains(tablename) {
35+
break;
36+
}
37+
}
38+
39+
// Output table declaration.
40+
write!(writer, "pub const RFC3454_{}: &[(char, Option<char>, Option<&str>)] = &[\n", tablename.replace(".", "_")).unwrap();
41+
42+
// For each line:
43+
let target_re = Regex::new(r"([0-9A-F]+)(-([0-9A-F]+))?(; ([0-9A-F]+)( ([0-9A-F]+))?( ([0-9A-F]+))?( ([0-9A-F]+))?;)?").unwrap();
44+
loop {
45+
let mut line = String::new();
46+
reader.read_line(&mut line).unwrap();
47+
48+
// Done when reach the end of the table.
49+
if line.contains("End Table") {
50+
break;
51+
}
52+
53+
// Skip RFC metadata.
54+
if line.contains("Hoffman & Blanchet") || line.contains("RFC 3454") {
55+
continue;
56+
}
57+
58+
// Generate an entry for each data line.
59+
if let Some(captures) = target_re.captures(&line) {
60+
let start = captures.get(1).unwrap();
61+
62+
// '\u{start}',
63+
let mut entry = String::from("'\\u{");
64+
entry.push_str(start.as_str());
65+
entry.push_str("}', ");
66+
67+
// '\u{start}', None,
68+
// '\u{start}', Some('\u{end}'),
69+
match captures.get(3) {
70+
None => entry.push_str("None, "),
71+
Some(end) => {
72+
entry.push_str("Some('\\u{");
73+
entry.push_str(end.as_str());
74+
entry.push_str("}'), ");
75+
}
76+
}
77+
78+
// 0-4 character replacement string
79+
let mut replace = String::new();
80+
for &i in [5, 7, 9, 11].iter() {
81+
match captures.get(i) {
82+
None => break,
83+
Some(c) => {
84+
replace.push_str("\\u{");
85+
replace.push_str(c.as_str());
86+
replace.push_str("}");
87+
}
88+
}
89+
}
90+
91+
// '\u{start}', None, None
92+
// '\u{start}', None, Some("replace")
93+
if replace.is_empty() {
94+
entry.push_str("None");
95+
} else {
96+
entry.push_str("Some(\"");
97+
entry.push_str(&replace);
98+
entry.push_str("\")");
99+
}
100+
101+
// Output entry for this line.
102+
write!(writer, " ({}),\n", entry).unwrap();
103+
}
104+
}
105+
106+
// End table definition.
107+
write!(writer, "];\n\n").unwrap();
108+
}

0 commit comments

Comments
 (0)