1use zarch::ebcdic::CodePage;
4
5const RUNTIME_OPTIONS: &[&str] = &[
8 "ABPERC", "ABTERMENC", "AIXBLD", "ALL31", "ANYHEAP", "BELOWHEAP", "CBLOPTS", "CBLPSHPOP", "CBLQDA", "CEEDUMP", "CHECK", "COUNTRY", "DEBUG", "DEPTHCONDLMT", "DYNDUMP", "ENVAR", "ERRCOUNT", "ERRUNIT", "FILEHIST", "FILETAG", "HEAP", "HEAPCHK",
9 "HEAPPOOLS", "HEAPZONES", "INFOMSGFILTER", "INQPCOPN", "INTERRUPT", "LIBSTACK", "MSGFILE", "MSGQ", "NATLANG", "NOTEST", "NOUSRHDLR", "OCSTATUS", "PAGEFRAMESIZE", "PC", "PLITASKCOUNT", "POSIX", "PROFILE", "PRTUNIT", "PUNUNIT", "RDRUNIT",
10 "RECPAD", "RPTOPTS", "RPTSTG", "RTEREUS", "SIMVRD", "STACK", "STORAGE", "TERMTHDACT", "TEST", "THREADHEAP", "THREADSTACK", "TRACE", "TRAP", "UPSI", "USRHDLR", "VCTRSAVE", "XPLINK", "XUFLOW",
11];
12
13pub const PARM_LIMIT: usize = 100;
15
16pub fn program_arguments(parm: &str) -> &str {
20 match parm.rfind('/') {
21 Some(at) if names_runtime_options(&parm[at + 1..]) => &parm[..at],
22 _ => parm,
23 }
24}
25
26fn names_runtime_options(text: &str) -> bool {
29 let (mut words, mut word, mut depth) = (Vec::new(), String::new(), 0i32);
30 for c in text.chars() {
31 match c {
32 '(' => depth += 1,
33 ')' => depth -= 1,
34 ',' | ' ' if depth <= 0 => {
35 words.push(std::mem::take(&mut word));
36 continue;
37 }
38 _ => {}
39 }
40 word.push(c);
41 }
42 words.push(word);
43 let words: Vec<&String> = words.iter().filter(|w| !w.is_empty()).collect();
44 words.is_empty() || words.iter().any(|w| RUNTIME_OPTIONS.iter().any(|o| o.eq_ignore_ascii_case(w.split('(').next().unwrap_or(w))))
45}
46
47pub fn parameter_area(arguments: &str, page: &CodePage) -> Vec<u8> {
50 let text = page.encode_lossy(arguments);
51 let mut area = (text.len() as u16).to_be_bytes().to_vec();
52 area.extend(&text);
53 area.resize(2 + PARM_LIMIT.max(text.len()), 0);
54 area
55}
56
57#[cfg(test)]
58mod tests {
59 use super::*;
60
61 #[test]
62 fn the_last_slash_ends_the_arguments_when_runtime_options_follow_it() {
63 assert_eq!(program_arguments("RUN=1,MODE=X"), "RUN=1,MODE=X");
64 assert_eq!(program_arguments("A/B/RPTOPTS(ON)"), "A/B");
65 assert_eq!(program_arguments("ABC/RPTOPTS(ON),MSGFILE(SYSOUT,FBA,121,0)"), "ABC");
66 assert_eq!(program_arguments("ABC/ rptstg(on) NOSUCH"), "ABC");
67 assert_eq!(program_arguments("ABC/"), "ABC");
68 assert_eq!(program_arguments("/TRAP(OFF)"), "");
69 assert_eq!(program_arguments("11/16/1967"), "11/16/1967", "the manual's example: 1967 is no runtime option");
70 }
71
72 #[test]
73 fn the_area_holds_a_halfword_length_and_the_arguments_in_ebcdic() {
74 let page = numeric::options::Options::default().code_page();
75 let area = parameter_area("AB 1", page);
76 assert_eq!(&area[..6], [0, 4, 0xC1, 0xC2, 0x40, 0xF1]);
77 assert_eq!(area.len(), 2 + PARM_LIMIT);
78 assert!(area[6..].iter().all(|&b| b == 0));
79 }
80}