CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hrydgard

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: hrydgard/ppsspp
Path: blob/master/Tools/langtool/src/inifile.rs
Views: 1401
1
use std::fs::File;
2
use std::io::{self, Write};
3
use std::path::{Path, PathBuf};
4
5
use crate::section::Section;
6
7
#[derive(Debug)]
8
pub struct IniFile {
9
pub filename: PathBuf,
10
pub preamble: Vec<String>,
11
pub sections: Vec<Section>,
12
pub has_bom: bool,
13
}
14
15
impl IniFile {
16
pub fn parse(filename: &str) -> io::Result<IniFile> {
17
let lines = read_lines(filename)?;
18
19
let mut sections = vec![];
20
let mut preamble = vec![];
21
let mut cur_section = None;
22
23
let mut has_bom = false;
24
25
for line in lines {
26
let line = line.unwrap();
27
28
let line = if let Some(line) = line.strip_prefix('\u{feff}') {
29
has_bom = true;
30
line
31
} else {
32
&line
33
};
34
35
if let Some('[') = line.chars().next() {
36
if let Some(right_bracket) = line.find(']') {
37
if let Some(section) = cur_section.take() {
38
sections.push(section);
39
}
40
41
let name = &line[1..right_bracket];
42
cur_section = Some(Section {
43
name: name.to_owned(),
44
title_line: line.to_owned(), // preserves comment and bom
45
lines: vec![],
46
});
47
} else {
48
// Bad syntax
49
break;
50
}
51
} else if let Some(cur_section) = &mut cur_section {
52
cur_section.lines.push(line.to_owned());
53
} else {
54
preamble.push(line.to_owned());
55
}
56
}
57
58
if let Some(section) = cur_section.take() {
59
sections.push(section);
60
}
61
62
let ini = IniFile {
63
filename: PathBuf::from(filename),
64
preamble,
65
sections,
66
has_bom,
67
};
68
Ok(ini)
69
}
70
71
pub fn write(&self) -> io::Result<()> {
72
let file = std::fs::File::create(&self.filename)?;
73
let mut file = std::io::LineWriter::new(file);
74
75
// Write BOM
76
if self.has_bom {
77
file.write_all("\u{feff}".as_bytes())?;
78
}
79
for line in &self.preamble {
80
file.write_all(line.as_bytes())?;
81
file.write_all(b"\n")?;
82
}
83
for section in &self.sections {
84
file.write_all(section.title_line.as_bytes())?;
85
file.write_all(b"\n")?;
86
for line in &section.lines {
87
file.write_all(line.as_bytes())?;
88
file.write_all(b"\n")?;
89
}
90
}
91
92
Ok(())
93
}
94
95
// Assumes alphabetical section order!
96
pub fn insert_section_if_missing(&mut self, section: &Section) -> bool {
97
// First, check if it's there.
98
99
for iter_section in &self.sections {
100
if iter_section.name == section.name {
101
return false;
102
}
103
}
104
105
// Then, find a suitable insertion spot
106
for (i, iter_section) in self.sections.iter_mut().enumerate() {
107
if iter_section.name > section.name {
108
println!("Inserting section {}", section.name);
109
self.sections.insert(i, section.clone());
110
return true;
111
}
112
}
113
// Reached the end for some reason? Add it.
114
// Also add an empty line to the previous section.
115
if let Some(last) = self.sections.last_mut() {
116
last.lines.push("".into());
117
}
118
self.sections.push(section.clone());
119
true
120
}
121
122
pub fn get_section_mut(&mut self, section_name: &str) -> Option<&mut Section> {
123
self.sections
124
.iter_mut()
125
.find(|section| section.name == section_name)
126
}
127
}
128
129
// Grabbed from a sample, a fast line reader iterator.
130
fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>>
131
where
132
P: AsRef<Path>,
133
{
134
let file = File::open(filename)?;
135
use std::io::BufRead;
136
Ok(io::BufReader::new(file).lines())
137
}
138
139