#include <libdef.h>
#include <lnmdef.h>
#include <stdio.h>
#include <string.h>
#include "ptyx.h"
#include "data.h"
#include "vms.h"
#define PTD$C_SEND_XON 0
#define PTD$C_SEND_BELL 1
#define PTD$C_SEND_XOFF 2
#define PTD$C_STOP_OUTPUT 3
#define PTD$C_RESUME_OUTPUT 4
#define PTD$C_CHAR_CHANGED 5
#define PTD$C_ABORT_OUTPUT 6
#define PTD$C_START_READ 7
#define PTD$C_MIDDLE_READ 8
#define PTD$C_END_READ 9
#define PTD$C_ENABLE_READ 10
#define PTD$C_DISABLE_READ 11
#define PTD$C_MAX_EVENTS 12
#define BUFFERS 6
#define PAGE 512
typedef struct tt_buffer
{
unsigned int flink;
unsigned int blink;
short int status;
short int length;
char data[VMS_TERM_BUFFER_SIZE];
} TT_BUF_STRUCT;
TT_BUF_STRUCT *tt_w_buff;
struct q_head _align(QUADWORD) buffer_queue = (0,0);
struct q_head _align(QUADWORD) read_queue = (0,0);
static char tt_name[64];
static $DESCRIPTOR (tt_name_desc, &tt_name);
static char ws_name[64];
static $DESCRIPTOR (ws_name_desc, &ws_name);
static struct tt_char {
char class;
char type;
short int page_width;
char characteristics[3];
char length;
int extended;
} tt_mode, tt_chars, orig_tt_chars;
struct mem_region
{
TT_BUF_STRUCT *start;
TT_BUF_STRUCT *end;
} ret_addr;
int read_stopped = FALSE;
int write_stopped = FALSE;
int tt_width;
int tt_length;
int tt_changed;
int tt_pasting=FALSE;
int tt_new_output=FALSE;
int trnlnm(char *in,int id,char *out);
int tt_write(char *tt_write_buf,int size);
void spawn (void);
static void tt_echo_ast(TT_BUF_STRUCT *buff_addr);
static void tt_read_ast(TT_BUF_STRUCT *buff_addr);
void tt_start_read(void);
int tt_read(char *buffer);
static void send_xon(void);
static void send_xoff(void);
static void send_bell(void);
static void char_change(void);
static void freeBuff (TT_BUF_STRUCT *buff_addr);
TT_BUF_STRUCT *getBuff(void);
static void CloseDown(int exit_status);
static void mbx_read_ast(void);
static void mbx_read(void);
#define DESCRIPTOR(name,string) struct dsc$descriptor_s name = \
{ strlen(string), DSC$K_DTYPE_T, DSC$K_CLASS_S, string }
int trnlnm(char *in, int id, char *out)
{
int status, num, len, attr = LNM$M_CASE_BLIND, foo = id;
short outlen;
struct itemlist
{
short buffer_length;
short item_code;
char *buffer_addr;
int *return_length;
} itmlst[] =
{
4 , LNM$_INDEX , &foo, 0,
255, LNM$_STRING , out , &outlen,
4 , LNM$_MAX_INDEX, &num, &len,
0 , 0
};
DESCRIPTOR(lognam,in);
DESCRIPTOR(tabnam,"LNM$DCL_LOGICAL");
status = sys$trnlnm(&attr,&tabnam,&lognam,0,itmlst);
if(status != SS$_NORMAL) return(-1);
out[outlen] = 0;
return(++num);
}
static int pty;
static int Xsocket;
void spawn (void)
{
int status;
static $DESCRIPTOR (dtime, "0 00:00:00.01");
static int delta[2];
register TScreen *screen = &term->screen;
static struct IOSB iosb;
static unsigned int flags;
static unsigned int uic;
static char imagename[64];
static int privs;
static $DESCRIPTOR(device, "FTA0:");
static int type;
static int class;
static int devdepend;
static int mem_size;
int i;
pid = 0;
mbx_chan = 0;
status = SYS$EXPREG (BUFFERS, &ret_addr, 0, 0);
if(!(status & SS$_NORMAL)) lib$signal(status);
tt_w_buff = (char *)ret_addr.end - PAGE + 1;
for(i=0; i < BUFFERS-1; i++)
{
freeBuff((char *)ret_addr.start +i*PAGE);
}
XtSetMappedWhenManaged( screen->TekEmu ? XtParent(tekWidget) :
XtParent(term), False );
XtRealizeWidget (screen->TekEmu ? XtParent(tekWidget) :
XtParent(term));
itemlist[0].buflen = 4;
itemlist[0].code = DVI$_DEVTYPE;
itemlist[0].buffer = &type;
itemlist[0].return_addr = &tt_name_desc.dsc$w_length;
itemlist[1].buflen = 4;
itemlist[1].code = DVI$_DEVCLASS;
itemlist[1].buffer = &class;
itemlist[1].return_addr = &tt_name_desc.dsc$w_length;
itemlist[2].buflen = 4;
itemlist[2].code = DVI$_DEVDEPEND;
itemlist[2].buffer = &devdepend;
itemlist[2].return_addr = &tt_name_desc.dsc$w_length;
itemlist[3].buflen = 4;
itemlist[3].code = DVI$_DEVDEPEND2;
itemlist[3].buffer = &tt_chars.extended;
itemlist[3].return_addr = &tt_name_desc.dsc$w_length;
itemlist[4].buflen = 0;
itemlist[4].code = 0;
status = sys$getdviw(0,0,&device,&itemlist,&iosb,0,0,0);
if(!(status & SS$_NORMAL)) lib$signal(status);
if(!(iosb.status & SS$_NORMAL)) lib$signal(iosb.status);
tt_chars.type = DT$_VT102;
tt_chars.class = class;
tt_chars.page_width = screen->max_col+1;
tt_chars.length = screen->max_row+1;
bcopy(&devdepend, &tt_chars.characteristics, 3);
tt_chars.extended |= TT2$M_ANSICRT | TT2$M_AVO | TT2$M_DECCRT;
status = ptd$create(&tt_chan,0,&tt_chars,12,0,0,0,&ret_addr);
if(!(status & SS$_NORMAL)) lib$signal(status);
itemlist[0].buflen = 64;
itemlist[0].code = DVI$_DEVNAM;
itemlist[0].buffer = &tt_name;
itemlist[0].return_addr = &tt_name_desc.dsc$w_length;
itemlist[1].buflen = 0;
itemlist[1].code = 0;
status = sys$getdviw(0,tt_chan,0,&itemlist,&iosb,0,0,0);
if(!(status & SS$_NORMAL)) CloseDown(status);
if(!(iosb.status & SS$_NORMAL)) CloseDown(iosb.status);
status = ptd$set_event_notification(tt_chan,&send_xon,0,0,PTD$C_SEND_XON);
if(!(status & SS$_NORMAL)) CloseDown(status);
status = ptd$set_event_notification(tt_chan,&send_xoff,0,0,PTD$C_SEND_XOFF);
if(!(status & SS$_NORMAL)) CloseDown(status);
status = ptd$set_event_notification(tt_chan,&send_bell,0,0,PTD$C_SEND_BELL);
if(!(status & SS$_NORMAL)) CloseDown(status);
status = ptd$set_event_notification(tt_chan,&char_change,0,0,PTD$C_CHAR_CHANGED);
if(!(status & SS$_NORMAL)) CloseDown(status);
status = sys$crembx(0,&mbx_chan,ACC$K_TERMLEN,0,255,0,0);
if(!(status & SS$_NORMAL)) CloseDown(status);
itemlist[0].buflen = 4;
itemlist[0].code = DVI$_UNIT;
itemlist[0].buffer = &mbxunit;
itemlist[0].return_addr = 0;
itemlist[1].buflen = 0;
itemlist[1].code = 0;
status = sys$getdviw(0,mbx_chan,0,&itemlist,&iosb,0,0,0);
if(!(status & SS$_NORMAL)) CloseDown(status);
if(!(iosb.status & SS$_NORMAL)) CloseDown(iosb.status);
tt_start_read();
itemlist[0].buflen = 4;
itemlist[0].code = JPI$_UIC;
itemlist[0].buffer = &uic;
itemlist[0].return_addr = 0;
itemlist[1].buflen = 0;
itemlist[1].code = 0;
status = sys$getjpiw(0,0,0,&itemlist,0,0,0);
if(!(status & SS$_NORMAL)) CloseDown(status);
trnlnm("DECW$DISPLAY",0,ws_name);
ws_name_desc.dsc$w_length = strlen(ws_name);
flags = PRC$M_INTER | PRC$M_NOPASSWORD | PRC$M_DETACH;
status = sys$creprc(&pid,&image,&tt_name_desc,&tt_name_desc,
&ws_name_desc,0,0,0,4,uic,mbxunit,flags);
if(!(status & SS$_NORMAL)) CloseDown(status);
mbx_read();
status = sys$bintim(&dtime,&delta);
if (!(status & SS$_NORMAL)) CloseDown(status);
status = sys$schdwk(0,0,&delta,&delta);
if (!(status & SS$_NORMAL)) CloseDown(status);
pty = 1;
screen->respond = pty;
pty_mask = 1 << pty;
Select_mask = pty_mask;
X_mask = 1 << Xsocket;
}
static void tt_echo_ast(TT_BUF_STRUCT *buff_addr)
{
int status;
if (buff_addr->length != 0)
{
status = LIB$INSQTI(buff_addr, &read_queue);
if((status != SS$_NORMAL) && (status != LIB$_ONEENTQUE))
{
CloseDown(status);
}
}
else
{
freeBuff(buff_addr);
}
}
int tt_write(char *tt_write_buf, int size)
{
int status;
TT_BUF_STRUCT *echoBuff;
if(write_stopped) return (0);
memmove(&tt_w_buff->data,tt_write_buf,size);
echoBuff = getBuff();
if (echoBuff != LIB$_QUEWASEMP)
{
status = PTD$WRITE (tt_chan, &tt_echo_ast, echoBuff,
&tt_w_buff->status, size,
&echoBuff->status, VMS_TERM_BUFFER_SIZE);
}
else
{
status = PTD$WRITE (tt_chan, 0, 0, &tt_w_buff->status, size, 0, 0);
}
if (status & SS$_NORMAL)
{
if ((tt_w_buff->status != SS$_NORMAL) &&
(tt_w_buff->status != SS$_DATAOVERUN) &&
(tt_w_buff->status != SS$_DATALOST))
{
CloseDown(tt_w_buff->status);
}
}
else
{
CloseDown(status);
}
return(size);
}
static void tt_read_ast(TT_BUF_STRUCT *buff_addr)
{
int status;
if (buff_addr->status & SS$_NORMAL)
{
status = LIB$INSQTI(buff_addr, &read_queue);
if ((status != SS$_NORMAL) && (status != LIB$_ONEENTQUE))
{
CloseDown(status);
}
}
else
CloseDown(buff_addr->status);
tt_start_read();
sys$wake(0,0);
return;
}
void tt_start_read(void)
{
int status;
static int size;
TT_BUF_STRUCT *buff_addr;
buff_addr = getBuff();
if (buff_addr != LIB$_QUEWASEMP)
{
if(!tt_pasting){
status = PTD$READ (0, tt_chan, &tt_read_ast, buff_addr,
&buff_addr->status, VMS_TERM_BUFFER_SIZE);
if ((status & SS$_NORMAL) != SS$_NORMAL)
{
CloseDown(status);
}
}
}
else
{
read_stopped = TRUE;
}
return;
}
int tt_read(char *buffer)
{
TT_BUF_STRUCT *read_buff;
int status;
int len;
status = LIB$REMQHI(&read_queue, &read_buff);
if(status == LIB$_QUEWASEMP){
return(0);
}
else if (status & SS$_NORMAL)
{
len = read_buff->length;
memmove(buffer,&read_buff->data,len);
freeBuff(read_buff);
tt_new_output=TRUE;
}
else
CloseDown(status);
return(len);
}
static void send_xon(void)
{
write_stopped = FALSE;
}
static void send_xoff(void)
{
write_stopped = TRUE;
}
static void send_bell(void)
{
Bell();
}
static void char_change(void)
{
int status;
if(!(term->screen.TekEmu))
{
status = sys$qiow(0,tt_chan,IO$_SENSEMODE,0,0,0,&tt_mode,8,0,0,0,0);
if(!(status & SS$_NORMAL)) CloseDown(status);
if((term->screen.max_row != tt_mode.length) ||
(term->screen.max_col != tt_mode.page_width))
{
tt_length = tt_mode.length;
tt_width = tt_mode.page_width;
tt_changed = TRUE;
}
}
}
static void freeBuff (TT_BUF_STRUCT *buff_addr)
{
int ast_stat;
int status;
ast_stat = SYS$SETAST(0);
if (!read_stopped)
{
LIB$INSQHI(buff_addr, &buffer_queue);
}
else
{
status = PTD$READ (0, tt_chan, &tt_read_ast, buff_addr,
&buff_addr->status, VMS_TERM_BUFFER_SIZE);
if (status & SS$_NORMAL)
{
read_stopped = FALSE;
}
else
{
CloseDown(status);
}
}
if (ast_stat == SS$_WASSET) ast_stat = SYS$SETAST(1);
}
TT_BUF_STRUCT *getBuff(void)
{
int status;
TT_BUF_STRUCT *buff_addr;
status = LIB$REMQHI(&buffer_queue, &buff_addr);
if (status & SS$_NORMAL)
{
return(buff_addr);
}
else
{
return(status);
}
}
static void CloseDown(int exit_status)
{
int status;
if(pid != 0)
{
status = sys$forcex(&pid,0,0);
if(!(status & SS$_NORMAL)) lib$signal(status);
}
if(mbx_chan != 0)
{
sys$dassgn(mbx_chan);
}
status = ptd$cancel(tt_chan);
if(!(status & SS$_NORMAL)) lib$signal(status);
status = ptd$delete(tt_chan);
if(!(status & SS$_NORMAL)) lib$signal(status);
if(!(exit_status & SS$_NORMAL)) lib$signal(exit_status);
exit(1);
}
static void mbx_read_ast(void)
{
int status;
pid = 0;
status = mbx_read_iosb.status;
if (!(status & SS$_NORMAL)) CloseDown(status);
status = (unsigned long int) mbx_buf.acc$l_finalsts;
if (!(status & SS$_NORMAL)) CloseDown(status);
CloseDown(1);
}
static void mbx_read(void)
{
int status;
static int size;
size = ACC$K_TERMLEN;
status = sys$qio(0,mbx_chan,
IO$_READVBLK,
&mbx_read_iosb,
&mbx_read_ast,
0,
&mbx_buf,
size,0,0,0,0);
if (!(status & SS$_NORMAL)) CloseDown(status);
return;
}