/*
BEGIN DOCUMENTATION

Name: TCMPLI.C 					Created: 09/08/83  DTS
					    Last Update: 01/13/83
Title: TCM PL/I User Interface

Index: FMS, text editor, editor, TCM

Abstract: Invokes separate TCM editing task to aquire textual data 
	  from a CRT that is being used concurrently by FMS.

Usage: See "TCM.DOC" for PL/I usage

	Routine	Function performed by slave task

	TINIT	Initialize TCM, clear all text buffers
	TWINCR	Create new window, allocate buffer space,
		Receive initial text data or input file name
	TCOLL	Start edit session for named window.
	TRETRV	Retreive text line from named window.
	TWINSA	Save named text window to file.
	TWINDE	Delete named window (and associated buffer).
	TWINRF	Refresh window Screen image.
	TSTOP	Cause TCM task to end all processing and exit.


Parameters: See "TCM.DOC"

Environment: RSX11M V4.0, DECUS C Compiler, AIS PL/I Compiler
	     MMR PL/I Interface

See Also: TCM.C

Description: The text collection management (TCM) slave task is installed
	     as "...TCM".  This allows it to be spawned from this program
	     and built as a multi-user task for RSX11M-PLUS. When the TCM
	     slave is spawned it is passed a command line which contains
	     the name of this calling task. Once this is done all data
	     passes between the caller (this program) and the slave
	     through a common set of task to task communication routines.
	     These routines (vsend & vrecv) allow sending and receiving
	     arbitarily long pieces of data. The calling task always
	     sends a command buffer to the slave.  The slave task always
	     sends a return code back to the caller when the command is
	     complete.  Some of the commands send or receive C text
	     strings. 


Example(s):

Uses:

Internal: See TCMNOTES.DOC

Update History: 01/13/83 DTS:	Added simple detach/attach around TINIT,
				TWINCR, TCOLL, and TWINRF

END DOCUMENTATION
*/



#include <clang.c>
#include <stdio.h>
#include <cx.h>
#include <signal.c>
#include <plistring.c>
#include <tparbf.h>
#include "tcmdefs.h"
#include "tcmerr.h"

/* #define debug 0 */
#define plinull -1		/* Null PL/I pointer */
#define TILUN 5

/* External Routines */

extern charpointer plistr();
extern plient();
extern callpli();
extern r50toa();
extern ascr50();
extern spwn();
extern srda();
extern wtse();

/* Forward References */

extern int tsndcmd();
extern tcmabt();
extern tcm_status();
extern tcmrcv();
extern tflgwait();

/* Global Variables */

#define	off	0		/* values for tcmstate */
#define	idle	1
#define	edit	2
#define	saving	3

dsect	"tcmdsw";
static	int tcmdsw;		/* DSW of last directive error */
dsect	"";

    static int	tcmevf;		/* Event flag used for receive, abort */
    static int	tcmabf;		/* Event flag set if tcmaborted, not used */
    static int	tcflag;		/* Event flag for asynchronous TCM done */
    static pointer tcmxst = NULL; /* Pointer to exit_status for async calls */
    static int  tcmabst[8];	/* Abort status for tcm slave task */
    struct cmdbuff srbuf;	/* Command buffer to send to slave */
    struct retbuf  ret;		/* Status returned from slave */
    struct rad50   tcmslv;	/* Task name for slave TCM task */
    struct tparbf tskpar;	/* Task header information */
    int		tcmstate = off;	/* flag to mark current state */
    boolean	tskabo = false;	/* TCM aborted flag */
    char	tcmotf[] = "SY:TCM.TXT"; /* Default output file for TWINSA */



/* TINIT: (INPUT: a_flag,r_flag; OUTPUT: rc);
	  globals in: tcmstate,tcmslv,tcmevf,tskabo;
	  globals out:tcmstate,tcmslv,tcmevf,tcmabf,tcmdsw,tskabo,tskpar;

The first call to the TCM routines by a PL/I program should always be
TINIT. This will spawn (SPWN$) the TCM slave task and use an event
flag and an ast to indicate if the TCM task exits.  A receive data ast is also
specified to set an event flag on receiving data.  By using an ast to 
set a boolean on the slave abort and receiving data at ast state the 
task can asynchonously receive status and set a single user event 
flag.  After sending each command the calling task (this program) does
a receive of the status (waiting for either receive data or TCM task
exit). 

Note: This routine is very RSX11M specific!

Program logic for TINIT:

        IF TCM not started THEN
	    Translate running task name to ASCII
	    tcmaborted := false
            Spawn "...TCM" slave task (set a_flag & tcmaborted on exit) with our name.
	    set tcm started flag
        ELSE
	    IF TCM busy THEN
		wait for last command to complete
	    ENDIF
            Send (cmd := 'I')
        ENDIF
	Enable receive ast for r_flag
        Receive (from any task) rc status (or TCM exit)
	Set TCMSLV (slave task) to sender's name
*/

