[Search for users]
[Overall Top Noters]
[List of all Conferences]
[Download this site]
Title: | AMIGA NOTES |
Notice: | Join us in the *NEW* conference - HYDRA::AMIGA_V2 |
Moderator: | HYDRA::MOORE |
|
Created: | Sat Apr 26 1986 |
Last Modified: | Wed Feb 05 1992 |
Last Successful Update: | Fri Jun 06 1997 |
Number of topics: | 5378 |
Total number of notes: | 38326 |
2401.0. "UW update from Mike Leibow for Meshuguna terminal emulator" by PRNSYS::LOMICKAJ (Jeff Lomicka) Mon Mar 27 1989 11:57
This update came flying into my mailbox, and Mike asked me to post it here.
It requires VMS V5.1 - because it uses the TW/PY drivers:
Date: 21-MAR-1989 17:46:01.66
From: DECWRL::"MSL5864%[email protected]" "Mike Leibow (MOOF) 21-Mar-89 1102 EDT"
Subj: Forgot to send the code
To: lomickaj@prnsys
/* uw.c Session multiplexer for Unix windows protocol
19-April-1988 J.A.Lomicka & M.S.Leibow
20-March-1989 M.S.Leibow -- Made some bug fixes
*/
#include ssdef
#include descrip
#include dvidef
#include climsgdef
#include iodef
#include ttdef
#include tt2def
#include stdio
#define CB_DIR_HTOM 0000
#define CB_DIR_MTOH 0100
#define CB_DIR 0100
#define CB_FN_NEWW 0000
#define CB_FN_KILLW 0010
#define CB_FN_ISELW 0020
#define CB_FN_OSELW 0030
#define CB_FN_META 0050
#define CB_FN_CTLCH 0060
#define CB_FN_MAINT 0070
#define CB_FN 0070
#define START_SESSIONS 0000
#define END_SESSIONS 0007
/*
test macro is used to signal errors from system services
*/
#define test( s) {int st; st = (s); if( (st&1)!=1) LIB$SIGNAL( st);}
/*
This routine returns a pointer to a descriptor of the supplied
string. The descriptors are static allocated, and up to "Md1" may be
used at once. After that, the old ones are re-used. Be careful!
The primary use of this routine is to allow passing of C strings into
VMS system facilities and RTL functions.
*/
struct dsc$descriptor_s *descptr( s, l)
char *s;
int l; /* l is optional, and if not provided, strlen( s) is used instead */
{
int *argc;
#define Md1 5
static next_d = 0;
static struct dsc$descriptor_s dsclist[ Md1];
argc = &s;
if( next_d >= Md1) next_d = 0;
if( argc[ -1] == 1) dsclist[ next_d].dsc$w_length = strlen(s);
else dsclist[ next_d].dsc$w_length = l;
dsclist[ next_d].dsc$b_dtype = DSC$K_DTYPE_T;
dsclist[ next_d].dsc$b_class = DSC$K_CLASS_S;
dsclist[ next_d].dsc$a_pointer = s;
return( &dsclist[ next_d++]);
}
/*
These two structures, along with ttdef.h, are good for manipulating
terminal characteristics.
*/
typedef struct
{/* Terminal characteristics buffer */
unsigned char class, type;
unsigned short width;
unsigned tt1 : 24;
unsigned char page;
unsigned long tt2;
} TTCHAR;
typedef struct
{ /* More terminal characteristics (hidden in the status block) */
short status;
char txspeed;
char rxspeed;
long trash;
} TTCHARIOSB;
/*
The following group of routines are for reading the terminal
*/
typedef struct
{ /* Terminal file structure */
int chan; /* VMS I/O channel */
TTCHAR old_char; /* Original characteristics of terminal to return */
TTCHARIOSB old_iosb;/* when the terminal is closed */
int pos, len; /* Length and current position in inbuf */
int outpos; /* Position in output buffer */
int (*readaction)();/* Action to call when data is available */
char *param; /* Parameter to readaction */
long evn; /* Event flag number for outstanding read */
int out; /* True if read is outstanding */
struct { unsigned short status, len, term, tlen;} iosb;
unsigned char inbuf[ 512]; /* Place to keep incoming chars until needed */
unsigned char outbuf[ 512]; /* Place to keep outgoing chars until sent */
} TFILE;
int iosizelimit = 512;
static readonly int noterm[] = {0,0}; /* Terminator list of NONE */
/*
Event queue
*/
#define EQSIZE 128
int (*eqr[ EQSIZE])();
char *eqp[ EQSIZE];
int eqs=0, eqin=0, eqout=0;
int eqef;
static Treadast( tf)
TFILE *tf;
{ /* Read has completed, The read event processor is queued */
tf->pos = 0;
tf->len = tf->iosb.len;
tf->out = 0;
if( eqs < EQSIZE)
{
eqr[ eqin] = tf->readaction;
eqp[ eqin] = tf->param;
eqin = (eqin + 1)&(EQSIZE-1);
eqs++;
test( SYS$SETEF( eqef));
}
else printf( "Event queue overflow!\n");
}
TFILE *Topen( fname, sync, readaction, param) /* Open a terminal device */
char *fname; /* Device to assign channel to */
int sync; /* TRUE to force sync, false to trust VMS */
int (*readaction)();/* Action to call when data is available */
char *param; /* Parameter to readaction */
{
TTCHAR new_char; /* New terminal characteristics */
TFILE *tf; /* Terminal file to return */
tf = calloc( 1, sizeof( *tf));
test( SYS$ASSIGN( descptr( fname), &tf->chan, 0, 0));
test( SYS$QIOW( 0, tf->chan, IO$_SENSEMODE, 0, 0, 0, &tf->old_char,
12, 0, 0, 0, 0));
new_char = tf->old_char;
if( sync)
{
new_char.tt1 |= TT$M_HOSTSYNC; /* Make sure VMS does this */
new_char.tt1 |= TT$M_TTSYNC; /* Make sure VMS does this too */
}
new_char.tt2 |= TT2$M_PASTHRU; /* pass everything */
new_char.tt1 |= TT$M_EIGHTBIT; /* Get all bits */
new_char.tt1 |= TT$M_NOBRDCST; /* don't get broadcast mess */
test( SYS$QIOW( 0, tf->chan, IO$_SETMODE, 0, 0, 0, &new_char,
12, 0, 0, 0, 0));
/*
Post the first read for one character
*/
tf->readaction = readaction;
tf->param = param;
test( LIB$GET_EF( &tf->evn));
test( SYS$CLREF( tf->evn));
tf->out = 1;
test( SYS$QIO( tf->evn, tf->chan,
IO$_READVBLK | IO$M_NOECHO | IO$M_TRMNOECHO | IO$M_NOFILTR,
&tf->iosb, Treadast, tf,
tf->inbuf, 1, 0, noterm, 0, 0));
return( tf);
}
Tflush( tf) /* Flush pending output to tf */
TFILE *tf;
{
if( tf->outpos > 0)
{
test( SYS$QIOW( 0, tf->chan, IO$_WRITEVBLK | IO$M_NOFORMAT,
0, 0, 0,
tf->outbuf, tf->outpos, 0, 0, 0, 0));
tf->outpos = 0;
}
}
Tputc( tf, c) /* Put a character to a terminal */
int c; /* Character to put */
TFILE *tf; /* Place to put it */
{
tf->outbuf[ tf->outpos++] = c;
if( tf->outpos >= iosizelimit) Tflush( tf);
}
Tputs( tf, s) /* Put a string to a terminal */
TFILE *tf; /* Place to put it */
unsigned char *s;
{
for(; *s != 0; s++)
{
Tputc( tf, *s);
}
}
Tclose( tf) /* Close a terminal device */
TFILE *tf; /* Context to close */
{
Tputs( tf, "\r\n");
Tflush( tf);
test( SYS$QIOW( 0, tf->chan, IO$_SETMODE, 0, 0, 0, &tf->old_char,
12, 0, 0, 0, 0));
test( SYS$DASSGN( tf->chan));
free( tf);
}
int Tgetc( tf) /* Read a character */
TFILE *tf; /* Terminal to read from */
{
while( tf->pos >= tf->len)
{ /* No data available, post request to VMS and wait for it to return */
Tpeekc( tf, 1); /* Post the read */
test( SYS$WAITFR( tf->evn));
}
return( tf->inbuf[ tf->pos++]);
}
int Tpeekc( tf, n) /* Peek at next character */
TFILE *tf; /* Terminal to read from */
int n; /* Smallest read to respond to */
/*
This routine returns the top thing in the input buffer. If the
input buffer is empty, it returns -1, but also submits a new
request to VMS to read whatever's there.
*/
{
if( tf->pos >= tf->len)
{ /* Input buffer is empty, go ask VMS */
struct /* Typeahdad buffer description */
{
short count; /* Count of typeahead buffer */
unsigned char first; /* Value of first character, if any */
char notused1;
long notused2;
} tabuf;
if( tf->out)
{ /* Already have a read outstanding, don't submit another one */
return( -1);
}
test( SYS$QIOW( 0, tf->chan,
IO$_SENSEMODE | IO$M_TYPEAHDCNT,
0, 0, 0,
&tabuf, sizeof( tabuf), 0, 0, 0, 0));
if( tabuf.count == 0) tabuf.count = n; /* Minimum read */
if( tabuf.count > 512) tabuf.count = 512;
test( SYS$CLREF( tf->evn));
tf->out = 1;
test( SYS$QIO( tf->evn, tf->chan,
IO$_READVBLK | IO$M_NOECHO | IO$M_TRMNOECHO | IO$M_NOFILTR,
&tf->iosb, Treadast, tf,
tf->inbuf, tabuf.count, 0, noterm, 0, 0));
return( -1);
}
else return( tf->inbuf[ tf->pos]);
}
/*
uw session multiplexer code
*/
#define SESSION_COUNT 7
#define READBUFSIZE 1024
char ctlch[8] = { '\000', '\001', '\023', '/021', '\000' };
typedef struct /* Session control block */
{
int chan; /* Channel to PY driver path to session */
short iosb[ 4]; /* IOSB of pending read */
int id; /* Session number within port */
struct uwport *port; /* Controlling port */
unsigned char readbuf[ READBUFSIZE]; /* Input buffer for pending PY read */
} SESSION;
typedef struct uwport
{
TFILE *tf; /* Terminal "file" */
int inses; /* Keyboard's session number */
int outses; /* Display's session number */
SESSION pt[ SESSION_COUNT]; /* Session state */
} UWPORT;
static Preadast( pt)
SESSION *pt;
{ /* Read has completed, The read event processor is queued */
extern pyhasdata();
if (pt->id == -1) return;
if( eqs < EQSIZE)
{
eqr[ eqin] = pyhasdata;
eqp[ eqin] = pt;
eqin = (eqin + 1)&(EQSIZE-1);
eqs++;
test( SYS$SETEF( eqef));
}
else printf( "Event queue overflow!\n");
}
pyhasdata( pt) /* Data has arrived from a session. Send it to the correct port
*
/
SESSION *pt;
{
int i;
TFILE *tf;
UWPORT *pf;
if (pt->id == -1) return;
tf = pt->port->tf;
pf = pt->port;
if( pt->port->outses != pt->id)
{ /* Wrong session, perform switch session */
Tputc( pf->tf, 1);
Tputc( pf->tf, CB_DIR_HTOM | CB_FN_OSELW | (pt->id+1));
pt->port->outses = pt->id;
}
for( i=0; i<pt->iosb[ 1]; i++)
{ /* Transmit each character, quoting the ^A's. */
if( pt->readbuf[ i] == '\001' || pt->readbuf[i] == '\023' ||
pt->readbuf[i] == '\021')
{ /* Special characters have to be quoted */
Tputc( pf->tf, 1);
switch (pt->readbuf[i] )
{
case '\001' :
Tputc( pf->tf, CB_DIR_HTOM | CB_FN_CTLCH | 1);
break;
case '\023' :
Tputc( pf->tf, CB_DIR_HTOM | CB_FN_CTLCH | 2);
break;
case '\021' :
Tputc( pf->tf, CB_DIR_HTOM | CB_FN_CTLCH | 3);
break;
default:
Tputc( pf->tf, CB_DIR_HTOM | CB_FN_CTLCH);
break;
}
}
else
{ /* This is normal data, just send it */
Tputc( tf, pt->readbuf[ i]);
}
}
/*
Resubmit the read request to the session
*/
Tflush( tf);
test( SYS$QIO( 0, pt->chan, IO$_READVBLK, pt->iosb,
Preadast, pt, pt->readbuf, READBUFSIZE,
0, 0, 0, 0));
}
pixdata( pf) /* Process data from the uw */
UWPORT *pf;
{
char ch;
short ttiosb[ 4];
int chcount;
TFILE *tf;
tf = pf->tf;
chcount = 0;
while( Tpeekc( tf, 1) >= 0)
{ /* As long as characters are available */
if( ++chcount > 20)
{ /* We've been a pig about clogging the event queue. Process it */
chcount = 0;
events();
continue;
}
ch = Tgetc( tf, 1); /* Get what's available */
if( ch == 'A'-64)
{ /* ^A prefix, is a session command */
ch = Tgetc( tf, 1);
if ((ch & CB_DIR) == CB_DIR_HTOM) continue;
/*
Dispatch on function code
*/
switch( ch & CB_FN )
{
case CB_FN_ISELW: /* Switch input */
if ((ch&7) == 0) continue;
pf->inses = (ch&7) - 1;
continue;
case CB_FN_MAINT: /* Mainten. commands */
switch(ch&7)
{
case END_SESSIONS:
Tputs( tf, "\r\nExiting.\r\n");
Tclose( tf);
exit( 1);
}
continue;
case CB_FN_NEWW:
if ((ch&7) == 0) continue;
newsession( pf, (ch&7) - 1);
continue;
case CB_FN_KILLW:
if ((ch&7) == 0) continue;
killsession( pf, (ch&7) - 1);
continue;
case CB_FN_CTLCH:
ch = ctlch[ch&7];
break;
default:
continue;
}
}
if (pf->pt[pf->inses].id == -1) continue;
test( SYS$QIOW( 0, pf->pt[ pf->inses].chan, IO$_WRITEVBLK, ttiosb,
0, 0, &ch, 1, 0, 0, 0, 0));
}
}
newsession( pf, i)
UWPORT *pf; /* Port to do session in */
int i; /* Session number */
{
if (pf->pt[i].id != -1) return;
pf->pt[ i].id = i;
pf->pt[ i].port = pf;
test( SYS$ASSIGN( descptr( "PYA0:"), &pf->pt[ i].chan, 0, 0));
test( SYS$QIO( 0, pf->pt[ i].chan, IO$_READVBLK, pf->pt[ i].iosb,
Preadast, &pf->pt[ i], pf->pt[ i].readbuf, READBUFSIZE,
0, 0, 0, 0));
}
killsession( pf, i)
UWPORT *pf; /* Port to do session in */
int i; /* Session number */
{
if (pf->pt[i].id == -1) return;
if (pf->outses == pf->pt[i].id) pf->outses = -1;
pf->pt[ i].id = -1;
test( SYS$CANCEL( pf->pt[ i].chan));
test( SYS$DASSGN( pf->pt[ i].chan));
}
UWPORT *newport( devicename) /* Start another uw channel */
char *devicename; /* TT device with uw attached */
{
UWPORT *ret;
int i;
ret= calloc( 1, sizeof( *ret));
for (i=0; i != SESSION_COUNT; i++) ret->pt[i].id = -1;
ret->outses = -1; /* Force an output session selection */
/*
Start reading the keyboard.
*/
ret->tf = Topen( devicename, 1, pixdata, ret);
newsession( ret, 0);/* Open channel to the first session */
Tputc( ret->tf, 1); Tputc( ret->tf, CB_DIR_HTOM | CB_FN_MAINT |
START_SESSIONS);
Tputc( ret->tf, 1); Tputc( ret->tf, CB_DIR_HTOM | CB_FN_NEWW | 1);
return( ret);
}
main( argc, argv)
int argc;
char *argv[];
{
int i;
/*
Open each port
*/
if( argc > 1) for( i=1; i<argc; i++) newport( argv[ i]);
else
{ /* No argument list, take port list from portlist file */
FILE *pl; /* Port list file */
pl = fopen( "uw$ports", "r");
if( pl != NULL)
{ /* if input file exists, read in the list of ports */
for(;;)
{ /* For each line of input file */
char s[ 256];
if( fgets( s, 255, pl) == NULL)
{ /* End of file, close and stop here */
fclose( pl);
break;
}
s[ strlen( s)-1] = 0; /* Eat the linefeed */
newport( s);
}
}
else newport( "SYS$INPUT"); /* No argv or input file, use terminal *
/
}
/*
Process the event queue
*/
for(;;)
{ /* Process the event queue */
test( SYS$CLREF( eqef));
events();
test( SYS$WAITFR( eqef));
}
}
events()
{
int (*r)();
char *p;
while( eqs > 0)
{ /* Process each event in the queue */
r = eqr[ eqout];
p = eqp[ eqout];
eqout = (eqout + 1)&(EQSIZE-1);
eqs--;
(*r)( p);
}
}
========================================================================
T.R | Title | User | Personal Name | Date | Lines
|
---|