pub mod abend;
pub use rt::calendar;
pub use rt::cics;
pub use rt::codec;
pub use rt::digest;
pub use rt::evidence;
pub use compile::collating;
pub use compile::declaratives;
pub mod edit;
pub use rt::files;
pub use compile::layout;
pub mod le;
pub use rt::lir;
pub use compile::linage;
pub mod loader;
pub mod lower;
pub mod machine;
pub use rt::module;
pub mod oo;
pub use compile::picture;
pub mod printer;
pub mod report;
use compile::sort;
pub mod sql;
pub use rt::strings;
pub mod terminal;
#[cfg(test)]
mod testing;
pub use rt::tn3270;
pub mod unit;
pub use compile::{Compiled, EntryPoint, compile, compile_at, compile_time, entry_points};
pub(crate) use compile::{procedure, section_end};
pub use machine::{Abend, Ending};
use abend::AbendCode;
use unit::AddProgram;
use std::io::{BufRead, Write};
use syntax::Pos;
pub trait Execute {
fn run(&self, out: &mut dyn Write, err: &mut dyn Write) -> Result<Ending, Abend>;
fn run_with(&self, dds: files::Dds, out: &mut dyn Write, err: &mut dyn Write) -> Result<Ending, Abend>;
fn execute<'w>(
&self,
library: unit::Library,
dds: files::Dds,
sysin: Option<Box<dyn BufRead + 'w>>,
clock: unit::Clock,
out: &'w mut dyn Write,
err: &'w mut dyn Write,
) -> Result<(Ending, i16), Abend>;
#[allow(clippy::too_many_arguments)]
fn execute_with<'w>(
&self,
library: unit::Library,
dds: files::Dds,
sysin: Option<Box<dyn BufRead + 'w>>,
clock: unit::Clock,
database: Option<&'w mut (dyn sql::Database + '_)>,
out: &'w mut dyn Write,
err: &'w mut dyn Write,
) -> Result<(Ending, i16), Abend>;
#[allow(clippy::too_many_arguments)]
fn execute_observed<'w>(
&self,
library: unit::Library,
dds: files::Dds,
sysin: Option<Box<dyn BufRead + 'w>>,
clock: unit::Clock,
database: Option<&'w mut (dyn sql::Database + '_)>,
out: &'w mut dyn Write,
err: &'w mut dyn Write,
observer: Option<unit::Observer<'w>>,
) -> Result<(Ending, i16), Abend>;
fn execute_cics<'w>(
&self,
library: unit::Library,
dds: files::Dds,
task: cics::Task,
clock: unit::Clock,
out: &'w mut dyn Write,
err: &'w mut dyn Write,
) -> Result<(Ending, cics::Task), Abend>;
#[allow(clippy::too_many_arguments)]
fn execute_cics_with<'w>(
&self,
library: unit::Library,
dds: files::Dds,
task: cics::Task,
clock: unit::Clock,
database: Option<&'w mut (dyn sql::Database + '_)>,
out: &'w mut dyn Write,
err: &'w mut dyn Write,
) -> Result<(Ending, cics::Task), Abend>;
#[allow(clippy::too_many_arguments)]
fn execute_cics_observed<'w>(
&self,
library: unit::Library,
dds: files::Dds,
task: cics::Task,
clock: unit::Clock,
database: Option<&'w mut (dyn sql::Database + '_)>,
out: &'w mut dyn Write,
err: &'w mut dyn Write,
observer: Option<unit::Observer<'w>>,
) -> Result<(Ending, cics::Task), Abend>;
}
impl Execute for Compiled {
fn run(&self, out: &mut dyn Write, err: &mut dyn Write) -> Result<Ending, Abend> {
self.run_with(files::Dds::default(), out, err)
}
fn run_with(&self, dds: files::Dds, out: &mut dyn Write, err: &mut dyn Write) -> Result<Ending, Abend> {
self.execute(unit::Library::default(), dds, None, unit::Clock::System, out, err).map(|(ending, _)| ending)
}
fn execute<'w>(
&self,
library: unit::Library,
dds: files::Dds,
sysin: Option<Box<dyn BufRead + 'w>>,
clock: unit::Clock,
out: &'w mut dyn Write,
err: &'w mut dyn Write,
) -> Result<(Ending, i16), Abend> {
self.execute_with(library, dds, sysin, clock, None, out, err)
}
fn execute_with<'w>(
&self,
library: unit::Library,
dds: files::Dds,
sysin: Option<Box<dyn BufRead + 'w>>,
clock: unit::Clock,
database: Option<&'w mut (dyn sql::Database + '_)>,
out: &'w mut dyn Write,
err: &'w mut dyn Write,
) -> Result<(Ending, i16), Abend> {
self.execute_observed(library, dds, sysin, clock, database, out, err, None)
}
fn execute_observed<'w>(
&self,
library: unit::Library,
dds: files::Dds,
sysin: Option<Box<dyn BufRead + 'w>>,
clock: unit::Clock,
database: Option<&'w mut (dyn sql::Database + '_)>,
out: &'w mut dyn Write,
err: &'w mut dyn Write,
observer: Option<unit::Observer<'w>>,
) -> Result<(Ending, i16), Abend> {
oo::refuse_to_run(&self.program)?;
let mut run_unit = unit::RunUnit::new(library, dds, sysin, clock, out, err);
run_unit.observer = observer;
run_unit.sql = database.map(sql::Session::new);
let me = run_unit.add(None, &self.program, self.layout.size as usize);
let ending = machine::Machine::activation(self, me, &mut run_unit, true).and_then(|mut m| m.run_procedure());
let settled = run_unit.sql.as_mut().map_or(Ok(()), |s| s.settle(&self.program.id, ending.is_ok()).map(drop));
let closed = run_unit.close_all();
let ending = ending?;
settled.map_err(|a| Abend { code: a.code.into(), message: a.message, pos: Pos::default(), file: None })?;
closed.map_err(|m| Abend { code: AbendCode::Ironwork, message: m, pos: Pos::default(), file: None })?;
Ok((ending, run_unit.return_code()))
}
fn execute_cics<'w>(
&self,
library: unit::Library,
dds: files::Dds,
task: cics::Task,
clock: unit::Clock,
out: &'w mut dyn Write,
err: &'w mut dyn Write,
) -> Result<(Ending, cics::Task), Abend> {
self.execute_cics_with(library, dds, task, clock, None, out, err)
}
fn execute_cics_with<'w>(
&self,
library: unit::Library,
dds: files::Dds,
task: cics::Task,
clock: unit::Clock,
database: Option<&'w mut (dyn sql::Database + '_)>,
out: &'w mut dyn Write,
err: &'w mut dyn Write,
) -> Result<(Ending, cics::Task), Abend> {
self.execute_cics_observed(library, dds, task, clock, database, out, err, None)
}
fn execute_cics_observed<'w>(
&self,
library: unit::Library,
dds: files::Dds,
mut task: cics::Task,
clock: unit::Clock,
database: Option<&'w mut (dyn sql::Database + '_)>,
out: &'w mut dyn Write,
err: &'w mut dyn Write,
observer: Option<unit::Observer<'w>>,
) -> Result<(Ending, cics::Task), Abend> {
oo::refuse_to_run(&self.program)?;
let mut run_unit = unit::RunUnit::new(library, dds, None, clock, out, err);
run_unit.observer = observer;
run_unit.sql = database.map(sql::Session::new);
let me = run_unit.add(None, &self.program, self.layout.size as usize);
run_unit.eib = run_unit.push_temporary(&[0; cics::EIB_LEN]);
let commarea = task.commarea.take();
let length = commarea.as_ref().map_or(0, Vec::len);
let commarea = commarea.map(|c| run_unit.push_temporary(&c));
run_unit.cics = Some(task);
let ending = machine::Machine::activation(self, me, &mut run_unit, true).and_then(|mut m| {
m.begin_task(commarea, length);
m.run_procedure()
});
let settled = run_unit.sql.as_mut().map_or(Ok(()), |s| s.end_task(&self.program.id, ending.is_ok()).map(drop));
let mut closed = run_unit.close_all();
for (name, f) in run_unit.cics_files.drain() {
if let Err(e) = f.close() {
closed = closed.and(Err(format!("closing CICS file {name}: {e}")));
}
}
let mut task = run_unit.cics.take().unwrap_or_default();
if let Err(e) = task.flush_td(self.options.code_page()) {
closed = closed.and(Err(format!("writing transient data: {e}")));
}
let ending = ending.map_err(|a| match a.code {
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 },
_ => a,
})?;
settled.map_err(|a| Abend { code: a.code.into(), message: a.message, pos: Pos::default(), file: None })?;
closed.map_err(|m| Abend { code: AbendCode::Ironwork, message: m, pos: Pos::default(), file: None })?;
Ok((ending, task))
}
}
#[cfg(test)]
mod tests;