#define CMDLEN 10

tinit(narg,aflag,rflag,rc)
    int narg,*aflag,*rflag,*rc;
{
    char cmdline[CMDLEN];
    register char *cmdptr;
    int srsize;


	plient("TINIT");
	iff narg != 3 then signal(NUMARGS);
	iff (tcmstate == off) or tskabo then {
	    tcmevf = *rflag;
	    tskabo = *aflag;
	    cmdptr = cpystr(cmdline,"TCM ");	/* Set up command line */
	    gtsk(&tskpar);
	    r50toa(cmdptr,&tskpar.g_tstn,2);
	    ascr50(6,"MCR...",&tcmslv);		/* Send command to MCR */
	    tskabo = false; tcmabst[0] = 0;
	    tcmdet(TILUN);
	    tcmdsw = spwn(&tcmslv,NULL,tskabo,&tcmabt,tcmabst,cmdline,CMDLEN);
	}
	else {
	    iff (*rc = tcm_status()) != TS_SUC then
		goto tinitxit;
	    tcmdet(TILUN);
	    tcmdsw = tsndcmd('I');
	}
	iff tcmdsw != IS_SUC then
	    { *rc = TE_SRV; goto tinitxit; };
	iff (tcmdsw = srda(&tcmrcv)) != IS_SUC then	/* Enable receive ast */
	    *rc = TE_AST;
	iff (*rc = tflgwait()) == TS_SUC then {
	    srsize = sizeof(ret);
	    iff ((tcmdsw = vrecva(&tcmslv,&ret,&srsize)) != IS_SUC) or (srsize != sizeof(ret)) then
		*rc = TE_SRV;
	    else {
		tcmstate = idle;
		*rc = ret.cd;
		tcmatt(TILUN);
	    }
	}
	else iff tcmabst[0] == 2 then
	    *rc = TE_INS;
tinitxit: ;

} /* end tinit */



/* TWINCR: (INPUT: w_name,init_data,row,col,height,width,virt_chars,
	    [max_chars]; OUTPUT: rc);

	   globals in: tcmstate;
	   globals out:tcmdsw,srbuf;

Send command to create CRT window on screen

Program Logic for TWINCR:

	IF tcm_status() != TS_SUC
	    exit with rc = tcm_status;
	ELSE
	    srbuf.name := w_name;
	    srbuf.row  := row;
	    srbuf.height := height;
	    srbuf.width := width;
	    srbuf.chars := virt_chars;
	    IF max_chars is defined THEN
		srbuf.max_chars := max_chars;
	    ELSE srbuf.max_chars := 0;
	    ENDIF
	    IF init_data != "" THEN
		srbuf.opflag := 'T';
	    ELSE srbuf.opflag := ' ';
	    ENDIF
	    Send (cmd := 'C')
	    IF srbuf.opflag = 'T' THEN
		Send init_data (text or file name)
	    ENDIF
	    Receive status (rc)
	ENDIF
*/

twincr(narg,w_name,init_data,row,col,height,width,virt_chars,max_chars,rc)
    int narg;
    plistring w_name, init_data;
    pointer row,col,height,width,virt_chars,max_chars,rc;
{
    pointer retcd;

	plient("TWINCR");
	iff narg == 8 then
	    retcd = max_chars;
	else iff narg == 9 then
	    retcd = rc;
	else signal(NUMARGS);
	iff (*retcd = tcm_status()) != TS_SUC then
	    goto twincrxit;
	setname(w_name);
        srbuf.row  = ifx row == plinull thenx 0 elsex *row;
        srbuf.col  = ifx col == plinull thenx 0 elsex *col;
        srbuf.height = ifx height == plinull thenx 0 elsex *height;
        srbuf.width = ifx width == plinull thenx 0 elsex *width;
        srbuf.virt_chars = ifx virt_chars == plinull thenx 0 elsex *virt_chars;
        srbuf.max_chars = ifx (narg == 8) or (max_chars == plinull) thenx
	    0 elsex *max_chars;
	srbuf.opflag = ifx plilen(init_data) > 0 thenx 'T' elsex ' ';
	tcmdet(TILUN);			/* Detach terminal */
        iff (tcmdsw = tsndcmd('C')) == IS_SUC then
	    iff srbuf.opflag == 'T' then
	        tcmdsw = vsend(&tcmslv,plistr(init_data),plilen(init_data));
	iff tcmdsw == IS_SUC then
	    recv_status(retcd);
	else
	    *retcd = TE_SRV;
	tcmatt(TILUN);			/* Attach terminal */
twincrxit: ;
} /* end twincr */


