#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Mode {
In,
Out,
InOut,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Initial {
Text(String),
Bytes(Vec<u8>),
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Protection {
Askip,
Prot,
Unprot,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Intensity {
Norm,
Brt,
Drk,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Attrb {
pub protection: Protection,
pub numeric: bool,
pub intensity: Intensity,
pub detectable: bool,
pub cursor: bool,
pub fset: bool,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Field {
pub name: Option<String>,
pub line: u16,
pub column: u16,
pub length: u16,
pub attrb: Attrb,
pub initial: Option<Initial>,
pub picin: Option<String>,
pub picout: Option<String>,
pub occurs: u16,
pub group: Option<String>,
pub justify_right: bool,
pub fill_zero: bool,
pub color: Option<String>,
pub hilight: Option<String>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Map {
pub name: String,
pub lines: u16,
pub columns: u16,
pub line: u16,
pub column: u16,
pub ctrl: Vec<String>,
pub tioapfx: bool,
pub dsatts: Vec<String>,
pub fields: Vec<Field>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Mapset {
pub name: String,
pub mode: Mode,
pub ctrl: Vec<String>,
pub maps: Vec<Map>,
}
pub const EXTENDED: &[(&str, char, bool)] = &[
("COLOR", 'C', true),
("PS", 'P', true),
("HILIGHT", 'H', true),
("VALIDN", 'V', true),
("OUTLINE", 'U', false),
("SOSI", 'M', false),
("TRANSP", 'T', false),
];
pub fn picture_size(pic: &str) -> u32 {
let chars: Vec<char> = pic.chars().collect();
let (mut size, mut i) = (0, 0);
while i < chars.len() {
let c = chars[i].to_ascii_uppercase();
i += 1;
let mut repeat = 1;
if chars.get(i) == Some(&'(')
&& let Some(close) = chars[i..].iter().position(|&c| c == ')')
{
repeat = chars[i + 1..i + close].iter().collect::<String>().parse().unwrap_or(1);
i += close + 1;
}
if !matches!(c, 'S' | 'V') {
size += repeat;
}
}
size
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Slot {
pub field: usize,
pub occurrence: u16,
pub control: Option<usize>,
pub extended: usize,
pub data: usize,
pub size: usize,
}
impl Slot {
pub fn length_at(&self) -> Option<usize> {
self.control
}
pub fn attribute_at(&self) -> Option<usize> {
self.control.map(|c| c + 2)
}
}
pub fn extended_attributes(map: &Map) -> Vec<&'static str> {
EXTENDED.iter().filter(|(a, _, _)| map.dsatts.iter().any(|d| d == a)).map(|(a, _, _)| *a).collect()
}
pub fn slots(map: &Map, input: bool) -> Vec<Slot> {
let k = extended_attributes(map).len();
let mut at = if map.tioapfx { 12 } else { 0 };
let mut out = Vec::new();
let mut group: Option<&str> = None;
for (i, f) in map.fields.iter().enumerate().filter(|(_, f)| f.name.is_some()) {
let lead = match &f.group {
Some(g) => {
let first = group != Some(g.as_str());
group = Some(g);
first
}
None => {
group = None;
true
}
};
let picture = if input { &f.picin } else { &f.picout };
let size = picture.as_deref().map_or(usize::from(f.length), |p| picture_size(p) as usize);
let copies = if f.group.is_none() { f.occurs.max(1) } else { 1 };
for occurrence in 0..copies {
let control = lead.then_some(at);
if lead {
at += 3 + k;
}
out.push(Slot { field: i, occurrence, control, extended: at - k, data: at, size });
at += size;
}
}
out
}