



		    PNOTICE_rje.alm                 04/02/85  1516.9r w 04/02/85  1516.8        2853



	dec	1			"version 1 structure
	dec	1			"no. of pnotices
	dec	3			"no. of STIs
	dec	100			"lgth of all pnotices + no. of pnotices
          acc       "Copyright (c) 1972 by Massachusetts Institute of
Technology and Honeywell Information Systems, Inc."

	aci	"C1RJEM0B0000"
	aci	"C2RJEM0B0000"
	aci	"C3RJEM0B0000"
	end
   



		    ibm2780_.pl1                    08/08/90  1040.5rew 08/08/90  1038.5      227745



/****^  ***********************************************************
        *                                                         *
        * Copyright, (C) BULL HN Information Systems Inc., 1990   *
        *                                                         *
        * Copyright, (C) Honeywell Information Systems Inc., 1982 *
        *                                                         *
        * Copyright (c) 1972 by Massachusetts Institute of        *
        * Technology and Honeywell Information Systems, Inc.      *
        *                                                         *
        *********************************************************** */




/****^  HISTORY COMMENTS:
  1) change(90-06-13,Vu), approve(90-06-13,MCR8178), audit(90-07-13,Bubric),
     install(90-08-08,MR12.4-1023):
     ibm2780_ gets "size" condition after 99 attaches.
                                                   END HISTORY COMMENTS */


/* ibm2780_: An I/O module for communicating with an IBM 2780 or its equivilent. */

/* Coded March 1977 by David Vinograd */

ibm2780_: proc;

/* Parameters */

dcl  a_iocbp ptr;
dcl  a_option (*) char (*) var;			/* Options for attach */
dcl  a_sw bit (1);					/* com_err_ switch for attach */
dcl  a_code fixed bin (35);
dcl  a_mode fixed bin;				/* The open mode */
dcl  a_buf_ptr ptr;
dcl  a_data_ptr ptr;
dcl  a_buf_chars fixed bin (21);
dcl  a_data_chars fixed bin (21);
dcl  a_pos_type fixed bin;
dcl  a_pos_value fixed bin (21);
dcl  a_order char (*);
dcl  a_infop ptr;
dcl  a_new_modes char (*);
dcl  a_old_modes char (*);

/* Automatic */

dcl  com_err_sw bit (1);				/* Set if com_err_ sould be called on attach error */
dcl  charp ptr;
dcl  attach_tag picture "99";
dcl  input_chars fixed bin;				/* number of characters to transmitted */
dcl  num_chars_rec fixed bin;				/* number of characters recieved */
dcl  code fixed bin (35);
dcl  iocbp ptr;
dcl  mask bit (36) aligned;				/* For setting ips mask */
dcl  i fixed bin (21);
dcl  j fixed bin;
dcl  k fixed bin;
dcl  open_mode fixed bin;
dcl  device char (32);
dcl  remaining_chars fixed bin (21);
dcl  data_chars fixed bin (21);
dcl  order char (32);
dcl  infop ptr;
dcl  prefix char (2) var;
dcl  input char (400) var;
dcl  output char (400) var;
dcl  ctl_string char (256) var;
dcl  card_image char (80) var;
dcl  comm_attach_name char (32) var;
dcl  terminal_attach_options char (256) var;
dcl  comm_attach_options char (256) var;
dcl  comm_attach_desc char (256) var;
dcl  comm char (32) var;
dcl  tty char (32) var;
dcl  dummy_arg char (32);
dcl  carriage_ctl_string char (8) ;
dcl  slew_ctl_string char (6) ;
dcl  temp_iocbp ptr;
dcl  char_mode_set bit (1);
dcl  multi_record_cnt fixed bin;
dcl  trans_mode_set bit (1);

dcl 1 send_nontransparent aligned,
    2 len fixed bin,
    2 char_string char (256);

dcl 1 local_bsc_modes like set_bsc_modes aligned;

dcl 1 set_bsc_modes aligned based (infop),
    2 transparent bit (1) unal,
    2 char_mode bit (1) unal,
    2 pad bit (34) unal;

/* Internal static */

/* ..... the next six variables should be per comm attachment rather than int static */

dcl  last_select char (32) int static;			/* last device selected */
dcl  comm_iocbp ptr int static init (null);
dcl  quit_mode bit (1) int static init ("0"b);
dcl  EM char (1) int static init ("");
dcl  attach_count fixed bin init (0) int static;
dcl  comm_open bit (1) int static init ("0"b);


dcl  default_carriage_ctl_table (4) char (4) aligned static init ("/", "/", "S", "T");
dcl  carriage_ctl_table (4) char (4) aligned static init ((4) (4)" ");
dcl  default_slew_ctl_table (6) char (4) aligned static init ("    ", "A", "   ",
     "A", "   	", "A");
dcl  slew_ctl_table (6) char (4) aligned static init ((6) (4)" ");
dcl  printer_select char (2) int static init ("/");
dcl  punch_select char (2) int static init ("4");

/* Constants */

dcl  terminal_device_name char (8) int static options (constant) init ("ibm2780_");
dcl  space char (1) static int init (" ") options (constant);
dcl  carriage_control_char fixed bin int static init (1) options (constant);

/* External stuff */

dcl  convert_string_$input entry (char (*) var, ptr, char (*) var, fixed bin (35));
dcl  convert_string_$output entry (char (*) var, ptr, char (*) var, fixed bin (35));
dcl  get_ttt_info_ entry (ptr, fixed bin (35));
dcl  continue_to_signal_ entry (fixed bin (35));
dcl  get_temp_segment_ entry (char (*), ptr, fixed bin (35));
dcl  release_temp_segment_ entry (char (*), ptr, fixed bin (35));
dcl  hcs_$reset_ips_mask entry (bit (36) aligned, bit (36) aligned);
dcl  hcs_$set_ips_mask entry (bit (36) aligned, bit (36) aligned);
dcl  iox_$propagate entry (ptr);
dcl  iox_$position entry (ptr, fixed bin, fixed bin (21), fixed bin (35));
dcl  com_err_ entry options (variable);
dcl  iox_$attach_ioname entry (char (*), ptr, char (*), fixed bin (35));
dcl  iox_$detach_iocb entry (ptr, fixed bin (35));
dcl  iox_$close entry (ptr, fixed bin (35));
dcl  iox_$open entry (ptr, fixed bin, bit (36), fixed bin (35));
dcl  iox_$get_chars entry (ptr, ptr, fixed bin, fixed bin, fixed bin (35));
dcl  iox_$put_chars entry (ptr, ptr, fixed bin, fixed bin (35));
dcl  iox_$control entry (ptr, char (*), ptr, fixed bin (35));
dcl  iox_$err_no_operation entry;

dcl (addr, addrel, bin, char, convert, copy, hbound, length, ltrim) builtin;
dcl (min, mod, null, rtrim, substr) builtin;

dcl  ibm2780_conv_$slew_ctl_table_ptr ptr ext;
dcl  ibm2780_conv_$carriage_ctl_table_ptr ptr ext;
dcl  sys_info$max_seg_size fixed bin ext;
dcl  error_table_$bad_conversion fixed bin (35) ext;
dcl  error_table_$bisync_bid_fail ext fixed bin (35);
dcl  error_table_$no_operation fixed bin (35) ext;
dcl  error_table_$bad_arg ext fixed bin (35);
dcl  error_table_$bad_mode ext fixed bin (35);
dcl  error_table_$not_detached ext fixed bin (35);
dcl  error_table_$wrong_no_of_args ext fixed bin (35);
dcl  error_table_$noarg ext fixed bin (35);
dcl  error_table_$badopt ext fixed bin (35);

dcl  conversion condition;
dcl  cleanup condition;
dcl  quit condition;
dcl  any_other condition;

dcl  info_fixed fixed bin based (infop);
dcl  info_string char (32) based (infop);
dcl  char_string char (80) based (charp);

%include ibm2780_data;
%include remote_ttt_info;
%include iocb;
%include iox_modes;
%include io_call_info;

/* Attach entry point */

ibm2780_attach: entry (a_iocbp, a_option, a_sw, a_code);

	iocbp = a_iocbp;
	com_err_sw = a_sw;
	code, a_code = 0;

	adp = null;
	if iocbp -> iocb.attach_descrip_ptr ^= null then do;
	     code = error_table_$not_detached;
	     call abort_attach ("^a", iocbp -> iocb.name);
	end;

	call get_temp_segment_ (terminal_device_name, adp, code); /* Temp segment for attach data */
	if code ^= 0 then call abort_attach ("Unable to allocate temp segment.", "");

/* Initialize IOCB variables */

	ad.bits = "0"b;
	ad.fixed = 0;
	ad.ptrs = null;
	ad.chars = "";
	ad.printer_select = printer_select;
	ad.punch_select = punch_select;
	ad.char_mode = ebcdic;
	ad.record_len = 80;
	ad.phys_line_length = 80;

	ad.kill_char = "@";
	ad.erase_char = "#";
	ad.ttt_ptrs = null;
	ad.ttt_bits = "1"b;

	if comm_iocbp = null then do;
	     carriage_ctl_table (*) = default_carriage_ctl_table (*);
	     ibm2780_conv_$carriage_ctl_table_ptr = addr (carriage_ctl_table);
	     slew_ctl_table (*) = default_slew_ctl_table (*);
	     ibm2780_conv_$slew_ctl_table_ptr = addr (slew_ctl_table);
	end;

/* Process options */

	if hbound (a_option, 1) < 1 then do;		/* Must be at least one */
	     code = error_table_$wrong_no_of_args;
	     call abort_attach ("Bad attach description.", "");
	end;
	trans_mode_set, char_mode_set = "0"b;
	comm_attach_desc, comm_attach_options = "";
	tty, comm = "";
	terminal_attach_options = "";
	comm_attach_name = "";
	do i = 1 to hbound (a_option, 1);
	     if a_option (i) = "-size" then do;
		code = error_table_$badopt;
		call abort_attach ("bad option", ((a_option (i))));
	     end;
	     if a_option (i) ^= "-comm" then
		terminal_attach_options = terminal_attach_options || space || a_option (i);
	     if a_option (i) = "-transparent" then do;
		ad.transparent = "1"b;
		trans_mode_set = "1"b;
		comm_attach_options = comm_attach_options || space || a_option (i);
	     end;
	     else if a_option (i) = "-terminal_type" | a_option (i) = "-ttp" then do;
		ad.terminal_type = get_arg ();
		call get_ttt_info_ (addr (ad.remote_ttt_info), code);
		if code ^= 0 then call abort_attach ("Unable to set terminal type tables", "");
	     end;
	     else if a_option (i) = "-carriage_ctl" then do;
		carriage_ctl_string = get_arg ();
		do j = 1 to 4;
		     carriage_ctl_table (j) = substr (carriage_ctl_string, (j * 2) - 1, 2);
		end;
	     end;
	     else if a_option (i) = "-slew_ctl" then do;
		slew_ctl_string = get_arg ();
		do j = 1 to 3;
		     slew_ctl_table (j*2) = substr (slew_ctl_string, (j * 2) -1, 2);
		end;
	     end;
	     else if a_option (i) = "-nontransparent" then do;
		trans_mode_set = "1"b;
		ad.transparent = "0"b;
		comm_attach_options = comm_attach_options || space || a_option (i);
	     end;
	     else if a_option (i) = "-ascii" then do;
		char_mode_set = "1"b;
		ad.char_mode = ascii;
		comm_attach_options = comm_attach_options || space || a_option (i);
	     end;
	     else if a_option (i) = "-ebcdic" then do;
		char_mode_set = "1"b;
		ad.char_mode = ebcdic;
		comm_attach_options = comm_attach_options || space || a_option (i);
	     end;
	     else if a_option (i) = "-multi_record" then ad.multi_record = "1"b;
	     else if a_option (i) = "-physical_line_length" | a_option (i) = "-pll" then
		ad.phys_line_length = cv_dec_arg ();
	     else if a_option (i) = "-horizontal_tab" | a_option (i) = "-htab" then ad.ht = "1"b;
	     else if a_option (i) = "-multi_point" then
		ad.terminal_id = get_arg ();
	     else if a_option (i) = "-printer_select" then
		ad.printer_select = get_arg ();
	     else if a_option (i) = "-punch_select" then
		ad.punch_select = get_arg ();
	     else if a_option (i) = "-device" then dummy_arg = get_arg (); /* skip this one, but record we got it */
	     else if a_option (i) = "-tty" then
		tty = get_arg ();
	     else if a_option (i) = "-comm" then do;
		i = i + 1;
		if i > hbound (a_option, 1) then goto no_arg;
		comm = a_option (i);
	     end;
	     else comm_attach_options = comm_attach_options || space || a_option (i);
	end;

	if tty = "" then do;
	     code = error_table_$badopt;
	     call abort_attach ("No ""-tty"" option given.", "");
	end;

	if comm = "" then do;
	     code = error_table_$badopt;
	     call abort_attach ("No ""-comm"" option given.", "");
	end;