/* TCOLL: (INPUT:w_name,c_pos,err_level,max_time,[e_flag] ; OUTPUT:rc,exit_status);

Program Logic:

	IF tcm_status() != TS_SUC
	    exit with rc = tcm_status;
	ELSE
	    srbuf.name := w_name;
	    srbuf.opflag := c_pos;	 * Cursor flag *
	    srbuf.row  := err_level;
	    srbuf.max_chars := max_time;
	    IF terminal attached THEN
		srbuf.height := 1;
	    ELSE srbuf.height := 0;
	    ENDIF
	    IF terminal slave THEN
		srbuf.width := 1;
	    ELSE
		srbuf.width := 0;
		set terminal to slave;
	    ENDIF
	    srbuf.cmd  := 'E';
	    Send (cmd := 'E');
	    IF srbuf.height = 1 THEN	 * was attached *
		detach terminal;
	    ENDIF
	    IF e_flag = 0 (or null) THEN
		tcflag := 0;
		Receive Status(exit_status);
		IF srbuf.height = 1 THEN * was attached *
		    attach terminal;
		ENDIF
		IF srbuf.width = 0 THEN	 * wasn't slave *
		    set terminal to noslave;
		ENDIF
	    ELSE tcflag := e_flag;
		tcm state := edit
		rc := TS_SUC;
	    ENDIF
	ENDIF
*/

tcoll(narg,w_name,c_pos,err_level,max_time,e_flag,rc,exitstat)
    int narg;
    plistring w_name,c_pos;
    pointer err_level,max_time,e_flag,rc,exitstat;
{
    pointer retcd;

	plient("TCOLL");
	iff narg == 6 then
	    retcd = e_flag;
	else iff narg == 7 then
	    retcd = rc;
	else signal(NUMARGS);
	iff (*retcd = tcm_status()) == TS_SUC then {
	    iff narg == 6 then
		{ tcflag = 0; tcmxst = rc; }
	    else {
		tcmxst = exitstat;
		tcflag = ifx e_flag == plinull thenx 0 elsex *e_flag;
	    }
	    setname(w_name);
	    srbuf.opflag = *plistr(c_pos);	/* Cursor flag */
	    srbuf.row  = *err_level;
	    srbuf.max_chars = ifx max_time == plinull thenx 0 elsex *max_time;
	    iff tcflag != 0 then
		tcmstate = edit;
	    tcmdet(TILUN);		/* Detach terminal */
	    tcmdsw = tsndcmd('E');
	    iff (tcflag == 0) and (tcmdsw == IS_SUC) then
	    {
		recv_status(tcmxst);
		tcmatt(TILUN);		/* Attach terminal */
	    }
	    else iff tcmdsw == IS_SUC then
	        *retcd = TS_SUC;
	    else
		*retcd = TE_SRV;
	}
} /* end tcoll */



/* TRETRV: (INPUT:w_name ; OUTPUT:stng,rc);

Retrieve line from text window, wait if tcoll called with e_flag.

Program Logic:

	IF tcm_status() != TS_SUC
	    exit with rc = tcm_status;
	ELSE
	    srbuf.name := w_name;
	    Send (cmd := 'R')
	    Receive stng
	    Receive Status
        ENDIF
*/

tretrv(narg,w_name,stng,rc)
    int narg;
    plistring w_name,stng;
    pointer rc;
{
    int srsize;
    register charpointer sp;

	plient("TRETRV");
	iff narg != 3 then signal(NUMARGS);
        iff (*rc = tcm_status()) == TS_SUC then {
	    setname(w_name);
	    iff (tcmdsw = tsndcmd('R')) != IS_SUC then
		*rc = TE_SRV;
	    else iff (*rc = tflgwait()) == TS_SUC then {
		srsize = stng plisize;
		sp = plistr(stng);
		iff ((tcmdsw = vrecv(&tcmslv,sp,&srsize)) != IS_SUC) then
		    *rc = TE_SRV;
		else {
		    plicpy(stng,sp,srsize);	/* set PL/I string */
		    setf(tcmevf);		/* Don't wait on receive */
		    recv_status(rc);
		}
	    }
	}
} /* end tretrv */



