[comp.sources.sun] v02i011: 3270tool, Part01/03

mcgrew@dartagnan.rutgers.edu (Charles Mcgrew) (05/30/90)

Submitted-by: robert%shangri-la@gatech.edu (Robert Viduya)
Posting-number: Volume 2, Issue 11
Archive-name: 3270tool/part01


This is something I wrote a couple of years ago, but due to some problems
here at Tech, have only just now gotten permission to release.  As a result,
the code has been in production use here on campus for most of that time
and has proven to be pretty solid.  I won't guarantee that it's entirely
bug free (I'm not *that* stupid) but I'll just say that I've not found any
in quite some time and none of the people who use it have reported any.
There are certainly some areas of improvement but more on that later.

This program is called 3270tool and is meant to replace tn3270 in a
SunView environment.  It's biggest advantage over tn3270 is that it takes
advantage of it's environment by supporting the full IBM 3278 character
set (something an ASCII terminal can't do) and not forcing the user to
remember what key on his keyboard maps to a particular IBM key since all
such keys are available from the mouse as well as the keyboard.

The man page explains how to do things and the README talks a bit
about the program as well as areas of improvements but since I've pretty
much moved into an X environment, I don't think those improvements will
be coming from me.  The X version of the program is almost done and offers
a few significant improvements already like a user-definable keyboard
mapping (those .Xdefaults files are a *big* improvement over SunView's
.defaults file) as well as a wider range of font sizes and a wider range
of IBM terminal types that are supported.

Anyway, share and enjoy...

			robert

---cut here---
#! /bin/sh
#	Run the following text with /bin/sh to create:
#		File      kybd.c              	(28446 bytes)
#		File      screen.c            	(24454 bytes)
#		File      README              	(2205 bytes)
#		File      BtnClear            	(541 bytes)
if test -f 'kybd.c'
then
	echo "`basename $0`: can't extract" 'kybd.c' "- file exists" 1>&2
else
	sed 's/^X//' << '--End_of_kybd.c--' > 'kybd.c'
X/*
X * Copyright 1989 by Georgia Tech Research Corporation, Atlanta, GA.
X * Copyright 1988, 1989 by Robert Viduya.
X *
X *                         All Rights Reserved
X */
X
X/*
X *	kybd.c
X *		This module handles the keyboard for the 3270 emulator.
X */
X#include <sys/types.h>
X#include <suntool/sunview.h>
X#include <suntool/menu.h>
X#include <suntool/canvas.h>
X#include <suntool/seln.h>
X#include <suntool/panel.h>
X#include <sundev/kbio.h>
X#include <sundev/kbd.h>
X#include <fcntl.h>
X#include <stdio.h>
X#include "3270.h"
X#include "3270_enc.h"
X
X/*
X * The following table is used to translate ascii key codes to 3270
X * character generator symbol.  Note that this is not an ebcdic
X * translation.  See xlate.h for details.
X */
Xu_char	asc2cg[128] = {
X	CG_NULLBLANK,	CG_NULLBLANK,	CG_NULLBLANK,	CG_NULLBLANK,
X	CG_NULLBLANK,	CG_NULLBLANK,	CG_NULLBLANK,	CG_NULLBLANK,
X	CG_NULLBLANK,	CG_NULLBLANK,	CG_NULLBLANK,	CG_NULLBLANK,
X	CG_NULLBLANK,	CG_NULLBLANK,	CG_NULLBLANK,	CG_NULLBLANK,
X	CG_NULLBLANK,	CG_NULLBLANK,	CG_NULLBLANK,	CG_NULLBLANK,
X	CG_NULLBLANK,	CG_NULLBLANK,	CG_NULLBLANK,	CG_NULLBLANK,
X	CG_NULLBLANK,	CG_NULLBLANK,	CG_NULLBLANK,	CG_CENT,
X	CG_SOLIDBAR,	CG_NULLBLANK,	CG_NULLBLANK,	CG_NULLBLANK,
X	CG_BLANK,	CG_EXCLAMATION,	CG_DQUOTE,	CG_NUMBER,
X	CG_DOLLAR,	CG_PERCENT,	CG_AMPERSAND,	CG_SQUOTE,
X	CG_LPAREN,	CG_RPAREN,	CG_ASTERISK,	CG_PLUS,
X	CG_COMMA,	CG_MINUS,	CG_PERIOD,	CG_FSLASH,
X	CG_ZERO,	CG_ONE,		CG_TWO,		CG_THREE,
X	CG_FOUR,	CG_FIVE,	CG_SIX,		CG_SEVEN,
X	CG_EIGHT,	CG_NINE,	CG_COLON,	CG_SEMICOLON,
X	CG_LESS,	CG_EQUAL,	CG_GREATER,	CG_QUESTION,
X	CG_AT,		CG_CA,		CG_CB,		CG_CC,
X	CG_CD,		CG_CE,		CG_CF,		CG_CG,
X	CG_CH,		CG_CI,		CG_CJ,		CG_CK,
X	CG_CL,		CG_CM,		CG_CN,		CG_CO,
X	CG_CP,		CG_CQ,		CG_CR,		CG_CS,
X	CG_CT,		CG_CU,		CG_CV,		CG_CW,
X	CG_CX,		CG_CY,		CG_CZ,		CG_LBRACKET,
X	CG_BSLASH,	CG_RBRACKET,	CG_NOT,		CG_UNDERSCORE,
X	CG_GRAVE,	CG_LA,		CG_LB,		CG_LC,
X	CG_LD,		CG_LE,		CG_LF,		CG_LG,
X	CG_LH,		CG_LI,		CG_LJ,		CG_LK,
X	CG_LL,		CG_LM,		CG_LN,		CG_LO,
X	CG_LP,		CG_LQ,		CG_LR,		CG_LS,
X	CG_LT,		CG_LU,		CG_LV,		CG_LW,
X	CG_LX,		CG_LY,		CG_LZ,		CG_LBRACE,
X	CG_BROKENBAR,	CG_RBRACE,	CG_TILDE,	CG_NULLBLANK
X};
X
Xu_char	cg2asc[256] = {
X	' ',	' ',	' ',	' ',	' ',	' ',	' ',	' ',
X	'>',	'<',	'[',	']',	')',	'(',	'}',	'{',
X	' ',	'=',	'\'',	'"',	'/',	'\\',	'|',	'|',
X	'?',	'!',	'$',	'c',	'L',	'Y',	'P',	'o',
X	'0',	'1',	'2',	'3',	'4',	'5',	'6',	'7',
X	'8',	'9',	'B',	'S',	'#',	'@',	'%',	'_',
X	'&',	'-',	'.',	',',	':',	'+',	'^',	'~',
X	'*',	'^',	'^',	'~',	'~',	'`',	'\'',	',',
X	'a',	'e',	'i',	'o',	'u',	'a',	'o',	'y',
X	'a',	'e',	'e',	'i',	'o',	'u',	'u',	'c',
X	'a',	'e',	'i',	'o',	'u',	'a',	'e',	'i',
X	'o',	'u',	'a',	'e',	'i',	'o',	'u',	'n',
X	'A',	'E',	'I',	'O',	'U',	'A',	'O',	'Y',
X	'A',	'E',	'E',	'I',	'O',	'U',	'Y',	'C',
X	'A',	'E',	'I',	'O',	'U',	'A',	'E',	'I',
X	'O',	'U',	'A',	'E',	'I',	'O',	'U',	'N',
X	'a',	'b',	'c',	'd',	'e',	'f',	'g',	'h',
X	'i',	'j',	'k',	'l',	'm',	'n',	'o',	'p',
X	'q',	'r',	's',	't',	'u',	'v',	'w',	'x',
X	'y',	'z',	'a',	'0',	'a',	'c',	';',	'*',
X	'A',	'B',	'C',	'D',	'E',	'F',	'G',	'H',
X	'I',	'J',	'K',	'L',	'M',	'N',	'O',	'P',
X	'Q',	'R',	'S',	'T',	'U',	'V',	'W',	'X',
X	'Y',	'Z',	'A',	'0',	'A',	'C',	';',	'*',
X	' ',	' ',	' ',	' ',	' ',	' ',	' ',	' ',
X	' ',	' ',	' ',	' ',	' ',	' ',	' ',	' ',
X	' ',	' ',	' ',	' ',	' ',	' ',	' ',	' ',
X	' ',	' ',	' ',	' ',	' ',	' ',	' ',	' ',
X	' ',	' ',	' ',	' ',	' ',	' ',	' ',	' ',
X	' ',	' ',	' ',	' ',	' ',	' ',	' ',	' ',
X	' ',	' ',	' ',	' ',	' ',	' ',	' ',	' ',
X	' ',	' ',	' ',	' ',	' ',	' ',	' ',	' ',
X};
X
Xbool		kybdlock = FALSE,	/* kybd locked */
X		insert = FALSE;		/* insert mode */
Xu_char		aid = AID_NO;		/* current attention ID */
XMenu		Key_menu;
X
Xextern u_char		screen_buf[ROWS * COLS];
Xextern int		cursor_addr, buffer_addr;
Xextern Pixwin		*pixwin;
Xextern Canvas		canvas;
Xextern Pixfont		*ibmfont;
Xextern Frame		frame;
Xextern int		net_sock;
Xextern bool		formatted, cursor_alt, cursor_blink, mono_case;
Xextern Seln_client	s_client;
Xextern int		char_width, char_height, char_base;
X
Xextern int	key_panel_toggle ();
Xextern u_char	*get_field_attribute ();
Xextern int	stuff_seln ();
X
X
X/*
X * Toggle insert mode.
X */
Xinsert_mode (on)
Xbool	on;
X{
X    if (on) {
X	insert = TRUE;
X	status_disp (51, CG_INSERT);
X    }
X    else {
X	insert = FALSE;
X	status_disp (51, CG_BLANK);
X    }
X}
X
X
X/*
X * Update shift mode indicator.  Not used currently, until I can figure out
X * how to reliably read the state of the CAPS lock key.
X */
Xupdate_shift ()
X{
X    int		on, v;
X
X    v = (int) window_get (canvas, WIN_EVENT_STATE, SHIFT_LEFT);
X    printf ("SHIFT_LEFT=%d ", v);
X    on = v;
X
X    v = (int) window_get (canvas, WIN_EVENT_STATE, SHIFT_RIGHT);
X    printf ("SHIFT_RIGHT=%d ", v);
X    on |= v;
X
X    v = (int) window_get (canvas, WIN_EVENT_STATE, SHIFT_LOCK);
X    printf ("SHIFT_LOCK=%d ", v);
X    on |= v;
X
X    v = (int) window_get (canvas, WIN_EVENT_STATE, SHIFT_CAPSLOCK);
X    printf ("SHIFT_CAPSLOCK=%d\n", v);
X    on |= v;
X
X    status_disp (41, on ? CG_UPSHIFT : CG_BLANK);
X}
X
X
X/*
X * Handle an AID (Attention IDentifier) key.  This is the common stuff that
X * gets executed for all AID keys (PFs, PAs, Clear and etc).
X */
Xkey_AID (aid_code)
Xint	aid_code;
X{
X    status_disp (1, CG_BLANK);
X    status_disp (8, CG_LOCK);
X    status_disp (9, CG_BLANK);
X    status_disp (10, CG_CLOCKLEFT);
X    status_disp (11, CG_CLOCKRIGHT);
X    insert_mode (FALSE);
X    kybdlock = TRUE;
X    aid = aid_code;
X    do_read_modified ();
X    status_disp (1, CG_UNDERA);
X}
X
X
X/*
X * Handle an ordinary displayable character key.  Lots of stuff to handle
X * insert-mode, protected fields and etc.
X */
Xbool
Xkey_Character (cgcode)
Xint	cgcode;
X{
X    register int	baddr, end_baddr, t_baddr;
X    register u_char	*fa;
X
X    if (kybdlock)
X	return (FALSE);
X    baddr = cursor_addr;
X    fa = get_field_attribute (baddr);
X    if (IS_FA (screen_buf[baddr]) || FA_IS_PROTECTED (*fa)) {
X	status_disp (8, CG_LOCK);
X	status_disp (9, CG_BLANK);
X	status_disp (10, CG_LEFTARROW);
X	status_disp (11, CG_HUMAN);
X	status_disp (12, CG_RIGHTARROW);
X	kybdlock = TRUE;
X	return (FALSE);
X    }
X    else {
X	if (FA_IS_NUMERIC (*fa)
X	&&  !((cgcode >= CG_ZERO && cgcode <= CG_NINE) || cgcode == CG_MINUS || cgcode == CG_PERIOD)) {
X	    status_disp (8, CG_LOCK);
X	    status_disp (9, CG_BLANK);
X	    status_disp (10, CG_HUMAN);
X	    status_disp (11, CG_CN);
X	    status_disp (12, CG_CU);
X	    status_disp (13, CG_CM);
X	    kybdlock = TRUE;
X	    return (FALSE);
X	}
X	else {
X	    if (insert && screen_buf[baddr]) {
X		/* find next null or next fa */
X		end_baddr = baddr;
X		do {
X		    INC_BA (end_baddr);
X		    if (screen_buf[end_baddr] == CG_NULLBLANK
X		    ||  IS_FA (screen_buf[end_baddr]))
X			break;
X		} while (end_baddr != baddr);
X		if (screen_buf[end_baddr] != CG_NULLBLANK) {
X		    status_disp (8, CG_LOCK);
X		    status_disp (9, CG_BLANK);
X		    status_disp (10, CG_HUMAN);
X		    status_disp (11, CG_GREATER);
X		    kybdlock = TRUE;
X		    return (FALSE);
X		}
X		else {
X		    if (end_baddr > baddr)
X			bcopy ((char *) &screen_buf[baddr], (char *) &screen_buf[baddr+1], end_baddr - baddr);
X		    else {
X			bcopy ((char *) &screen_buf[0], (char *) &screen_buf[1], end_baddr);
X			screen_buf[0] = screen_buf[(ROWS * COLS) - 1];
X			bcopy ((char *) &screen_buf[baddr], (char *) &screen_buf[baddr+1], ((ROWS * COLS) - 1) - baddr);
X		    }
X		    screen_buf[baddr] = cgcode;
X		    cursor_off ();
X		    t_baddr = baddr;
X		    while (t_baddr != end_baddr) {
X			screen_update (t_baddr, *fa);
X			INC_BA (t_baddr);
X		    }
X		    screen_update (t_baddr, *fa);
X		}
X	    }
X	    else {
X		screen_buf[baddr] = cgcode;
X		cursor_off ();
X		screen_update (baddr, *fa);
X	    }
X	    INC_BA (baddr);
X	    if (IS_FA (screen_buf[baddr])) {
X		if (FA_IS_NUMERIC (screen_buf[baddr])) {
X		    if (FA_IS_PROTECTED (screen_buf[baddr])) {
X			/* skip to next unprotected */
X			while (TRUE) {
X			    INC_BA (baddr);
X			    if (IS_FA (screen_buf[baddr])
X			    &&  !FA_IS_PROTECTED (screen_buf[baddr]))
X				break;
X			}
X			INC_BA (baddr);
X		    }
X		    else
X			INC_BA (baddr);
X		}
X		else
X		    INC_BA (baddr);
X	    }
X	    cursor_move (baddr);
X	    cursor_on ();
X	    *fa |= FA_MODIFY;
X	}
X    }
X    return (TRUE);
X}
X
X
X/*
X * Toggle underline/block cursor.
X */
Xkey_AltCr ()
X{
X    alt_cursor ((bool) (!cursor_alt));
X}
X
X
X/*
X * Toggle blink/no-blink cursor.
X */
Xkey_CursorBlink ()
X{
X    blink_cursor ((bool) (!cursor_blink));
X}
X
X
X/*
X * Toggle mono-/dual-case operation.
X */
Xkey_MonoCase ()
X{
X    change_case ((bool) (!mono_case));
X}
X
X
X/*
X * Tab forward to next field.
X */
Xkey_FTab ()
X{
X    register int	baddr, nbaddr;
X
X    if (kybdlock)
X	return;
X    nbaddr = cursor_addr;
X    INC_BA (nbaddr);
X    while (TRUE) {
X	baddr = nbaddr;
X	INC_BA (nbaddr);
X	if (IS_FA (screen_buf[baddr])
X	&&  !FA_IS_PROTECTED (screen_buf[baddr])
X	&&  !IS_FA (screen_buf[nbaddr]))
X	    break;
X	if (baddr == cursor_addr) {
X	    cursor_move (0);
X	    return;
X	}
X    }
X    INC_BA (baddr);
X    cursor_move (baddr);
X}
X
X
X/*
X * Tab backward to previous field.
X */
Xkey_BTab ()
X{
X    register int	baddr, nbaddr;
X    int			sbaddr;
X
X    if (kybdlock)
X	return;
X    baddr = cursor_addr;
X    DEC_BA (baddr);
X    if (IS_FA (screen_buf[baddr]))	/* at bof */
X	DEC_BA (baddr);
X    sbaddr = baddr;
X    while (TRUE) {
X	nbaddr = baddr;
X	INC_BA (nbaddr);
X	if (IS_FA (screen_buf[baddr])
X	&&  !FA_IS_PROTECTED (screen_buf[baddr])
X	&&  !IS_FA (screen_buf[nbaddr]))
X	    break;
X	DEC_BA (baddr);
X	if (baddr == sbaddr) {
X	    cursor_move (0);
X	    return;
X	}
X    }
X    INC_BA (baddr);
X    cursor_move (baddr);
X}
X
X
X/*
X * Reset keyboard lock.
X */
Xkey_Reset ()
X{
X    register int	i;
X
X    kybdlock = FALSE;
X    insert_mode (FALSE);
X    for (i = 0; i < 9; i++)
X	status_disp (i + 8, CG_BLANK);
X}
X
X
X/*
X * Move to first unprotected field on screen.
X */
Xkey_Home ()
X{
X    register int	baddr, nbaddr;
X    register u_char	*fa;
X
X    if (kybdlock)
X	return;
X    fa = get_field_attribute (0);
X    if (!FA_IS_PROTECTED (*fa))
X	cursor_move (0);
X    else {
X	nbaddr = 1;		/* start at 2nd col, 1st col is fa */
X	while (TRUE) {
X	    baddr = nbaddr;
X	    INC_BA (nbaddr);
X	    if (IS_FA (screen_buf[baddr])
X	    &&  !FA_IS_PROTECTED (screen_buf[baddr])
X	    &&  !IS_FA (screen_buf[nbaddr]))
X		break;
X	    if (baddr == 0) {
X		cursor_move (0);
X		return;
X	    }
X	}
X	INC_BA (baddr);
X	cursor_move (baddr);
X    }
X}
X
X
X/*
X * Cursor left 1 position.
X */
Xkey_Left ()
X{
X    register int	baddr;
X
X    if (kybdlock)
X	return;
X    baddr = cursor_addr;
X    DEC_BA (baddr);
X    cursor_move (baddr);
X}
X
X
X/*
X * Cursor right 1 position.
X */
Xkey_Right ()
X{
X    register int	baddr;
X
X    if (kybdlock)
X	return;
X    baddr = cursor_addr;
X    INC_BA (baddr);
X    cursor_move (baddr);
X}
X
X
X/*
X * Cursor left 2 positions.
X */
Xkey_Left2 ()
X{
X    register int	baddr;
X
X    if (kybdlock)
X	return;
X    baddr = cursor_addr;
X    DEC_BA (baddr);
X    DEC_BA (baddr);
X    cursor_move (baddr);
X}
X
X
X/*
X * Cursor right 2 positions.
X */
Xkey_Right2 ()
X{
X    register int	baddr;
X
X    if (kybdlock)
X	return;
X    baddr = cursor_addr;
X    INC_BA (baddr);
X    INC_BA (baddr);
X    cursor_move (baddr);
X}
X
X
X/*
X * Cursor up 1 position.
X */
Xkey_Up ()
X{
X    register int	baddr;
X
X    if (kybdlock)
X	return;
X    baddr = cursor_addr - COLS;
X    if (baddr < 0)
X	baddr = (cursor_addr + (ROWS * COLS)) - COLS;
X    cursor_move (baddr);
X}
X
X
X/*
X * Cursor down 1 position.
X */
Xkey_Down ()
X{
X    register int	baddr;
X
X    if (kybdlock)
X	return;
X    baddr = (cursor_addr + COLS) % (COLS * ROWS);
X    cursor_move (baddr);
X}
X
X
X/*
X * Cursor to first field on next line or any lines after that.
X */
Xkey_Newline ()
X{
X    register int	baddr;
X    register u_char	*fa;
X
X    if (kybdlock)
X	return;
X    baddr = (cursor_addr + COLS) % (COLS * ROWS);	/* down */
X    baddr = (baddr / COLS) * COLS;			/* 1st col */
X    fa = get_field_attribute (baddr);
X    if (fa != (&screen_buf[baddr]) && !FA_IS_PROTECTED (*fa))
X	cursor_move (baddr);
X    else {	/* find next unprotected */
X	if (fa == (&screen_buf[baddr]) && !FA_IS_PROTECTED (*fa)) {
X	    INC_BA (baddr);
X	}
X	else {
X	    while (TRUE) {
X		INC_BA (baddr);
X		if (IS_FA (screen_buf[baddr])
X		&&  !FA_IS_PROTECTED (screen_buf[baddr]))
X		    break;
X		if (baddr == cursor_addr) {
X		    cursor_move (0);
X		    return;
X		}
X	    }
X	    INC_BA (baddr);
X	}
X	cursor_move (baddr);
X    }
X}
X
X
X/*
X * DUP key
X */
Xkey_Dup ()
X{
X    register int	baddr, nbaddr;
X
X    if (key_Character (CG_DUP)) {
X	nbaddr = cursor_addr;
X	INC_BA (nbaddr);
X	while (TRUE) {
X	    baddr = nbaddr;
X	    INC_BA (nbaddr);
X	    if (IS_FA (screen_buf[baddr])
X	    &&  !FA_IS_PROTECTED (screen_buf[baddr])
X	    &&  !IS_FA (screen_buf[nbaddr]))
X		break;
X	    if (baddr == cursor_addr) {
X		cursor_move (0);
X		return;
X	    }
X	}
X	INC_BA (baddr);
X	cursor_move (baddr);
X    }
X}
X
X
X/*
X * FM key
X */
Xkey_FieldMark ()
X{
X    (void) key_Character (CG_FM);
X}
X
X
X/*
X * Enter AID key.
X */
Xkey_Enter ()
X{
X    if (kybdlock)
X	return;
X    key_AID (AID_ENTER);
X}
X
X
X/*
X * PA1 AID key
X */
Xkey_PA1 ()
X{
X    if (kybdlock)
X	return;
X    key_AID (AID_PA1);
X}
X
X
X/*
X * PA2 AID key
X */
Xkey_PA2 ()
X{
X    if (kybdlock)
X	return;
X    key_AID (AID_PA2);
X}
X
X
X/*
X * PA3 AID key
X */
Xkey_PA3 ()
X{
X    if (kybdlock)
X	return;
X    key_AID (AID_PA3);
X}
X
X
X/*
X * PF1 AID key
X */
Xkey_PF1 ()
X{
X    if (kybdlock)
X	return;
X    key_AID (AID_PF1);
X}
X
X
X/*
X * PF2 AID key
X */
Xkey_PF2 ()
X{
X    if (kybdlock)
X	return;
X    key_AID (AID_PF2);
X}
X
X
X/*
X * PF3 AID key
X */
Xkey_PF3 ()
X{
X    if (kybdlock)
X	return;
X    key_AID (AID_PF3);
X}
X
X
X/*
X * PF4 AID key
X */
Xkey_PF4 ()
X{
X    if (kybdlock)
X	return;
X    key_AID (AID_PF4);
X}
X
X
X/*
X * PF5 AID key
X */
Xkey_PF5 ()
X{
X    if (kybdlock)
X	return;
X    key_AID (AID_PF5);
X}
X
X
X/*
X * PF6 AID key
X */
Xkey_PF6 ()
X{
X    if (kybdlock)
X	return;
X    key_AID (AID_PF6);
X}
X
X
X/*
X * PF7 AID key
X */
Xkey_PF7 ()
X{
X    if (kybdlock)
X	return;
X    key_AID (AID_PF7);
X}
X
X
X/*
X * PF8 AID key
X */
Xkey_PF8 ()
X{
X    if (kybdlock)
X	return;
X    key_AID (AID_PF8);
X}
X
X
X/*
X * PF9 AID key
X */
Xkey_PF9 ()
X{
X    if (kybdlock)
X	return;
X    key_AID (AID_PF9);
X}
X
X
X/*
X * PF10 AID key
X */
Xkey_PF10 ()
X{
X    if (kybdlock)
X	return;
X    key_AID (AID_PF10);
X}
X
X
X/*
X * PF11 AID key
X */
Xkey_PF11 ()
X{
X    if (kybdlock)
X	return;
X    key_AID (AID_PF11);
X}
X
X
X/*
X * PF12 AID key
X */
Xkey_PF12 ()
X{
X    if (kybdlock)
X	return;
X    key_AID (AID_PF12);
X}
X
X
X/*
X * PF13 AID key
X */
Xkey_PF13 ()
X{
X    if (kybdlock)
X	return;
X    key_AID (AID_PF13);
X}
X
X
X/*
X * PF14 AID key
X */
Xkey_PF14 ()
X{
X    if (kybdlock)
X	return;
X    key_AID (AID_PF14);
X}
X
X
X/*
X * PF15 AID key
X */
Xkey_PF15 ()
X{
X    if (kybdlock)
X	return;
X    key_AID (AID_PF15);
X}
X
X
X/*
X * PF16 AID key
X */
Xkey_PF16 ()
X{
X    if (kybdlock)
X	return;
X    key_AID (AID_PF16);
X}
X
X
X/*
X * PF17 AID key
X */
Xkey_PF17 ()
X{
X    if (kybdlock)
X	return;
X    key_AID (AID_PF17);
X}
X
X
X/*
X * PF18 AID key
X */
Xkey_PF18 ()
X{
X    if (kybdlock)
X	return;
X    key_AID (AID_PF18);
X}
X
X
X/*
X * PF19 AID key
X */
Xkey_PF19 ()
X{
X    if (kybdlock)
X	return;
X    key_AID (AID_PF19);
X}
X
X
X/*
X * PF20 AID key
X */
Xkey_PF20 ()
X{
X    if (kybdlock)
X	return;
X    key_AID (AID_PF20);
X}
X
X
X/*
X * PF21 AID key
X */
Xkey_PF21 ()
X{
X    if (kybdlock)
X	return;
X    key_AID (AID_PF21);
X}
X
X
X/*
X * PF22 AID key
X */
Xkey_PF22 ()
X{
X    if (kybdlock)
X	return;
X    key_AID (AID_PF22);
X}
X
X
X/*
X * PF23 AID key
X */
Xkey_PF23 ()
X{
X    if (kybdlock)
X	return;
X    key_AID (AID_PF23);
X}
X
X
X/*
X * PF24 AID key
X */
Xkey_PF24 ()
X{
X    if (kybdlock)
X	return;
X    key_AID (AID_PF24);
X}
X
X
X/*
X * System Request AID key
X */
Xkey_SysReq ()
X{
X    if (kybdlock)
X	return;
X    key_AID (AID_SYSREQ);
X}
X
X
X/*
X * Clear AID key
X */
Xkey_Clear ()
X{
X    if (kybdlock)
X	return;
X    bzero ((char *) screen_buf, sizeof (screen_buf));
X    buffer_addr = 0;
X    cursor_off ();
X    pw_writebackground (pixwin, 0, 0, COL_TO_X (COLS), ROW_TO_Y (ROWS), PIX_CLR);
X    cursor_move (0);
X    cursor_on ();
X    key_AID (AID_CLEAR);
X}
X
X
X/*
X * Cursor Select key (light pen simulator).
X */
Xkey_CursorSelect ()
X{
X    register u_char	*fa, *sel;
X
X    if (kybdlock)
X	return;
X    fa = get_field_attribute (cursor_addr);
X    if (!FA_IS_SELECTABLE (*fa)) {
X	status_disp (8, CG_LOCK);
X	status_disp (9, CG_BLANK);
X	status_disp (10, CG_LEFTARROW);
X	status_disp (11, CG_HUMAN);
X	status_disp (12, CG_RIGHTARROW);
X	kybdlock = TRUE;
X    }
X    else {
X	sel = fa + 1;
X	switch (*sel) {
X	    case CG_GREATER:		/* > */
X		*sel = CG_QUESTION;	/* change to ? */
X		screen_update (sel - screen_buf, *fa);
X		*fa &= ~FA_MODIFY;	/* clear mdt */
X		break;
X	    case CG_QUESTION:		/* ? */
X		*sel = CG_GREATER;	/* change to > */
X		screen_update (sel - screen_buf, *fa);
X		*fa |= FA_MODIFY;	/* set mdt */
X		break;
X	    case CG_BLANK:		/* space */
X	    case CG_NULLBLANK:		/* null */
X		key_AID (AID_SELECT);
X		break;
X	    case CG_AMPERSAND:		/* & */
X		key_AID (AID_ENTER);
X		break;
X	    default:
X		status_disp (8, CG_LOCK);
X		status_disp (9, CG_BLANK);
X		status_disp (10, CG_LEFTARROW);
X		status_disp (11, CG_HUMAN);
X		status_disp (12, CG_RIGHTARROW);
X		kybdlock = TRUE;
X	}
X    }
X}
X
X
X/*
X * Erase End Of Field Key.
X */
Xkey_EraseEOF ()
X{
X    register int	baddr;
X    register u_char	*fa;
X
X    if (kybdlock)
X	return;
X    baddr = cursor_addr;
X    fa = get_field_attribute (baddr);
X    if (FA_IS_PROTECTED (*fa) || IS_FA (screen_buf[baddr])) {
X	status_disp (8, CG_LOCK);
X	status_disp (9, CG_BLANK);
X	status_disp (10, CG_LEFTARROW);
X	status_disp (11, CG_HUMAN);
X	status_disp (12, CG_RIGHTARROW);
X	kybdlock = TRUE;
X    }
X    else {
X	if (formatted) {	/* erase to next field attribute */
X	    cursor_off ();
X	    do {
X		screen_buf[baddr] = CG_NULLBLANK;
X		screen_update (baddr, *fa);
X		INC_BA (baddr);
X	    } while (!IS_FA (screen_buf[baddr]));
X	    *fa |= FA_MODIFY;
X	    cursor_on ();
X	}
X	else {	/* erase to end of screen */
X	    cursor_off ();
X	    do {
X		screen_buf[baddr] = CG_NULLBLANK;
X		screen_update (baddr, *fa);
X		INC_BA (baddr);
X	    } while (baddr != 0);
X	    cursor_on ();
X	}
X    }
X}
X
X
X/*
X * Erase all Input Key.
X */
Xkey_EraseInput ()
X{
X    register int	baddr, sbaddr;
X    u_char		fa;
X    bool		f;
X
X    if (kybdlock)
X	return;
X    cursor_off ();
X    if (formatted) {
X	/* find first field attribute */
X	baddr = 0;
X	do {
X	    if (IS_FA (screen_buf[baddr]))
X		break;
X	    INC_BA (baddr);
X	} while (baddr != 0);
X	sbaddr = baddr;
X	f = FALSE;
X	do {
X	    fa = screen_buf[baddr];
X	    if (!FA_IS_PROTECTED (fa)) {
X		screen_buf[baddr] &= ~FA_MODIFY;
X		do {
X		    INC_BA (baddr);
X		    if (!f) {
X			cursor_move (baddr);
X			f = TRUE;
X		    }
X		    if (!IS_FA (screen_buf[baddr])) {
X			screen_buf[baddr] = CG_NULLBLANK;
X			screen_update (baddr, fa);
X		    }
X		}
X		while (!IS_FA (screen_buf[baddr]));
X	    }
X	    else {	/* skip protected */
X		do {
X		    INC_BA (baddr);
X		} while (!IS_FA (screen_buf[baddr]));
X	    }
X	} while (baddr != sbaddr);
X	if (!f)
X	    cursor_move (0);
X    }
X    else {
X	bzero ((char *) screen_buf, sizeof (screen_buf));
X	pw_writebackground (
X	    pixwin,
X	    0, 0, COL_TO_X (COLS), ROW_TO_Y (ROWS),
X	    PIX_CLR
X	);
X	cursor_move (0);
X    }
X    cursor_on ();
X}
X
X
X/*
X * Delete char key.
X */
Xkey_Delete ()
X{
X    register int	baddr, end_baddr, t_baddr;
X    register u_char	*fa;
X
X    if (kybdlock)
X	return;
X    baddr = cursor_addr;
X    fa = get_field_attribute (baddr);
X    if (FA_IS_PROTECTED (*fa) || IS_FA (screen_buf[baddr])) {
X	status_disp (8, CG_LOCK);
X	status_disp (9, CG_BLANK);
X	status_disp (10, CG_LEFTARROW);
X	status_disp (11, CG_HUMAN);
X	status_disp (12, CG_RIGHTARROW);
X	kybdlock = TRUE;
X    }
X    else {
X	/* find next fa */
X	end_baddr = baddr;
X	do {
X	    INC_BA (end_baddr);
X	    if (IS_FA (screen_buf[end_baddr]))
X		break;
X	} while (end_baddr != baddr);
X	DEC_BA (end_baddr);
X	if (end_baddr > baddr)
X	    bcopy ((char *) &screen_buf[baddr+1], (char *) &screen_buf[baddr], end_baddr - baddr);
X	else {
X	    bcopy ((char *) &screen_buf[baddr+1], (char *) &screen_buf[baddr], ((ROWS * COLS) - 1) - baddr);
X	    screen_buf[(ROWS * COLS) - 1] = screen_buf[0];
X	    bcopy ((char *) &screen_buf[1], (char *) &screen_buf[0], end_baddr);
X	}
X	screen_buf[end_baddr] = CG_NULLBLANK;
X	cursor_off ();
X	t_baddr = baddr;
X	while (t_baddr != end_baddr) {
X	    screen_update (t_baddr, *fa);
X	    INC_BA (t_baddr);
X	}
X	screen_update (t_baddr, *fa);
X	cursor_on ();
X    }
X}
X
X
X/*
X * Set insert mode key.
X */
Xkey_Insert ()
X{
X    if (kybdlock)
X	return;
X    insert_mode (TRUE);
X}
X
X
X/*
X * Catch and dispatch events coming in from suntools.  There are currently
X * two versions of this routine, one for type 3 keyboards (on Sun3's) and
X * one for type 4 keyboards (on Sun 386i's).  This should really be revamped
X * and made more general using a user customizable key definition configuration
X * file.  Mouse actions are also handled in here.
X */
X/*ARGSUSED*/
XNotify_value
Xcanvas_event_proc (win, event, arg)
XWindow	win;
XEvent	*event;
Xcaddr_t	arg;
X{
X    register int	baddr;
X    int			cgcode;
X
X#ifdef DEBUG
X	printf (
X	    "event: code=%d, flags=0x%x, shiftmask=0x%x, x,y=%d,%d\n",
X	    event->ie_code, event->ie_flags, event->ie_shiftmask,
X	    event->ie_locx, event->ie_locy
X	);
X#endif
X    switch (event_id (event)) {
X
X	/* function keys on top of keyboard */
X#ifdef TYPE4KBD
X	case KEY_TOP(1):
X	    if (event_shiftmask (event) & META_SHIFT_MASK)
X	        key_AltCr ();
X	    else
X	        key_PF1 ();
X	    break;
X	case KEY_TOP(2):
X	    if (event_shiftmask (event) & META_SHIFT_MASK)
X		key_CursorBlink ();
X	    else
X		key_PF2 ();
X	    break;
X	case KEY_TOP(3):
X	    if (event_shiftmask (event) & META_SHIFT_MASK)
X		key_Reset ();
X	    else
X		key_PF3 ();
X	    break;
X	case KEY_TOP(4):
X	    key_PF4 ();
X	    break;
X	case KEY_TOP(5):
X	    key_PF5 ();
X	    break;
X	case KEY_TOP(6):
X	    key_PF6 ();
X	    break;
X	case KEY_TOP(7):
X	    key_PF7 ();
X	    break;
X	case KEY_TOP(8):
X	    key_PF8 ();
X	    break;
X	case KEY_TOP(9):
X	    if (event_shiftmask (event) & META_SHIFT_MASK)
X		key_MonoCase ();
X	    else
X		key_PF9 ();
X	    break;
X	case KEY_TOP(10):
X	    key_PF10 ();
X	    break;
X	case KEY_TOP(11):
X	    key_PF11 ();
X	    break;
X	case KEY_TOP(12):
X	    key_PF12 ();
X	    break;
X#else
X	case KEY_TOP(1):
X	    key_AltCr ();
X	    break;
X	case KEY_TOP(2):
X	    key_CursorBlink ();
X	    break;
X	case KEY_TOP(3):
X	    key_Reset ();
X	    break;
X	case KEY_TOP(9):
X	    key_MonoCase ();
X	    break;
X#endif
X
X	/* function keys on right of keyboard */
X	case KEY_RIGHT(1):
X	    if (event_shiftmask (event) & META_SHIFT_MASK)
X		key_PA1 ();
X	    else
X		key_Dup ();
X	    break;
X	case KEY_RIGHT(2):
X	    if (event_shiftmask (event) & META_SHIFT_MASK)
X		key_PA2 ();
X	    else
X		key_FieldMark ();
X	    break;
X	case KEY_RIGHT(3):
X	    if (event_shiftmask (event) & META_SHIFT_MASK)
X		key_Clear ();
X	    else
X		key_CursorSelect ();
X	    break;
X	case KEY_RIGHT(4):
X	    if (event_shiftmask (event) & META_SHIFT_MASK)
X		key_PF13 ();
X	    else
X		key_EraseEOF ();
X	    break;
X	case KEY_RIGHT(5):
X	    if (event_shiftmask (event) & META_SHIFT_MASK)
X		key_PF14 ();
X	    else
X		key_EraseInput ();
X	    break;
X	case KEY_RIGHT(6):
X	    if (event_shiftmask (event) & META_SHIFT_MASK)
X		key_PF15 ();
X	    else
X		key_SysReq ();
X	    break;
X	case KEY_RIGHT(7):
X	    if (event_shiftmask (event) & META_SHIFT_MASK)
X		key_PF16 ();
X	    else
X		key_Delete ();
X	    break;
X	case KEY_RIGHT(8):
X	    if (event_shiftmask (event) & META_SHIFT_MASK)
X		key_PF17 ();
X	    else
X		key_Up ();
X	    break;
X	case KEY_RIGHT(9):
X	    if (event_shiftmask (event) & META_SHIFT_MASK)
X		key_PF18 ();
X	    else
X		key_Insert ();
X	    break;
X	case KEY_RIGHT(10):
X	    if (event_shiftmask (event) & META_SHIFT_MASK)
X		key_PF19 ();
X	    else
X		key_Left ();
X	    break;
X	case KEY_RIGHT(11):
X	    if (event_shiftmask (event) & META_SHIFT_MASK)
X		key_PF20 ();
X	    else
X		key_Home ();
X	    break;
X	case KEY_RIGHT(12):
X	    if (event_shiftmask (event) & META_SHIFT_MASK)
X		key_PF21 ();
X	    else
X		key_Right ();
X	    break;
X	case KEY_RIGHT(13):
X	    if (event_shiftmask (event) & META_SHIFT_MASK)
X		key_PF22 ();
X	    else
X		key_Left2 ();
X	    break;
X	case KEY_RIGHT(14):
X	    if (event_shiftmask (event) & META_SHIFT_MASK)
X		key_PF23 ();
X	    else
X		key_Down ();
X	    break;
X	case KEY_RIGHT(15):
X	    if (event_shiftmask (event) & META_SHIFT_MASK)
X		key_PF24 ();
X	    else
X		key_Right2 ();
X	    break;
X
X	/* mouse events */
X	case MS_LEFT:	/* left mouse move cursor under pointer */
X	    if (kybdlock)
X		return (NOTIFY_IGNORED);
X	    baddr = ROWCOL_TO_BA(Y_TO_ROW (event_y (event)), 
X				 X_TO_COL (event_x (event)));
X	    while (baddr >= (COLS * ROWS))
X		baddr -= COLS;
X	    cursor_move (baddr);
X	    break;
X	case MS_MIDDLE:	/* middle mouse sets selections */
X	    baddr = ROWCOL_TO_BA(Y_TO_ROW (event_y (event)), 
X				 X_TO_COL (event_x (event)));
X	    while (baddr >= (COLS * ROWS))
X		baddr -= COLS;
X	    set_seln (cursor_addr, baddr);
X	    break;
X	case MS_RIGHT:	/* right mouse pops up canvas menu */
X	    if (event_is_down (event))
X		menu_show (Key_menu, win, event, 0);
X	    break;
X	case LOC_RGNENTER:	/* mouse entered window */
X	    if (seln_acquire (s_client, SELN_CARET) != SELN_CARET)
X		fprintf (stderr, "can't acquire SELN_CARET!\n");
X	    break;
X
X#ifdef DEBUG
X	/* things we need to catch in order for stuff to work
X	 * right, but we don't need to do anything explicitely
X	 * with them.
X	 */
X	case LOC_RGNEXIT:
X	case KBD_USE:
X	case KBD_DONE:
X	case WIN_REPAINT:
X	case WIN_RESIZE:
X	    break;
X
X	/* the system seems to pass these on AFTER it's
X	 * finished processing them.  so we gotta ignore them.
X	 */
X	case KEY_LEFT(1):	/* STOP */
X	case KEY_LEFT(2):	/* AGAIN */
X	case KEY_LEFT(3):	/* PROPS */
X	case KEY_LEFT(4):	/* UNDO */
X	case KEY_LEFT(5):	/* EXPOSE */
X	case KEY_LEFT(6):	/* PUT */
X	case KEY_LEFT(7):	/* OPEN */
X	case KEY_LEFT(8):	/* GET */
X	case KEY_LEFT(9):	/* FIND */
X	case KEY_LEFT(10):	/* DELETE */
X	    break;
X#endif
X
X	/* miscellany (character keys) */
X	default:
X	    if ((event_shiftmask (event) & META_SHIFT_MASK)) {
X		event_set_id (event, (event_id (event) & ~0x80));
X		switch (event_id (event)) {
X		    case 0x7F:	/* delete */
X		    case 0x08:	/* backspace */
X			/* alt-delete or alt-backspace is home */
X			key_Home ();
X			break;
X		    case '1':
X			key_PF1 ();
X			break;
X		    case '2':
X			key_PF2 ();
X			break;
X		    case '3':
X			key_PF3 ();
X			break;
X		    case '4':
X			key_PF4 ();
X			break;
X		    case '5':
X			key_PF5 ();
X			break;
X		    case '6':
X			key_PF6 ();
X			break;
X		    case '7':
X			key_PF7 ();
X			break;
X		    case '8':
X			key_PF8 ();
X			break;
X		    case '9':
X			key_PF9 ();
X			break;
X		    case '0':
X			key_PF10 ();
X			break;
X		    case '-':
X			key_PF11 ();
X			break;
X		    case '=':
X			key_PF12 ();
X			break;
X		    default:
X			return (NOTIFY_IGNORED);
X			break;
X		}
X	    }
X	    else if ((event_id (event) >= ' ' && event_id (event) <= '~')
X	    ||  event_id (event) == 0x1B) {
X		/* if a printable key or the escape key */
X		if (event_id (event) == 0x1B
X		&&  (event_shiftmask (event) & SHIFTMASK) != 0) {
X		    /* fake shift-ESC to something unique */
X		    event_set_id (event, 0x1C);
X		}
X		cgcode = asc2cg[event_id (event)];
X		if (cgcode == CG_NULLBLANK)
X		    return (NOTIFY_IGNORED);
X		else
X		    (void) key_Character (cgcode);
X	    }
X	    else if (event_id (event) == 0x08)
X		key_Left ();
X	    else if (event_id (event) == 0x09)
X		key_FTab ();
X	    else if (event_id (event) == 0x0A)
X		key_Newline ();
X	    else if (event_id (event) == 0x0D)
X		key_Enter ();
X	    else if (event_id (event) == 0x7F)
X		key_BTab ();
X	    else {
X#ifdef DEBUG
X		fprintf (stderr, "unknown event: %d\n", event_id (event));
X#endif
X		return (NOTIFY_IGNORED);
X	    }
X	    break;
X    }
X    return (NOTIFY_DONE);
X}
X
X
X/*
X * Initialize the canvas menu.
X */
Xmenu_init ()
X{
X
X    Key_menu = menu_create (
X	MENU_ITEM,
X	    MENU_STRING,		"Show/Hide Key Panel",
X	    MENU_ACTION_PROC,		key_panel_toggle,
X	    0,
X	MENU_PULLRIGHT_ITEM, "Other Keys", menu_create (
X	    MENU_ITEM,
X		MENU_STRING,		"Reset",
X		MENU_ACTION_PROC,	key_Reset,
X		0,
X	    MENU_ITEM,
X		MENU_STRING,		"Erase EOF",
X		MENU_ACTION_PROC,	key_EraseEOF,
X		0,
X	    MENU_ITEM,
X		MENU_STRING,		"Erase Inp",
X		MENU_ACTION_PROC,	key_EraseInput,
X		0,
X	    MENU_ITEM,
X		MENU_STRING,		"Delete",
X		MENU_ACTION_PROC,	key_Delete,
X		0,
X	    MENU_ITEM,
X		MENU_STRING,		"Insert",
X		MENU_ACTION_PROC,	key_Insert,
X		0,
X	    MENU_ITEM,
X		MENU_STRING,		"Dup",
X		MENU_ACTION_PROC,	key_Dup,
X		0,
X	    MENU_ITEM,
X		MENU_STRING,		"FM",
X		MENU_ACTION_PROC,	key_FieldMark,
X		0,
X	    MENU_ITEM,
X		MENU_STRING,		"CursorSel",
X		MENU_ACTION_PROC,	key_CursorSelect,
X		0,
X	    MENU_ITEM,
X		MENU_STRING,		"Alternate Cursor",
X		MENU_ACTION_PROC,	key_AltCr,
X		0,
X	    MENU_ITEM,
X		MENU_STRING,		"Cursor Blink",
X		MENU_ACTION_PROC,	key_CursorBlink,
X		0,
X	    MENU_ITEM,
X		MENU_STRING,		"Monocase",
X		MENU_ACTION_PROC,	key_MonoCase,
X		0,
X	    0
X	),
X	MENU_ITEM,
X	    MENU_STRING,		"Stuff",
X	    MENU_ACTION_PROC,		stuff_seln,
X	    0,
X	0
X    );
X
X}
--End_of_kybd.c--
	if test 28446 -ne `wc -c < 'kybd.c'`
	then
		echo "`basename $0`: error in" 'kybd.c' ": sent 28446 chars, received `wc -c < 'kybd.c'`" 1>&2
	fi
fi
if test -f 'screen.c'
then
	echo "`basename $0`: can't extract" 'screen.c' "- file exists" 1>&2
else
	sed 's/^X//' << '--End_of_screen.c--' > 'screen.c'
X/*
X * Copyright 1989 by Georgia Tech Research Corporation, Atlanta, GA.
X * Copyright 1988, 1989 by Robert Viduya.
X *
X *                         All Rights Reserved
X */
X
X/*
X *	screen.c
X *		This module handles interpretation of the 3270 data stream
X *		and other screen management actions.
X */
X#include <sys/types.h>
X#include <sys/time.h>
X#include <errno.h>
X#include <suntool/sunview.h>
X#include <suntool/canvas.h>
X#include <suntool/menu.h>
X#include <stdio.h>
X#include "3270.h"
X#include "3270_enc.h"
X
X/* ebcdic to 3270 character generator xlate table */
X
Xu_char	ebc2cg[256] = {
X	CG_NULLBLANK,	CG_PERIOD,	CG_PERIOD,	CG_PERIOD,
X	CG_PERIOD,	CG_PERIOD,	CG_PERIOD,	CG_PERIOD,
X	CG_PERIOD,	CG_PERIOD,	CG_PERIOD,	CG_PERIOD,
X	CG_OVERBAR2,	CG_OVERBAR6,	CG_PERIOD,	CG_PERIOD,
X	CG_PERIOD,	CG_PERIOD,	CG_PERIOD,	CG_PERIOD,
X	CG_PERIOD,	CG_OVERBAR3,	CG_PERIOD,	CG_PERIOD,
X	CG_PERIOD,	CG_OVERBAR1,	CG_PERIOD,	CG_PERIOD,
X	CG_DUP,		CG_PERIOD,	CG_FM,		CG_PERIOD,
X	CG_PERIOD,	CG_PERIOD,	CG_PERIOD,	CG_PERIOD,
X	CG_PERIOD,	CG_PERIOD,	CG_PERIOD,	CG_PERIOD,
X	CG_PERIOD,	CG_PERIOD,	CG_PERIOD,	CG_PERIOD,
X	CG_PERIOD,	CG_PERIOD,	CG_PERIOD,	CG_PERIOD,
X	CG_PERIOD,	CG_PERIOD,	CG_PERIOD,	CG_PERIOD,
X	CG_PERIOD,	CG_PERIOD,	CG_PERIOD,	CG_PERIOD,
X	CG_PERIOD,	CG_PERIOD,	CG_PERIOD,	CG_PERIOD,
X	CG_PERIOD,	CG_PERIOD,	CG_PERIOD,	CG_OVERBAR4,
X	CG_BLANK,	CG_LBRACKET,	CG_RBRACKET,	CG_POUND,
X	CG_YEN,		CG_PT,		CG_CURRENCY,	CG_SHARPS,
X	CG_SECTION,	CG_OVERSCORE,	CG_CENT,	CG_PERIOD,
X	CG_LESS,	CG_LPAREN,	CG_PLUS,	CG_SOLIDBAR,
X	CG_AMPERSAND,	CG_DEGREE,	CG_BREVE,	CG_CIRCUMFLEX,
X	CG_DIAERESIS,	CG_ACUTE,	CG_CEDILLA,	CG_LAACUTE1,
X	CG_LEACUTE1,	CG_LIACUTE1,	CG_EXCLAMATION,	CG_DOLLAR,
X	CG_ASTERISK,	CG_RPAREN,	CG_SEMICOLON,	CG_NOT,
X	CG_MINUS,	CG_FSLASH,	CG_LOACUTE1,	CG_LUACUTE1,
X	CG_LATILDE,	CG_LOTILDE,	CG_LYDIAERESIS,	CG_LAACUTE2,
X	CG_LEACUTE2,	CG_LEGRAVE1,	CG_BROKENBAR,	CG_COMMA,
X	CG_PERCENT,	CG_UNDERSCORE,	CG_GREATER,	CG_QUESTION,
X	CG_LIACUTE2,	CG_LOACUTE2,	CG_LUACUTE2,	CG_LUDIAERESIS1,
X	CG_LCCEDILLA1,	CG_LADIAERESIS,	CG_LEDIAERESIS,	CG_LIDIAERESIS,
X	CG_LODIAERESIS,	CG_GRAVE,	CG_COLON,	CG_NUMBER,
X	CG_AT,		CG_SQUOTE,	CG_EQUAL,	CG_DQUOTE,
X	CG_LUDIAERESIS2,CG_LA,		CG_LB,		CG_LC,
X	CG_LD,		CG_LE,		CG_LF,		CG_LG,
X	CG_LH,		CG_LI,		CG_LACIRCUMFLEX,CG_LECIRCUMFLEX,
X	CG_LICIRCUMFLEX,CG_LOCIRCUMFLEX,CG_LUCIRCUMFLEX,CG_LAGRAVE,
X	CG_LEGRAVE2,	CG_LJ,		CG_LK,		CG_LL,
X	CG_LM,		CG_LN,		CG_LO,		CG_LP,
X	CG_LQ,		CG_LR,		CG_LIGRAVE,	CG_LOGRAVE,
X	CG_LUGRAVE,	CG_LNTILDE,	CG_CAACUTE,	CG_CEACUTE,
X	CG_CIACUTE,	CG_TILDE,	CG_LS,		CG_LT,
X	CG_LU,		CG_LV,		CG_LW,		CG_LX,
X	CG_LY,		CG_LZ,		CG_COACUTE,	CG_CUACUTE,
X	CG_CATILDE,	CG_COTILDE,	CG_CY1,		CG_CA1,
X	CG_CE1,		CG_CE2,		CG_CI1,		CG_CO1,
X	CG_CU1,		CG_CY2,		CG_CC1,		CG_CADIAERESIS,
X	CG_CEDIAERESIS,	CG_CIDIAERESIS,	CG_CODIAERESIS,	CG_CUDIAERESIS,
X	CG_CACIRCUMFLEX,CG_CECIRCUMFLEX,CG_CICIRCUMFLEX,CG_COCIRCUMFLEX,
X	CG_LBRACE,	CG_CA,		CG_CB,		CG_CC,
X	CG_CD,		CG_CE,		CG_CF,		CG_CG,
X	CG_CH,		CG_CI,		CG_CUCIRCUMFLEX,CG_CAGRAVE,
X	CG_CEGRAVE,	CG_CIGRAVE,	CG_PERIOD,	CG_PERIOD,
X	CG_RBRACE,	CG_CJ,		CG_CK,		CG_CL,
X	CG_CM,		CG_CN,		CG_CO,		CG_CP,
X	CG_CQ,		CG_CR,		CG_COGRAVE,	CG_CUGRAVE,
X	CG_CNTILDE,	CG_PERIOD,	CG_PERIOD,	CG_PERIOD,
X	CG_BSLASH,	CG_LAE,		CG_CS,		CG_CT,
X	CG_CU,		CG_CV,		CG_CW,		CG_CX,
X	CG_CY,		CG_CZ,		CG_SSLASH0,	CG_LADOT,
X	CG_LCCEDILLA2,	CG_PERIOD,	CG_PERIOD,	CG_MINUS,
X	CG_ZERO,	CG_ONE,		CG_TWO,		CG_THREE,
X	CG_FOUR,	CG_FIVE,	CG_SIX,		CG_SEVEN,
X	CG_EIGHT,	CG_NINE,	CG_CAE,		CG_BSLASH0,
X	CG_CADOT,	CG_CCCEDILLA,	CG_MINUS,	CG_OVERBAR7
X};
X
X/* 3270 character generator to ebcdic xlate table */
X/* generated programmatically from ebc2cg */
X
Xu_char	cg2ebc[256] = {
X	0x00, 0x19, 0x0c, 0x15, 0x3f, 0x00, 0x0d, 0xff,	/* 0x00 */
X	0x6e, 0x4c, 0x41, 0x42, 0x5d, 0x4d, 0xd0, 0xc0,
X	0x40, 0x7e, 0x7d, 0x7f, 0x61, 0xe0, 0x4f, 0x6a,	/* 0x10 */
X	0x6f, 0x5a, 0x5b, 0x4a, 0x43, 0x44, 0x45, 0x46,
X	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,	/* 0x20 */
X	0xf8, 0xf9, 0x47, 0x48, 0x7b, 0x7c, 0x6c, 0x6d,
X	0x50, 0x60, 0x4b, 0x6b, 0x7a, 0x4e, 0x5f, 0x49,	/* 0x30 */
X	0x51, 0x52, 0x53, 0xa1, 0x54, 0x79, 0x55, 0x56,
X	0x57, 0x58, 0x59, 0x62, 0x63, 0x64, 0x65, 0x66,	/* 0x40 */
X	0x67, 0x68, 0x69, 0x70, 0x71, 0x72, 0x73, 0x74,
X	0x75, 0x76, 0x77, 0x78, 0x80, 0x8a, 0x8b, 0x8c,	/* 0x50 */
X	0x8d, 0x8e, 0x8f, 0x90, 0x9a, 0x9b, 0x9c, 0x9d,
X	0x9e, 0x9f, 0xa0, 0xaa, 0xab, 0xac, 0xad, 0xae,	/* 0x60 */
X	0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
X	0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe,	/* 0x70 */
X	0xbf, 0xca, 0xcb, 0xcc, 0xcd, 0xda, 0xdb, 0xdc,
X	0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88,	/* 0x80 */
X	0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
X	0x98, 0x99, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,	/* 0x90 */
X	0xa8, 0xa9, 0xe1, 0xea, 0xeb, 0xec, 0x1e, 0x1c,
X	0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8,	/* 0xA0 */
X	0xc9, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
X	0xd8, 0xd9, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,	/* 0xB0 */
X	0xe8, 0xe9, 0xfa, 0xfb, 0xfc, 0xfd, 0x5e, 0x5c,
X	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 0xC0 */
X	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
X	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 0xD0 */
X	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
X	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 0xE0 */
X	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
X	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 0xF0 */
X	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
X};
X
X#define ITIMER_NULL	((struct itimerval *) 0)
X#define TIMER_IVAL	250000L	/* usec's */
X
X/* code_table is used to translate buffer addresses to the 3270
X * datastream representation
X */
Xu_char	code_table[64] = {
X    0x40, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
X    0xC8, 0xC9, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
X    0x50, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7,
X    0xD8, 0xD9, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
X    0x60, 0x61, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
X    0xE8, 0xE9, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
X    0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
X    0xF8, 0xF9, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
X};
X
Xextern Frame		frame;
XCanvas			canvas;
XPixwin			*pixwin;
XCursor			cursor;
XPixfont			*ibmfont;
Xint			cursor_addr, buffer_addr;
Xbool			cursor_displayed = FALSE;
Xbool			cursor_blink_on = TRUE;
Xbool			cursor_alt = FALSE, cursor_blink = FALSE;
Xbool			mono_case = FALSE;
X
X/* the following are set from values in the 3270 font */
Xint			char_width, char_height, char_base;
X
Xu_char			screen_buf[ROWS * COLS];
Xbool			formatted = FALSE;	/* set in screen_disp */
Xstruct itimerval	blink_timer;
X
Xextern u_char	obuf[], *obptr;
Xextern u_char	aid;
X
XNotify_value		timer ();
Xextern Notify_value	canvas_event_proc ();
X
X
X/*
X * Initialize the screen canvas.  Should only be called once.
X */
Xscreen_init ()
X{
X    if ((ibmfont = pf_open (FONT3270)) == (Pixfont *) 0) {
X	perror ("3270tool: can't open 3270.font");
X	exit (1);
X    }
X    char_width = CHAR_WIDTH;
X    char_height = CHAR_HEIGHT;
X    char_base = CHAR_BASE;
X    canvas = window_create (
X	frame, CANVAS,
X	CANVAS_AUTO_EXPAND,	FALSE,
X	CANVAS_AUTO_SHRINK,	FALSE,
X	CANVAS_HEIGHT,		ROW_TO_Y (ROWS + 1) + 4,
X	CANVAS_WIDTH,		COL_TO_X (COLS),
X	CANVAS_MARGIN,		0,
X	CANVAS_RETAINED,	TRUE,
X	WIN_HEIGHT,		ROW_TO_Y (ROWS + 1) + 4 + 0,
X	WIN_WIDTH,		COL_TO_X (COLS) + 0,
X	WIN_EVENT_PROC,		canvas_event_proc,
X	WIN_CONSUME_PICK_EVENTS,WIN_NO_EVENTS,
X				LOC_WINENTER,
X				LOC_WINEXIT,
X				WIN_MOUSE_BUTTONS,
X				WIN_UP_EVENTS,
X				0,
X	WIN_CONSUME_KBD_EVENTS,	WIN_NO_EVENTS,
X				KBD_USE,
X				KBD_DONE,
X				WIN_ASCII_EVENTS,
X				WIN_LEFT_KEYS,
X				WIN_RIGHT_KEYS,
X				WIN_TOP_KEYS,
X				0,
X	0
X    );
X    cursor = window_get (canvas, WIN_CURSOR);
X    cursor_set (cursor, CURSOR_OP, PIX_SRC^PIX_DST, 0);
X    window_set (canvas, WIN_CURSOR, cursor, 0);
X    window_fit (canvas);
X    window_fit (frame);
X    pixwin = canvas_pixwin (canvas);
X    pw_vector (
X	pixwin,
X	0, ROW_TO_Y (ROWS) + 2,
X	COL_TO_X (COLS), ROW_TO_Y (ROWS) + 2,
X	PIX_SET, 1
X    );
X    bzero ((char *) screen_buf, sizeof (screen_buf));
X    cursor_addr = 0;
X    buffer_addr = 0;
X    pw_batch_on (pixwin);
X    screen_disp ();
X    cursor_on ();
X    status_disp (0, CG_BOX4);
X    status_disp (1, CG_UNDERA);
X    status_disp (2, CG_BOXSOLID);
X    blink_timer.it_interval.tv_sec = 0;
X    blink_timer.it_interval.tv_usec = TIMER_IVAL;
X    blink_timer.it_value.tv_sec = 0;
X    blink_timer.it_value.tv_usec = TIMER_IVAL;
X    (void) notify_set_itimer_func (&blink_timer, timer, ITIMER_REAL, &blink_timer, ITIMER_NULL);
X}
X
X
X/*
X * Update the status line by displaying "symbol" at column "col".
X */
Xstatus_disp (col, symbol)
Xint	col, symbol;
X{
X    PW_CHAR (pixwin, COL_TO_X (col), ROW_TO_Y (ROWS) + 4, PIX_SRC, symbol);
X}
X
X
X/*
X * Timer function for implementing cursor blink.
X */
X/*ARGSUSED*/
XNotify_value
Xtimer (client, which)
XNotify_client	client;
Xint		which;
X{
X    if (cursor_blink && cursor_displayed) {	/* blink the cursor */
X	cursor_blink_on = !cursor_blink_on;
X	if (cursor_alt)
X	    pw_writebackground (
X		pixwin,
X		COL_TO_X (BA_TO_COL (cursor_addr)),
X		ROW_TO_Y (BA_TO_ROW (cursor_addr)),
X		COL_TO_X (1),
X		ROW_TO_Y (1),
X		PIX_SET^PIX_DST
X	    );
X	else
X	    pw_writebackground (
X		pixwin,
X		COL_TO_X (BA_TO_COL (cursor_addr)),
X		ROW_TO_Y (BA_TO_ROW (cursor_addr) + 1) - 1,
X		COL_TO_X (1),
X		1,
X		PIX_SET^PIX_DST
X	    );
X    }
X    return (NOTIFY_DONE);
X}
X
X
X/*
X * Turn off the timer/cursor-blink so we can safely update the screen.
X */
Xtimer_hold ()
X{
X    (void) notify_set_itimer_func (&blink_timer, timer, ITIMER_REAL, ITIMER_NULL, ITIMER_NULL);
X    if (cursor_blink && cursor_displayed && !cursor_blink_on) {
X	cursor_blink_on = TRUE;
X	if (cursor_alt)
X	    pw_writebackground (
X		pixwin,
X		COL_TO_X (BA_TO_COL (cursor_addr)),
X		ROW_TO_Y (BA_TO_ROW (cursor_addr)),
X		COL_TO_X (1),
X		ROW_TO_Y (1),
X		PIX_SET^PIX_DST
X	    );
X	else
X	    pw_writebackground (
X		pixwin,
X		COL_TO_X (BA_TO_COL (cursor_addr)),
X		ROW_TO_Y (BA_TO_ROW (cursor_addr) + 1) - 1,
X		COL_TO_X (1),
X		1,
X		PIX_SET^PIX_DST
X	    );
X    }
X}
X
X
X/*
X * Turn on the timer/cursor-blink after we have safely updated the screen.
X */
Xtimer_release ()
X{
X    cursor_blink_on = TRUE;
X    blink_timer.it_interval.tv_sec = 0;
X    blink_timer.it_interval.tv_usec = TIMER_IVAL;
X    blink_timer.it_value.tv_sec = 0;
X    blink_timer.it_value.tv_usec = TIMER_IVAL;
X    (void) notify_set_itimer_func (&blink_timer, timer, ITIMER_REAL, &blink_timer, ITIMER_NULL);
X}
X
X
X/*
X * Toggle cursor blink
X */
Xblink_cursor (on)
Xbool	on;
X{
X    timer_hold ();
X    cursor_blink = on;
X    timer_release ();
X}
X
X
X/*
X * Make the cursor disappear.
X */
Xcursor_off ()
X{
X    timer_hold ();
X    if (cursor_displayed) {
X	cursor_displayed = FALSE;
X	pw_batch_on (pixwin);
X	if (cursor_alt)
X	    pw_writebackground (
X		pixwin,
X		COL_TO_X (BA_TO_COL (cursor_addr)),
X		ROW_TO_Y (BA_TO_ROW (cursor_addr)),
X		COL_TO_X (1),
X		ROW_TO_Y (1),
X		PIX_SET^PIX_DST
X	    );
X	else
X	    pw_writebackground (
X		pixwin,
X		COL_TO_X (BA_TO_COL (cursor_addr)),
X		ROW_TO_Y (BA_TO_ROW (cursor_addr) + 1) - 1,
X		COL_TO_X (1),
X		1,
X		PIX_SET^PIX_DST
X	    );
X    }
X    timer_release ();
X    clear_seln ();
X}
X
X
X/*
X * Make the cursor visible.
X */
Xcursor_on ()
X{
X    timer_hold ();
X    if (!cursor_displayed) {
X	if (cursor_alt)
X	    pw_writebackground (
X		pixwin,
X		COL_TO_X (BA_TO_COL (cursor_addr)),
X		ROW_TO_Y (BA_TO_ROW (cursor_addr)),
X		COL_TO_X (1),
X		ROW_TO_Y (1),
X		PIX_SET^PIX_DST
X	    );
X	else
X	    pw_writebackground (
X		pixwin,
X		COL_TO_X (BA_TO_COL (cursor_addr)),
X		ROW_TO_Y (BA_TO_ROW (cursor_addr) + 1) - 1,
X		COL_TO_X (1),
X		1,
X		PIX_SET^PIX_DST
X	    );
X	cursor_displayed = TRUE;
X	pw_batch_off (pixwin);
X    }
X    timer_release ();
X}
X
X
X/*
X * Toggle the cursor (block/underline).
X */
Xalt_cursor (alt)
Xbool	alt;
X{
X    if (alt != cursor_alt) {
X	cursor_off ();
X	cursor_alt = alt;
X	cursor_on ();
X    }
X}
X
X
X/*
X * Move the cursor to the specified buffer address.
X */
Xcursor_move (baddr)
Xint	baddr;
X{
X    timer_hold ();
X    if (cursor_displayed) {
X	if (cursor_alt)
X	    pw_writebackground (
X		pixwin,
X		COL_TO_X (BA_TO_COL (cursor_addr)),
X		ROW_TO_Y (BA_TO_ROW (cursor_addr)),
X		COL_TO_X (1),
X		ROW_TO_Y (1),
X		PIX_SET^PIX_DST
X	    );
X	else
X	    pw_writebackground (
X		pixwin,
X		COL_TO_X (BA_TO_COL (cursor_addr)),
X		ROW_TO_Y (BA_TO_ROW (cursor_addr) + 1) - 1,
X		COL_TO_X (1),
X		1,
X		PIX_SET^PIX_DST
X	    );
X    }
X    cursor_addr = baddr;
X    if (cursor_displayed) {
X	if (cursor_alt)
X	    pw_writebackground (
X		pixwin,
X		COL_TO_X (BA_TO_COL (cursor_addr)),
X		ROW_TO_Y (BA_TO_ROW (cursor_addr)),
X		COL_TO_X (1),
X		ROW_TO_Y (1),
X		PIX_SET^PIX_DST
X	    );
X	else
X	    pw_writebackground (
X		pixwin,
X		COL_TO_X (BA_TO_COL (cursor_addr)),
X		ROW_TO_Y (BA_TO_ROW (cursor_addr) + 1) - 1,
X		COL_TO_X (1),
X		1,
X		PIX_SET^PIX_DST
X	    );
X    }
X    timer_release ();
X}
X
X
X/*
X * Redraw the entire screen.
X */
Xscreen_disp ()
X{
X    register int	baddr, sbaddr;
X    register u_char	ch;
X    bool		is_zero, is_high;
X
X    cursor_off ();
X    formatted = FALSE;
X    baddr = 0;
X    do {
X	if (IS_FA (screen_buf[baddr])) {
X	    formatted = TRUE;
X	    break;
X	}
X	INC_BA (baddr);
X    } while (baddr != 0);
X    if (formatted) {	/* formatted display */
X	sbaddr = baddr;
X	do {
X	    is_zero = FA_IS_ZERO (screen_buf[baddr]);
X	    is_high = FA_IS_HIGH (screen_buf[baddr]);
X	    do {	/* display the field */
X		INC_BA (baddr);
X		if (is_zero)
X		    ch = CG_BLANK;
X		else {
X		    ch = screen_buf[baddr];
X		    /* this if xlates lowercase to uppercase */
X		    if (mono_case && ((ch & 0xE0) == 0x40 || (ch & 0xE0) == 0x80))
X			ch |= 0x20;
X		}
X		PW_CHAR (
X		    pixwin,
X		    COL_TO_X (BA_TO_COL (baddr)),
X		    ROW_TO_Y (BA_TO_ROW (baddr)),
X		    PIX_SRC, ch
X		);
X		if (is_high)
X		    PW_CHAR (
X			pixwin,
X			COL_TO_X (BA_TO_COL (baddr)) + 1,
X			ROW_TO_Y (BA_TO_ROW (baddr)),
X			PIX_SRC|PIX_DST, ch
X		    );
X	    } while (!IS_FA (screen_buf[baddr]));
X	} while (baddr != sbaddr);
X    }
X    else {		/* unformatted display */
X	baddr = 0;
X	do {
X	    ch = screen_buf[baddr];
X	    /* this if xlates lowercase to uppercase */
X	    if (mono_case && ((ch & 0xE0) == 0x40 || (ch & 0xE0) == 0x80))
X		ch |= 0x20;
X	    PW_CHAR (
X		pixwin,
X		COL_TO_X (BA_TO_COL (baddr)),
X		ROW_TO_Y (BA_TO_ROW (baddr)),
X		PIX_SRC, ch
X	    );
X	    INC_BA (baddr);
X	} while (baddr != 0);
X    }
X    cursor_on ();
X}
X
X
X/*
X * Set the formatted screen flag.  A formatted screen is a screen that
X * has at least one field somewhere on it.
X */
Xset_formatted ()
X{
X    register int	baddr;
X
X    formatted = FALSE;
X    baddr = 0;
X    do {
X	if (IS_FA (screen_buf[baddr])) {
X	    formatted = TRUE;
X	    break;
X	}
X	INC_BA (baddr);
X    } while (baddr != 0);
X}
X
X
X/*
X * Find the field attribute for the given buffer address.
X */
Xu_char	*
Xget_field_attribute (baddr)
Xregister int	baddr;
X{
X    static u_char	fake_fa;
X    int			sbaddr;
X
X    sbaddr = baddr;
X    do {
X	if (IS_FA (screen_buf[baddr]))
X	    return (&(screen_buf[baddr]));
X	DEC_BA (baddr);
X    } while (baddr != sbaddr);
X    fake_fa = 0xE0;
X    return (&fake_fa);
X}
X
X
X/*
X * Update the character on the screen addressed by the given buffer address
X * from the off-screen buffer.
X */
Xscreen_update (baddr, fa)
Xregister int	baddr;
Xu_char		fa;
X{
X    register u_char	ch;
X    bool		is_zero, is_high;
X
X    is_zero = FA_IS_ZERO (fa);
X    is_high = FA_IS_HIGH (fa);
X    if (is_zero)
X	ch = CG_BLANK;
X    else {
X	ch = screen_buf[baddr];
X	/* this if xlates lowercase to uppercase */
X	if (mono_case && ((ch & 0xE0) == 0x40 || (ch & 0xE0) == 0x80))
X	    ch |= 0x20;
X    }
X    PW_CHAR (
X	pixwin,
X	COL_TO_X (BA_TO_COL (baddr)),
X	ROW_TO_Y (BA_TO_ROW (baddr)),
X	PIX_SRC, ch
X    );
X    if (is_high)
X	PW_CHAR (
X	    pixwin,
X	    COL_TO_X (BA_TO_COL (baddr)) + 1,
X	    ROW_TO_Y (BA_TO_ROW (baddr)),
X	    PIX_SRC|PIX_DST, ch
X	);
X}
X
X
X/*
X * Toggle mono-/dual-case mode.
X */
Xchange_case (mono)
Xbool	mono;
X{
X    if (mono_case != mono) {
X	mono_case = mono;
X	screen_disp ();
X    }
X}
X
X
X/*
X * Interpret an incoming 3270 datastream.
X */
Xnet_process (buf, buflen)
Xu_char	*buf;
Xint	buflen;
X{
X    switch (buf[0]) {	/* 3270 command */
X	case CMD_EAU:	/* erase all unprotected */
X	    do_erase_all_unprotected ();
X	    break;
X	case CMD_EWA:	/* erase/write alternate */
X	    /* on 3278-2, same as erase/write.  fallthrough */
X	case CMD_EW:	/* erase/write */
X	    bzero ((char *) screen_buf, sizeof (screen_buf));
X	    buffer_addr = 0;
X	    cursor_off ();
X	    pw_writebackground (pixwin, 0, 0, COL_TO_X (COLS), ROW_TO_Y (ROWS), PIX_CLR);
X	    cursor_move (0);
X	    /* fallthrough into write */
X	case CMD_W:	/* write */
X	    do_write (buf, buflen);
X	    break;
X	case CMD_RB:	/* read buffer */
X	    do_read_buffer ();
X	    break;
X	case CMD_RM:	/* read modifed */
X	    do_read_modified ();
X	    break;
X	case CMD_NOP:	/* no-op */
X	    break;
X	default:
X	    /* unknown 3270 command */
X	    exit (1);
X    }
X}
X
X
X/*
X * Process a 3270 Read-Modified command and transmit the data back to the
X * host.
X */
Xdo_read_modified ()
X{
X    register int	baddr, sbaddr;
X
X    obptr = &obuf[0];
X    if (aid != AID_PA1 && aid != AID_PA2
X    &&  aid != AID_PA3 && aid != AID_CLEAR) {
X	if (aid == AID_SYSREQ) {
X	    *obptr++ = 0x01;	/* soh */
X	    *obptr++ = 0x5B;	/*  %  */
X	    *obptr++ = 0x61;	/*  /  */
X	    *obptr++ = 0x02;	/* stx */
X	}
X	else {
X	    *obptr++ = aid;
X	    *obptr++ = code_table[(cursor_addr >> 6) & 0x3F];
X	    *obptr++ = code_table[cursor_addr & 0x3F];
X	}
X	baddr = 0;
X	if (formatted) {
X	    /* find first field attribute */
X	    do {
X		if (IS_FA (screen_buf[baddr]))
X		    break;
X		INC_BA (baddr);
X	    } while (baddr != 0);
X	    sbaddr = baddr;
X	    do {
X		if (FA_IS_MODIFIED (screen_buf[baddr])) {
X		    INC_BA (baddr);
X		    *obptr++ = ORDER_SBA;
X		    *obptr++ = code_table[(baddr >> 6) & 0x3F];
X		    *obptr++ = code_table[baddr & 0x3F];
X		    do {
X			if (screen_buf[baddr])
X			    *obptr++ = cg2ebc[screen_buf[baddr]];
X			INC_BA (baddr);
X		    } while (!IS_FA (screen_buf[baddr]));
X		}
X		else {	/* not modified - skip */
X		    do {
X			INC_BA (baddr);
X		    } while (!IS_FA (screen_buf[baddr]));
X		}
X	    } while (baddr != sbaddr);
X	}
X	else {
X	    do {
X		if (screen_buf[baddr])
X		    *obptr++ = cg2ebc[screen_buf[baddr]];
X		INC_BA (baddr);
X	    } while (baddr != 0);
X	}
X    }
X    else
X	*obptr++ = aid;
X    net_output (obuf, obptr - obuf);
X}
X
X
X/*
X * Process a 3270 Read-Buffer command and transmit the data back to the
X * host.
X */
Xdo_read_buffer ()
X{
X    register int	baddr;
X    u_char		fa;
X
X    obptr = &obuf[0];
X    *obptr++ = aid;
X    *obptr++ = code_table[(cursor_addr >> 6) & 0x3F];
X    *obptr++ = code_table[cursor_addr & 0x3F];
X    baddr = 0;
X    do {
X	if (IS_FA (screen_buf[baddr])) {
X	    *obptr++ = ORDER_SF;
X	    fa = 0x00;
X	    if (FA_IS_PROTECTED (screen_buf[baddr]))
X		fa |= 0x20;
X	    if (FA_IS_NUMERIC (screen_buf[baddr]))
X		fa |= 0x10;
X	    if (FA_IS_MODIFIED (screen_buf[baddr]))
X		fa |= 0x01;
X	    fa |= ((screen_buf[baddr] | FA_INTENSITY) << 2);
X	    *obptr++ = fa;
X	}
X	else
X	    *obptr++ = cg2ebc[screen_buf[baddr]];
X	INC_BA (baddr);
X    } while (baddr != 0);
X    net_output (obuf, obptr - obuf);
X}
X
X
X/*
X * Process a 3270 Erase All Unprotected command.
X */
Xdo_erase_all_unprotected ()
X{
X    register int	baddr, sbaddr;
X    u_char		fa;
X    bool		f;
X
X    cursor_off ();
X    if (formatted) {
X	/* find first field attribute */
X	baddr = 0;
X	do {
X	    if (IS_FA (screen_buf[baddr]))
X		break;
X	    INC_BA (baddr);
X	} while (baddr != 0);
X	sbaddr = baddr;
X	f = FALSE;
X	do {
X	    fa = screen_buf[baddr];
X	    if (!FA_IS_PROTECTED (fa)) {
X		screen_buf[baddr] &= ~FA_MODIFY;
X		do {
X		    INC_BA (baddr);
X		    if (!f) {
X			cursor_move (baddr);
X			f = TRUE;
X		    }
X		    if (!IS_FA (screen_buf[baddr])) {
X			screen_buf[baddr] = CG_NULLBLANK;
X			screen_update (baddr, fa);
X		    }
X		} while (!IS_FA (screen_buf[baddr]));
X	    }
X	    else {
X		do {
X		    INC_BA (baddr);
X		} while (!IS_FA (screen_buf[baddr]));
X	    }
X	} while (baddr != sbaddr);
X	if (!f)
X	    cursor_move (0);
X    }
X    else {
X	bzero ((char *) screen_buf, sizeof (screen_buf));
X	pw_writebackground (pixwin, 0, 0, COL_TO_X (COLS), ROW_TO_Y (ROWS), PIX_CLR);
X	buffer_addr = 0;
X	cursor_move (0);
X    }
X    cursor_on ();
X    aid = AID_NO;
X    key_Reset ();
X}
X
X
X/*
X * Process a 3270 Write command.
X */
Xdo_write (buf, buflen)
Xu_char	buf[];
Xint	buflen;
X{
X    register u_char	*cp;
X    register int	baddr;
X    u_char		*current_fa;
X    bool		last_cmd;
X    bool		wcc_keyboard_restore, wcc_sound_alarm;
X
X    buffer_addr = cursor_addr;
X    wcc_sound_alarm = WCC_SOUND_ALARM (buf[1]);
X    wcc_keyboard_restore = WCC_KEYBOARD_RESTORE (buf[1]);
X    status_disp (8, CG_LOCK);
X    status_disp (9, CG_BLANK);
X    status_disp (10, CG_CS);
X    status_disp (11, CG_CY);
X    status_disp (12, CG_CS);
X    status_disp (13, CG_CT);
X    status_disp (14, CG_CE);
X    status_disp (15, CG_CM);
X    if (WCC_RESET_MDT (buf[1])) {
X	baddr = 0;
X	do {
X	    if (IS_FA (screen_buf[baddr]))
X		screen_buf[baddr] &= ~FA_MODIFY;
X	    INC_BA (baddr);
X	} while (baddr != 0);
X    }
X    last_cmd = TRUE;
X    cursor_off ();
X    current_fa = get_field_attribute (buffer_addr);
X    for (cp = &buf[2]; cp < (buf + buflen); cp++) {
X	switch (*cp) {
X	    case ORDER_GE:	/* graphic escape - ignore */
X		last_cmd = TRUE;
X		break;
X	    case ORDER_SF:	/* start field */
X		cp++;		/* skip field attribute */
X		screen_buf[buffer_addr] = FA_BASE;
X		if (*cp & 0x20)
X		    screen_buf[buffer_addr] |= FA_PROTECT;
X		if (*cp & 0x10)
X		    screen_buf[buffer_addr] |= FA_NUMERIC;
X		if (*cp & 0x01)
X		    screen_buf[buffer_addr] |= FA_MODIFY;
X		screen_buf[buffer_addr] |= (*cp >> 2) & FA_INTENSITY;
X		current_fa = &(screen_buf[buffer_addr]);
X		screen_update (buffer_addr, *current_fa);
X		formatted = TRUE;
X		INC_BA (buffer_addr);
X		last_cmd = TRUE;
X		break;
X	    case ORDER_SBA:	/* set buffer address */
X		cp += 2;	/* skip buffer address */
X		if ((*(cp-1) & 0xC0) == 0x00) /* 14-bit binary */
X		    buffer_addr = ((*(cp-1) & 0x3F) << 8) | *cp;
X		else	/* 12-bit coded */
X		    buffer_addr = ((*(cp-1) & 0x3F) << 6) | (*cp & 0x3F);
X		buffer_addr %= (COLS * ROWS);
X		current_fa = get_field_attribute (buffer_addr);
X		last_cmd = TRUE;
X		break;
X	    case ORDER_IC:	/* insert cursor */
X		cursor_move (buffer_addr);
X		last_cmd = TRUE;
X		break;
X	    case ORDER_PT:	/* program tab */
X		baddr = buffer_addr;
X		while (TRUE) {
X		    if (IS_FA (screen_buf[baddr])
X		    &&  (!FA_IS_PROTECTED (screen_buf[baddr]))) {
X			current_fa = &screen_buf[baddr];
X			INC_BA (baddr);
X			buffer_addr = baddr;
X			if (!last_cmd) {
X			    while (!IS_FA (screen_buf[baddr])) {
X				screen_buf[baddr] = CG_NULLBLANK;
X				screen_update (baddr, *current_fa);
X				INC_BA (baddr);
X			    }
X			}
X			break;
X		    }
X		    else {
X			INC_BA (baddr);
X			if (baddr == 0) {
X			    buffer_addr = baddr;
X			    current_fa = get_field_attribute (baddr);
X			    break;
X			}
X		    }
X		}
X		last_cmd = TRUE;
X		break;
X	    case ORDER_RA:	/* repeat to address */
X		cp += 2;	/* skip buffer address */
X		if ((*(cp-1) & 0xC0) == 0x00) /* 14-bit binary */
X		    baddr = ((*(cp-1) & 0x3F) << 8) | *cp;
X		else	/* 12-bit coded */
X		    baddr = ((*(cp-1) & 0x3F) << 6) | (*cp & 0x3F);
X		baddr %= (COLS * ROWS);
X		cp++;		/* skip char to repeat */
X		if (*cp == ORDER_GE)
X		    cp++;
X		if (buffer_addr == baddr) {
X		    screen_buf[buffer_addr] = ebc2cg[*cp];
X		    screen_update (buffer_addr, *current_fa);
X		    INC_BA (buffer_addr);
X		}
X		while (buffer_addr != baddr) {
X		    screen_buf[buffer_addr] = ebc2cg[*cp];
X		    screen_update (buffer_addr, *current_fa);
X		    INC_BA (buffer_addr);
X		}
X		current_fa = get_field_attribute (buffer_addr);
X		last_cmd = TRUE;
X		break;
X	    case ORDER_EUA:	/* erase unprotected to address */
X		cp += 2;	/* skip buffer address */
X		if ((*(cp-1) & 0xC0) == 0x00) /* 14-bit binary */
X		    baddr = ((*(cp-1) & 0x3F) << 8) | *cp;
X		else	/* 12-bit coded */
X		    baddr = ((*(cp-1) & 0x3F) << 6) | (*cp & 0x3F);
X		baddr %= (COLS * ROWS);
X		do {
X		    if (IS_FA (screen_buf[buffer_addr]))
X			current_fa = &(screen_buf[buffer_addr]);
X		    else if (!FA_IS_PROTECTED (*current_fa)) {
X			screen_buf[buffer_addr] = CG_NULLBLANK;
X			screen_update (buffer_addr, *current_fa);
X		    }
X		    INC_BA (buffer_addr);
X		} while (buffer_addr != baddr);
X		current_fa = get_field_attribute (buffer_addr);
X		last_cmd = TRUE;
X		break;
X	    case ORDER_MF:	/* modify field */
X	    case ORDER_SFE:	/* start field extended */
X	    case ORDER_SA:	/* set attribute */
X		/* unsupported 3270 order */
X		break;
X	    default:	/* enter character */
X		screen_buf[buffer_addr] = ebc2cg[*cp];
X		screen_update (buffer_addr, *current_fa);
X		INC_BA (buffer_addr);
X		last_cmd = FALSE;
X		break;
X	}
X    }
X    cursor_on ();
X    set_formatted ();
X    if (wcc_keyboard_restore) {
X	key_Reset ();
X	aid = AID_NO;
X    }
X    if (wcc_sound_alarm)
X	window_bell (canvas);
X}
--End_of_screen.c--
	if test 24454 -ne `wc -c < 'screen.c'`
	then
		echo "`basename $0`: error in" 'screen.c' ": sent 24454 chars, received `wc -c < 'screen.c'`" 1>&2
	fi
fi
if test -f 'README'
then
	echo "`basename $0`: can't extract" 'README' "- file exists" 1>&2
else
	sed 's/^X//' << '--End_of_README--' > 'README'
X
X Copyright 1989 by Georgia Tech Research Corporation, Atlanta, GA.
X Copyright 1988, 1989 by Robert Viduya.
X
X                         All Rights Reserved
X
X
XTwo things to do before compiling and installing 3270tool:
X
X	1.	Copy 3270.font to wherever you want to keep it.  It's the
X		vfont file that 3270tool requires to run.  Change the
X		definition for FONT3270 in the Makefile to point to this file.
X		Also change the man page FILES section.
X
X	2.	If you're compiling on a system with a type-4 keyboard,
X		add "-DTYPE4KBD" to the CFLAGS defintion in the Makefile.
X		This enables the special keyboard mapping described in
X		the manual page.
X	
XTo compile:
X	make
X
XTo install:
X	make install
X
X
XNotes:
X
X3270tool was written as a replacement for tn3270 after I got tired of
Xhaving to remember all the key mappings.  I fanatically wrote it to be as
Xclose to a 3278 as possible.  The font used was created by peering
Xthrough a magnifying glass at a real IBM terminal and copying the
Xsymbols pixel by pixel.  The font encoding doesn't use EBCDIC, but
Xinstead matches the 3270 character generator as documented in chapter
X12 in the "3270 Information Display System - Character Set Reference"
Xmanual.  This actually made some operations easier.  The drawback is
Xthat incoming characters have to be mapped from EBCDIC to the internal
Xmap.  Other manuals used were "3270 Information Display System - Data
XStream Programmer's Reference" and "3270 Information Display System -
X3278 Display Station Operator's Guide".  These manuals, particularly
Xthe Programmer's Reference, are not for casual reading.
X
XSome future enhancements would be nice.  Emulating a real 3270 light
Xpen with the mouse wouldn't be difficult.  Supporting different models
Xof the 3278 so that Erase/Write-Alternate commands changes the screen
Xsize would be a little more difficult.  I don't have a color sun, so I
Xdidn't put in color.  Basic four color support shouldn't be that hard
Xto add.  Extended Field Attributes and Character Attributes are not
Xsupported as well as Programmed Symbol Sets and Partitions.  A
Xmonochrome sun is capable of handling most of these, a color sun
Xis capable of handling all of them.  Printer support would also be nice.
--End_of_README--
	if test 2205 -ne `wc -c < 'README'`
	then
		echo "`basename $0`: error in" 'README' ": sent 2205 chars, received `wc -c < 'README'`" 1>&2
	fi
fi
if test -f 'BtnClear'
then
	echo "`basename $0`: can't extract" 'BtnClear' "- file exists" 1>&2
else
	sed 's/^X//' << '--End_of_BtnClear--' > 'BtnClear'
X/* Format_version=1, Width=32, Height=32, Depth=1, Valid_bits_per_item=16
X */
X	0xFFFF,0xFFFF,0x8000,0x0001,0x8000,0x0001,0x8000,0x0001,
X	0x8000,0x0001,0x8000,0x0001,0x8000,0x0001,0x8000,0x0001,
X	0x8000,0x0001,0x8000,0x0001,0x8000,0x0001,0x8000,0x0001,
X	0x9860,0x0001,0xA421,0x8629,0xA022,0x4135,0xA023,0x8721,
X	0xA422,0x0921,0x9821,0xC521,0x8000,0x0001,0x8000,0x0001,
X	0x8000,0x0001,0x8000,0x0001,0x8000,0x0001,0x8000,0x0001,
X	0x8000,0x0001,0x8000,0x0001,0x8000,0x0001,0x8000,0x0001,
X	0x8000,0x0001,0x8000,0x0001,0x8000,0x0001,0xFFFF,0xFFFF
--End_of_BtnClear--
	if test 541 -ne `wc -c < 'BtnClear'`
	then
		echo "`basename $0`: error in" 'BtnClear' ": sent 541 chars, received `wc -c < 'BtnClear'`" 1>&2
	fi
fi
exit 0
--
Robert Viduya					   robert@shangri-la.gatech.edu
Office of Computing Services
Georgia Institute of Technology					 (404) 894-6296
Atlanta, Georgia	30332-0275