/* cross check attach descriptions */

	if ^char_mode_set then comm_attach_options = comm_attach_options || " -ebcdic";
	if ^trans_mode_set then comm_attach_options = comm_attach_options || " -nontransparent";

	if ad.multi_record then do;
	     ad.record_len = 400;
	     comm_attach_options = comm_attach_options || " -size 400 -multi_record 7";
	end;
	else comm_attach_options = comm_attach_options || " -size 80";

	if ad.char_mode = ascii & ad.transparent then do;
	     code = error_table_$badopt;
	     call abort_attach ("Unsupported attachment mode", "");
	end;

/* Compare attach description with on-line description of device */

	call check_attach_description;
	if code ^= 0 then call abort_attach ("Attach  mismatch on  option ^a", ((a_option (i))));

/* Attach through comm dim */

	/* use attach_count as comm_tag, use at least two digits */
	if attach_count < 100 then do;
	     attach_tag = attach_count;
	     comm_attach_name = terminal_device_name || attach_tag;
	  end;
	else comm_attach_name = terminal_device_name || ltrim(char(attach_count));
	attach_count = attach_count + 1;
	last_select = "";
	comm_attach_desc = comm || space || tty || space || comm_attach_options;
	if comm_iocbp = null then do;
	     call iox_$attach_ioname ((comm_attach_name), temp_iocbp, (comm_attach_desc), code);
	     if code ^= 0 then call abort_attach ("Unable to attach to comm channel", "");
	     comm_iocbp = temp_iocbp;
	end;

	ad.attach_desc = terminal_device_name || space || comm || space || terminal_attach_options;

/* Mask and complete the iocb */

	mask = "0"b;
	on any_other call handler;
	call hcs_$set_ips_mask ("0"b, mask);
	iocbp -> iocb.attach_descrip_ptr = addr (ad.attach_desc);
	iocbp -> iocb.attach_data_ptr = adp;
	iocbp -> iocb.open = ibm2780_open;
	iocbp -> iocb.detach_iocb = ibm2780_detach;
	call iox_$propagate (iocbp);
	call hcs_$reset_ips_mask (mask, mask);
	revert any_other;

attach_return:
	return;
no_arg:
	code = error_table_$noarg;
	call abort_attach ("No argument after ^a.", (a_option (i-1)));


/* Detach entry point */

ibm2780_detach: entry (a_iocbp, a_code);

	iocbp = a_iocbp;
	code, a_code = 0;
	adp = iocbp -> iocb.attach_data_ptr;

	if comm_iocbp ^= null then do;
	     call iox_$detach_iocb (comm_iocbp, a_code);
	     comm_iocbp = null;
	end;

	mask = "0"b;
	on any_other call handler;
	call hcs_$set_ips_mask ("0"b, mask);
	iocbp -> iocb.attach_descrip_ptr = null;
	call iox_$propagate (iocbp);
	call hcs_$reset_ips_mask (mask, mask);
	revert any_other;

	call release_temp_segment_ (terminal_device_name, adp, (0));
	return;

/* Open entry point */

ibm2780_open: entry (a_iocbp, a_mode, a_sw, a_code);

	iocbp = a_iocbp -> iocb.actual_iocb_ptr;
	code, a_code = 0;
	adp = iocbp -> iocb.attach_data_ptr;

	open_mode = a_mode;
	if ^((open_mode = Stream_input) | (open_mode = Stream_output) | (open_mode = Stream_input_output)) then do;
bad_mode:	     a_code = error_table_$bad_mode;
	     return;
	end;

	ad.open_description = rtrim (iox_modes (open_mode), space);

	if ^comm_open & comm_iocbp ^= null then do;
	     call iox_$open (comm_iocbp, a_mode, "0"b, a_code);
	     if a_code ^= 0 then return;
	     comm_open = "1"b;
	end;

	mask = "0"b;
	on any_other call handler;
	call hcs_$set_ips_mask ("0"b, mask);
	if ((open_mode = Stream_input) | (open_mode = Stream_input_output)) then do;
	     iocbp -> iocb.get_chars = ibm2780_get_chars;
	end;
	if ((open_mode = Stream_output) | (open_mode = Stream_input_output)) then do;
	     iocbp -> iocb.put_chars = ibm2780_put_chars;
	end;
	iocbp -> iocb.control = ibm2780_control;
	iocbp -> iocb.position = ibm2780_position;
	iocbp -> iocb.modes = ibm2780_modes;
	iocbp -> iocb.close = ibm2780_close;
	iocbp -> iocb.open_descrip_ptr = addr (ad.open_description);
	call iox_$propagate (iocbp);
	call hcs_$reset_ips_mask (mask, mask);
	revert any_other;
	return;

/* Close entry point */

ibm2780_close: entry (a_iocbp, a_code);

	iocbp = a_iocbp -> iocb.actual_iocb_ptr;
	code, a_code = 0;
	adp = iocbp -> iocb.attach_data_ptr;

	if comm_iocbp ^= null then do;
	     call iox_$close (comm_iocbp, a_code);
	     comm_open = "0"b;
	end;

	mask = "0"b;
	on any_other call handler;
	call hcs_$set_ips_mask ("0"b, mask);
	iocbp -> iocb.open_descrip_ptr = null;
	iocbp -> iocb.open = ibm2780_open;
	iocbp -> iocb.detach_iocb = ibm2780_detach;
	iocbp -> iocb.control = iox_$err_no_operation;
	iocbp -> iocb.position = iox_$err_no_operation;
	iocbp -> iocb.modes = iox_$err_no_operation;
	call iox_$propagate (iocbp);
	call hcs_$reset_ips_mask (mask, mask);
	revert any_other;
	return;

/* Put_chars entry point */

ibm2780_put_chars: entry (a_iocbp, a_data_ptr, a_data_chars, a_code);

	iocbp = a_iocbp -> iocb.actual_iocb_ptr;
	code, a_code = 0;
	if comm_iocbp = null then do;
	     a_code = error_table_$no_operation;
	     return;
	end;
	adp = iocbp -> iocb.attach_data_ptr;

	if a_data_chars < 0 | a_data_chars > sys_info$max_seg_size * 4 then do;
	     a_code = error_table_$bad_arg;
	     return;
	end;
	remaining_chars = a_data_chars;		/* This is decremented as data is sent */
	charp = a_data_ptr;
	do while (remaining_chars > 0);
	     call put_string;
	     if code ^= 0 then goto put_chars_ret;
	end;
put_chars_ret:
	a_code = code;
	return;

/* Get_chars entry point */

ibm2780_get_chars: entry (a_iocbp, a_buf_ptr, a_buf_chars, a_data_chars, a_code);

	iocbp = a_iocbp -> iocb.actual_iocb_ptr;
	adp = iocbp -> iocb.attach_data_ptr;
	code, a_code = 0;
	if comm_iocbp = null then do;
	     a_code = error_table_$no_operation;
	     return;
	end;
	a_data_chars, data_chars = 0;
	remaining_chars = a_buf_chars;
	charp = a_buf_ptr;

	call get_string;
get_chars_ret:
	a_code = code;
	a_data_chars = data_chars;
	return;

/* Control entry point */

ibm2780_control: entry (a_iocbp, a_order, a_infop, a_code);

	iocbp = a_iocbp -> iocb.actual_iocb_ptr;
	adp = iocbp -> iocb.attach_data_ptr;
	infop = a_infop;
	order = a_order;
	code, a_code = 0;
	if comm_iocbp = null then goto nop;
	if order = "set_bsc_modes" then do;
	     ad.transparent = set_bsc_modes.transparent;
	     if set_bsc_modes.char_mode then ad.char_mode = ebcdic;
	     else ad.char_mode = ascii;
	     call iox_$control (comm_iocbp, order, infop, code);
	     if code ^= 0 then goto control_ret;
	     if ad.multi_record then multi_record_cnt = 7;
	     else multi_record_cnt = 1;
	     if ad.multi_record then
		call iox_$control (comm_iocbp, "set_multi_record_mode", addr (multi_record_cnt), code);
	end;
	else if order = "select_device" then do;
	     if info_string = last_select then go to control_ret; /* already there */
	     last_select = info_string;
	     if info_string = teleprinter then
		ad.device_type = printer;
	     else if info_string = printer | info_string = punch then
		ad.device_type = info_string;
	     else do;
nop:		code = error_table_$no_operation;
		goto control_ret;
	     end;
	     call select_device;
	     if ad.device_type = printer then call init_printer;
	end;
	else if order = "set_multi_record_mode" then do;
	     ad.multi_record = "1"b;
	     if info_fixed > 7 | info_fixed < 1 then do;
		code = error_table_$no_operation;
		goto control_ret;
	     end;
	     goto do_control;
	end;
	else if order = "io_call" then call ibm2780_io_call;
	else if order = "reset" then ad.edited = "1"b;
	else
do_control:
	call iox_$control (comm_iocbp, order, infop, code);
control_ret:
	a_code = code;
	return;

/* Position entry point */

ibm2780_position: entry (a_iocbp, a_pos_type, a_pos_value, a_code);

	iocbp = a_iocbp -> iocb.actual_iocb_ptr;
	adp = iocbp -> iocb.attach_data_ptr;
	code, a_code = 0;
	if comm_iocbp = null then do;
	     a_code = error_table_$no_operation;
	     return;
	end;
	call iox_$position (comm_iocbp, a_pos_type, a_pos_value, a_code);
	return;

ibm2780_modes: entry (a_iocbp, a_new_modes, a_old_modes, a_code);

	iocbp = a_iocbp -> iocb.actual_iocb_ptr;
	adp = iocbp -> iocb.attach_data_ptr;
	code, a_code = 0;
	if a_new_modes = "non_edited" then
	     ad.edited = "0"b;
	else if a_new_modes = "default" then
	     ad.edited = "1"b;
	else code = error_table_$bad_mode;
	return;

check_attach_description: proc;

/* This proc compares the input attach description  with the one on line and returns an error
   if there is a mismatch. */

	end check_attach_description;

cv_dec_arg: proc returns (fixed bin);

	     i = i + 1;				/* Advance to next arg */
	     if i > hbound (a_option, 1) then goto no_arg;
	     terminal_attach_options = terminal_attach_options || space || a_option (i);
	     on conversion go to bad_dec_arg;
	     return (bin ((a_option (i))));
bad_dec_arg:
	     code = error_table_$bad_conversion;
	     call abort_attach ("Invalid decimal number. ^a", ((a_option (i))));

	end cv_dec_arg;

get_arg:	proc returns (char (*) var);

/* This proc picks up the next arg in the option array */
	     i = i + 1;
	     if i > hbound (a_option, 1) then goto no_arg;
	     terminal_attach_options = terminal_attach_options || space || a_option (i);
	     return ((a_option (i)));

	end get_arg;


abort_attach: proc (str1, str2);
dcl (str1, str2) char (*) aligned;

/* This proc handles attach errors */

	     if com_err_sw then call com_err_ (code, terminal_device_name, str1, str2);
	     a_code = code;
	     if comm_iocbp ^= null then do;
		call iox_$detach_iocb (comm_iocbp, (0));
		comm_iocbp = null;
	     end;
	     if adp ^= null then
		call release_temp_segment_ (terminal_device_name, adp, code);
	     go to attach_return;

	end abort_attach;

select_device: proc;

/* This proc selects the device and the terminal */

	     if ad.terminal_id ^= "" then do;
		if ad.device_type = printer then
		     ctl_string = ad.terminal_id || ad.printer_select || ENQ;
		else if ad.device_type = punch then
		     ctl_string = ad.terminal_id || ad.punch_select || ENQ;
		else return;
	     end;
	     else do;
		if ad.device_type = punch then ctl_string = ad.punch_select;
		else if ad.device_type = printer then ctl_string = ad.printer_select;
		else return;
	     end;
	     call write_nontransparent;
	     return;

	end select_device;

set_tabs:	proc;

/* This proc sets the tabs of the selected terminal. */

	     ctl_string = ESC || HT;			/* control prefix */
	     do i = 1 to ad.phys_line_length;
		if mod (i, 10) = 0 then substr (ctl_string, i, 1) = HT;
	     end;
	     call write_nontransparent;
	     return;

	end set_tabs;

put_string: proc;