/* TWINSA: (INPUT: w_name,text_save,[e_flag]; OUTPUT: rc,exit_status);

Program logic:

	IF tcm_status() != TS_SUC
	    exit with rc = tcm_status;
	ELSE
	    IF text_save NULL (= "") THEN
		text_save := TCM.TXT	* set default file spec *
	    ENDIF
	    srbuf.name := w_name;
	    Send (cmd := 'F');
	    Send text_save (output file name);
	    RC := TS_SUC;
	    IF e_flag null THEN
		tcflag := 0;
	    ELSE
		tcflag := e_flag;
		Receive Status(exit_status);
	    ENDIF
	ENDIF
*/

twinsa(narg,w_name,text_save,e_flag,rc,exitstat)
    int narg;
    plistring w_name,text_save;
    pointer e_flag,rc,exitstat;
{
    register pointer retcd;
    register charpointer tsave;
    register int tlen;

	plient("TWINSA");
	iff narg == 4 then
	    retcd = e_flag;
	else iff narg == 5 then
	    retcd = rc;
	else signal(NUMARGS);
	iff (*retcd = tcm_status()) == TS_SUC then {
	    iff narg == 4 then
		{ tcflag = 0; tcmxst = rc; }
	    else {
		tcmxst = exitstat;
		tcflag = ifx e_flag == plinull thenx 0 elsex *e_flag;
	    }
	    iff (tlen = plilen(text_save)) == 0 then
		{ tsave = tcmotf; tlen = strlen(tcmotf); }
	    else
		tsave = plistr(text_save);
	    setname(w_name);
	    iff tcflag != 0 then
		tcmstate = saving;
	    iff (tcmdsw = tsndcmd('F')) == IS_SUC then
		tcmdsw = vsend(&tcmslv,tsave,tlen);
	    iff (tcflag == 0) and (tcmdsw == IS_SUC) then {
		recv_status(tcmxst);
	        *retcd = TS_SUC;
	    }
	    else
		*retcd = TE_SRV;
	}
} /* end twinsa */




/* TWINDE: (INPUT:w_name; OUTPUT:rc)

Delete text window.

Program Logic:

	IF tcm_status() != TS_SUC
	    exit with rc = tcm_status;
	ELSE
	    srbuf.name := w_name;
	    IF w_name = " " THEN
		Send (cmd := 'I')
	    ELSE
		Send (cmd := 'D')
	    ENDIF
	    Receive Status (rc)
	ENDIF
*/

twinde(narg,w_name,rc)
    plistring w_name;
    pointer rc;
{
	plient("TWINDE");
	iff narg != 2 then signal(NUMARGS);
        iff (*rc = tcm_status()) == TS_SUC then {
	    setname(w_name);
	    iff *plistr(w_name) == ' ' then
		tcmdsw = tsndcmd('I');
	    else
		tcmdsw = tsndcmd('D');
	    iff (tcmdsw == IS_SUC) then
		recv_status(rc);
	}
} /* end twinde */

/* TWINRF: (INPUT:w_name; OUTPUT:rc)

Refresh window on screen.

Program Logic:

	IF tcm_status() != TS_SUC
	    exit with rc = tcm_status;
	ELSE
	    srbuf.name := w_name;
	    Send (cmd := 'S')
	    Receive Status (rc)
	ENDIF
*/

twinrf(narg,w_name,rc)
    plistring w_name;
    pointer rc;
{
	plient("TWINRF");
	iff narg != 2 then signal(NUMARGS);
        iff (*rc = tcm_status()) == TS_SUC then {
	    setname(w_name);
	    tcmdet(TILUN);
	    tcmdsw = tsndcmd('S');
	    iff (tcmdsw == IS_SUC) then
		recv_status(rc);
	    tcmatt(TILUN);
	}

} /* end twinrf */

/* TSTOP: (INPUT: ; OUTPUT:rc)

Stop text collection task.

Program Logic:

	IF tcm_status() != TS_SUC
	    exit with rc = tcm_status;
	ELSE
	    Send (cmd := 'X')
	    Receive Status (or exit status of TCM)
	ENDIF
*/


