[Search for users] [Overall Top Noters] [List of all Conferences] [Download this site]

Conference hydra::amiga_v1

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 14: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%RITVAX.BITNET@CORNELLC.ccs.cornell.edu" "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.RTitleUserPersonal
Name
DateLines