1pub mod abend;
5pub use rt::calendar;
6pub use rt::cics;
7pub use rt::codec;
8pub use rt::digest;
9pub use rt::evidence;
10pub use compile::collating;
11pub use compile::declaratives;
12pub mod edit;
13pub use rt::files;
14pub use compile::layout;
15pub mod le;
16pub use rt::lir;
17pub use compile::linage;
18pub mod loader;
19pub mod lower;
20pub mod machine;
21pub use rt::module;
22pub mod oo;
23pub use compile::picture;
24pub mod printer;
25pub mod report;
26use compile::sort;
27pub mod sql;
28pub use rt::strings;
29pub mod terminal;
30#[cfg(test)]
31mod testing;
32pub use rt::tn3270;
33pub mod unit;
34
35pub use compile::{Compiled, EntryPoint, compile, compile_at, compile_time, entry_points};
36pub(crate) use compile::{procedure, section_end};
37pub use machine::{Abend, Ending};
38
39use abend::AbendCode;
40use unit::AddProgram;
41use std::io::{BufRead, Write};
42use syntax::Pos;
43
44pub trait Execute {
46 fn run(&self, out: &mut dyn Write, err: &mut dyn Write) -> Result<Ending, Abend>;
47
48 fn run_with(&self, dds: files::Dds, out: &mut dyn Write, err: &mut dyn Write) -> Result<Ending, Abend>;
50
51 fn execute<'w>(
54 &self,
55 library: unit::Library,
56 dds: files::Dds,
57 sysin: Option<Box<dyn BufRead + 'w>>,
58 clock: unit::Clock,
59 out: &'w mut dyn Write,
60 err: &'w mut dyn Write,
61 ) -> Result<(Ending, i16), Abend>;
62
63 #[allow(clippy::too_many_arguments)]
65 fn execute_with<'w>(
66 &self,
67 library: unit::Library,
68 dds: files::Dds,
69 sysin: Option<Box<dyn BufRead + 'w>>,
70 clock: unit::Clock,
71 database: Option<&'w mut (dyn sql::Database + '_)>,
72 out: &'w mut dyn Write,
73 err: &'w mut dyn Write,
74 ) -> Result<(Ending, i16), Abend>;
75
76 #[allow(clippy::too_many_arguments)]
79 fn execute_observed<'w>(
80 &self,
81 library: unit::Library,
82 dds: files::Dds,
83 sysin: Option<Box<dyn BufRead + 'w>>,
84 clock: unit::Clock,
85 database: Option<&'w mut (dyn sql::Database + '_)>,
86 out: &'w mut dyn Write,
87 err: &'w mut dyn Write,
88 observer: Option<unit::Observer<'w>>,
89 ) -> Result<(Ending, i16), Abend>;
90
91 fn execute_cics<'w>(
95 &self,
96 library: unit::Library,
97 dds: files::Dds,
98 task: cics::Task,
99 clock: unit::Clock,
100 out: &'w mut dyn Write,
101 err: &'w mut dyn Write,
102 ) -> Result<(Ending, cics::Task), Abend>;
103
104 #[allow(clippy::too_many_arguments)]
108 fn execute_cics_with<'w>(
109 &self,
110 library: unit::Library,
111 dds: files::Dds,
112 task: cics::Task,
113 clock: unit::Clock,
114 database: Option<&'w mut (dyn sql::Database + '_)>,
115 out: &'w mut dyn Write,
116 err: &'w mut dyn Write,
117 ) -> Result<(Ending, cics::Task), Abend>;
118
119 #[allow(clippy::too_many_arguments)]
122 fn execute_cics_observed<'w>(
123 &self,
124 library: unit::Library,
125 dds: files::Dds,
126 task: cics::Task,
127 clock: unit::Clock,
128 database: Option<&'w mut (dyn sql::Database + '_)>,
129 out: &'w mut dyn Write,
130 err: &'w mut dyn Write,
131 observer: Option<unit::Observer<'w>>,
132 ) -> Result<(Ending, cics::Task), Abend>;
133}
134
135impl Execute for Compiled {
136 fn run(&self, out: &mut dyn Write, err: &mut dyn Write) -> Result<Ending, Abend> {
137 self.run_with(files::Dds::default(), out, err)
138 }
139
140 fn run_with(&self, dds: files::Dds, out: &mut dyn Write, err: &mut dyn Write) -> Result<Ending, Abend> {
141 self.execute(unit::Library::default(), dds, None, unit::Clock::System, out, err).map(|(ending, _)| ending)
142 }
143
144 fn execute<'w>(
145 &self,
146 library: unit::Library,
147 dds: files::Dds,
148 sysin: Option<Box<dyn BufRead + 'w>>,
149 clock: unit::Clock,
150 out: &'w mut dyn Write,
151 err: &'w mut dyn Write,
152 ) -> Result<(Ending, i16), Abend> {
153 self.execute_with(library, dds, sysin, clock, None, out, err)
154 }
155
156 fn execute_with<'w>(
157 &self,
158 library: unit::Library,
159 dds: files::Dds,
160 sysin: Option<Box<dyn BufRead + 'w>>,
161 clock: unit::Clock,
162 database: Option<&'w mut (dyn sql::Database + '_)>,
163 out: &'w mut dyn Write,
164 err: &'w mut dyn Write,
165 ) -> Result<(Ending, i16), Abend> {
166 self.execute_observed(library, dds, sysin, clock, database, out, err, None)
167 }
168
169 fn execute_observed<'w>(
170 &self,
171 library: unit::Library,
172 dds: files::Dds,
173 sysin: Option<Box<dyn BufRead + 'w>>,
174 clock: unit::Clock,
175 database: Option<&'w mut (dyn sql::Database + '_)>,
176 out: &'w mut dyn Write,
177 err: &'w mut dyn Write,
178 observer: Option<unit::Observer<'w>>,
179 ) -> Result<(Ending, i16), Abend> {
180 oo::refuse_to_run(&self.program)?;
181 let mut run_unit = unit::RunUnit::new(library, dds, sysin, clock, out, err);
182 run_unit.observer = observer;
183 run_unit.sql = database.map(sql::Session::new);
184 let me = run_unit.add(None, &self.program, self.layout.size as usize);
185 let ending = machine::Machine::activation(self, me, &mut run_unit, true).and_then(|mut m| m.run_procedure());
186 let settled = run_unit.sql.as_mut().map_or(Ok(()), |s| s.settle(&self.program.id, ending.is_ok()).map(drop));
187 let closed = run_unit.close_all();
188 let ending = ending?;
189 settled.map_err(|a| Abend { code: a.code.into(), message: a.message, pos: Pos::default(), file: None })?;
190 closed.map_err(|m| Abend { code: AbendCode::Ironwork, message: m, pos: Pos::default(), file: None })?;
191 Ok((ending, run_unit.return_code()))
192 }
193
194 fn execute_cics<'w>(
195 &self,
196 library: unit::Library,
197 dds: files::Dds,
198 task: cics::Task,
199 clock: unit::Clock,
200 out: &'w mut dyn Write,
201 err: &'w mut dyn Write,
202 ) -> Result<(Ending, cics::Task), Abend> {
203 self.execute_cics_with(library, dds, task, clock, None, out, err)
204 }
205
206 fn execute_cics_with<'w>(
207 &self,
208 library: unit::Library,
209 dds: files::Dds,
210 task: cics::Task,
211 clock: unit::Clock,
212 database: Option<&'w mut (dyn sql::Database + '_)>,
213 out: &'w mut dyn Write,
214 err: &'w mut dyn Write,
215 ) -> Result<(Ending, cics::Task), Abend> {
216 self.execute_cics_observed(library, dds, task, clock, database, out, err, None)
217 }
218
219 fn execute_cics_observed<'w>(
220 &self,
221 library: unit::Library,
222 dds: files::Dds,
223 mut task: cics::Task,
224 clock: unit::Clock,
225 database: Option<&'w mut (dyn sql::Database + '_)>,
226 out: &'w mut dyn Write,
227 err: &'w mut dyn Write,
228 observer: Option<unit::Observer<'w>>,
229 ) -> Result<(Ending, cics::Task), Abend> {
230 oo::refuse_to_run(&self.program)?;
231 let mut run_unit = unit::RunUnit::new(library, dds, None, clock, out, err);
232 run_unit.observer = observer;
233 run_unit.sql = database.map(sql::Session::new);
234 let me = run_unit.add(None, &self.program, self.layout.size as usize);
235 run_unit.eib = run_unit.push_temporary(&[0; cics::EIB_LEN]);
236 let commarea = task.commarea.take();
237 let length = commarea.as_ref().map_or(0, Vec::len);
238 let commarea = commarea.map(|c| run_unit.push_temporary(&c));
239 run_unit.cics = Some(task);
240 let ending = machine::Machine::activation(self, me, &mut run_unit, true).and_then(|mut m| {
241 m.begin_task(commarea, length);
242 m.run_procedure()
243 });
244 let settled = run_unit.sql.as_mut().map_or(Ok(()), |s| s.end_task(&self.program.id, ending.is_ok()).map(drop));
245 let mut closed = run_unit.close_all();
246 for (name, f) in run_unit.cics_files.drain() {
247 if let Err(e) = f.close() {
248 closed = closed.and(Err(format!("closing CICS file {name}: {e}")));
249 }
250 }
251 let mut task = run_unit.cics.take().unwrap_or_default();
252 if let Err(e) = task.flush_td(self.options.code_page()) {
253 closed = closed.and(Err(format!("writing transient data: {e}")));
254 }
255 let ending = ending.map_err(|a| match a.code {
256 AbendCode::Check(_) | AbendCode::Protection => Abend { message: format!("{} ({}, which CICS reports as ASRA)", a.message, a.code), code: AbendCode::Cics("ASRA".into()), pos: a.pos, file: a.file },
257 _ => a,
258 })?;
259 settled.map_err(|a| Abend { code: a.code.into(), message: a.message, pos: Pos::default(), file: None })?;
260 closed.map_err(|m| Abend { code: AbendCode::Ironwork, message: m, pos: Pos::default(), file: None })?;
261 Ok((ending, task))
262 }
263}
264
265#[cfg(test)]
266mod tests;