/* This proc writes the data contained in input. */

	     input_chars = min (remaining_chars, ad.record_len);
	     input = substr (char_string, 1, input_chars);
	     remaining_chars = remaining_chars - input_chars;
	     charp = addr (substr (char_string, input_chars + 1, 1));
	     if ^quit_mode then do;
		if ad.transparent then do;
		     if ad.device_type = punch then input = input || copy (" ", 80-length (input));
		     else if ad.device_type = printer then
			input = input || copy (" ", ad.phys_line_length + carriage_control_char - length (input));
		end;
		prefix = "";
		k = 1;
		if ad.device_type ^= punch then do;
		     k = 3;
		     ad.escape_output = "0"b;
		     call convert_string_$output (substr (input, 1, 2), addr (ad.remote_ttt_info), prefix, code);
		     ad.escape_output = "1"b;
		     if code ^= 0 then return;
		end;
		call convert_string_$output (substr (input, k), addr (ad.remote_ttt_info), output, code);
		if code ^= 0 then return;
		output = prefix || output;
retry:		call iox_$put_chars (comm_iocbp, addrel (addr (output), 1), length (output), code);
		if code = error_table_$bisync_bid_fail then do;
		     on cleanup begin;
			quit_mode = "0"b;
		     end;
		     quit_mode = "1"b;
		     signal quit;
		     quit_mode = "0"b;
		     goto retry;
		end;
	     end;
	     return;

	end put_string;

get_string: proc;

/* This proc reads  data into the variable card_image up to the preset length */

	     call iox_$get_chars (comm_iocbp, addrel (addr (card_image), 1), 80, num_chars_rec, code);
	     if code ^= 0 then return;
	     card_image = substr (card_image, 1, num_chars_rec);
	     call convert_string_$input (card_image, addr (ad.remote_ttt_info), card_image, code);
	     if code ^= 0 then return;
	     if substr (card_image, num_chars_rec, 1) = EM then
		card_image = substr (card_image, 1, num_chars_rec -1);
	     char_string = card_image;
	     data_chars = data_chars + length (card_image);
	     charp = addr (substr (char_string, length (card_image) + 1, 1));
	     remaining_chars = remaining_chars - length (card_image);
	     return;

	end get_string;


ibm2780_io_call: proc;

/* This proc  handles the io_call orders by  mapping then into control order calls to this dim */

	     io_call_infop = infop;
	     order = io_call_info.order_name;
	     if order = "set_bsc_modes" then do;
		local_bsc_modes.char_mode = (ad.char_mode = ebcdic);
		local_bsc_modes.transparent = ad.transparent;
		do i = 1 to hbound (io_call_info.args, 1);
		     if io_call_info.args (i) = "ascii" then local_bsc_modes.char_mode = "0"b;
		     else if io_call_info.args (i) = "ebcdic" then local_bsc_modes.char_mode = "1"b;
		     else if io_call_info.args (i) = "transparent" then local_bsc_modes.transparent = "1"b;
		     else if io_call_info.args (i) = "nontransparent" then local_bsc_modes.transparent = "0"b;
		end;
		call iox_$control (iocbp, order, addr (local_bsc_modes), code);
		if code ^= 0 then return;
	     end;
	     else if order = "select_device" then do;
		device = io_call_info.args (1);
		call iox_$control (iocbp, order, addr (device), code);
	     end;
	     else if order = "set_multi_record_mode" then do;
		multi_record_cnt = convert (multi_record_cnt, io_call_info.args (1));
		call iox_$control (iocbp, order, addr (multi_record_cnt), code);
	     end;
	     else call iox_$control (comm_iocbp, "io_call", infop, code);
	     return;

	end ibm2780_io_call;

init_printer: proc;

/* This proc initializes the printer, setting tabs if required */

	     if ad.ht then call set_tabs;
	     return;

	end init_printer;

handler:	proc;

/* This proc handles faults that occur while masked */

	     call continue_to_signal_ (code);
	     return;

	end handler;
write_nontransparent: proc;

/* This proc sends the data in ctl_string in a nontransparent mode */


	     ad.escape_output = "0"b;
	     call convert_string_$output (ctl_string, addr (ad.remote_ttt_info), ctl_string, code);
	     ad.escape_output = "1"b;
	     if code ^= 0 then return;
	     send_nontransparent.char_string = ctl_string;
	     send_nontransparent.len = length (ctl_string);
	     call iox_$control (comm_iocbp, "send_nontransparent_msg", addr (send_nontransparent), code);

	     return;

	end write_nontransparent;
     end ibm2780_;
   



		    ibm2780_conv_.alm               02/02/88  1719.8r w 02/02/88  1538.2       30618



" ***********************************************************
" *                                                         *
" * Copyright, (C) Honeywell Information Systems Inc., 1982 *
" *                                                         *
" ***********************************************************
"ibm2780_conv_ - Conversion routine for producing ascii IBM2780 printer output
"	Coded March 1977 by David Vinograd

" 1) Version -- for new Printer DIM.

"  ******************************************************
"  *                                                    *
"  *                                                    *
"  * Copyright (c) 1972 by Massachusetts Institute of   *
"  * Technology and Honeywell Information Systems, Inc. *
"  *                                                    *
"  *                                                    *
"  ******************************************************


"
" The manner in which this procedure is utilized is described in detail
" in the listing of prt_conv_.
"
" This proc puts carriage control chars
" at the beginning of each output line.



	name	ibm2780_conv_

	segdef	printer
	segdef	punch
	segdef	teleprinter

	tempd	init_outp
	tempd	saved_outp
	tempd	saved_lp
	tempd	saved_sb

	tempd	saved_aq
	include	stack_header
	temp	carriage_ctl
	equ	pci,5
	equ	outp,3
	equ	inp,2


teleprinter:
printer:
	tra	send_init
	tra	send_chars
	tra	send_slew_pattern
	tra	send_slew_count

punch:
	tra	pr7|0
	tra	send_chars
	tra	pr7|0
	tra	no_slew
no_slew:
	lda	0,du
	tra	pr7|0


" 

	include	prt_conv_info


" 

send_init:

	spri3	init_outp		store output ptr
	ldq	2,dl		advance output ptr
	a9bd	outp|0,ql		..
	tra	pr7|0		return

" 

send_chars:
	eax2	0,2		set indicators from X2
	tmoz	nospace		if no white space, skip following

	mlr	(),(pr,rl),fill(040)  insert blanks into output
	desc9a	*,0		..
	desc9a	outp|0,x2		..

	a9bd	outp|0,2		step output pointer over blanks

nospace:
	mlr	(pr,rl),(pr,rl)	copy characters into output
	desc9a	inp|0,au		..
	desc9a	outp|0,au		..

	a9bd	inp|0,au		step input and output pointers
	a9bd	outp|0,au		..
	eax2	0		make sure X2 now zero
	tra	pr7|0		return to caller

" 

send_slew_pattern:
	eax7	0		initialize for search
	sprilp	saved_lp
	sprisb	saved_sb
	epbpsb	sp|0
	staq	saved_aq
	epaq	*
	lprplp	sb|stack_header.lot_ptr,*au
	ldaq	saved_aq
	equ	nslew,6
	epplp 	lp|slew_ctl_table_ptr,*
	rpt	nslew/2,2,tze	search for slew characters
	cmpa	lp|0,7		..
	ldq	lp|-1,7

stslew:
	epplp	saved_lp,*
	eppsb	saved_sb,*
	stq	carriage_ctl	save carriage control chars
	spri3	saved_outp	store output ptr
	epp3	init_outp,*	move ptr to register
	mlr	(pr),(pr)		move carriage control into output
	desc9a	carriage_ctl,2	..
	desc9a	pr3|0,2		..
	epp3	saved_outp,*	restore orignal output ptr
	tra	pr7|0		return to caller





send_slew_count:
	eaq	0,al		line count in QU
	sbla	3,dl		can slew at most 3 lines at a time
	tmoz	*+2		if more than 3 lines,
          ldq       3,du                do only 3 to start
	sprilp	saved_lp
	sprisb	saved_sb
	epbpsb	sp|0
	staq	saved_aq
	epaq	*
	lprplp	sb|stack_header.lot_ptr,*au
	ldaq	saved_aq
	ldq	lp|carriage_ctl_table_ptr,*qu
	eppsb	saved_sb,*
	epplp	saved_lp,*
	tra	stslew		and store it for later

	use internal_static
	join	/link/internal_static
	segdef	carriage_ctl_table_ptr
	segdef	slew_ctl_table_ptr
carriage_ctl_table_ptr:
	even
	its	-1,1
slew_ctl_table_ptr:
	its	-1,1



	end
  



		    ibm3780_.pl1                    08/08/90  1040.5rew 08/08/90  1037.8      445176



/****^  ***********************************************************
        *                                                         *
        * Copyright, (C) BULL HN Information Systems Inc., 1990   *
        *                                                         *
        * Copyright, (C) Honeywell Information Systems Inc., 1984 *
        *                                                         *
        *********************************************************** */

/* ibm3780_: An I/O module for communicating with an IBM 3780. */

/* Coded:     March 1977 by David Vinograd */
/* Modified:  1979 April by Art Beattie to accept abbreviated control
	    arguments, set default pll for printer to 120, and check for
	    required tty and comm control arguments. */
/* Rewritten: February 1984 by Allan Haggett because it did not work so well.
	    Of the things done differently in this version, the
	    multiplexing of multiple ibm3780_ attachments over a single
	    bisync_ attachment is the most important change. */
/* Modified:  July 1984 by Laurent Hazard to fix space expansion. */


/****^  HISTORY COMMENTS:
  1) change(86-07-28,Beattie), approve(86-07-28,MCR7483),
     audit(86-09-03,Brunelle), install(86-09-03,MR12.0-1144):
     Modify interpretation of 512 character limit to include protocol overhead.
  2) change(90-06-13,Vu), approve(90-06-13,MCR8178), audit(90-07-13,Bubric),
     install(90-08-08,MR12.4-1023):
     ibm3780_ gets "size" condition after 99 attaches.
                                                   END HISTORY COMMENTS */


/* * 
   *  Each ibm3780_ switch of a station is attached to a single bisync_
   *  switch. For each bisync_ attachment maintain a Comm Info Block
   *  (A rose is a rose ...) which describes the current state of affairs
   *  in the bisync_ world. Each ibm3780_ switch's "cib" is pointed to by
   *  "ad.cib_ptr".
   *
   *  In order for this to work, we depend upon a "select_device" control
   *  order being issued before resuming operations on a new ibm3780_
   *  switch (device). This allows us to change the characteristics of the
   *  bisync_ attachment to suit the ibm3780_ device about to be used.
* */

/* format: style4,indattr,ifthenstmt,ifthen,^indcomtxt,^indproc,indcom,comcol56 */
ibm3780_: procedure ();

	return;

/**** Parameters */

dcl  P_iocb_ptr	        pointer parameter;
dcl  P_code	        fixed bin (35) parameter;
dcl  P_attach_options       (*) char (*) varying parameter; /* attach */
dcl  P_loud_sw	        bit (1) parameter;	     /* attach */
dcl  P_open_mode	        fixed bin parameter;	     /* open */
dcl  P_ignore_sw	        bit (1) parameter;	     /* open */
dcl  P_inbuf_ptr	        pointer parameter;	     /* get_chars: ptr to user buffer */
dcl  P_inbuf_len	        fixed bin (21) parameter;  /* get_chars: length of user buffer */
dcl  P_inbuf_count	        fixed bin (21) parameter;  /* get_chars: count of char's we are returning */
dcl  P_outbuf_ptr	        pointer parameter;	     /* put_chars: ptr to user buffer */
dcl  P_outbuf_len	        fixed bin (21) parameter;  /* put_chars: count of char's to write */
dcl  P_pos_type	        fixed bin parameter;	     /* position */
dcl  P_pos_value	        fixed bin (21) parameter;  /* position */
dcl  P_order	        char (*) parameter;	     /* control: the order */
dcl  P_info_ptr	        pointer parameter;	     /* control: order info structure */
dcl  P_new_modes	        char (*) parameter;	     /* modes */
dcl  P_old_modes	        char (*) parameter;	     /* modes */

/**** Automatic */

dcl  ad_initialized_sw      bit (1);		     /* Attach data is meaningful? */
dcl  char_string_ptr        pointer;
dcl  code		        fixed bin (35);
dcl  unrecognized_attach_options char (256) varying;
dcl  data_count	        fixed bin (21);
dcl  option_comm	        char (32);
dcl  option_tty	        char (32);
dcl  info_ptr	        pointer;
dcl  iocb_ptr	        pointer;
dcl  loud_sw	        bit (1);		     /* Set if com_err_ sould be called on attach error */
dcl  ips_mask	        bit (36) aligned;
dcl  open_mode	        fixed bin;
dcl  order	        char (32);
dcl  converted_chars        char (512) varying;
dcl  remaining_count        fixed bin (21);
dcl  system_free_area_ptr   pointer;
dcl  two_digits             picture "99";

dcl  1 set_bsc_modes_auto   like info_set_bsc_modes aligned;

/**** Based */

dcl  info_string	        char (32) based (info_ptr);
dcl  char_string	        char (80) based (char_string_ptr);
dcl  system_free_area       area aligned based (system_free_area_ptr);

