1#[derive(Clone, Copy, Debug, PartialEq, Eq)]
5pub enum Mode {
6 In,
7 Out,
8 InOut,
9}
10
11#[derive(Clone, Debug, PartialEq, Eq)]
12pub enum Initial {
13 Text(String),
14 Bytes(Vec<u8>),
15}
16
17#[derive(Clone, Copy, Debug, PartialEq, Eq)]
18pub enum Protection {
19 Askip,
20 Prot,
21 Unprot,
22}
23
24#[derive(Clone, Copy, Debug, PartialEq, Eq)]
25pub enum Intensity {
26 Norm,
27 Brt,
28 Drk,
29}
30
31#[derive(Clone, Copy, Debug, PartialEq, Eq)]
32pub struct Attrb {
33 pub protection: Protection,
34 pub numeric: bool,
35 pub intensity: Intensity,
36 pub detectable: bool,
37 pub cursor: bool,
38 pub fset: bool,
39}
40
41#[derive(Clone, Debug, PartialEq, Eq)]
42pub struct Field {
43 pub name: Option<String>,
45 pub line: u16,
47 pub column: u16,
48 pub length: u16,
49 pub attrb: Attrb,
50 pub initial: Option<Initial>,
52 pub picin: Option<String>,
53 pub picout: Option<String>,
54 pub occurs: u16,
55 pub group: Option<String>,
56 pub justify_right: bool,
57 pub fill_zero: bool,
58 pub color: Option<String>,
59 pub hilight: Option<String>,
60}
61
62#[derive(Clone, Debug, PartialEq, Eq)]
63pub struct Map {
64 pub name: String,
65 pub lines: u16,
66 pub columns: u16,
67 pub line: u16,
68 pub column: u16,
69 pub ctrl: Vec<String>,
70 pub tioapfx: bool,
71 pub dsatts: Vec<String>,
72 pub fields: Vec<Field>,
73}
74
75#[derive(Clone, Debug, PartialEq, Eq)]
76pub struct Mapset {
77 pub name: String,
78 pub mode: Mode,
79 pub ctrl: Vec<String>,
80 pub maps: Vec<Map>,
81}
82
83pub const EXTENDED: &[(&str, char, bool)] = &[
85 ("COLOR", 'C', true),
86 ("PS", 'P', true),
87 ("HILIGHT", 'H', true),
88 ("VALIDN", 'V', true),
89 ("OUTLINE", 'U', false),
90 ("SOSI", 'M', false),
91 ("TRANSP", 'T', false),
92];
93
94pub fn picture_size(pic: &str) -> u32 {
96 let chars: Vec<char> = pic.chars().collect();
97 let (mut size, mut i) = (0, 0);
98 while i < chars.len() {
99 let c = chars[i].to_ascii_uppercase();
100 i += 1;
101 let mut repeat = 1;
102 if chars.get(i) == Some(&'(')
103 && let Some(close) = chars[i..].iter().position(|&c| c == ')')
104 {
105 repeat = chars[i + 1..i + close].iter().collect::<String>().parse().unwrap_or(1);
106 i += close + 1;
107 }
108 if !matches!(c, 'S' | 'V') {
109 size += repeat;
110 }
111 }
112 size
113}
114
115#[derive(Clone, Copy, Debug, PartialEq, Eq)]
119pub struct Slot {
120 pub field: usize,
121 pub occurrence: u16,
122 pub control: Option<usize>,
123 pub extended: usize,
124 pub data: usize,
125 pub size: usize,
126}
127
128impl Slot {
129 pub fn length_at(&self) -> Option<usize> {
131 self.control
132 }
133
134 pub fn attribute_at(&self) -> Option<usize> {
135 self.control.map(|c| c + 2)
136 }
137}
138
139pub fn extended_attributes(map: &Map) -> Vec<&'static str> {
141 EXTENDED.iter().filter(|(a, _, _)| map.dsatts.iter().any(|d| d == a)).map(|(a, _, _)| *a).collect()
142}
143
144pub fn slots(map: &Map, input: bool) -> Vec<Slot> {
147 let k = extended_attributes(map).len();
148 let mut at = if map.tioapfx { 12 } else { 0 };
149 let mut out = Vec::new();
150 let mut group: Option<&str> = None;
151 for (i, f) in map.fields.iter().enumerate().filter(|(_, f)| f.name.is_some()) {
152 let lead = match &f.group {
153 Some(g) => {
154 let first = group != Some(g.as_str());
155 group = Some(g);
156 first
157 }
158 None => {
159 group = None;
160 true
161 }
162 };
163 let picture = if input { &f.picin } else { &f.picout };
164 let size = picture.as_deref().map_or(usize::from(f.length), |p| picture_size(p) as usize);
165 let copies = if f.group.is_none() { f.occurs.max(1) } else { 1 };
166 for occurrence in 0..copies {
167 let control = lead.then_some(at);
168 if lead {
169 at += 3 + k;
170 }
171 out.push(Slot { field: i, occurrence, control, extended: at - k, data: at, size });
172 at += size;
173 }
174 }
175 out
176}