tstop(narg,rc)
    int narg;
    pointer rc;
{
	plient("TSTOP");
	iff narg != 1 then signal(NUMARGS);
        iff (*rc = tcm_status()) == TS_SUC then {
	    tcmdsw = tsndcmd('X');
	    iff (tcmdsw == IS_SUC) then
		recv_status(rc);
	    iff (tskabo != false) and (tcmabst[0] == IS_SUC) then
		*rc = TS_SUC;
	}
	tcmstate = off;
} /* end tstop */



/* TCM_STATUS: Check tcm state and wait if last command busy

	Output: TS_SUC if tcm is running & commands are finished
		otherwise an error.

Program Logic:

	IF tcm not started THEN
	    rc := TE_STA
	ELSE IF tcm aborted THEN
	    rc := TE_ACT
	ELSE IF tcm busy
	    wait for last command to complete
	    IF status > 0 then rc := TS_SUC
	    ELSE rc := status (of last command)
	ENDIF
*/

int
tcm_status()
{
    register int rc;

#ifdef debug
    register charpointer str;
	str = "\033[16;1Htcmstate = % tcmdsw = %.";
	msgti(str,tcmstate,tcmdsw);
#endif
	rc = TS_SUC;			/* default */
	iff tcmstate == off then
	    rc = TE_STA;
	else iff tskabo != false then
	    rc = TE_ACT;
	else iff tcmstate != idle then {	/* tcm is busy */
	    iff (tcmdsw = wtse(tcflag)) == IS_SUC then { /* wait on user flag */
		iff (tcmxst != NULL) and (*tcmxst < 0) then
		    rc = *tcmxst;
	    }
	    else
		rc = TE_EVF;
	}
	tcmxst = NULL;
	return(rc);
} /* end tcm_status */




/* TSNDCMD: (INPUT:command_char) Set Command code & send to slave task

	globals in: tcmslv,srbuf,tskabo;
	globals out: srbuf.cmd;
*/

int
tsndcmd(cmdch)
    char cmdch;
{
    srbuf.cmd = cmdch;
    iff tskabo != false then
	return(IE_ACT);
    else
	return(vsend(&tcmslv,&srbuf,sizeof(srbuf)));
} /* end tsndcmd */



/* STRSET: Copy PL/I string into C string */

strset(out,in)
    charpointer out;
    plistring in;
{
    register int length;
    register charpointer input;

	length = plilen(in);
	for(input = plistr(in); length > 0; length--)
	    *out++ = *input++;
	*out = eos;
} /* end strset */


/* SETNAME: Copy PL/I name string to srbuf.name, check length
	globals in:
	globals out: srbuf.name;
*/

setname(wname)
    plistring wname;
{
    register int len;

        iff (len = plilen(wname)) < 1 or (len > sizeof(srbuf.name) - 1) then
	    signal(STRINGSIZE);
	strset(&srbuf.name,wname);
} /* end setname */



/* Wait for logical or of receive & abort flags */

int
tflgwait()
{
    register int rc;
/*
    unsigned int flags[4];	* RDAF 4 word buffer *

	iff (tcmdsw = wtlo0(tcmevm)) != IS_SUC then
	    return(TE_SRV);
	else iff (tcmdsw = rdaf(&flags)) != IS_SUC then
	    return(TE_SRV);
	else iff (flags[0] & (1 << (tcmevf-1))) != 0 then * TCM Aborted *
	    return(TE_ACT);
	else return(TS_SUC);
*/
	iff (tcmdsw = wtse(tcmevf)) == IS_SUC then {
	    dsar();
	    clef(tcmevf);
	    enar();
	    iff tskabo != false then rc = TE_ACT;
	    else rc = TS_SUC;
	}
	else rc = TE_EVF;
	return(rc);
} /* end tflgwait */


/* Receive status from TCM task */

recv_status(stat)
    pointer stat;
{
    int srsize;

	srsize = sizeof(ret);
	iff (*stat = tflgwait()) == TS_SUC then {
	    /* note: vrecv will hang if TCM aborted after xfer starts */
	    iff ((tcmdsw = vrecv(&tcmslv,&ret,&srsize)) != IS_SUC) or (srsize < sizeof(ret)) then
		*stat = TE_SRV;
	    else {
		*stat = ret.cd;
		tcmdsw = ret.dsw;
	    }
	    iff tskabo then *stat = TE_ACT;	/* Override return status if aborted */
	}
} /* end recv_status */