/**** Used by "control" entry. */
dcl  1 info_read_status     aligned based (info_ptr),
       2 event_channel      fixed bin (71),
       2 input_pending      bit (1);

dcl  1 info_set_bsc_modes   aligned based (info_ptr),
       2 transparent        bit (1) unal,
       2 ebcdic_sw	        bit (1) unal,
       2 pad	        bit (34) unal;


/**** Internal static and constants. */

dcl  static_attach_count    fixed bin init (0) int static;
dcl  static_conv_proc_initialized_sw bit (1) static init ("0"b); /* Per process */
/**** CIB list head and tail. */
dcl  first_cib_ptr	        pointer internal static init (null ());
dcl  last_cib_ptr	        pointer internal static init (null ());

dcl  BASE_VALUE	        fixed bin internal static options (constant) init (64);
dcl  IBM3780_BIGGEST_BUFFER_SIZE fixed bin internal static options (constant) init (512);
dcl  PROTOCOL_OVERHEAD      fixed bin internal static options (constant) init (8);

dcl  IRS		        char (1) internal static options (constant) init ("");
dcl  IGS		        char (1) internal static options (constant) init ("");
dcl  ME		        char (32) init ("ibm3780_") internal static options (constant);
dcl  NL		        char (1) internal static options (constant) init ("
");
dcl  DEFAULT_PRINTER_SELECT char (1) internal static options (constant) init ("");
dcl  DEFAULT_PUNCH_SELECT   char (1) internal static options (constant) init ("");
dcl  SPACE	        char (1) internal static options (constant) init (" ");
dcl  SPACE_CHAR	        (2) char (1) internal static options (constant) init (" ", "@"); /* ASCII & EBCDIC */
dcl  (LOWERCASE	        init ("abcdefghijklmnopqrstuvwxyz"),
     UPPERCASE	        init ("ABCDEFGHIJKLMNOPQRSTUVWXYZ")) char (26) internal static options (constant);
dcl  DEFAULT_CARRIAGE_CTL_TABLE (4) char (4) aligned internal static options (constant) init ("M", "/", "S", "T");
dcl  DEFAULT_SLEW_CTL_TABLE (6) char (4) aligned internal static options (constant)
		        init ("    ",	     /* (4) NUL */
		        "A",		     /* ESC A   */
		        "   ",					     /* (3) NUL VT */
		        "A",		     /* ESC A   */
		        "   	",	     /* (3) NUL TAB */
		        "A");		     /* ESC A   */

/**** Entries */

dcl  com_err_	        entry options (variable);
dcl  continue_to_signal_    entry (fixed bin (35));
dcl  convert_string_$input  entry (char (*) var, pointer, char (*) var, fixed bin (35));
dcl  convert_string_$output entry (char (*) var, pointer, char (*) var, fixed bin (35));
dcl  cu_$arg_list_ptr       entry () returns (pointer);
dcl  cu_$arg_ptr	        entry (fixed bin, pointer, fixed bin (21), fixed bin (35));
dcl  cv_dec_check_	        entry (char (*), fixed bin (35)) returns (fixed bin (35));
dcl  get_system_free_area_  entry returns (pointer);
dcl  get_ttt_info_	        entry (pointer, fixed bin (35));
dcl  hcs_$reset_ips_mask    entry (bit (36) aligned, bit (36) aligned);
dcl  hcs_$set_ips_mask      entry (bit (36) aligned, bit (36) aligned);
dcl  ibm3780_io_call_control_ entry (pointer, pointer, pointer, fixed bin (35));
dcl  ioa_$rsnnl	        entry options (variable);
dcl  ioa_$general_rs        entry (pointer, fixed bin, fixed bin, char (*), fixed bin, bit (1) aligned, bit (1) aligned);

/**** External */

dcl  (error_table_$action_not_performed,
     error_table_$bad_arg,
     error_table_$bad_conversion,
     error_table_$bad_mode,
     error_table_$badopt,
     error_table_$bisync_bid_fail,
     error_table_$inconsistent,
     error_table_$no_operation,
     error_table_$noarg,
     error_table_$not_attached,
     error_table_$not_closed,
     error_table_$not_detached,
     error_table_$not_open,
     error_table_$null_info_ptr,
     error_table_$wrong_no_of_args) fixed bin (35) external static;
dcl  ibm3780_conv_$transparent fixed bin external;
dcl  ibm3780_conv_$slew_ctl_table_ptr pointer external;
dcl  ibm3780_conv_$carriage_ctl_table_ptr pointer external;
dcl  sys_info$max_seg_size  fixed bin external;


dcl  (any_other, cleanup, quit) condition;

dcl  (addr, after, before, char, codeptr, copy, divide, fixed,
     hbound, lbound, length, ltrim, maxlength, min, null, rtrim, 
     search, substr, translate, unspec) builtin;
%page;
	/* Attach an IO switch to a new or existing comm switch. */

ibm3780_attach:
     entry (P_iocb_ptr, P_attach_options, P_loud_sw, P_code);

	/* Copy parameters and make gullibility check. */
	iocb_ptr = P_iocb_ptr;
	loud_sw = P_loud_sw;
	code, P_code = 0;


	if iocb_ptr -> iocb.attach_descrip_ptr ^= null () then do;
	     P_code = error_table_$not_detached;
	     if loud_sw then call com_err_ (P_code, ME, "Switch ^a.", iocb_ptr -> iocb.name);
	     return;
	end;

	adp = null ();			     /* No attach data yet. */
	ad_initialized_sw = "0"b;		     /* ... */
	cib_ptr = null ();
	system_free_area_ptr = get_system_free_area_ ();

	on condition (cleanup) call attach_cleaner ();

	if hbound (P_attach_options, 1) < 4 then
	     call abort_attach (error_table_$wrong_no_of_args,
		"At least ""-comm"" and ""-tty"" must be supplied.");

	/* One time: Put some defaults here. These values also live in the */
	/* attach data and are set at each "select_device". */
	if ^static_conv_proc_initialized_sw then do;
	     ibm3780_conv_$carriage_ctl_table_ptr = addr (DEFAULT_CARRIAGE_CTL_TABLE);
	     ibm3780_conv_$slew_ctl_table_ptr = addr (DEFAULT_SLEW_CTL_TABLE);
	     ibm3780_conv_$transparent = 0;
	     static_conv_proc_initialized_sw = "1"b;
	end;

	/* Setup default attach data. */
	call allocate_attach_data ();
	ad_initialized_sw = "1"b;		     /* Trust it now. */

	ad.attach_desc = rtrim (ME);		     /* ibm3780_ */
	unrecognized_attach_options = "";	     /* Pass these to comm module. */
	option_tty, option_comm = "";

	/* Simply move this loop into its own procedure. It may punt. */
	call process_attach_options ();

	/* Do we have all required options -comm and -tty ? */
	if option_comm = "" then call abort_attach (error_table_$noarg, """-comm""");
	if option_tty = "" then call abort_attach (error_table_$noarg, """-tty""");

	/* Cross-check attach options. */
	if (ad.char_mode = ASCII & ad.transparent) then
	     call abort_attach (error_table_$inconsistent, "^/Control arguments -ascii and -transparent.");

	if ad.phys_line_length = 0 then	     /* We will decide? */
	     if ad.device_type = PRINTER then ad.phys_line_length = 120;
	     else ad.phys_line_length = 80;

	/* These values are taken from old ibm3780_ code. */
	if (^ad.transparent | ad.multi_record) then
	     ad.record_len = IBM3780_BIGGEST_BUFFER_SIZE;
	else ad.record_len = ad.phys_line_length;

	/* See this procedure for notes. */
	call set_ad_multirecord_info ();

	/* Find a Comm Info Block for this channel. */
	do cib_ptr = first_cib_ptr repeat (cib_ptr -> cib.chain.next_cib_ptr) while (cib_ptr ^= null ());
	     if cib_ptr -> cib.device_channel = option_tty then
		goto CHANNEL_HAS_CIB;
	end;

	/* Fell through... have to create a new CIB. */
	call cib_create (cib_ptr);		     /* Allocate it. */
	cib.device_channel = option_tty;

CHANNEL_HAS_CIB:				     /* Ith switch for this CIB. */
	ad.cib_ptr = cib_ptr;		     /* Have to get at switch's CIB. */

	/* Do we have to attach the comm module? */
	if ^cib.attached_sw then do;		     /* Once per target channel. */

	     /* See this procedure for fascinating notes. */
	     call attach_comm_module (option_comm, option_tty, unrecognized_attach_options, cib.comm_iocb_ptr);
	     cib.attached_sw = "1"b;
	end;

	/* Make changes and tell anyone concerned. */
	ips_mask = ""b;
	on condition (any_other) call any_other_handler ();

	call hcs_$set_ips_mask ((""b), ips_mask);

	iocb_ptr -> iocb.attach_descrip_ptr = addr (ad.attach_desc);
	iocb_ptr -> iocb.attach_data_ptr = adp;
	iocb_ptr -> iocb.open = ibm3780_open;
	iocb_ptr -> iocb.detach_iocb = ibm3780_detach;

	/* This switch is now officially using this CIB. */
	cib.n_attached = cib.n_attached + 1;

	call iox_$propagate (iocb_ptr);

	revert condition (cleanup);		     /* All is OK now. */

	call hcs_$reset_ips_mask (ips_mask, ips_mask);

	revert condition (any_other);		     /* Not our fault. */

ATTACH_RETURN:				     /* Non local target for abort_attach. */
	return;
%page;
ibm3780_detach:
     entry (P_iocb_ptr, P_code);

	iocb_ptr = P_iocb_ptr;
	P_code = 0;

	/* Just be sure it is attached and opened. */
	if iocb_ptr -> iocb.attach_descrip_ptr = null () then do;
	     P_code = error_table_$not_attached;
	     return;
	end;

	if iocb_ptr -> iocb.open_descrip_ptr ^= null () then do;
	     P_code = error_table_$not_closed;
	     return;
	end;

	/* Looks good so finish initialization. */
	system_free_area_ptr = get_system_free_area_ ();
	adp = iocb_ptr -> iocb.attach_data_ptr;
	cib_ptr = ad.cib_ptr;

	/* Remove knowledge of this switch from the CIB. */
	cib.n_attached = cib.n_attached - 1;

	call attach_cleaner ();		     /* Maybe free the CIB too. */

	ips_mask = ""b;			     /* Complete IOCB. */

	on condition (any_other) call any_other_handler ();
	call hcs_$set_ips_mask ((""b), ips_mask);

	iocb_ptr -> iocb.attach_descrip_ptr = null ();
	iocb_ptr -> iocb.attach_data_ptr = null ();
	iocb_ptr -> iocb.detach_iocb = iox_$err_not_attached;
	iocb_ptr -> iocb.open = iox_$err_not_attached;
	iocb_ptr -> iocb.control = iox_$err_not_attached;

	call iox_$propagate (iocb_ptr);
	call hcs_$reset_ips_mask (ips_mask, ips_mask);

	revert condition (any_other);

	return;
%page;
ibm3780_open:
     entry (P_iocb_ptr, P_open_mode, P_ignore_sw, P_code);

	iocb_ptr = P_iocb_ptr -> iocb.actual_iocb_ptr;
	P_code = 0;

	if iocb_ptr -> iocb.open_descrip_ptr ^= null () then do;
	     P_code = error_table_$not_closed;
	     return;
	end;

	open_mode = P_open_mode;

	/* We support SI, SO, and SIO. Comm switch is always SIO though. */
	if ^((open_mode = Stream_input) | (open_mode = Stream_output) | (open_mode = Stream_input_output)) then do;
	     P_code = error_table_$bad_mode;
	     return;
	end;

	adp = iocb_ptr -> iocb.attach_data_ptr;
	cib_ptr = ad.cib_ptr;

	ad.open_description = rtrim (iox_modes (open_mode));

	/* Is this the first open for this comm? */
	if ^cib.opened_sw then do;
	     call open_comm_module (P_code);
	     if P_code ^= 0 then return;	     /* Has to work. */
	     else cib.opened_sw = "1"b;
	end;

	ips_mask = ""b;

	on condition (any_other) call any_other_handler ();
	call hcs_$set_ips_mask ((""b), ips_mask);

	if ((open_mode = Stream_input) | (open_mode = Stream_input_output)) then do;
	     iocb_ptr -> iocb.get_chars = ibm3780_get_chars;
	     iocb_ptr -> iocb.get_line = ibm3780_get_line;
	end;

	if ((open_mode = Stream_output) | (open_mode = Stream_input_output)) then
	     iocb_ptr -> iocb.put_chars = ibm3780_put_chars;

	iocb_ptr -> iocb.control = ibm3780_control;
	iocb_ptr -> iocb.position = ibm3780_position;
	iocb_ptr -> iocb.modes = ibm3780_modes;
	iocb_ptr -> iocb.close = ibm3780_close;
	iocb_ptr -> iocb.detach_iocb = ibm3780_detach;

	/* Make it officially open. */
	iocb_ptr -> iocb.open_descrip_ptr = addr (ad.open_description);

	call iox_$propagate (iocb_ptr);

	call hcs_$reset_ips_mask (ips_mask, ips_mask);

	revert condition (any_other);

	return;
%page;
ibm3780_close:
     entry (P_iocb_ptr, P_code);

	iocb_ptr = P_iocb_ptr -> iocb.actual_iocb_ptr;
	P_code = 0;

	if iocb_ptr -> iocb.open_descrip_ptr = null () then do; /* Closed. */
	     P_code = error_table_$not_open;
	     return;
	end;

	adp = iocb_ptr -> iocb.attach_data_ptr;
	cib_ptr = ad.cib_ptr;

	/* Close the comm switch if this is the last ibm3780 switch on it. */
	if cib.opened_sw then
	     if cib.n_attached <= 1 then do;
		call iox_$close (cib.comm_iocb_ptr, (0));
		cib.opened_sw = "0"b;
	     end;

	ips_mask = ""b;

	on condition (any_other) call any_other_handler ();
	call hcs_$set_ips_mask ((""b), ips_mask);

	iocb_ptr -> iocb.open_descrip_ptr = null ();

	iocb_ptr -> iocb.open = ibm3780_open;
	iocb_ptr -> iocb.detach_iocb = ibm3780_detach;

	iocb_ptr -> iocb.control,
	     iocb_ptr -> iocb.position,
	     iocb_ptr -> iocb.modes,
	     iocb_ptr -> iocb.get_chars,
	     iocb_ptr -> iocb.get_line,
	     iocb_ptr -> iocb.put_chars = iox_$err_no_operation;

	call iox_$propagate (iocb_ptr);
	call hcs_$reset_ips_mask (ips_mask, ips_mask);

	revert condition (any_other);

	return;
%page;
/****^ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *   							       *
 *   Control Notes:						       *
 *							       *
 *   There is a crock here which will work as long as users of this IO       *
 *   module use the "select_device" order before initiating a new series     *
 *   of IO operations for a device. We take this as a cue to perform any     *
 *   necessary reconfiguration of the comm connection to suite the device    *
 *   selected. We also have to set static in the ibm3780_conv_ module so     *
 *   that the hacking performed by "prt_conv_", as called from someone       *
 *   like "remote_printer_" BEFORE calling iox_$put_chars, will result       *
 *   in the right transformations for this device. Not pretty...	       *
 *							       *
 *   All identifiers beginning with "info_" are based on "info_ptr".	       *
 *							       *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

ibm3780_control:
     entry (P_iocb_ptr, P_order, P_info_ptr, P_code);

	iocb_ptr = P_iocb_ptr -> iocb.actual_iocb_ptr;
	order = P_order;
	info_ptr = P_info_ptr;
	P_code, code = 0;

	adp = iocb_ptr -> iocb.attach_data_ptr;
	cib_ptr = ad.cib_ptr;

	/* Be compatible with old ibm3780_. */
	if cib.comm_iocb_ptr = null () then do;
	     P_code = error_table_$no_operation;
	     return;
	end;

	if order = "select_device" then do;	     /* setup device */

	     call reject_null_info ();

	     if info_string = TELEPRINTER then
		ad.device_type = PRINTER;
	     else if (info_string = PRINTER | info_string = PUNCH) then
		ad.device_type = info_string;
	     else do;			     /* Unknown device. Code is for compatibility. */
		P_code = error_table_$no_operation;
		return;
	     end;

	     if iocb_ptr = cib.last_selected_iocb_ptr then /* Last select over bisync_ was for this switch? */
		if ad.device_type = ad.last_selected_device then /* And we are selecting the same device? */
		     return;		     /* Optimize at a certain risk. */

	     call select_device (code);	     /* Select it and set */
	     if code ^= 0 then goto CONTROL_RETURN;
	     call configure_comm (code);	     /* up bisync_ for it. */
	     if code ^= 0 then goto CONTROL_RETURN;

	     /* It all worked so... */
	     cib.last_selected_iocb_ptr = iocb_ptr;
	     ad.last_selected_device = ad.device_type;

	end;				     /* select_device */

	else if order = "set_bsc_modes" then do;

	     call reject_null_info ();

	     ad.transparent = info_set_bsc_modes.transparent;
	     if info_set_bsc_modes.ebcdic_sw then
		ad.char_mode = EBCDIC;
	     else ad.char_mode = ASCII;

	     /* This informs bisync_ of changes. */
	     call configure_comm (code);

	end;				     /* set_bsc_modes */

	else if order = "set_multi_record_mode" then do;

	     ad.multi_record = "1"b;
	     goto PASS_CONTROL_ORDER;

	end;				     /* set_multi_record_mode */

	else if order = "runout" | order = "end_write_mode" then do;

	     call write_buffer ();
	     ad.output_buf = "";
	     goto PASS_CONTROL_ORDER;

	end;				     /* runout */

	else if order = "resetwrite" then do;

	     ad.output_buf = "";
	     goto PASS_CONTROL_ORDER;

	end;				     /* resetwrite */

	else if order = "resetread" then do;

	     ad.input_buf = "";
	     goto PASS_CONTROL_ORDER;

	end;				     /* resetread */

	else if order = "reset" then ad.edited = "1"b;
	else if order = "io_call" then
	     call ibm3780_io_call_control_ (adp, iocb_ptr, info_ptr, code);

	/* See if this is understood by comm module. */
	else do;
PASS_CONTROL_ORDER:
	     call iox_$control (cib.comm_iocb_ptr, order, info_ptr, code);
	end;

	/* Postprocessing: We have a say in read_status order. */
	if code = 0 then			     /* Comm took it. */
	     if order = "read_status" then	     /* And it was this. */
		info_read_status.input_pending = (length (ad.input_buf) > 0 | info_read_status.input_pending);

CONTROL_RETURN:
	P_code = code;			     /* Pass back any error. */
	return;


/**** Control entry procedure to make sure we have an info pointer. */
reject_null_info:
     procedure ();

	if info_ptr ^= null () then return;	     /* Continue... */

	code = error_table_$null_info_ptr;
	goto CONTROL_RETURN;

     end reject_null_info;
%page;
/**** This code is from old module. Note that the old module would never
      return a non-zero code, so we do not either. */

ibm3780_modes:
     entry (P_iocb_ptr, P_new_modes, P_old_modes, P_code);

	iocb_ptr = P_iocb_ptr -> iocb.actual_iocb_ptr;
	P_old_modes = "";			     /* No modes are passed back. */
	P_code = 0;

	if P_new_modes = "" then return;

	adp = iocb_ptr -> iocb.attach_data_ptr;

	if P_new_modes = "non_edited" then
	     ad.edited = "0"b;
	else if P_new_modes = "default" then
	     ad.edited = "1"b;
	else ;				     /* Old module would assign error to */
					     /* automatic variable, then return! */

	return;
%page;
ibm3780_position:
     entry (P_iocb_ptr, P_pos_type, P_pos_value, P_code);

	iocb_ptr = P_iocb_ptr -> iocb.actual_iocb_ptr;
	P_code = 0;

	adp = iocb_ptr -> iocb.attach_data_ptr;
	cib_ptr = ad.cib_ptr;

	call iox_$position (cib.comm_iocb_ptr, P_pos_type, P_pos_value, P_code);

	return;
%page;
/**** Get_line and get_chars perform the same operation (compatible with old). */

ibm3780_get_line:
ibm3780_get_chars:
     entry (P_iocb_ptr, P_inbuf_ptr, P_inbuf_len, P_inbuf_count, P_code);

	/*
   This procedure along with get_string do not seem to make any
   real use of the variable remaining_count, and assume that the caller
   has provided a big enough buffer to hold an entire card image.
   This is probably okay, but I'm not sure and it should be looked
   into in the near future. - CLM */

	iocb_ptr = P_iocb_ptr -> iocb.actual_iocb_ptr;
	P_code = 0;

	adp = iocb_ptr -> iocb.attach_data_ptr;
	cib_ptr = ad.cib_ptr;
	code = 0;

	P_inbuf_count, data_count = 0;	     /* Count of char's read. */
	remaining_count = P_inbuf_len;	     /* We can return this many. */
	char_string_ptr = P_inbuf_ptr;

	call get_string ();			     /* Do it here. */

GET_CHARS_RETURN:				     /* Update the output parameters from auto's. */
	P_code = code;
	P_inbuf_count = data_count;

	return;
%page;
ibm3780_put_chars:
     entry (P_iocb_ptr, P_outbuf_ptr, P_outbuf_len, P_code);

	iocb_ptr = P_iocb_ptr -> iocb.actual_iocb_ptr;
	P_code = 0;

	adp = iocb_ptr -> iocb.attach_data_ptr;
	cib_ptr = ad.cib_ptr;
	code = 0;

	if (P_outbuf_len < 0 | P_outbuf_len > sys_info$max_seg_size * 4) then do;
	     P_code = error_table_$bad_arg;
	     return;
	end;

	remaining_count = P_outbuf_len;
	char_string_ptr = P_outbuf_ptr;

	do while (remaining_count > 0);
	     call put_string ();
	     if code ^= 0 then goto PUT_CHARS_RETURN;
	end;

PUT_CHARS_RETURN:
	P_code = code;

	return;
%page;
/**** This is the procedure which does all the work for "get_chars".
      It returns the data in card_image to the user buffer. */

get_string:
     procedure ();

dcl  card_image	        char (80) varying;	     /* Card readers *always* send 80 characters. */
dcl  igs_pos	        fixed bin (21);
dcl  space_cnt	        fixed bin;

	if (length (ad.input_buf)) = 0 then
	     call read_buffer ();

	if ad.transparent then do;
	     if ad.multi_record then do;

		/* Need those 80 characters. */
		if length (ad.input_buf) < 80 then
		     call read_buffer ();	     /* Get more from comm. */
		card_image = substr (ad.input_buf, 1, 80);

		if length (ad.input_buf) > 80 then
		     ad.input_buf = substr (ad.input_buf, 81);
		else ad.input_buf = "";
	     end;
	     else do;
		card_image = ad.input_buf;
		ad.input_buf = "";
	     end;
	end;

	else do;				     /* Not transparent. */

	     /* If no IRS in buffer, then read some more. */
	     if search (ad.input_buf, IRS) = 0 then
		call read_buffer ();

	     card_image = before (ad.input_buf, IRS);
	     ad.input_buf = after (ad.input_buf, IRS);

	     /* Hack space compression. */
	     igs_pos = search (card_image, IGS);
	     do while (igs_pos > 0);
		space_cnt = fixed (unspec (substr (card_image, (igs_pos + 1), 1)), 9) - BASE_VALUE;
		card_image = substr (card_image, 1, (igs_pos - 1)) || copy (SPACE_CHAR (ad.char_mode), space_cnt)
		     || substr (card_image, (igs_pos + 2));
		igs_pos = search (card_image, IGS);
	     end;
	end;

	call convert_string_$input (card_image, addr (ad.ttt_info), converted_chars, code);
	if code ^= 0 then return;

	/* Copy bytes and update state. */
	char_string = converted_chars;
	data_count = data_count + length (converted_chars);
	char_string_ptr = substraddr (char_string, (length (converted_chars) + 1));
	remaining_count = remaining_count - length (card_image);

	return;



/**** Internal procedure of "get_string" to read data into the variable
      card_image up to the preset length.  We handle the case where there are
      characters already in our input buffer but we have been called to get
      more.  This allows us to go after a character we need (ie.  IRS) but
      did not get from comm last time.  */

read_buffer:
     procedure ();

dcl  n_read	        fixed bin (21);
dcl  n_not_processed        fixed bin (21);	     /* Now in buffer. */

	n_not_processed = length (ad.input_buf);     /* Could be zero. */
	if n_not_processed >= ad.record_len then return;


	call iox_$get_chars (cib.comm_iocb_ptr,
	     substraddr (ad.input_buf, (n_not_processed + 1)), /* Fill from here. */
	     (ad.record_len - n_not_processed),	     /* Up to this many. */
	     n_read, code);

	if code ^= 0 then goto GET_CHARS_RETURN;     /* Has to work. */

	ad.input_buf = substr (ad.input_buf, 1, (n_read + n_not_processed));

	return;

     end read_buffer;

     end get_string;
%page;
/**** This is the procedure which does all the work for "put_chars". It takes
      user data in chunks and puts it in the output buffer. This code is almost
      identical to that in the old ibm3780_ module. */

put_string:
     procedure ();

dcl  input	        char (512) varying;
dcl  input_count	        fixed bin;		     /* Number of characters to transmit. */
dcl  (igs_pos, igs_found_pos) fixed bin;
dcl  substring	        char (512) varying;

	input_count = min (remaining_count, ad.record_len);
	input = substr (char_string, 1, input_count);
	converted_chars = "";

	if ad.device_type ^= PUNCH then do;
	     ad.ttt_info.escape_output = "0"b;
	     call convert_string_$output (substr (input, 1, 2), addr (ad.ttt_info), converted_chars, code);
	     ad.ttt_info.escape_output = "1"b;
	     if code ^= 0 then return;
	     igs_found_pos = 3;
	end;
	else igs_found_pos = 1;

	igs_pos = search (substr (input, igs_found_pos), IGS);
	do while (igs_pos > 0);
	     call convert_string_$output (substr (input, igs_found_pos, igs_pos), addr (ad.ttt_info), substring, code);
	     if code ^= 0 then return;
	     igs_found_pos = igs_found_pos + igs_pos + 1;
	     converted_chars = converted_chars || substring;
	     converted_chars = converted_chars || substr (input, igs_found_pos - 1, 1);
	     igs_pos = search (substr (input, igs_found_pos), IGS);
	end;
	call convert_string_$output (substr (input, igs_found_pos), addr (ad.ttt_info), substring, code);
	if code ^= 0 then return;

	converted_chars = converted_chars || substring;

	if ad.transparent then do;
	     ad.output_buf = converted_chars;
	     call write_buffer ();
	     if code ^= 0 then return;
	     ad.output_buf = "";
	end;
	else do;

	     /* If we cannot stuff anymore, then we add IRS and write it. */
	     if length (ad.output_buf) + length (converted_chars) >= ad.record_len then do;
		call write_buffer ();
		if code ^= 0 then return;
		ad.output_buf = "";
	     end;
	     ad.output_buf = ad.output_buf || converted_chars || IRS;
	end;

	remaining_count = remaining_count - input_count;
	char_string_ptr = substraddr (char_string, (input_count + 1));
	return;

     end put_string;
%page;
/**** This is probably a crock. Anyway, this code is taken directly from old module. */

write_buffer:
     procedure ();

	if ^cib.in_quit_state_sw then do;	     /* This BISYNC_ is healthy? */
WRITE_BUFFER_RETRY:

	     call iox_$put_chars (cib.comm_iocb_ptr, substraddr (ad.output_buf, 1), length (ad.output_buf), code);
	     if code = 0 then return;

	     /* Check for bad bisync_ lossage. */
	     else if code = error_table_$bisync_bid_fail then do;

		on condition (cleanup) begin;
		     cib.in_quit_state_sw = "0"b;
		end;

		cib.in_quit_state_sw = "1"b;
		signal condition (quit);
		cib.in_quit_state_sw = "0"b;
		goto WRITE_BUFFER_RETRY;

	     end;
	end;

	return;

     end write_buffer;
%page;
/**** Select the device (ad.device_type) and the terminal (ad.terminal_id). */
select_device:
     procedure (P_code);

dcl  P_code	        fixed bin (35) parameter;

dcl  control_string	        char (256) varying;	     /* Send this. */
dcl  tab_pos	        fixed bin;

	P_code = 0;

	/* A non-null terminal ID means we have to prepend it to select. */
	if ad.terminal_id ^= "" then do;	     /* Have to send this? */
	     if ad.device_type = PRINTER then
		control_string = ad.terminal_id || ad.printer_select;
	     else if ad.device_type = PUNCH then
		control_string = ad.terminal_id || ad.punch_select;
	     else return;			     /* No select. */

	     control_string = control_string || ENQ;
	end;

	else do;				     /* No terminal ID. */
	     if ad.device_type = PRINTER then
		control_string = ad.printer_select;
	     else if ad.device_type = PUNCH then
		control_string = ad.punch_select;
	     else return;
	end;

	/* Do the actual select. This procedure, which is internal, writes "control_string". */
	call write_nontransparent ();

	/* May have to set tabs if we are selecting printer. */
	if (ad.device_type = PRINTER & ad.has_tabs) then do;

	     /* Clear control string forcibly. */
	     substr (control_string, 1, maxlength (control_string)) = "";

	     control_string = ESC || HT;	     /* Control prefix. */

	     /* Put a tab every 10th column. */
	     do tab_pos = 10 by 10 while (tab_pos < ad.phys_line_length);
		substr (control_string, tab_pos, 1) = HT;
	     end;

	     control_string = control_string || NL;
	     call write_nontransparent ();

	end;				     /* printer init */

WRITE_NONTRANSPARENT_ERROR:			     /* Our code parameter is set, return now. */
	return;


/****^ Internal procedure of "select_device". We transmit "control_string"
       in nontransparent mode in a single block.  We use "P_code" and return
       if any error is encountered. */

write_nontransparent:
     procedure ();

	ad.ttt_info.escape_output = "0"b;
	call convert_string_$output (control_string, addr (ad.ttt_info), control_string, P_code);
	ad.ttt_info.escape_output = "1"b;
	if P_code ^= 0 then goto WRITE_NONTRANSPARENT_ERROR;

	/* The old ibm3780_ copied data to a varying string overlay before calling bisync_. We do not. */

	call iox_$control (cib.comm_iocb_ptr, "send_nontransparent_msg", addr (control_string), P_code);
	if P_code ^= 0 then goto WRITE_NONTRANSPARENT_ERROR;

	return;

     end write_nontransparent;

     end select_device;
%page;
/****^ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *   							       *
 *   A "select_device" is being performed. We have multiple switches, each   *
 *   with a different requirement as to how the single comm (bisync_)	       *
 *   switch should be configured. We simply reconfigure to characteristics   *
 *   in the attach data for this switch. This is not fool-proof of course.   *
 *							       *
 *   This is also called at open time to be sure that BISYNC world is ready. *
 *							       *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

configure_comm:
     procedure (P_code);

dcl  P_code	        fixed bin (35) parameter;
dcl  multi_record_count     fixed bin (35);

	/* First, set the static used for output pre-conversion. */
	ibm3780_conv_$carriage_ctl_table_ptr = addr (ad.carriage_ctl_table);
	ibm3780_conv_$slew_ctl_table_ptr = addr (ad.slew_ctl_table);
	ibm3780_conv_$transparent = fixed (ad.transparent, 35, 0);

	/* Tell BISYNC_ about transparency and character mode. */
	unspec (set_bsc_modes_auto) = ""b;
	set_bsc_modes_auto.transparent = ad.transparent;
	if ad.char_mode = EBCDIC then set_bsc_modes_auto.ebcdic_sw = "1"b;

	call iox_$control (cib.comm_iocb_ptr, "set_bsc_modes", addr (set_bsc_modes_auto), P_code);
	if P_code ^= 0 then return;		     /* Bad lossage. */

	call set_ad_multirecord_info ();	     /* Set multi-record info based on transparency. */

	multi_record_count = ad.multi_record_count;
	call iox_$control (cib.comm_iocb_ptr, "set_multi_record_mode", addr (multi_record_count), P_code);

	return;

     end configure_comm;
%page;
set_ad_multirecord_info:
     procedure ();

/****^ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *   							     *
 *   This code is taken from the old ibm3780_ IO module.  I am not sure    *
 *   why it is done exactly like this, but we will leave it until is is    *
 *   proven defective. This procedure is called at attach time, and 	     *
 *   whenever we have to set the characteristics of the comm attachment.   *
 *							     *
 *   Note that the bit ad.multi_record is redundant, as a count of 1 means *
 *   that it is not multi-record. See bisync_.pl1.
 *							     *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

	/* Set multi-record information based on transparency mode. */
	if ^ad.transparent then do;
	     ad.multi_record = "1"b;
	     ad.multi_record_count = 512;
	end;
	else if ad.multi_record then do;
	     ad.multi_record = "1"b;
	     ad.multi_record_count = 6;
	end;
	else do;
	     ad.multi_record = "0"b;
	     ad.multi_record_count = 1;
	end;

	return;

     end set_ad_multirecord_info;
%page;
/**** Usage: call abort_attach (code, ioa_args) */
abort_attach:
     procedure () options (variable, non_quick);


dcl  the_code	        fixed bin (35) based (the_code_ptr);
dcl  the_code_ptr	        pointer;

dcl  abort_msg	        character (256);

	call cu_$arg_ptr (1, the_code_ptr, (0), (0));

	if loud_sw then do;			     /* an error message is requested */
	     call ioa_$general_rs (cu_$arg_list_ptr (), 2, 3, abort_msg, (0), "1"b, "0"b);
	     call com_err_ (the_code, ME, "Switch ^a. ^a", iocb_ptr -> iocb.name, abort_msg);
	end;

	call attach_cleaner ();		     /* Undo any work. */

	if the_code = 0 then		     /* Caller must get non-zero code. */
	     P_code = error_table_$action_not_performed;
	else P_code = the_code;

	go to ATTACH_RETURN;

     end abort_attach;
%page;
/**** Attach entry calls us to alloc and init our attach block. */

allocate_attach_data:
     procedure ();

	allocate ad in (system_free_area) set (adp);
	unspec (ad) = ""b;
	ad.ptrs = null ();			     /* Get these level */
	ad.chars = "";			     /*    3 variables. */
	ad.printer_select = DEFAULT_PRINTER_SELECT;
	ad.punch_select = DEFAULT_PUNCH_SELECT;
	ad.char_mode = EBCDIC;		     /* Default. */
	ad.record_len = 80;
	ad.carriage_ctl_table (*) = DEFAULT_CARRIAGE_CTL_TABLE (*);
	ad.slew_ctl_table (*) = DEFAULT_SLEW_CTL_TABLE (*);
					     /* Initialize remote_ttt_info. */
	ad.ttt_info.ttt_ptrs = null ();	     /* Again, assigning */
	ad.ttt_info.ttt_bits = "1"b;		     /*    to level 3's. */
	ad.ttt_info.terminal_type = "";
	ad.ttt_info.kill_char = "@";
	ad.ttt_info.erase_char = "#";

	return;

     end allocate_attach_data;
%page;
/**** Attach entry procedure for processing attachment arguments. */

process_attach_options:
     procedure ();

dcl  arg_idx	        fixed bin;		     /* Current option. */
dcl  arg_len	        fixed bin (21);
dcl  arg_ptr	        pointer;
dcl  arg		        char (arg_len) based (arg_ptr); /* An attach option. */
dcl  ctl_string	        char (8) varying;	     /* For carriage and slew control. */

	do arg_idx = lbound (P_attach_options, 1) to hbound (P_attach_options, 1);

	     /* Set up "arg" and add option to attach description. */
	     call access_option (arg_idx);

	     /* Do not let this one get through. */
	     if arg = "-size" then
		call abort_attach (error_table_$badopt, "^a", arg);
	     else if arg = "-transparent" then ad.transparent = "1"b;
	     else if arg = "-nontransparent" then ad.transparent = "0"b;
	     else if arg = "-ebcdic" then ad.char_mode = EBCDIC;
	     else if arg = "-ascii" then ad.char_mode = ASCII;
	     else if arg = "-horizontal_tab" | arg = "-htab" then ad.has_tabs = "1"b;
	     else if arg = "-multi_record" then ad.multi_record = "1"b;
	     else if arg = "-multi_point" then
		ad.terminal_id = fetch_arg ("Terminal ID");
	     else if arg = "-printer_select" then
		ad.printer_select = fetch_arg ("Printer select character");
	     else if arg = "-punch_select" then
		ad.punch_select = fetch_arg ("Punch select character");
	     else if arg = "-physical_line_length" | arg = "-pll" then
		ad.phys_line_length = fetch_numarg ("Line length");
	     else if arg = "-terminal_type" | arg = "-ttp" then do;
		ad.terminal_type = fetch_arg ("Terminal type");
		ad.terminal_type = translate (ad.terminal_type, UPPERCASE, LOWERCASE);
		call get_ttt_info_ (addr (ad.ttt_info), code);
		if code ^= 0 then call abort_attach (code, "Cannot get ttt info for ""^a"".", arg);
	     end;

	     /* The old ibm3780_ never checked lengths, so I suppose we cannot either. */
	     else if arg = "-carriage_ctl" then do;
		ctl_string = fetch_arg ("Carriage control characters");
		call set_carriage_ctl (ctl_string, ad.carriage_ctl_table);
	     end;
	     else if arg = "-slew_ctl" then do;
		ctl_string = fetch_arg ("Slew control characters");
		call set_slew_ctl (ctl_string, ad.slew_ctl_table);
	     end;
	     else if arg = "-device" then do;
		ad.device_type = fetch_arg ("Device name");

		/* Compatibility: No checking on name here. */
	     end;

	     /* These next two are required arguments. */
	     else if arg = "-comm" then option_comm = fetch_arg ("Comm module name");
	     else if arg = "-tty" then option_tty = fetch_arg ("TTY channel name");

	     else do;
		unrecognized_attach_options = unrecognized_attach_options || SPACE;
		unrecognized_attach_options = unrecognized_attach_options || arg;
	     end;

	end;				     /* option processing loop */

	return;
%page;
/**** Internal procedures of "process_attach_options" for argument manipulation. */

access_option:
     procedure (P_arg_idx);

dcl  P_arg_idx	        fixed bin parameter;

	/* Make "arg" reference P_attach_option (P_arg_idx). Assert: P_arg_idx <= bound (P_attach_options, 1) */
	arg_ptr = substraddr (P_attach_options (P_arg_idx), 1);
	arg_len = length (P_attach_options (P_arg_idx));

	/* All options go into our attach description. */
	ad.attach_desc = ad.attach_desc || SPACE || arg;

	return;

     end access_option;



/**** Procedures for fetching a value of a control (the current) argument. */

fetch_arg:
     procedure (P_desc) returns (char (*));

dcl  P_desc	        char (*) parameter;
dcl  control_arg	        char (32);

	control_arg = arg;			     /* Save it for error. */

	if arg_idx = hbound (P_attach_options, 1) then
	     call abort_attach (error_table_$noarg, "^a following ""^a"".", P_desc, control_arg);

	arg_idx = arg_idx + 1;		     /* Something is there. */

	call access_option (arg_idx);		     /* Set up "arg". */

	if arg = "" then
	     call abort_attach (0, "^a for ""^a"" must be a non-null string.", P_desc, control_arg);

	return (arg);

     end fetch_arg;



/**** Same thing except we return a fixed bin. */

fetch_numarg:
     procedure (P_desc) returns (fixed bin (35));

dcl  P_desc	        char (*) parameter;
dcl  control_arg	        char (32);
dcl  numarg	        fixed bin (35);
dcl  code		        fixed bin (35);	     /* Just for us. */

	control_arg = arg;

	if arg_idx = hbound (P_attach_options, 1) then
	     call abort_attach (error_table_$noarg, "^a following ""^a"".", P_desc, control_arg);

	arg_idx = arg_idx + 1;

	call access_option (arg_idx);

	numarg = cv_dec_check_ (arg, code);

	if code ^= 0 then
	     call abort_attach (error_table_$bad_conversion,
		"^a for ""^a"" must be a number; not ""^a"".", P_desc, control_arg, arg);

	return (numarg);			     /* Some number. */

     end fetch_numarg;



/**** Passed a varying string, set a control table array in the attach data. */

set_carriage_ctl:
     procedure (P_string, P_table);

dcl  P_string	        char (8) varying aligned parameter;
dcl  P_table	        (*) char (4) aligned parameter;
dcl  idx		        fixed bin;

/****^	Take the characters from the string 2 at a time, putting each pair
	in the next element of the table (vector). There is already a default
	control table in the table, put there at attach data initialization
	time.  NOTE: We take characters up to the last *pair* only. The old
	ibm3780_ marched on whether he had no characters or an odd number of
	characters.  We also make sure that we do not try to stuff characters
	off the end of the array (see "min" function at loop start. We do
	assume, correctly, that tables have lbound of 1. */

	do idx = 1 to min (hbound (P_table, 1), divide (length (P_string), 2, 17, 0));
	     P_table (idx) = substr (P_string, ((idx * 2) - 1), 2);
	end;

	return;


/**** Slew control table lives in elements 2, 4, and 6 of a six element vec. */

set_slew_ctl:
     entry (P_string, P_table);


	/* As usual, strip off chars until we run out of chars of string or elements of array. */
	/* Note that we divide the hbound by 2 as we double idx in loop. */
	do idx = 1 to min (divide (hbound (P_table, 1), 2, 17, 0), divide (length (P_string), 2, 17, 0));
	     P_table (idx * 2) = substr (P_string, ((idx * 2) - 1), 2);
	end;

	return;

     end set_carriage_ctl;


     end process_attach_options;
%page;
attach_cleaner:				     /* Cleanup handler */
     procedure ();

	/* If we do not have attach data, then there is nothing to do. */
	if adp = null () then return;

	if ad_initialized_sw then do;		     /* Trust it? */
	     if ad.cib_ptr ^= null () then	     /* Using a CIB? */
		call cib_janitor (ad.cib_ptr);     /* Still need it? */
	end;

	/* Ok, now free our attach data. */
	free ad in (system_free_area);
	adp = null ();			     /* Be clean. */

	return;

     end attach_cleaner;
%page;
attach_comm_module:
     procedure (P_io_module_name, P_tty_channel, P_other_args, P_iocb_ptr) options (non_quick);

/****^ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *   							     *
 *   For each CIB there is a comm attachment. There may be multiple	     *
 *   devices, and therefore switches, which are multiplexed over this	     *
 *   single unique attachment. We attach with the simplest attach	     *
 *   description possible, as per-device options are set for the comm	     *
 *   module at "select_device" time. The only option we must specify	     *
 *   at attach time is buffer size, as bisync_ will not allow us to	     *
 *   ask later for a buffer larger than that specified in the attach	     *
 *   options. We ask for the biggest we may need (512), plus some space    *
 *   for bisync_ overhead.					     *
 *							     *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

dcl  P_io_module_name       char (32) parameter;	     /* Input */
dcl  P_tty_channel	        char (32) parameter;	     /* Input */
dcl  P_other_args	        char (256) varying parameter; /* Input */
dcl  P_iocb_ptr	        pointer parameter;	     /* Output */

dcl  switch_name	        char (32);
dcl  attach_desc	        char (256);
dcl  attach_code	        fixed bin (35);

          /* Allows up to 99 attachments (compatibility code). 
             but if there are more than 99 then attach as many
             as required (related bug fix phx17327.) */

          static_attach_count = static_attach_count + 1;

          if static_attach_count < 100 then do;
               two_digits = static_attach_count;
       	     switch_name = rtrim (ME) || two_digits;
            end;
          else
               switch_name = rtrim (ME) || ltrim(char(static_attach_count));

	call ioa_$rsnnl ("^a ^a -size ^d ^a", attach_desc, (0),
	     P_io_module_name, P_tty_channel,

	/* Some IBM3780 emulators don't want more than 512 including
	   overhead added by whatever protocol being used.
          */
	     (IBM3780_BIGGEST_BUFFER_SIZE - PROTOCOL_OVERHEAD),
	     P_other_args);

	call iox_$attach_name (switch_name, P_iocb_ptr, attach_desc, codeptr (ibm3780_), attach_code);
	if attach_code ^= 0 then call abort_attach (attach_code, "Cannot attach comm module.^/Attach description: ""^a"".", attach_desc);

	return;

     end attach_comm_module;
%page;
open_comm_module:
     procedure (P_code);

dcl  P_code	        fixed bin (35) parameter;

	P_code = 0;
	call iox_$open (cib.comm_iocb_ptr, Stream_input_output, ("0"b), P_code);

	/* If open worked, then finish off the BISYNC initialization. */
	/* This *must* be done now before user tries to use any switch. */
	if P_code = 0 then
	     call configure_comm ((0));

	return;

     end open_comm_module;
%page;
/**** Procedures for managing CIBlocks. */

cib_create:
     procedure (P_cib_ptr);

dcl  P_cib_ptr	        pointer parameter;

	allocate cib in (system_free_area) set (P_cib_ptr);
	unspec (P_cib_ptr -> cib) = ""b;
	P_cib_ptr -> cib.comm_iocb_ptr = null ();
	P_cib_ptr -> cib.last_selected_iocb_ptr = null ();
	P_cib_ptr -> cib.next_cib_ptr = null ();
	P_cib_ptr -> cib.prev_cib_ptr = last_cib_ptr;/* null if first. */

	/* Thread it in. */
	if first_cib_ptr = null () then	     /* Very first CIB. */
	     first_cib_ptr = P_cib_ptr;
	else last_cib_ptr -> cib.next_cib_ptr = P_cib_ptr;

	/* This is now the most recent. */
	last_cib_ptr = P_cib_ptr;
	return;



/**** Checks to see if CIB is still needed. */
cib_janitor:
     entry (P_cib_ptr);

	/* If we have a comm attachment but no ibm3780_ users on it, then remove the comm. */
	if P_cib_ptr -> cib.attached_sw then	     /* Bisync_ attached? */
	     if P_cib_ptr -> cib.n_attached < 1 then do; /* Ibm3780_ switches. */
		call iox_$close (P_cib_ptr -> cib.comm_iocb_ptr, (0));
		call iox_$detach_iocb (P_cib_ptr -> cib.comm_iocb_ptr, (0));
		P_cib_ptr -> cib.attached_sw = "0"b;

		/* If first CIB, then update head of list. */
		if P_cib_ptr -> cib.prev_cib_ptr = null () then
		     first_cib_ptr = P_cib_ptr -> cib.next_cib_ptr;

		/* Our forward pointer is bequeathed to previous block. */
		else P_cib_ptr -> cib.prev_cib_ptr -> cib.next_cib_ptr = P_cib_ptr -> cib.next_cib_ptr;

		/* Are we the tail? */
		if P_cib_ptr -> cib.next_cib_ptr = null () then
		     last_cib_ptr = P_cib_ptr -> cib.prev_cib_ptr; /* Update static. */

		/* Our backward pointer goes into our "next" CIB. */
		else P_cib_ptr -> cib.next_cib_ptr -> cib.prev_cib_ptr = P_cib_ptr -> cib.prev_cib_ptr;

		/* It is unthreaded... free it. */
		free P_cib_ptr -> cib in (system_free_area);
		P_cib_ptr = null ();	     /* Useless now. */
	     end;

	return;


     end cib_create;
%page;
/**** Handler for IPS masked code. */

any_other_handler:
     procedure ();

	/* Simply unmask and lateral. */
	if ips_mask then call hcs_$reset_ips_mask (ips_mask, ips_mask);
	ips_mask = ""b;

	call continue_to_signal_ ((0));
	return;

     end any_other_handler;
%page;
/**** SUBSTRADDR functions stolen from hasp_host_. */

/**** Return a pointer to the specified character of a varying or nonvarying string.  When the substraddr
      builtin function is finally implemented, these internal procedures should be removed */

dcl  substraddr	        generic (substraddr_nonvarying when (character (*) nonvarying, fixed binary precision (1:35)),
		        substraddr_varying when (character (*) varying, fixed binary precision (1:35)));


substraddr_nonvarying:
     procedure (P_string, P_position) returns (pointer);

dcl  P_string	        character (*) nonvarying parameter;
dcl  P_position	        fixed binary (21) parameter;

dcl  string_overlay	        (length (P_string)) character (1) unaligned based (addr (P_string));

	return (addr (string_overlay (P_position)));

     end substraddr_nonvarying;


substraddr_varying:
     procedure (P_string, P_position) returns (pointer);

dcl  P_string	        character (*) varying parameter;
dcl  P_position	        fixed binary (21) parameter;

dcl  1 string_overlay       aligned based (addr (P_string)),
       2 lth	        fixed binary (21),
       2 characters	        (0 refer (string_overlay.lth)) character (1) unaligned;

	return (addr (string_overlay.characters (P_position)));

     end substraddr_varying;

%page; %include ibm3780_data;
%page; %include remote_ttt_info;
%page; %include iocb;
%page; %include iox_entries;
%page; %include iox_modes;

     end ibm3780_;




		    ibm3780_conv_.alm               02/02/88  1719.8r w 02/02/88  1538.3       38673



" ***********************************************************
" *                                                         *
" * Copyright, (C) Honeywell Information Systems Inc., 1982 *
" *                                                         *
" ***********************************************************
"ibm3780_conv_ - Conversion routine for producing ascii IBM3780 printer output
"	Coded March 1977 by David Vinograd

" 1) Version -- for new Printer DIM.

"  ******************************************************
"  *                                                    *
"  *                                                    *
"  * Copyright (c) 1972 by Massachusetts Institute of   *
"  * Technology and Honeywell Information Systems, Inc. *
"  *                                                    *
"  *                                                    *
"  ******************************************************


"
" The manner in which this procedure is utilized is described in detail
" in the listing of prt_conv_.
"
" This proc puts carriage control chars
" at the beginning of each output line.



	name	ibm3780_conv_
	segdef	printer
	segdef	punch
	segdef	teleprinter

	tempd	init_outp
	tempd	saved_outp
	tempd	saved_lp
	tempd	saved_sb

	tempd	saved_aq
	include	stack_header
	temp	carriage_ctl
	equ	pci,5
	equ	outp,3
	equ	inp,2


teleprinter:
printer:
	tra	send_init
	tra	send_chars
	tra	send_slew_pattern
	tra	send_slew_count

punch:
	tra	pr7|0
	tra	send_chars
	tra	pr7|0
	tra	no_slew
no_slew:
	lda	0,du
	tra	pr7|0
" 

	include	prt_conv_info


" 

send_init:

	spri3	init_outp		store output ptr
	ldq	2,dl		advance output ptr
	a9bd	outp|0,ql		..
	tra	pr7|0		return

" 

send_chars:
	sprilp	saved_lp
	sprisb	saved_sb
	staq	saved_aq
	epbpsb	sp|0
	epaq	*
	lprplp	sb|stack_header.lot_ptr,*au
	ldq	lp|transparent
	tze	spaceloop
	eaq	0,2
	tmoz	nospace
	tra	spaceout
spaceloop:
	eaq	0,2		white space count in QU
	tmoz	nospace		skip if no white space
	sbx2	63,du		can take only 63 at a time
	tmoz	*+2		..
	ldq	63,du		if more, take 63 to begin with
	cmpq	3,du		if fewer than 3 spaces,
	tmi	blankout		insert blanks instead

	mlr	(),(pr)		insert  dup char
	desc9a	dupchar,1	..
	desc9a	bb|0,1		..

	mlr	(qu),(pr)		insert dup count character
	desc9a	duptable,1	..
	desc9a	bb|0(1),1		..

	ldq	2,dl		step output pointer
	a9bd	bb|0,ql		..
	tra	spaceloop		loop

blankout:	mlr	(),(pr,rl),fill(040)  insert requisite number of blanks
	desc9a	*,0		..
	desc9a	bb|0,qu		..

	a9bd	bb|0,qu		bump output pointer
	tra	spaceloop		and loop

spaceout:
	epplp	saved_lp,*
	eppsb	saved_sb,*
	mlr	(),(pr,rl),fill(040)
	desc9a	*,0
	desc9a	bb|0,2

	a9bd	bb|0,2
nospace:
	epplp	saved_lp,*
	eppsb	saved_sb,*
	ldaq	saved_aq
	mlr	(pr,rl),(pr,rl)	copy characters into output
	desc9a	inp|0,au		..
	desc9a	outp|0,au		..

	a9bd	inp|0,au		step input and output pointers
	a9bd	outp|0,au		..
	eax2	0		make sure X2 now zero
	tra	pr7|0		return to caller

" 

send_slew_pattern:
	eax7	0		initialize for search
	sprilp	saved_lp
	sprisb	saved_sb
	epbpsb	sp|0
	staq	saved_aq
	epaq	*
	lprplp	sb|stack_header.lot_ptr,*au
	ldaq	saved_aq
	equ	nslew,6
	epplp	lp|slew_ctl_table_ptr,*
	rpt	nslew/2,2,tze	search for slew characters
	cmpa	lp|0,7		..
	ldq	lp|-1,7

stslew:
	epplp	saved_lp,*
	eppsb	saved_sb,*
	stq	carriage_ctl	save carriage control chars
	spri3	saved_outp	store output ptr
	epp3	init_outp,*	move ptr to register
	mlr	(pr),(pr)		move carriage control into output
	desc9a	carriage_ctl,2	..
	desc9a	pr3|0,2		..
	epp3	saved_outp,*	restore orignal output ptr
	tra	pr7|0		return to caller


send_slew_count:
	eaq	0,al		line count in QU
	sbla	3,dl		can slew at most 3 lines at a time
	tmoz	*+2		if more than 3 lines,
          ldq       3,du                do only 3 to start
	sprilp	saved_lp
	sprisb	saved_sb
	epbpsb	sp|0
	staq	saved_aq
	epaq	*
	lprplp	sb|stack_header.lot_ptr,*au
	ldaq	saved_aq
	ldq	lp|carriage_ctl_table_ptr,*qu
	tra	stslew		and store it for later

dupchar:
	vfd	o9/035
duptable:
	aci	"@ABCDEFGHIJKLMNO"
	aci	"PQRSTUVWXYZ[\]^_"
	aci	"`abcdefghijklmno"
	aci	"pqrstuvwxyz{|}~"
	use internal_static
	join	/link/internal_static
	segdef	carriage_ctl_table_ptr
	segdef	slew_ctl_table_ptr
	segdef	transparent

transparent:
	oct	0
	even
carriage_ctl_table_ptr:
	its	-1,1
slew_ctl_table_ptr:
	its	-1,1



	end
   



		    ibm3780_io_call_control_.pl1    04/02/85  1515.7rew 04/02/85  1514.5       55377



/* ***********************************************************
   *                                                         *
   * Copyright, (C) Honeywell Information Systems Inc., 1985 *
   *                                                         *
   *********************************************************** */
/* Module called to handle io_call control orders. */

/* Written:  March 1984 by Allan Haggett. */

ibm3780_io_call_control_:
     procedure (P_attach_data_ptr, P_iocb_ptr, P_info_ptr, P_code);

/**** Parameters */

dcl  P_attach_data_ptr      pointer;
dcl  P_iocb_ptr	        pointer parameter;
dcl  P_info_ptr	        pointer parameter;	     /* To io_call_info */
dcl  P_code	        fixed bin (35);

/**** Automatic */

dcl  arg_count	        fixed bin;
dcl  caller	        character (32);
dcl  code		        fixed bin (35);
dcl  device	        character (32);	     /* For select_device */
dcl  idx		        fixed bin;
dcl  iocb_ptr	        pointer;
dcl  multi_record_count     fixed bin (35);
dcl  order	        character (32);	     /* From io_call_info. */
dcl  (report,
     error)	        entry variable options (variable);
dcl  1 set_bsc_modes        automatic,
       2 transparent        bit (1) unaligned,
       2 ebcdic_sw	        bit (1) unaligned,
       2 pad	        bit (34) unaligned;

/**** Constant */

dcl  SIMPLE_ORDERS	        (5) character (32) internal static options (constant)
		        init ("runout", "end_write_mode", "resetread", "resetwrite", "reset");

/**** Entries and external. */

dcl  cv_dec_check_	        entry (character (*), fixed bin (35)) returns (fixed bin (35));
dcl  iox_$control	        entry (ptr, character (*), ptr, fixed bin (35));

dcl  (error_table_$badopt,
     error_table_$noarg,
     error_table_$no_operation) fixed bin (35) external static;

dcl (addr, hbound, null) builtin;
%page;
	/* Copy parameters. */
	adp = P_attach_data_ptr;		     /* Attach Data Ptr */
	iocb_ptr = P_iocb_ptr;
	io_call_infop = P_info_ptr;		     /* See io_call_info.incl.pl1 */
	P_code = 0;

	/* Get a pointer to the CommInfoBlock for this switch. This is */
	/* a block of information about the single "bisync_" attachment. */
	cib_ptr = ad.cib_ptr;

	order = io_call_info.order_name;
	arg_count = io_call_info.nargs;
	caller = io_call_info.caller_name;
	error = io_call_info.error;
	report = io_call_info.report;
	code = 0;				     /* Pass this back at the very end. */

	/* Check to see if this order can simply be passed on without any */
	/* further processing. Should we check the argument count? */
	do idx = 1 to hbound (SIMPLE_ORDERS, 1)
	     while (order ^= SIMPLE_ORDERS (idx));
	end;

	if (idx <= hbound (SIMPLE_ORDERS, 1)) then
	     call iox_$control (iocb_ptr, order, null (), code);

	else if (order = "set_bsc_modes") then do;

	     /* No arguments means we just make sure bisync_ is in sync. */
	     set_bsc_modes.ebcdic_sw = (ad.char_mode = EBCDIC);
	     set_bsc_modes.transparent = ad.transparent;

	     do idx = 1 to arg_count;

		if (io_call_info.args (idx) = "ascii") then
		     set_bsc_modes.ebcdic_sw = "0"b;
		else if (io_call_info.args (idx) = "ebcdic") then
		     set_bsc_modes.ebcdic_sw = "1"b;
		else if (io_call_info.args (idx) = "transparent") then
		     set_bsc_modes.transparent = "1"b;
		else if (io_call_info.args (idx) = "nontransparent") then
		     set_bsc_modes.transparent = "0"b;
		else do;			     /* Unknown keyword. */
		     call error (error_table_$badopt, caller, "Invalid BISYNC mode: ^a", io_call_info.args (idx));
		     goto ERROR_RETURN;	     /* code = 0 */
		end;
	     end;

	     /* Keywords are processed, pass it to ourself. */
	     call iox_$control (iocb_ptr, order, addr (set_bsc_modes), code);

	end;

	/* Debugging order. */
	else if (order = "ibm3780_info") then do;

	     call report ("Bisync modes:^21t^[non^]transparent,^[ascii^;ebcdic^]",
		^ad.transparent, (ad.char_mode = ASCII));
	     call report ("Multi-record:^21t^[ON^;OFF^] (count=^d)",
		ad.multi_record, ad.multi_record_count);
	     call report ("Record length:^21t^d", ad.record_len);

	end;

	else if (order = "select_device") then do;
	     if (arg_count < 1) then do;
		call error (error_table_$noarg, caller, "No device name for ^a order.", order);
		goto ERROR_RETURN;
	     end;

	     /* Copy device string and pass pointer. */
	     device = io_call_info.args (1);
	     call iox_$control (iocb_ptr, order, addr (device), code);

	     /* Interpret code returned by ibm3780_. */
	     if (code = error_table_$no_operation) then do;
		call error (0, caller, "Invalid device name: ^a", device);
		code = 0;			     /* So io_call does not try again. */
	     end;
	end;

	else if (order = "set_multi_record_mode") then do;

	     if (arg_count = 0) then
		call iox_$control (iocb_ptr, order, null (), code);
	     else do;			     /* Get number. */
		multi_record_count = get_numeric_arg (1, "record count");
		call iox_$control (iocb_ptr, order, addr (multi_record_count), code);
	     end;
	end;

	/* See if bisync_ will accommodate. */
	else call iox_$control (cib.comm_iocb_ptr, "io_call", io_call_infop, code);

ERROR_RETURN:
	P_code = code;			     /* Pass it back. */

	return;
%page;
get_numeric_arg:
     procedure (P_idx, P_what) returns (fixed bin (35));

dcl  P_idx	        fixed bin parameter;
dcl  P_what	        character (*) parameter;

dcl  bad_pos	        fixed bin (35);	     /* From cv_deck_check_. */
dcl  result	        fixed bin (35);

	if (P_idx > arg_count) then do;
	     call error (error_table_$noarg, caller, "No ^a for ^a order.",
		P_what, order);
	     goto ERROR_RETURN;
	end;

	result = cv_dec_check_ ((io_call_info.args (P_idx)), bad_pos);
	if (bad_pos ^= 0) then do;
	     call error (0, caller, "Bad integer value for ^a: ^a", P_what, io_call_info.args (P_idx));
	     goto ERROR_RETURN;
	end;

	if (result < 0) then do;
	     call error (0, caller, "Value for ^a cannot be less than zero: ^d",
		P_what, result);
	     goto ERROR_RETURN;
	end;

	return (result);

     end get_numeric_arg;

%page; %include ibm3780_data;
%page; %include remote_ttt_info;
%page; %include io_call_info;

     end ibm3780_io_call_control_;






		    bull_copyright_notice.txt       08/30/05  1008.4r   08/30/05  1007.3    00020025

                                          -----------------------------------------------------------


Historical Background

This edition of the Multics software materials and documentation is provided and donated
to Massachusetts Institute of Technology by Group Bull including Bull HN Information Systems Inc. 
as a contribution to computer science knowledge.  
This donation is made also to give evidence of the common contributions of Massachusetts Institute of Technology,
Bell Laboratories, General Electric, Honeywell Information Systems Inc., Honeywell Bull Inc., Groupe Bull
and Bull HN Information Systems Inc. to the development of this operating system. 
Multics development was initiated by Massachusetts Institute of Technology Project MAC (1963-1970),
renamed the MIT Laboratory for Computer Science and Artificial Intelligence in the mid 1970s, under the leadership
of Professor Fernando Jose Corbato.Users consider that Multics provided the best software architecture for 
managing computer hardware properly and for executing programs. Many subsequent operating systems
incorporated Multics principles.
Multics was distributed in 1975 to 2000 by Group Bull in Europe , and in the U.S. by Bull HN Information Systems Inc., 
as successor in interest by change in name only to Honeywell Bull Inc. and Honeywell Information Systems Inc. .

                                          -----------------------------------------------------------

Permission to use, copy, modify, and distribute these programs and their documentation for any purpose and without
fee is hereby granted,provided that the below copyright notice and historical background appear in all copies
and that both the copyright notice and historical background and this permission notice appear in supporting
documentation, and that the names of MIT, HIS, Bull or Bull HN not be used in advertising or publicity pertaining
to distribution of the programs without specific prior written permission.
    Copyright 1972 by Massachusetts Institute of Technology and Honeywell Information Systems Inc.
    Copyright 2006 by Bull HN Information Systems Inc.
    Copyright 2006 by Bull SAS
    All Rights Reserved
