Skip to main content

ironwork_rt/cics/
command.rs

1//! An EXEC CICS command as ironwork runs it (lir.md §9.5): which command, and each option it reads
2//! as a place, a value, text or a bare keyword. `P`, `O` and `S` are the executor's handles to a
3//! data item, to any other operand and to text: the LIR's ids by default, the walker's own
4//! references in the interpreter.
5
6use super::Condition;
7use crate::lir::{Operand, ParaId, PlaceId, SymId};
8use crate::module::ModuleError;
9use crate::module::codec::{Decode, Encode, Reader, Writer};
10use crate::{codec_enum, codec_struct};
11
12/// An option's argument: a data item, another operand (a literal, LENGTH OF and the like), text
13/// the translator kept as written (a label, a name that is not a data item), or none at all.
14#[derive(Clone, Copy, Debug, PartialEq, Eq)]
15pub enum Datum<P = PlaceId, O = Operand, S = SymId> {
16    Place(P),
17    Value(O),
18    Text(S),
19    Bare,
20}
21
22/// An option that may be absent.
23pub type Opt<P = PlaceId, O = Operand, S = SymId> = Option<Datum<P, O, S>>;
24
25#[derive(Clone, Debug, PartialEq, Eq)]
26pub struct CicsCommand<P = PlaceId, O = Operand, S = SymId> {
27    /// The command as written, which messages name: SEND for SEND MAP written as SEND MAP(name).
28    pub name: S,
29    pub command: Cics<P, O, S>,
30    pub resp: Resp<P, O, S>,
31    /// The data items of the block's options an input could steer, in the order an observer is
32    /// told them before the command runs, whether or not the command reads them.
33    pub sinks: Vec<(P, Sink)>,
34}
35
36/// What an observer is told an option's data item is.
37#[derive(Clone, Copy, Debug, PartialEq, Eq)]
38pub enum Sink {
39    DynamicTransfer,
40    RecordKey,
41    RecordUpdate,
42    Log,
43    Screen,
44    WebResponse,
45    HttpHeader,
46    OutboundHost,
47    OutboundHttp,
48    QueueName,
49    Sysid,
50}
51
52impl Sink {
53    /// The sink's kind, as an observer's event names it.
54    pub fn kind(self) -> &'static str {
55        match self {
56            Self::DynamicTransfer => "cics-dynamic-transfer",
57            Self::RecordKey => "record-key",
58            Self::RecordUpdate => "record-update",
59            Self::Log => "log",
60            Self::Screen => "screen",
61            Self::WebResponse => "web-response",
62            Self::HttpHeader => "http-header",
63            Self::OutboundHost => "outbound-host",
64            Self::OutboundHttp => "outbound-http",
65            Self::QueueName => "queue-name",
66            Self::Sysid => "cics-sysid",
67        }
68    }
69}
70
71/// RESP, RESP2 and NOHANDLE, which decide what raising a condition does.
72#[derive(Clone, Debug, PartialEq, Eq)]
73pub struct Resp<P = PlaceId, O = Operand, S = SymId> {
74    pub resp: Opt<P, O, S>,
75    pub resp2: Opt<P, O, S>,
76    pub nohandle: bool,
77}
78
79/// One variant per command ironwork carries out; any other is `Unsupported`.
80#[derive(Clone, Debug, PartialEq, Eq)]
81pub enum Cics<P = PlaceId, O = Operand, S = SymId> {
82    File { verb: FileControl, file: Opt<P, O, S>, options: FileOptions<P, O, S> },
83    /// CHANNEL and IMMEDIATE are kept only for the INVREQ they raise below the task's first level.
84    Return { transid: Opt<P, O, S>, commarea: Opt<P, O, S>, length: Opt<P, O, S>, channel: Opt<P, O, S>, immediate: bool },
85    Link(Transfer<P, O, S>),
86    Xctl(Transfer<P, O, S>),
87    Abend { abcode: Opt<P, O, S>, cancel: bool },
88    /// Each condition with its paragraph, or None to remove its entry.
89    HandleCondition(Vec<(Condition, Option<ParaId>)>),
90    IgnoreCondition(Vec<Condition>),
91    PushHandle,
92    PopHandle,
93    /// PROGRAM or LABEL sets the exit, RESET reactivates it, and with none of them it is CANCEL.
94    HandleAbend { program: Opt<P, O, S>, label: Option<ParaId>, reset: bool },
95    HandleAid,
96    SendMap { map: Opt<P, O, S>, mapset: Opt<P, O, S>, from: Opt<P, O, S>, maponly: bool, dataonly: bool, cursor: Opt<P, O, S>, control: Control },
97    ReceiveMap { map: Opt<P, O, S>, mapset: Opt<P, O, S>, into: Opt<P, O, S>, set: Opt<P, O, S> },
98    SendControl { cursor: Opt<P, O, S>, control: Control },
99    Receive(Record<P, O, S>),
100    Asktime { abstime: Opt<P, O, S> },
101    /// `outputs` are the options that name a date or time form, in the order written.
102    Formattime { abstime: Opt<P, O, S>, datesep: Opt<P, O, S>, timesep: Opt<P, O, S>, outputs: Vec<(S, Datum<P, O, S>)> },
103    Assign(Assign<P, O, S>),
104    Getmain { flength: Opt<P, O, S>, length: Opt<P, O, S>, initimg: Opt<P, O, S>, set: Opt<P, O, S> },
105    Freemain,
106    Enq,
107    Deq,
108    Delay,
109    /// Settles the SQL session's unit of work.
110    Syncpoint { rollback: bool },
111    Address { eib: Opt<P, O, S>, commarea: Opt<P, O, S>, cwa: Opt<P, O, S>, twa: Opt<P, O, S> },
112    SendText { from: Opt<P, O, S>, length: Opt<P, O, S> },
113    WriteOperator { text: Opt<P, O, S>, textlength: Opt<P, O, S> },
114    WriteqTs { queue: Opt<P, O, S>, from: Opt<P, O, S>, length: Opt<P, O, S>, rewrite: bool, item: Opt<P, O, S>, numitems: Opt<P, O, S> },
115    ReadqTs { queue: Opt<P, O, S>, next: bool, item: Opt<P, O, S>, numitems: Opt<P, O, S>, record: Record<P, O, S> },
116    DeleteqTs { queue: Opt<P, O, S> },
117    WriteqTd { queue: Opt<P, O, S>, from: Opt<P, O, S>, length: Opt<P, O, S> },
118    ReadqTd { queue: Opt<P, O, S>, record: Record<P, O, S> },
119    DeleteqTd { queue: Opt<P, O, S> },
120    /// "EXEC CICS … is not supported yet", naming the command, when reached.
121    Unsupported,
122    /// A block the walker refuses as it binds it (a HANDLE label that names no procedure, HANDLE
123    /// ABEND with two of PROGRAM, LABEL, CANCEL and RESET): this IRONWORK abend, once the task
124    /// check and the observer's sinks have passed. Only lowering makes it.
125    Refused(S),
126}
127
128#[derive(Clone, Copy, Debug, PartialEq, Eq)]
129pub enum FileControl {
130    Read,
131    Write,
132    Rewrite,
133    Delete,
134    Unlock,
135    Startbr,
136    Resetbr,
137    Readnext,
138    Readprev,
139    Endbr,
140}
141
142#[derive(Clone, Debug, PartialEq, Eq)]
143pub struct FileOptions<P = PlaceId, O = Operand, S = SymId> {
144    pub ridfld: Opt<P, O, S>,
145    pub keylength: Opt<P, O, S>,
146    pub reqid: Opt<P, O, S>,
147    pub from: Opt<P, O, S>,
148    pub numrec: Opt<P, O, S>,
149    pub record: Record<P, O, S>,
150    pub generic: bool,
151    pub rrn: bool,
152    pub gteq: bool,
153    pub equal: bool,
154    pub update: bool,
155}
156
157/// Where a record read arrives: INTO, or SET's pointer; LENGTH, which also limits it. WRITE's
158/// LENGTH is the same option.
159#[derive(Clone, Debug, PartialEq, Eq)]
160pub struct Record<P = PlaceId, O = Operand, S = SymId> {
161    pub into: Opt<P, O, S>,
162    pub set: Opt<P, O, S>,
163    pub length: Opt<P, O, S>,
164}
165
166/// LINK's and XCTL's options.
167#[derive(Clone, Debug, PartialEq, Eq)]
168pub struct Transfer<P = PlaceId, O = Operand, S = SymId> {
169    pub program: Opt<P, O, S>,
170    pub commarea: Opt<P, O, S>,
171    pub length: Opt<P, O, S>,
172}
173
174/// SEND MAP's and SEND CONTROL's write command and write control character options.
175#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
176pub struct Control {
177    pub erase: bool,
178    pub freekb: bool,
179    pub alarm: bool,
180    pub frset: bool,
181}
182
183/// The ASSIGN options ironwork answers.
184#[derive(Clone, Debug, PartialEq, Eq)]
185pub struct Assign<P = PlaceId, O = Operand, S = SymId> {
186    pub applid: Opt<P, O, S>,
187    pub sysid: Opt<P, O, S>,
188    pub userid: Opt<P, O, S>,
189    pub netname: Opt<P, O, S>,
190    pub facility: Opt<P, O, S>,
191    pub startcode: Opt<P, O, S>,
192    pub abcode: Opt<P, O, S>,
193    pub program: Opt<P, O, S>,
194    pub cwaleng: Opt<P, O, S>,
195    pub twaleng: Opt<P, O, S>,
196}
197
198impl<P, O, S> Cics<P, O, S> {
199    /// The variant's name, as the command it carries out is spelt.
200    pub fn name(&self) -> &'static str {
201        match self {
202            Self::File { verb, .. } => verb.name(),
203            Self::Return { .. } => "RETURN",
204            Self::Link(_) => "LINK",
205            Self::Xctl(_) => "XCTL",
206            Self::Abend { .. } => "ABEND",
207            Self::HandleCondition(_) => "HANDLE CONDITION",
208            Self::IgnoreCondition(_) => "IGNORE CONDITION",
209            Self::PushHandle => "PUSH HANDLE",
210            Self::PopHandle => "POP HANDLE",
211            Self::HandleAbend { .. } => "HANDLE ABEND",
212            Self::HandleAid => "HANDLE AID",
213            Self::SendMap { .. } => "SEND MAP",
214            Self::ReceiveMap { .. } => "RECEIVE MAP",
215            Self::SendControl { .. } => "SEND CONTROL",
216            Self::Receive(_) => "RECEIVE",
217            Self::Asktime { .. } => "ASKTIME",
218            Self::Formattime { .. } => "FORMATTIME",
219            Self::Assign(_) => "ASSIGN",
220            Self::Getmain { .. } => "GETMAIN",
221            Self::Freemain => "FREEMAIN",
222            Self::Enq => "ENQ",
223            Self::Deq => "DEQ",
224            Self::Delay => "DELAY",
225            Self::Syncpoint { .. } => "SYNCPOINT",
226            Self::Address { .. } => "ADDRESS",
227            Self::SendText { .. } => "SEND TEXT",
228            Self::WriteOperator { .. } => "WRITE OPERATOR",
229            Self::WriteqTs { .. } => "WRITEQ TS",
230            Self::ReadqTs { .. } => "READQ TS",
231            Self::DeleteqTs { .. } => "DELETEQ TS",
232            Self::WriteqTd { .. } => "WRITEQ TD",
233            Self::ReadqTd { .. } => "READQ TD",
234            Self::DeleteqTd { .. } => "DELETEQ TD",
235            Self::Unsupported => "unsupported",
236            Self::Refused(_) => "refused",
237        }
238    }
239}
240
241/// Turns a command's handles into another executor's, as lowering turns the walker's references
242/// into the LIR's ids.
243pub trait Handles<P, O, S> {
244    type Place;
245    type Value;
246    type Text;
247    type Error;
248    fn place(&mut self, place: P) -> Result<Self::Place, Self::Error>;
249    fn value(&mut self, value: O) -> Result<Self::Value, Self::Error>;
250    fn text(&mut self, text: S) -> Result<Self::Text, Self::Error>;
251}
252
253type Mapped<H, P, O, S, T> = Result<T, <H as Handles<P, O, S>>::Error>;
254type DatumOf<H, P, O, S> = Datum<<H as Handles<P, O, S>>::Place, <H as Handles<P, O, S>>::Value, <H as Handles<P, O, S>>::Text>;
255type OptOf<H, P, O, S> = Option<DatumOf<H, P, O, S>>;
256type CommandOf<H, P, O, S> = CicsCommand<<H as Handles<P, O, S>>::Place, <H as Handles<P, O, S>>::Value, <H as Handles<P, O, S>>::Text>;
257type CicsOf<H, P, O, S> = Cics<<H as Handles<P, O, S>>::Place, <H as Handles<P, O, S>>::Value, <H as Handles<P, O, S>>::Text>;
258type RecordOf<H, P, O, S> = Record<<H as Handles<P, O, S>>::Place, <H as Handles<P, O, S>>::Value, <H as Handles<P, O, S>>::Text>;
259type TransferOf<H, P, O, S> = Transfer<<H as Handles<P, O, S>>::Place, <H as Handles<P, O, S>>::Value, <H as Handles<P, O, S>>::Text>;
260
261impl<P, O, S> Datum<P, O, S> {
262    pub fn map<H: Handles<P, O, S>>(self, h: &mut H) -> Mapped<H, P, O, S, DatumOf<H, P, O, S>> {
263        Ok(match self {
264            Self::Place(p) => Datum::Place(h.place(p)?),
265            Self::Value(o) => Datum::Value(h.value(o)?),
266            Self::Text(s) => Datum::Text(h.text(s)?),
267            Self::Bare => Datum::Bare,
268        })
269    }
270}
271
272fn opt<P, O, S, H: Handles<P, O, S>>(o: Opt<P, O, S>, h: &mut H) -> Mapped<H, P, O, S, OptOf<H, P, O, S>> {
273    o.map(|d| d.map(h)).transpose()
274}
275
276impl<P, O, S> CicsCommand<P, O, S> {
277    /// The same command over `h`'s handles, each mapped in the order the fields are written.
278    pub fn map<H: Handles<P, O, S>>(self, h: &mut H) -> Mapped<H, P, O, S, CommandOf<H, P, O, S>> {
279        let name = h.text(self.name)?;
280        let command = self.command.map(h)?;
281        let resp = Resp { resp: opt(self.resp.resp, h)?, resp2: opt(self.resp.resp2, h)?, nohandle: self.resp.nohandle };
282        let sinks = self.sinks.into_iter().map(|(p, sink)| Ok((h.place(p)?, sink))).collect::<Result<_, _>>()?;
283        Ok(CicsCommand { name, command, resp, sinks })
284    }
285}
286
287impl<P, O, S> Record<P, O, S> {
288    fn map<H: Handles<P, O, S>>(self, h: &mut H) -> Mapped<H, P, O, S, RecordOf<H, P, O, S>> {
289        Ok(Record { into: opt(self.into, h)?, set: opt(self.set, h)?, length: opt(self.length, h)? })
290    }
291}
292
293impl<P, O, S> Transfer<P, O, S> {
294    fn map<H: Handles<P, O, S>>(self, h: &mut H) -> Mapped<H, P, O, S, TransferOf<H, P, O, S>> {
295        Ok(Transfer { program: opt(self.program, h)?, commarea: opt(self.commarea, h)?, length: opt(self.length, h)? })
296    }
297}
298
299impl<P, O, S> Cics<P, O, S> {
300    fn map<H: Handles<P, O, S>>(self, h: &mut H) -> Mapped<H, P, O, S, CicsOf<H, P, O, S>> {
301        Ok(match self {
302            Self::File { verb, file, options: o } => Cics::File {
303                verb,
304                file: opt(file, h)?,
305                options: FileOptions {
306                    ridfld: opt(o.ridfld, h)?,
307                    keylength: opt(o.keylength, h)?,
308                    reqid: opt(o.reqid, h)?,
309                    from: opt(o.from, h)?,
310                    numrec: opt(o.numrec, h)?,
311                    record: o.record.map(h)?,
312                    generic: o.generic,
313                    rrn: o.rrn,
314                    gteq: o.gteq,
315                    equal: o.equal,
316                    update: o.update,
317                },
318            },
319            Self::Return { transid, commarea, length, channel, immediate } => {
320                Cics::Return { transid: opt(transid, h)?, commarea: opt(commarea, h)?, length: opt(length, h)?, channel: opt(channel, h)?, immediate }
321            }
322            Self::Link(t) => Cics::Link(t.map(h)?),
323            Self::Xctl(t) => Cics::Xctl(t.map(h)?),
324            Self::Abend { abcode, cancel } => Cics::Abend { abcode: opt(abcode, h)?, cancel },
325            Self::HandleCondition(labels) => Cics::HandleCondition(labels),
326            Self::IgnoreCondition(conditions) => Cics::IgnoreCondition(conditions),
327            Self::PushHandle => Cics::PushHandle,
328            Self::PopHandle => Cics::PopHandle,
329            Self::HandleAbend { program, label, reset } => Cics::HandleAbend { program: opt(program, h)?, label, reset },
330            Self::HandleAid => Cics::HandleAid,
331            Self::SendMap { map, mapset, from, maponly, dataonly, cursor, control } => {
332                Cics::SendMap { map: opt(map, h)?, mapset: opt(mapset, h)?, from: opt(from, h)?, maponly, dataonly, cursor: opt(cursor, h)?, control }
333            }
334            Self::ReceiveMap { map, mapset, into, set } => Cics::ReceiveMap { map: opt(map, h)?, mapset: opt(mapset, h)?, into: opt(into, h)?, set: opt(set, h)? },
335            Self::SendControl { cursor, control } => Cics::SendControl { cursor: opt(cursor, h)?, control },
336            Self::Receive(record) => Cics::Receive(record.map(h)?),
337            Self::Asktime { abstime } => Cics::Asktime { abstime: opt(abstime, h)? },
338            Self::Formattime { abstime, datesep, timesep, outputs } => {
339                let (abstime, datesep, timesep) = (opt(abstime, h)?, opt(datesep, h)?, opt(timesep, h)?);
340                let outputs = outputs.into_iter().map(|(name, d)| Ok((h.text(name)?, d.map(h)?))).collect::<Result<_, _>>()?;
341                Cics::Formattime { abstime, datesep, timesep, outputs }
342            }
343            Self::Assign(a) => Cics::Assign(Assign {
344                applid: opt(a.applid, h)?,
345                sysid: opt(a.sysid, h)?,
346                userid: opt(a.userid, h)?,
347                netname: opt(a.netname, h)?,
348                facility: opt(a.facility, h)?,
349                startcode: opt(a.startcode, h)?,
350                abcode: opt(a.abcode, h)?,
351                program: opt(a.program, h)?,
352                cwaleng: opt(a.cwaleng, h)?,
353                twaleng: opt(a.twaleng, h)?,
354            }),
355            Self::Getmain { flength, length, initimg, set } => Cics::Getmain { flength: opt(flength, h)?, length: opt(length, h)?, initimg: opt(initimg, h)?, set: opt(set, h)? },
356            Self::Freemain => Cics::Freemain,
357            Self::Enq => Cics::Enq,
358            Self::Deq => Cics::Deq,
359            Self::Delay => Cics::Delay,
360            Self::Syncpoint { rollback } => Cics::Syncpoint { rollback },
361            Self::Address { eib, commarea, cwa, twa } => Cics::Address { eib: opt(eib, h)?, commarea: opt(commarea, h)?, cwa: opt(cwa, h)?, twa: opt(twa, h)? },
362            Self::SendText { from, length } => Cics::SendText { from: opt(from, h)?, length: opt(length, h)? },
363            Self::WriteOperator { text, textlength } => Cics::WriteOperator { text: opt(text, h)?, textlength: opt(textlength, h)? },
364            Self::WriteqTs { queue, from, length, rewrite, item, numitems } => {
365                Cics::WriteqTs { queue: opt(queue, h)?, from: opt(from, h)?, length: opt(length, h)?, rewrite, item: opt(item, h)?, numitems: opt(numitems, h)? }
366            }
367            Self::ReadqTs { queue, next, item, numitems, record } => {
368                Cics::ReadqTs { queue: opt(queue, h)?, next, item: opt(item, h)?, numitems: opt(numitems, h)?, record: record.map(h)? }
369            }
370            Self::DeleteqTs { queue } => Cics::DeleteqTs { queue: opt(queue, h)? },
371            Self::WriteqTd { queue, from, length } => Cics::WriteqTd { queue: opt(queue, h)?, from: opt(from, h)?, length: opt(length, h)? },
372            Self::ReadqTd { queue, record } => Cics::ReadqTd { queue: opt(queue, h)?, record: record.map(h)? },
373            Self::DeleteqTd { queue } => Cics::DeleteqTd { queue: opt(queue, h)? },
374            Self::Unsupported => Cics::Unsupported,
375            Self::Refused(why) => Cics::Refused(h.text(why)?),
376        })
377    }
378
379    /// The paragraphs HANDLE CONDITION and HANDLE ABEND name.
380    pub fn labels(&self) -> Vec<ParaId> {
381        match self {
382            Self::HandleCondition(labels) => labels.iter().filter_map(|&(_, p)| p).collect(),
383            Self::HandleAbend { label, .. } => label.iter().copied().collect(),
384            _ => Vec::new(),
385        }
386    }
387}
388
389impl FileControl {
390    pub fn name(self) -> &'static str {
391        match self {
392            Self::Read => "READ",
393            Self::Write => "WRITE",
394            Self::Rewrite => "REWRITE",
395            Self::Delete => "DELETE",
396            Self::Unlock => "UNLOCK",
397            Self::Startbr => "STARTBR",
398            Self::Resetbr => "RESETBR",
399            Self::Readnext => "READNEXT",
400            Self::Readprev => "READPREV",
401            Self::Endbr => "ENDBR",
402        }
403    }
404}
405
406/// A condition's tag is its place in DFHRESP's order.
407impl Encode for Condition {
408    fn encode(&self, w: &mut Writer) {
409        w.leb(*self as u64);
410    }
411}
412
413impl Decode for Condition {
414    fn decode(r: &mut Reader<'_>) -> Result<Self, ModuleError> {
415        let at = r.position();
416        let tag = r.leb()?;
417        usize::try_from(tag).ok().and_then(|i| Condition::ALL.get(i).copied()).ok_or_else(|| r.malformed(at, format!("Condition has no tag {tag}")))
418    }
419}
420
421codec_enum!(Datum { Place(place) = 0, Value(value) = 1, Text(text) = 2, Bare = 3 });
422codec_struct!(CicsCommand { name, command, resp, sinks });
423codec_enum!(Sink {
424    DynamicTransfer = 0,
425    RecordKey = 1,
426    RecordUpdate = 2,
427    Log = 3,
428    Screen = 4,
429    WebResponse = 5,
430    HttpHeader = 6,
431    OutboundHost = 7,
432    OutboundHttp = 8,
433    QueueName = 9,
434    Sysid = 10,
435});
436codec_struct!(Resp { resp, resp2, nohandle });
437// Tags 1 and 9 are retired; HandleAbend, whose PROGRAM is a datum, is 34, and Return, with CHANNEL
438// and IMMEDIATE, is 35.
439codec_enum!(Cics {
440    File { verb, file, options } = 0,
441    Link(transfer) = 2,
442    Xctl(transfer) = 3,
443    Abend { abcode, cancel } = 4,
444    HandleCondition(handlers) = 5,
445    IgnoreCondition(conditions) = 6,
446    PushHandle = 7,
447    PopHandle = 8,
448    HandleAid = 10,
449    SendMap { map, mapset, from, maponly, dataonly, cursor, control } = 11,
450    ReceiveMap { map, mapset, into, set } = 12,
451    SendControl { cursor, control } = 13,
452    Receive(record) = 14,
453    Asktime { abstime } = 15,
454    Formattime { abstime, datesep, timesep, outputs } = 16,
455    Assign(assign) = 17,
456    Getmain { flength, length, initimg, set } = 18,
457    Freemain = 19,
458    Enq = 20,
459    Deq = 21,
460    Delay = 22,
461    Syncpoint { rollback } = 23,
462    Address { eib, commarea, cwa, twa } = 24,
463    SendText { from, length } = 25,
464    WriteOperator { text, textlength } = 26,
465    WriteqTs { queue, from, length, rewrite, item, numitems } = 27,
466    ReadqTs { queue, next, item, numitems, record } = 28,
467    DeleteqTs { queue } = 29,
468    WriteqTd { queue, from, length } = 30,
469    ReadqTd { queue, record } = 31,
470    DeleteqTd { queue } = 32,
471    Unsupported = 33,
472    HandleAbend { program, label, reset } = 34,
473    Return { transid, commarea, length, channel, immediate } = 35,
474    Refused(why) = 36,
475});
476codec_enum!(FileControl {
477    Read = 0,
478    Write = 1,
479    Rewrite = 2,
480    Delete = 3,
481    Unlock = 4,
482    Startbr = 5,
483    Resetbr = 6,
484    Readnext = 7,
485    Readprev = 8,
486    Endbr = 9,
487});
488codec_struct!(FileOptions { ridfld, keylength, reqid, from, numrec, record, generic, rrn, gteq, equal, update });
489codec_struct!(Record { into, set, length });
490codec_struct!(Transfer { program, commarea, length });
491codec_struct!(Control { erase, freekb, alarm, frset });
492codec_struct!(Assign { applid, sysid, userid, netname, facility, startcode, abcode, program, cwaleng, twaleng });