/* TCMABT: Ast for TCM abort
	  globals in: tcmstate,tcmxst,tskpar;
	  globals out:tcmstate,tcmevf,tcmdsw,tskabo,*tcmxst;

Program Logic:

	unstop self (in case we were stopped)
	set flag(a_flag)
	set flag(r_flag)
	tcm abort := true
	IF tcmstate = edit (or = saving) AND tcflag > 0 THEN
	    set flag(tcflag)
	    *tcmexitstatus = TE_ACT
	ENDIF
	IF tcmstate != off THEN
	    tcmstate := started
	ENDIF
*/

tcmabt()
{
	astset();			/* save registers */
	ustp(&tskpar.g_tstn);		/* unstop self if stopped */
	iff setf(tcmevf) < 0 then	/* Note: spawn causes tcmabf to set */
	    tcmdsw = $dsw;
	tskabo = true;
#ifdef debug
	msgti("TCM aborted status = %",tcmabst[0]);
#endif
	iff (tcmstate == edit) or (tcmstate == saving) then {
	    iff tcflag != 0 then
		iff setf(tcflag) < 0 then
		    tcmdsw = $dsw;
	    iff tcmxst != NULL then
		*tcmxst = TE_ACT;
	}
	iff (tcmstate != off) and (tcmabst[0] == IS_SUC) then
	    tcmstate = idle;
	astx(1);		/* remove addr of exit status block */
} /* end tcmabt */



/* TCMRCV: Ast for TCM receive

Program Logic:

	set flag(a_flag)
	IF tcmstate = edit (or saving) THEN
	    receive tcmexit status (if pointer not null)
	    tcmexit status pointer := null
	    IF tcflag > 0 THEN
		set flag(tcflag)
	    ENDIF
	    IF tcmstate != off THEN
		tcmstate := started
	    ENDIF
	ENDIF
*/

tcmrcv()
{
	astset();		/* save registers */
	iff setf(tcmevf) < 0 then
	    tcmdsw = $dsw;
	else {
	    iff (tcmstate == edit) or (tcmstate == saving) then {
		iff tcmxst != NULL then
		    recv_status(tcmxst);
		iff tcflag != 0 then
		    iff setf(tcflag) < 0 then
		        tcmdsw = $dsw;
	    }
	}
	iff tcmstate != off then
	    tcmstate = idle;
	astx(0);
} /* end tcmrcv */



/***	Attach terminal (TI:) for input, set full duplex, typeahead    ***/

tcmatt(lun)

    int	 lun;    
{
    int fnc;	/* parm definitions for qio */
    int iosb[2];
    union {
	   int i;
	   pointer p;
	  } devpar[6];
/*    union {
	   int	dev;
	   char name[2];
	  } dnam;

    int	 unit;
    int ttchar[5];
    register int i,c;

    * assign TI: device to given lun *

	dnam.name[0] = 'T';
	dnam.name[1] = 'I';
	unit = 0;

	alun(lun,dnam.dev,unit);

*/

    /* Attach terminal to capture all characters */

	fnc = IO_ATT;
	iosb[0] = 0;
	devpar[0].i = 0;
	devpar[1].i = 0;
	devpar[2].i = 0;


	iff qiow(fnc,lun,tcmabf,iosb,0,devpar) < 0
	    then msgti("TCM Attach error dsw = %.",$dsw);

/*    * Set terminal characteristics for fullduplex & typeahead *

	fnc = SF_SMC;
	ttchar[0] = TC_FDX + 256;	* Set full duplex *
	ttchar[1] = TC_ACR + 0;		* Clear wrap *
	ttchar[2] = TC_RAT + 256;	* Set typeahead *
	devpar[0].p = ttchar;
	devpar[1].i = 6;		* Number of bytes in ttchar table *

	iff qiow(fnc,lun,eflag,iosb,0,devpar) < 0
	    then error("ATTACH - SMC error dsw = %d\n",$dsw);


*/

} /* end tcmatt */



/***	Detach terminal & kill outstanding I/O    ***/

tcmdet(lun)

    int	lun;
{
    int iosb[2];

	iff qiow(IO_KIL,lun,tcmabf,iosb,0,0) < 0
	    then msgti("I/O Kill error, lun %.",lun);
	iff qiow(IO_DET,lun,tcmabf,iosb,0,0) < 0
	    then msgti("Detach error, lun %.",lun);

} /* end tcmdet */
