/*!
  @file           ven041.c
  @author         JoergM
  @brief          virtual_terminal Unique Interface to Various Types of Terminals
  @see            

\if EMIT_LICENCE

    ========== licence begin  GPL
    Copyright (c) 2001-2005 SAP AG

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
    ========== licence end



\endif
*/

#define MOD__ "ven041.c:"

#include "geo002.h"
#include "gen04.h"
#include "gen500.h"
#include "geo001.h"
#include "geo57.h"
#include "hen40.h"
/* includes ven00tc */

#define	VT_EOF			0	/* end of field */
#define	VT_SONCF		1	/* start of non-continuation field */
#define	VT_SOCF			2	/* start of continuation field */
#define	FIELD_DELIMITERS	3	/* number of field delimiter types */

#define LINEVALUES              20	/* debug line hex bytes */
#define VT_LABEL_SIZE           8
#define SK_NUMBER               9
#define BLANK                   (' ')
#define CHBLANK                 ((chtype)' ')
#define DELTA_TAB               8

/*
 *  Virtual Terminal Attributes contain an index into an array
 *  of curses attributes (blink,bold,colors,...).
 *  The index within the attribute byte implies a certain table size.
 *  The algorithm for the extraction of the index from the
 *  attribute byte must match with the table size.
 */
#define	MAXATTRIBUTES		16
#define	ATTR_TO_IDX(x)		( (x) & 15 )
#define	ATTR(x)			( sql04_attrib_table [ ATTR_TO_IDX(x) ].att )

#define is_invisible(x)		( sql04_attrib_table [ ATTR_TO_IDX(x) ].invis )
#define is_protect(x)		( ( (x) & BIT_UNPROTECTED ) == 0 )
#define is_unprot(x)		( ( (x) & BIT_UNPROTECTED ) != 0 )
#define is_mixed(x)		( ( (x) & BIT_MIXED ) != 0 )

#define LINE(x)                 ((x) / sql04_cols)
#define COLUMN(x)               ((x) % sql04_cols)

#ifdef  DEBUG_RTE
static	char			*DEBUGFILE = "/tmp/vt.diag" ;
static	FILE			*debugfp = NULL;
#define	DBGSCREEN(_s,_a,_l,_t)	{debug_screen((UCHAR*)(_s), \
				(UCHAR*)(_a),(int)(_l),(_t));}
#else	/*DEBUG_RTE*/
#define	DBGSCREEN(_s,_a,_l,_t)	{}
#endif	/*DEBUG_RTE*/

/*--------------------------------------------------------------------------*/
/*------------------    GLOBAL FUNCTION PROTOTYPES     ---------------------*/
/*--------------------------------------------------------------------------*/

global	void			sqlcton ();
global	void			sqlctoff ();
global	void			sqlctio ();
global	void			sqlcttable ();
global	void			sqlctgtable ();
global	void			sqltrelease ();
global	void			sqlthold ();
global	void			sqltermvar ();
#ifdef	OLD
global	void			sqltmap ();
#endif	/*OLD*/
global	void			sqldbgvt (char *, ...);

/*--------------------------------------------------------------------------*/
/*------------------  EXTERNAL FUNCTION PROTOTYPES     ---------------------*/
/*--------------------------------------------------------------------------*/

extern	char			*sqlerrs ();
extern	void			sqlabort ();
extern	void			sql47_ctop ();

extern	void			exit ();

/*--------------------------------------------------------------------------*/
/*------------------     LOCAL FUNCTION PROTOTYPES     ---------------------*/
/*--------------------------------------------------------------------------*/

static	void			sql04_retkey_array ();
static	void			sql04_attrib_array ();
static	void			sql04_colors_array ();
static	void			sql04_update_colors ();
static	chtype			sql04_convert_color ();

static	void			sql04_get_options ();
static	void			sql04_full_screen ();
static	void			sql04_part_screen ();
static	void			sql04_write_sysline ();
static	void			sql04_write_softkeys ();
static	int			sql04_get_key ();
static	int			sql04_input_character ();
static	void			sql04_put_charstring ();

static	void			sql04_init_ins ();
static	void			sql04_reset_ins ();
static	void			sql04_insert_on ();
static	void			sql04_insert_off ();

static	void			sql04_local_keys ();
static	void			sql04_delete ();
static	int			sql04_rubout ();
static	void			sql04_erase_to_eof ();
static	int			sql04_shift_left ();
static	int			sql04_shift_right ();
static	void			sql04_next_unprot ();
static	int			sql04_next_field ();
static	int			sql04_prev_field ();
static	void			sql04_position_changed ();

static	int			sql04_in_field ();
static	int			sql04_find_next ();
static	int			sql04_find_prev ();
static	int			sql04_find_unprot ();
static	int			sql04_find_eof ();

#ifdef	MARK_NOCH_ZU_TUN
static	void			sql04_write_marked ();
static	boolean			sql04_in_marked_area ();
#endif
static	void			sql04_addch ();
static	void			sql04_beep_flash ();

#ifdef DEBUG_RTE
static	void			debug_init ();
static	SIGNALFUNCTYPE		debug_catch ();
static	void			debug_screen ();
static	void			debug_hexline ();
static	void			debug_charline ();
static	void			debug_key_array ();
#endif

/*--------------------------------------------------------------------------*/
/*----------------     EXTERNAL DATA DEFINITIONS     -----------------------*/
/*--------------------------------------------------------------------------*/

extern	int			sql01_vt_clear ;
#ifdef KANJI
extern	char			*sql01_dblang ;
#endif

/*--------------------------------------------------------------------------*/
/*------------------     LOCAL DATA DEFINITIONS     ------------------------*/
/*--------------------------------------------------------------------------*/

struct attrib_info
{
	chtype		att ;           /* curses attribute */
	boolean		invis ;         /* invisible attribute is set */
	boolean		changed ;       /* modified by sqlttable */
	enum1		fg ;            /* foreground color */
	enum1		bg ;            /* background color */
};
static	struct attrib_info	sql04_attrib_table [ MAXATTRIBUTES ];

static	int	sql04_turned_on ;        /* 'sqlton' successfully executed */
static	int	sql04_released ;         /* 'sqltrelease' executed */
static	int	sql04_has_colors ;       /* the terminal has colors */
static	int	sql04_screen_size ;      /* size of screen in bytes */
static	int	sql04_lines ;            /* LINES modified by sqlton */
static	int	sql04_cols ;             /* COLS at sqlton */
static	int	sql04_tio_count ;        /* number of calls to 'sqltio' */
static	int	sql04_term_initialized ; /* terminal initialization done */
static	int	sql04_attrib_changed ;   /* attributes changed by 'sqlttable' */
static	int	sql04_first_linechg ;    /* first line with screen modific. */
static	int	sql04_last_linechg ;     /* last line with screen modific. */
static	int	sql04_ring_bell ;        /* sound terminal's bell */
static	int	sql04_mark_option ;      /* specifies, how to mark text */
static	int	sql04_wait_for_input ;   /* wait for input after output */
static	int	sql04_usage_mode ;       /* VT_FORM/VT_EDIT, for CR and TAB */
static	int	sql04_return_on_last ;   /* if cursor moves beyond last field */
static	int	sql04_return_on_first ;  /* if cursor moves ahead first field */
static	int	sql04_enable_charkey ;   /* return after printable character */
static	int	sql04_enable_ctrlkey ;   /* return after control character */
#ifndef	SAFE_CTRLKEY
static	int	sql04_old_enable_ctrlkey ;
#endif
static	int	sql04_position ;         /* cursor position index in buffer */
static	int	sql04_displpos ;         /* cursor position index on display */
static	int	sql04_insert_mode ;      /* if in insert mode */
static	int	sql04_insert_save ;      /* insert_mode at begin of sqlctio */
static	int	sql04_before_first ;     /* if before first unprotected char */
static	int	sql04_behind_last ;      /* if behind last unprotected char */
static	int	sql04_screen_changed ;   /* screen has been modified */

static	TERMIO_INFO   sql04_termio_extern ;	/* extern modes */
static	TERMIO_INFO   sql04_termio_intern ;	/* intern modes */
static	TERMIO_INFO   sql04_termio_ctlkey ;	/* modes for VTKEY_CONTROL */

static	UCHAR	*sql04_tio_screen ;             /* screen argument of sqltio */
static	UCHAR	*sql04_tio_attrib ;             /* attrib argument of sqltio */

static	UCHAR   *sql04_save_screen ;            /* saved screen contents */
static	UCHAR   *sql04_save_attrib ;            /* saved attributes contents */
#ifdef	PRINT_LINES_CHANGED
static	UCHAR	*sql04_check_screen ;           /* last input screen contents */
#endif
#ifdef KANJI
typedef	enum1			tsp8_uni_error ;
#define		uni_ok			0
#define		uni_no_such_encoding	1
#define		uni_not_translatable	2
#define		uni_dest_too_short	3
#define		uni_src_too_short	4
#define		uni_is_singlebyte	5
#define		uni_is_multibyte	6
#define		uni_is_incomplete	7

typedef	enum1			tsp8_uni_load_error ;
#define		uni_load_ok		0

static	void			*sql04_encoding_ptr ;  /* uni_trans */
static	tsp00_Int2		sql04_encoding_cnt ;   /* uni_trans */
static	tsp00_Int2		sql04_codeset ;        /* uni_trans */
static	UCHAR			*sql04_charmodes ;     /* character modes */
#endif

#ifdef	SCRLIB
static	int	sql04_sk_count ;                /* number of sofkeys */
#endif
static	UCHAR	sql04_save_sys_text [ 132 ];	/* saved message line */
static	UCHAR	sql04_save_sys_attr [ 132 ];	/* saved message attributes */
static	char	sql04_save_sk_text [ 2 * VT_LABEL_SIZE * SK_NUMBER ];

static	boolean	sql04_marked ;           /* if mark key pressed */
static	boolean	sql04_mark_on ;          /* if 'sqltio' requested mark */
static	int	sql04_mark_apos ;        /* startpos of marked field */
static	int	sql04_mark_epos ;        /* endpos of marked field */
static	chtype	sql04_mark_attrib ;      /* curses attribute for marked areas */

#ifdef	DEBUG_RTE
static	char	*sql04_color_name [] = { "b/w" , "white" , "black" , "red" ,
			  "green" , "yellow" , "blue" , "magenta" , "cyan" };
#endif

/*--------------------------------------------------------------------------*/
/*-----------------------     EXECUTABLE CODE     --------------------------*/
/*==========================================================================*/

/*
 *  'sqlton' initializes the virtual terminal.
 */

#undef MF__
#define MF__ MOD__"sqlcton"
global	void	sqlcton ( 
char			*returnkeys_array ,
tsp00_Int2		*size_returnkeys ,
char			*attributes_array ,
tsp00_Int2		*size_attributes ,
char			*colors_array ,
tsp00_Int2		*size_colors ,
boolean			*c_has_sysline ,
char			*c_label ,
tsp00_Int2		*maxlines ,
tsp00_Int2		*maxcols ,
UCHAR			**cscreen_buf ,
UCHAR			**cattrib_buf ,
boolean			*cgraphic ,
boolean			*cmark ,
boolean			*cwindows ,
boolean			*c_ok )
{

    int                 rc ;
    int                 idx ;
    SIGNALFUNCTYPE	(* oldsigint)();


    DBGIN;

    /*
     *  Initialize the return code.
     */
    *c_ok = FALSE ;

    if ( sql04_turned_on )
    {
		DBG1 (( MF__,"sqlton already performed\n" ));
		return ;
    }

    /*
     *  Check, if the PASCAL<->C mapper (ven04) is compatible.
     */
    rc = 0 ;
    if ( *size_returnkeys != VTKEY_LAST )
    {
	DBG1(( MF__, "sqlton internal: wrong no of key set elems\n" ))
	DBG1(( MF__, "size_returnkeys      = %d\n", *size_returnkeys ))
	DBG1(( MF__, "VTKEY_LAST           = %d\n", VTKEY_LAST ))
	rc ++ ;
    }
    if ( *size_attributes != VTA_LAST )
    {
	DBG1(( MF__, "sqlton internal: wrong no of attrib set elems\n" ))
	DBG1(( MF__, "size_attributes      = %d\n", *size_attributes ))
	DBG1(( MF__, "VTA_LAST             = %d\n", VTA_LAST ))
	rc ++ ;
    }
    if ( *size_colors != VTC_LAST )
    {
	DBG1(( MF__, "sqlton internal: wrong no of color set elems\n" ))
	DBG1(( MF__, "size_colors          = %d\n", *size_colors ))
	DBG1(( MF__, "VTC_LAST             = %d\n", VTC_LAST ))
	rc ++ ;
    }
    if ( rc ) return ;

    /*
     *  Get all required environment strings
     *  and, if necessary, export TERM and TERMINFO.
     */
    rc = sql04_get_environment ();
    if ( rc < 0 ) return ;

#if T31 || T35 || RM6
    /*
     *  Initialize the standard character classification (ctype).
     */
    (void) setchrclass ( (char*) 0 );
#endif

    /*
     *  Read our own character classification file.
     *  The only class of interest is 'isprint'.
     *  All non-space characters in this file are treated as printable.
     */
    rc = sql04_read_chrclass ();
    if ( rc < 0 ) return ;

    /*
     *  Allow interrupts during initialization.
     */
    oldsigint = signal ( SIGINT , SIG_DFL );

    /*
     *  Save the termio values as they were outside of curses.
     */
    (void) GET_TERMIO ( 0 , &sql04_termio_extern );

#if OSF1
    /*
     *  Prepare a termio structure for use inside curses
     */
    COPY ( &sql04_termio_intern , &sql04_termio_extern ,
				    sizeof(sql04_termio_intern) );
    /*
     *  Adjust the termio flags which are not equally set by all
     *  curses implementations.
     */
    sql04_termio_intern.c_iflag &= ~(ISTRIP|INLCR|IGNCR|ICRNL);
    sql04_termio_intern.c_oflag &= ~(ONLCR|OCRNL|TABDLY);
    sql04_termio_intern.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK);

    /* sql04_termio_intern.c_iflag &= ~(IXON); don't catch Ctrl-Q and Ctrl-S */
    for ( idx = 0 ; idx < CC_SIZE ; idx ++ ) sql04_termio_intern.c_cc[idx] = 0 ;
    sql04_termio_intern.c_cc[VINTR ] = ('C'&0x1f);
    sql04_termio_intern.c_cc[VQUIT ] = ('Y'&0x1f);
    sql04_termio_intern.c_cc[VMIN  ] = 1 ;
    sql04_termio_intern.c_cc[VTIME ] = 1 ;

#if defined(VSTART) && (VSTART < CC_SIZE)
    sql04_termio_intern.c_cc[VSTART] = ('Q'&0x1f);
#endif
#if defined(VSTOP) && (VSTOP < CC_SIZE)
    sql04_termio_intern.c_cc[VSTOP ] = ('S'&0x1f); 
#endif
#endif /*OSF1*/
#if OSF1
    /* make this mode always active for OSF1, switching is impossible on OSF1 */
    (void) SET_TERMIO ( 0 , &sql04_termio_intern );
#endif

    /*
     *  Initialize curses.
     *  'initscr' will never return unsuccessful.
     *  On error it writes a message and exits.
     *  If successful it returns stdscr.
     *  Verify this here, just in case...
     */
    if ( (initscr() != stdscr) || (stdscr == 0) )
    {
	DBG1(( MF__, "sqlton: error in curses-initscr() \n" ))
	(void) SET_TERMIO ( 0 , &sql04_termio_extern );
	DBG1 (( MF__,"restored external terminal settings \n" ))
	(void) signal ( SIGINT , oldsigint );
	return ;
    }

    /*
     *  Avoid using tabs.
     *  On some systems tabs are unreliably expanded by terminal driver.
     */
    init_tabs = 0 ;
    tab = 0 ;
    set_tab = 0 ;
    back_tab = 0 ;
    clear_all_tabs = 0 ;

#if ! OSF1 /* already taken care of -- see SET_TERMIO ( above ) */
    /*
     *  Set input modes.
     */
    (void) noecho ();
    (void) cbreak ();
    (void) nonl ();
#endif

#if ! OSF1 /* can't call GET_TERMIO() during curses mode */
    /*
     *  Save the termio values as they are inside of curses.
     */
    (void) GET_TERMIO ( 0 , &sql04_termio_intern );
#endif

#if ! OSF1 /* can't call SET_TERMIO() during curses mode */
    /*
     *  Adjust the termio flags which are not equally set by all
     *  curses implementations.
     */
    sql04_termio_intern.c_iflag &= ~(ISTRIP|INLCR|IGNCR|ICRNL);
    sql04_termio_intern.c_oflag &= ~(ONLCR|OCRNL|TABDLY);
    sql04_termio_intern.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK);
    (void) SET_TERMIO ( 0 , &sql04_termio_intern );
    DBG1 (( MF__,"restored internal terminal settings \n" ))

    /*
     *  Prepare a termio structure for later use with VTKEY_CONTROL.
     */
    COPY ( &sql04_termio_ctlkey , &sql04_termio_intern ,
				sizeof(sql04_termio_ctlkey) );
    /* sql04_termio_ctlkey.c_iflag &= ~(IXON); don't catch Ctrl-Q and Ctrl-S */
    for ( idx = 0 ; idx < CC_SIZE ; idx ++ ) sql04_termio_ctlkey.c_cc[idx] = 0 ;
    sql04_termio_ctlkey.c_cc[VINTR ] = ('C'&0x1f);
    sql04_termio_ctlkey.c_cc[VQUIT ] = ('Y'&0x1f);
    sql04_termio_ctlkey.c_cc[VMIN  ] = 1 ;
    sql04_termio_ctlkey.c_cc[VTIME ] = 1 ;
#if defined(VSTART) && (VSTART < CC_SIZE)
    sql04_termio_ctlkey.c_cc[VSTART] = ('Q'&0x1f);
#endif
#if defined(VSTOP) && (VSTOP < CC_SIZE)
    sql04_termio_ctlkey.c_cc[VSTOP ] = ('S'&0x1f);
#endif
#endif /*! OSF1*/

    /*
     *  Initialize the graphic characters conversion table.
     */
    *cgraphic = sql04_init_graphic_table ();
    DBG1 (( MF__,"has_graphic %d \n", *cgraphic ))

    /*
     *  Fill the available attributes table.
     */
    sql04_attrib_array ( attributes_array );

    /*
     *  Initialize the color feature.
     */
#if A_COLOR
#ifndef A_BGCOLOR
    (void) start_color ();
#endif /*A_BGCOLOR*/
#endif /*A_COLOR*/

    /*
     *  Fill the available colors table.
     */
    sql04_colors_array ( colors_array );

    /*
     *  Initialize the key list.
     */
    rc = sql04_make_key_list ();
    if ( rc < 0 )
    {
	(void) endwin ();
	(void) SET_TERMIO ( 0 , &sql04_termio_extern );
	DBG1 (( MF__,"restored external terminal settings \n" ))
	(void) signal ( SIGINT , oldsigint );
	return ;
    }

    /*
     *  Fill the available returnkeys table.
     */
    sql04_retkey_array ( returnkeys_array );

    /*
     *  After initialization we can return to the normal signal handling.
     */
    (void) signal ( SIGINT , oldsigint );

    /*
     *  if the keyboard has a MARK-Key and the terminal is able to display
     *  inverse- or blink-alltributes, then the virtual terminal provides
     *  the mark-functionalities
     */
    if ( enter_reverse_mode )
	sql04_mark_attrib = A_REVERSE ;
    else if ( enter_blink_mode )
	    sql04_mark_attrib = A_BLINK ;
	else
	    sql04_mark_attrib = 0 ;
/*JH
    *cmark = ( key_mark && sql04_mark_attrib ) ? 1 : ( sql04_mark_attrib = 0 );
*/
    *cmark = 0 ;        /* later */
    DBG1 (( MF__,"marking possible %d \n", *cmark ))

    /*
     *  Windows are not yet implemented.
     */
    *cwindows = 0 ;

    /*
     *  Get the lines and columns of the terminal.
     *  If the application runs in a window, the current window size
     *  will be used throughout the whole session.
     */
    sql04_lines = LINES ;
    sql04_cols  = COLS ;

#ifdef SCRLIB
    *c_has_sysline = TRUE ;
    *c_label = 1 ; /* short soft key labels */
    sql04_sk_count = SK_NUMBER ;
    /* Falls es keine hardwaremaessige Softkeyzeile gibt , vermindern sich die
       nutzbaren Zeilen um 1 */
    if ( ! f_skzex() ) sql04_lines -- ;
#else /*SCRLIB*/
    *c_has_sysline = has_status_line && to_status_line && from_status_line ;
    if ( sql04_hif_softkeys )
	*c_label = 1 ; /* short soft key labels */
    else
	*c_label = 0 ; /* no soft key labels */
#endif /*SCRLIB*/
    DBG1 (( MF__,"has_sysline %d \n", *c_has_sysline ))

    *maxlines = (tsp00_Int2) sql04_lines ;
    *maxcols  = (tsp00_Int2) sql04_cols ;
    sql04_screen_size = sql04_lines * sql04_cols ;
    DBG1 (( MF__,"maxlines    %d \n", *maxlines ))
    DBG1 (( MF__,"maxcols     %d \n", *maxcols ))
    DBG1 (( MF__,"screen_size %d \n", sql04_screen_size ))

    /*
     *  Allocate buffers for screen and attribute contents.
     */
    ALLOC_MEM_EO57( (void **)cscreen_buf, sql04_screen_size );
    ALLOC_MEM_EO57( (void **)cattrib_buf, sql04_screen_size );
    ALLOC_MEM_EO57( (void **)&sql04_save_screen, sql04_screen_size );
    ALLOC_MEM_EO57( (void **)&sql04_save_attrib, sql04_screen_size );
#ifdef	PRINT_LINES_CHANGED
    ALLOC_MEM_EO57( (void **)&sql04_check_screen, sql04_screen_size );
#endif
#ifdef KANJI
    ALLOC_MEM_EO57( (void **)&sql04_charmodes, sql04_screen_size );
#endif

    if (    !*cscreen_buf
	 || !*cattrib_buf
         || !sql04_save_screen
	 || !sql04_save_attrib
#ifdef	PRINT_LINES_CHANGED
         || ! sql04_check_screen
#endif
#ifdef KANJI
         || ! sql04_charmodes
#endif
       )
    {
	(void) endwin ();
	(void) SET_TERMIO ( 0 , &sql04_termio_extern );
	DBG1 (( MF__,"restored external terminal settings \n" ))
	return ;
    }
    DBG1 (( MF__,"cscreen_buf     0x%08lx \n", (long) *cscreen_buf ))
    DBG1 (( MF__,"cattrib_buf     0x%08lx \n", (long) *cattrib_buf ))
    DBG1 (( MF__,"save_screen     0x%08lx \n", (long) sql04_save_screen ))
    DBG1 (( MF__,"save_attrib     0x%08lx \n", (long) sql04_save_attrib ))
#ifdef	PRINT_LINES_CHANGED
    DBG1 (( MF__,"check_screen    0x%08lx \n", (long) sql04_check_screen ))
#endif
#ifdef KANJI
    DBG1 (( MF__,"charmodes       0x%08lx \n", (long) sql04_charmodes   ))
#endif

    FILL ( *cscreen_buf        , ' '  , sql04_screen_size );
    FILL ( *cattrib_buf        , 0    , sql04_screen_size );
    FILL ( sql04_save_screen   , ' '  , sql04_screen_size );
    FILL ( sql04_save_attrib   , 0    , sql04_screen_size );
#ifdef	PRINT_LINES_CHANGED
    FILL ( sql04_check_screen  , 0xff , sql04_screen_size );
#endif
#ifdef KANJI
    FILL ( sql04_charmodes     , 0    , sql04_screen_size );
#endif
    FILL ( sql04_save_sys_text , ' '  , sizeof(sql04_save_sys_text) );
    FILL ( sql04_save_sys_attr , 0    , sizeof(sql04_save_sys_attr) );
    FILL ( sql04_save_sk_text  , ' '  , sizeof(sql04_save_sk_text)  );

#ifdef KANJI
    /*
     *  Load UNICODE tables.
     */
    {
	tsp8_uni_load_error	load_ret ;
	char			msg [ 40 ];
	char			dblang [ 64 ];

	if ( sql01_dblang && *sql01_dblang )
	{
	    sql47_ctop ( dblang , sql01_dblang , sizeof(dblang) );
	    s82uni_fload ( &sql04_encoding_ptr , &sql04_encoding_cnt , FALSE ,
					  dblang , &sql04_codeset , &load_ret );
	    if ( load_ret != uni_load_ok )
	    {
		s82uni_load_error ( load_ret , msg );
		DBG1(( MF__, "sqlton: %.40s\n", msg ))
		(void) endwin ();
		(void) SET_TERMIO ( 0 , &sql04_termio_extern );
		DBG1 (( MF__,"restored external terminal settings \n" ))
		return ;
	    }
	}
	else
	{
	    sql04_encoding_ptr = 0 ;
	    sql04_encoding_cnt = 0 ;
	    sql04_codeset      = 0 ;
	}
    }
#endif

    /*
     *  Force a full screen write at the first call to 'sqltio'.
     */
    sql01_vt_clear = TRUE ;

    /*
     *  Force rebuild of attributes and screen.
     */
    for ( idx = 0 ; idx < MAXATTRIBUTES ; idx++ )
	sql04_attrib_table[idx].changed = TRUE ;

    /*
     *  Anything is perfect.
     */
    sql04_tio_count = 1 ; /* F.H. for sqlthold */
    sql04_turned_on = TRUE ;
    *c_ok = TRUE ;

#ifdef DEBUG_DEBUG
    DBG1 (( MF__,"isprint values: \n" ))
    for ( idx = 0 ; idx < 16 ; idx ++ )
    {
	int fillchar;
	DBG1 (( MF__,"0x%02x:  ", idx<<4 ))
	for ( fillchar = 0 ; fillchar < 16 ; fillchar ++ )
	    DBG1 (( MF__,"%2d", isprint((idx<<4)|fillchar)?1:0 ))
	DBG1 (( MF__,"\n" ))
    }
    DBG1 (( MF__,"chrclass values: \n" ))
    for ( idx = 0 ; idx < 16 ; idx ++ )
    {
	int fillchar;
	DBG1 (( MF__,"0x%02x:  ", idx<<4 ))
	for ( fillchar = 0 ; fillchar < 16 ; fillchar ++ )
	    DBG1 (( MF__,"%2d", sql04_chrclass[(idx<<4)|fillchar]?1:0 ))
	DBG1 (( MF__,"\n" ))
    }
#endif
}

/*==========================================================================*/

/*
 *  'sqltoff' releases the virtual terminal.
 *  If 'msg' is all blanks, it is not written.
 */
#undef MF__
#define MF__ MOD__"sqlctoff"
global	void	sqlctoff ( 
char           **cscreen_buf ,
char           **cattrib_buf ,
char           *msg )
{
    int             i ;
#ifdef	SCRLIB
    extern VS       vs_fd ;
#endif


    DBGIN;
    DBGSCREEN ( msg , msg , 80 , "sqltoff message" )

    if ( ! sql04_turned_on )
    {
    	DBG1(( MF__, "sqlton never called\n" ))
	    return ;
    }

    /*
     *  Clear screen only if something has been written to it.
     *  Some applications may misbehave in the way that they
     *  suppress 'sqltio' when running in batch mode but
     *  calling 'sqlton'-'sqltoff' anyway.
     *  In this case we suppress the clearing of the screen.
     */
    (void) attrset ( A_NORMAL );
    (void) clear ();
    if ( sql04_tio_count > 1 /* sqlton ! */ )
    {
	(void) refresh ();
#ifdef	SCRLIB
	(void) d_sftkys (&vs_fd);    /* erase softkeys */
	(void) msg_mode ();          /* enter message mode (to_status_line) */
	(void) cbol ();		 /* cursor begin of line */
	(void) attrset ( A_NORMAL );
	/* Overwrite status line with blanks */
	for ( i = 0 ; i < sql04_cols ; i ++ ) (void) addch ( CHBLANK );
	(void) cbol ();		 /* cursor begin of line */
	(void) screen_mode ();       /* enter screen mode (from_status_line) */
#else	/*SCRLIB*/
	FILL ( sql04_save_sys_text , ' ' , sizeof(sql04_save_sys_text) );
	FILL ( sql04_save_sys_attr , 0   , sizeof(sql04_save_sys_attr) );
	FILL ( sql04_save_sk_text  , ' ' , sizeof(sql04_save_sk_text)  );
	sql04_write_sysline ( sql04_save_sys_text , sql04_save_sys_attr );
	sql04_write_softkeys ( sql04_save_sk_text );
#endif	/*SCRLIB*/
    }

    /*
     *  Reset the screen to the 'outside curses' state.
     */
    (void) endwin ();

    /*
     *  On some systems 'endwin' leaves stdio in full buffered mode.
     */
    (void) setvbuf ( stdin  , (char*) 0 , _IOLBF , BUFSIZ );
    (void) setvbuf ( stdout , (char*) 0 , _IOLBF , BUFSIZ );
    (void) setvbuf ( stderr , (char*) 0 , _IONBF , BUFSIZ );

    /*
     *  Since we modified the termio values by ourself,
     *  we restore them completely to their previous state.
     */
    (void) SET_TERMIO ( 0 , &sql04_termio_extern );
    DBG1 (( MF__,"restored external terminal settings \n" ))

    /*
     *  If the terminal initialization strings have been sent,
     *  the terminal must be reset.
     */
    if ( sql04_term_initialized )
    {
	/*
	 *  Reset the terminal.
	 */
	PUTP ( keypad_local );
	if ( init_prog  ) (void) system ( init_prog );
	if ( reset_file ) (void) sql04_cat ( reset_file );
	PUTP ( reset_1string );
	PUTP ( reset_2string );
	PUTP ( reset_3string );
	(void) fflush ( stdout );

	sql04_term_initialized = FALSE ;

	/*
	 *  Issue the user's reset command.
	 */
	if ( sql04_env_DBTERMRESET )
	    (void) system ( sql04_env_DBTERMRESET );
    }

    /*
     *  'endwin' arranges for a later call to 'refresh'.
     *  None of the curses data structures is released.
     *  To finally leave curses, 'delwin' is called
     *  which frees all data allocated by curses.
     */
    (void) delwin ( stdscr );

    /*
     *  Print the message.
     *  Terminate message with '\0'.
     *  Strip trailing spaces.
     *  Print only, if not empty.
     */
    for ( i = 0 ; (i < 80-1) && sql04_isprint(msg[i]&0xff) ; i ++ );
    for (       ; (i >  0)   &&       isspace(msg[i]&0xff) ; i -- );
    if ( sql04_isprint(msg[i]&0xff) && ! isspace(msg[i]&0xff) ) i ++ ;
    if ( i > 0 )
    {
	(void) fwrite ( msg , 1 , i , stdout );
	(void) fputc ( '\n' ,stdout );
	(void) fflush  ( stdout );
    }

    /*
     *  Free buffers.
     */
    DBG1 (( MF__,"free *cscreen_buf 0x%08lx \n", (long) *cscreen_buf ))
    FREE_MEM_EO57 ( *cscreen_buf );
    *cscreen_buf = 0 ;

    DBG1 (( MF__,"free *cattrib_buf 0x%08lx \n", (long) *cattrib_buf ))
    FREE_MEM_EO57 ( *cattrib_buf );
    *cattrib_buf = 0 ;

    DBG1 (( MF__,"free save_screen  0x%08lx \n", (long) sql04_save_screen ))
    FREE_MEM_EO57 ( sql04_save_screen );
    sql04_save_screen = 0 ;

    DBG1 (( MF__,"free save_attrib  0x%08lx \n", (long) sql04_save_attrib ))
    FREE_MEM_EO57 ( sql04_save_attrib );
    sql04_save_attrib = 0 ;

#ifdef	PRINT_LINES_CHANGED
    DBG1 (( MF__,"free check_screen 0x%08lx \n", (long) sql04_check_screen ))
    FREE_MEM_EO57 ( sql04_check_screen );
    sql04_check_screen = 0 ;
#endif

#ifdef KANJI
    DBG1 (( MF__,"free charmodes    0x%08lx \n", (long) sql04_charmodes ))
    FREE_MEM_EO57 ( sql04_charmodes );
    sql04_charmodes = 0 ;
#endif

    sql04_turned_on = FALSE ;
    sql04_released  = FALSE ;
    sql04_tio_count = 0 ;
}

/*==========================================================================*/

/*
 *  'sqltio' writes a screen image
 *  and, if 'wait_for_input', reads keys and characters from the keyboard.
 */

/*ARGSUSED*/	/* c_sk_text only for screenlib */

#undef MF__
#define MF__ MOD__"sqlctio"
global	void	sqlctio ( screen ,
			  attrib ,
			  cursorline ,
			  cursorcolumn ,
			  c_sk_text ,
			  c_sys_text ,
			  c_sys_attr ,
			  insert_text ,
			  insert_pos ,
			  insert_opt ,
			  c_vt_options ,
			  c_returnkeys ,
			  c_rejectkeys ,
			  num_of_lines ,
			  num_of_cols ,
			  mark_begin ,
			  mark_end ,
			  screen_changed ,
			  c_keystroke ,
			  c_refresh ,
			  c_ok )

UCHAR			**screen ;        /* screen buffer                */
UCHAR			**attrib ;        /* attributes buffer            */
tsp00_Int2		*cursorline ;     /* cursorposition (line)        */
tsp00_Int2		*cursorcolumn ;   /* cursorposition (column)      */
UCHAR			*c_sk_text ;      /* text for softkeys            */
UCHAR			*c_sys_text ;     /* text for status line         */
UCHAR			*c_sys_attr ;     /* attributes for status line   */
UCHAR			*insert_text ;    /* text for insert label        */
tsp00_Int2		*insert_pos ;     /* position for insert label    */
UCHAR			*insert_opt ;     /* attributes for insert label  */
char			*c_vt_options ;   /* options                      */
char			*c_returnkeys ;   /* table of returnkeys          */
char			*c_rejectkeys ;   /* table of rejectkeys          */
boolean			c_refresh ;       /* refresh before screen output */
tsp00_Int2		*num_of_lines ;   /* returns screen lines         */
tsp00_Int2		*num_of_cols ;    /* returns screen columns       */
tsp00_Int2		*mark_begin ;     /* returns begin of marked area */
tsp00_Int2		*mark_end ;       /* returns end of marked area   */
boolean			*screen_changed ; /* returns if screen changed    */
char			*c_keystroke ;    /* returns release key          */
boolean			*c_ok ;           /* returncode                   */

{
    int             keyfunc ;


    if ( ! sql04_turned_on )
    {
	DBG1(( MF__, "sqlton never called\n" ))
	*c_ok = FALSE ;
	return ;
    }

    if ( sql04_released )
    {
	DBG1(( MF__,"sqltio after sqltrelease \n" ))
	*c_ok = FALSE ;
	return ;
    }

    sql04_tio_count ++ ;			/* count the calls to sqltio */
    sql04_tio_screen = *screen ;		/* get a pointer value */
    sql04_tio_attrib = *attrib ;		/* get a pointer value */
    *c_ok            = TRUE ;			/* initialize output argument */
    *num_of_lines    = (tsp00_Int2) sql04_lines ;	/* initialize output argument */
    *num_of_cols     = (tsp00_Int2) sql04_cols ;	/* initialize output argument */
    *screen_changed  = FALSE ;			/* initialize output argument */

    DBG1 (( MF__,"\n" ))
    DBG1 (( MF__,"called +++++ %d +++++\n", sql04_tio_count ))
    DBG1 (( MF__,"screen       0x%08lx \n", (long) sql04_tio_screen ))
    DBG1 (( MF__,"attrib       0x%08lx \n", (long) sql04_tio_attrib ))
    DBG1 (( MF__,"screen_size  %d \n", sql04_screen_size ))
    DBG1 (( MF__,"screen_lines %d \n", sql04_lines ))
    DBG1 (( MF__,"screen_cols  %d \n", sql04_cols ))

    /*
     *  At the first call to sqltio send the terminal initialization strings.
     */
    if ( ! sql04_term_initialized )
    {
	if ( init_prog ) (void) system ( init_prog );
	if ( init_file ) (void) sql04_cat ( init_file );
#if OSF1 /* must resume curses mode before calling curses routines */
        (void) refresh ();
#endif
	PUTP ( init_1string );
	PUTP ( init_2string );
	PUTP ( init_3string );
	PUTP ( keypad_xmit );
	sql04_term_initialized = TRUE ;
    }

    /*
     *  Extract the options from the options array.
     */
    sql04_get_options ( c_vt_options );
    DBG1 (( MF__,"refresh            = %d\n", c_refresh ))

    /*
     *  Update the attributes table if sqlttable has been called.
     *  Using 'init_pair' refreshes the screen immediately.
     *  To avoid this clear the screen and update the colors
     *  immediately before writing the new screen.
     */
    if ( sql04_has_colors && sql04_attrib_changed ) sql04_update_colors ();

    DBGSCREEN ( sql04_tio_screen , sql04_tio_attrib ,
		sql04_screen_size , "input screen" )

#ifdef KANJI
    /*
     *  Create the charmodes array from the screen buffer.
     */
    {
	tsp8_uni_error		retcode ;
	tsp00_Int4		err_char_no ;

	if ( sql04_encoding_ptr && sql04_encoding_cnt )
	{
	    s80uni_charlayout (sql04_tio_screen ,
				(tsp00_Int4) sql04_screen_size ,
				sql04_codeset , sql04_charmodes ,
				&retcode , &err_char_no );
	    if ( retcode != uni_ok )
	    {
		DBG1 (( MF__,"s80uni_charlayout error %d pos %d \n",
				    (int) retcode , (int) err_char_no ))
		DBG1(( MF__,"s80uni_charlayout error %d pos %d \n",
					    (int) retcode , (int) err_char_no ))
		*c_ok = FALSE ;
		return ;
	    }
	}
    }
#endif

    /*
     *  Write the new screen image.
     *  'full_screen' clears and rewrites the complete screen.
     *  It also (re-)initializes the save buffers.
     *  'part_screen' writes only the changed lines.
     */
#ifdef	FORCE_REFRESH
    sql01_vt_clear = TRUE ;
#endif
    if ( sql01_vt_clear || c_refresh )
	sql04_full_screen ();
    else
	sql04_part_screen ();

    /*
     *  Initialize the insert mode and write the insert label.
     */
    sql04_init_ins ( insert_pos , insert_text , insert_opt );

    /*
     *  Mark the marked characters.
     */
#ifdef MARK_NOCH_ZU_TUN
    sql04_mark_on = ( sql04_mark_option && (*mark_begin < *mark_end) );
#else
    sql04_mark_on = FALSE ;
#endif
    if ( sql04_mark_on )
	sql04_mark_apos = *mark_begin - 1 ;
    else
	sql04_mark_apos = -1 ;
    DBG1 (( MF__,"mark_begin %d \n", *mark_begin ))
    DBG1 (( MF__,"mark_end   %d \n", *mark_end   ))
    DBG1 (( MF__,"mark_apos  %d \n", sql04_mark_apos   ))

    /*
     *  Compute the current cursor position in the screen buffer.
     *  The virtual terminal interface counts from 1 to lines,
     *  curses counts from 0 to lines-1.
     */
    DBG1 (( MF__,"cursorline   %d \n", *cursorline   ))
    DBG1 (( MF__,"cursorcolumn %d \n", *cursorcolumn ))
    sql04_position = (*cursorline - 1) * sql04_cols + (*cursorcolumn - 1);
    if ( (sql04_position < 0) || (sql04_position >= sql04_screen_size) )
    {
	sql04_position = 0 ;
    }
#ifdef KANJI
    while ( (sql04_position > 0) && sql04_charmodes[sql04_position] )
	sql04_position -- ;
#endif
    sql04_displpos = sql04_position ;

    /*
     *  Move the cursor to the requested position
     *  and output the screen.
     */
    (void) move ( LINE(sql04_displpos) , COLUMN(sql04_displpos) );
    if ( sql04_env_DBTERMREDRAW ) (void) clearok ( stdscr , TRUE );
    (void) refresh ();

    /*
     *  If changed, write the new message line.
     */
    if ( sql01_vt_clear ||
	 memcmp ( (char*) c_sys_text , (char*) sql04_save_sys_text ,
					sizeof(sql04_save_sys_text) ) ||
	 memcmp ( (char*) c_sys_attr , (char*) sql04_save_sys_attr ,
					sizeof(sql04_save_sys_attr) )    )
    {
	DBGSCREEN ( c_sys_text , c_sys_attr , sql04_cols , "Message Line" );
	sql04_write_sysline ( c_sys_text , c_sys_attr );

	COPY ( sql04_save_sys_text , c_sys_text , sizeof(sql04_save_sys_text) );
	COPY ( sql04_save_sys_attr , c_sys_attr , sizeof(sql04_save_sys_attr) );
    }

    /*
     *  If changed, write the new softkey labels.
     */
    if ( sql01_vt_clear ||
	 memcmp ( (char*) c_sk_text , (char*) sql04_save_sk_text ,
					sizeof(sql04_save_sk_text) ) )
    {
	DBGSCREEN ( c_sk_text , c_sk_text , 153 , "Softkeys" );
	sql04_write_softkeys ( c_sk_text );
	COPY ( sql04_save_sk_text , c_sk_text , sizeof(sql04_save_sk_text) );
    }

    /*
     *  Sound terminal's bell, if requested.
     *  Some terminals can't generate an audible signal, but may be able
     *  to flash the screen (light it up for a short time).
     */
    if ( sql04_ring_bell )
    {
	sql04_beep_flash ();
    }

    /*
     *  If 'sqlttable' was called, all steps for updating the screen
     *  have now been taken. Reset the flag.
     *  Applies also to the clear flag.
     */
    sql04_attrib_changed = FALSE ;
    sql01_vt_clear = FALSE ;

    /*
     *  Initialize global flag.
     */
    sql04_screen_changed = FALSE ;

    /*
     *  If requested, wait for keyboard input.
     */
    if ( sql04_wait_for_input )
    {
#ifdef DEBUG_DEBUG
	debug_key_array ( "return:" , c_returnkeys );
	debug_key_array ( "reject:" , c_rejectkeys );
#endif

#if ! OSF1 /* can't call SET_TERMIO() during curses mode */
	/*
	 *  If VTKEY_CONTROL is in the returnkeys,
	 *  'sql04_enable_ctrlkey' has been set by 'get_options'.
	 */
#ifdef	SAFE_CTRLKEY
        if ( sql04_enable_ctrlkey )
	{
	    DBG1 (( MF__,"sqltio(%d): control_key enabled \n", sql04_tio_count ))
	    /* set special input mode */
	    (void) SET_TERMIO ( 0 , &sql04_termio_ctlkey );
	}
#else
	/*
	 *  Change the termio values only, if this is a change to the
	 *  last setting of 'sql04_enable_ctrlkey'.
	 *  ('ioctl'/'tcsetattr' consumes some time).
	 */
        if ( sql04_enable_ctrlkey )
	{
	    if ( !sql04_old_enable_ctrlkey )
	    {
		DBG1 (( MF__,"sqltio(%d): control_key enabled \n", sql04_tio_count ))
		/* set special input mode */
		(void) SET_TERMIO ( 0 , &sql04_termio_ctlkey );
	    }
	}
	else
	{
	    if ( sql04_old_enable_ctrlkey )
	    {
		DBG1 (( MF__,"sqltio(%d): control_key disabled\n", sql04_tio_count ))
		/* reset special input mode */
		(void) SET_TERMIO ( 0 , &sql04_termio_intern );
	    }
	}
	sql04_old_enable_ctrlkey = sql04_enable_ctrlkey ;
#endif	/*SAFE_CTRLKEY*/
#endif /*! OSF1*/

	/*
	 *  Initialize the end of input flags.
	 */
	sql04_before_first = FALSE ;
	sql04_behind_last = FALSE ;

	/*
	 *  Loop until
	 *  - a returnkey is pressed,
	 *  - option "return_on_last" is active and the cursor is behind
	 *    the last unprotected character
	 *  - option "return_on_first" is active and the cursor is before
	 *    the first unprotected character
	 */
	while ( ! sql04_behind_last && ! sql04_before_first )
	{
	    if ( sql04_enable_charkey )
	    {
		/*
		 *  return on any printable character.
		 */
		keyfunc = sql04_get_key ();
		if ( (keyfunc == VTKEY_UNKNOWN)   ||
		     (keyfunc == VTKEY_CHARACTER) ||
		     (keyfunc == VTKEY_CONTROL)      ) break ;
	    }
	    else /* sql04_enable_charkey */
	    {
		/*
		 *  Change input fields. Enter printable characters.
		 *  Leave the loop, if a non-printable character or key
		 *  was received or after the last unprotected character
		 *  has been changed.
		 */
		while ( ! sql04_behind_last )
		{
		    keyfunc = sql04_input_character ();
		    if ( keyfunc != VTKEY_CHARACTER ) break ;

		    sql04_part_screen ();
		    (void) move ( LINE(sql04_displpos) ,
				COLUMN(sql04_displpos) );
		    (void) refresh ();
		}
		/* while !behind_last */
	    }
	    /* sql04_enable_charkey */

	    DBG1 (( MF__,"Key: %s return=%d reject=%d \n",
		    sql04_key_name(keyfunc) , c_returnkeys[keyfunc] ,
					      c_rejectkeys[keyfunc] ))

	    if ( sql04_behind_last || c_returnkeys[keyfunc] ) break ;
	    if ( c_rejectkeys[keyfunc] )
	    {
		sql04_beep_flash ();
		continue ;
	    }

	    switch ( keyfunc )
	    {
	    case VTKEY_MARK :
#ifdef MARK_NOCH_ZU_TUN
		sql04_mark_apos = sql04_position ;
		sql04_marked    = TRUE ;
		sql04_mark_on   = sql04_mark_on ? FALSE : TRUE ;
		*mark_begin     = (tsp00_Int2) (sql04_position + 1);
		sql04_write_marked ();
		DBG1 (( MF__,"vtinout : MARK_KEY pressed, mark_on now = %d\n",
							 sql04_mark_on))
#endif
		break ;

	    case VTKEY_INSERT_CHAR :
		if ( sql04_insert_mode )
		    sql04_insert_off ( insert_pos );
		else
		    sql04_insert_on  ( insert_pos , insert_text , insert_opt );
		break ;

	    case VTKEY_REFRESH :
		sql04_full_screen ();
		if ( sql04_insert_mode )
		    sql04_insert_on ( insert_pos , insert_text , insert_opt );
		(void) move ( LINE(sql04_displpos) , COLUMN(sql04_displpos) );
		(void) refresh ();
		sql04_write_sysline ( c_sys_text , c_sys_attr );
		sql04_write_softkeys ( c_sk_text );
		COPY ( sql04_save_sys_text , c_sys_text ,
			sizeof(sql04_save_sys_text) );
		COPY ( sql04_save_sys_attr , c_sys_attr ,
			sizeof(sql04_save_sys_attr) );
		COPY ( sql04_save_sk_text , c_sk_text ,
			sizeof(sql04_save_sk_text) );
		break ;

	    default :
		sql04_local_keys ( keyfunc );
		sql04_part_screen ();
	    }
	    /* switch */

	    (void) move ( LINE(sql04_displpos) , COLUMN(sql04_displpos) );
	    (void) refresh ();
	}
	/* while !behind_last && !before_first */

#if ! OSF1 /* can't call SET_TERMIO() during curses mode */
#ifdef	SAFE_CTRLKEY
        if ( sql04_enable_ctrlkey )
	{
	    DBG1 (( MF__,"sqltio(%d): control_key disabled\n", sql04_tio_count ))
	    /* reset special input mode */
	    (void) SET_TERMIO ( 0 , &sql04_termio_intern );
	}
#endif	/*SAFE_CTRLKEY*/
#endif /*OSF1*/

    }
    /* wait for input */

    /*
     *  Return the key function and value.
     */
    c_keystroke[0] = (char) keyfunc ;
    c_keystroke[1] = (char) sql04_key_value ;

    /*
     *  Return the mark positions.
     */
    if ( sql04_marked )
    {
	*mark_end = (tsp00_Int2) (sql04_position + 1);
	if ( *mark_end < *mark_begin )
	{
	    int save_mark ;
	    save_mark = *mark_begin ;
	    *mark_begin = *mark_end ;
	    *mark_end = (tsp00_Int2) save_mark ;
	}
    }

    /*
     *  Return the current cursor position.
     */
    *cursorline   = (tsp00_Int2) (LINE(sql04_displpos) + 1);
    *cursorcolumn = (tsp00_Int2) (COLUMN(sql04_displpos) + 1);

    /*
     *  Return the screen change status.
     */
    *screen_changed = (boolean) sql04_screen_changed ;

    /*
     *  Remove the insert label from the screen since it might be
     *  elsewhere at the next call to 'sqltio'.
     */
    sql04_reset_ins ( insert_pos );

    DBG1 (( MF__,"returning +++++++++++++\n" ))
}

/*==========================================================================*/

/*
 *  'sqlttable' sets the attributes table.
 */

global	void	sqlcttable ( elem , att_array , fg , bg )

tsp00_Int2		elem ;
char			*att_array ;
enum1			fg ;
enum1			bg ;

{
    if ( (elem < 0) || (elem >= MAXATTRIBUTES) )
    {
		MSGCD (( -11987, ERR_TYPE, "VTERM   ",
			"sqlttable: illegal attribute index %d \n", elem ));
		sqlabort ();
		return ;
    }

    DBG1 (( MF__,"sqlttable: %2d fg/bg %d/%d (%s/%s) %s %s %s %s %s \n" ,
	elem , fg , bg , sql04_color_name[fg] , sql04_color_name[bg] ,
	att_array[0]?"BRIGHT":""    , att_array[1]?"REVERSE":"" ,
	att_array[2]?"UNDERLINE":"" , att_array[3]?"BLINK":""   ,
	att_array[4]?"INVISIBLE":"" ))


    /*
     *  We have to redraw the complete screen if any of the attributes
     *  changed. Otherwise the optimization would only redraw those parts
     *  of the screen which changed their character contents.
     */
    sql01_vt_clear = TRUE ;
    sql04_attrib_changed = TRUE ;
    sql04_attrib_table[elem].changed = TRUE ;
    sql04_attrib_table[elem].invis   = FALSE ;
    sql04_attrib_table[elem].att     = 0 ;

#ifdef SCRLIB_BOLD     /* Probleme mit Screenlib und bold */
    if ( att_array[0] ) sql04_attrib_table[elem].att |= A_BOLD ;
#endif
#ifndef	SCRLIB
#if ! sun /*&& ! T31*/
    if ( att_array[0] ) sql04_attrib_table[elem].att |= A_BOLD ;
#endif
#endif

    if ( att_array[1] ) sql04_attrib_table[elem].att |= A_REVERSE ;
    if ( att_array[2] ) sql04_attrib_table[elem].att |= A_UNDERLINE ;
    if ( att_array[3] ) sql04_attrib_table[elem].att |= A_BLINK ;
    if ( att_array[4] ) sql04_attrib_table[elem].invis = TRUE ;

    sql04_attrib_table[elem].fg = fg ;
    sql04_attrib_table[elem].bg = bg ;
    /*
     *  Defer the conversion of the colors to the attribute until the next
     *  sqltio is called: init_pair refreshes the screen immediately !
     */

    DBGG (( "sqlttable: curses attr 0x%08lx \n",
	    (long) sql04_attrib_table[elem].att ))
}

/*==========================================================================*/

/*
 *  'sqltgtable' reads the attributes table.
 */

global	void	sqlctgtable ( elem , att_array , fg , bg )

tsp00_Int2		elem ;
char			*att_array ;
enum1			*fg ;
enum1			*bg ;

{
    if ( (elem < 0) || (elem >= MAXATTRIBUTES) )
    {
		MSGCD (( -11987, ERR_TYPE, "VTERM   ",
			"sqltgtable: illegal attribute index %d \n", elem ));
		sqlabort ();
		return ;
    }

    FILL ( att_array , 0 , VTA_LAST );

    if ( sql04_attrib_table[elem].att & A_BOLD      ) att_array[0] = TRUE ;
    if ( sql04_attrib_table[elem].att & A_REVERSE   ) att_array[1] = TRUE ;
    if ( sql04_attrib_table[elem].att & A_UNDERLINE ) att_array[2] = TRUE ;
    if ( sql04_attrib_table[elem].att & A_BLINK     ) att_array[3] = TRUE ;
    if ( sql04_attrib_table[elem].invis             ) att_array[4] = TRUE ;

    *fg = sql04_attrib_table[elem].fg ;
    *bg = sql04_attrib_table[elem].bg ;
}

/*==========================================================================*/

/*
 *  'sqltrelease' suspends curses mode
 *  and temporarily restores shell mode.
 *  Curses mode will be resumed through a call to 'sqlthold'.
 */

/*ARGSUSED*/ /* term_ref unused */
global	void	sqltrelease ( term_ref )

tsp00_Int4		term_ref ;

{
#ifdef SCRLIB
    register int    i ;
    extern VS       vs_fd ;
#endif


    if ( ! sql04_turned_on ) return ;
    sql04_released = TRUE ;
    DBG1 (( MF__,"sqltrelease: called \n" ))

    /*
     *  Clear screen only if something has been written to it.
     *  Some applications may misbehave in the way that they
     *  suppress 'sqltio' when running in batch mode but
     *  calling 'sqlton'-'sqltoff' anyway.
     *  In this case we suppress the clearing of the screen.
     */
    (void) attrset ( A_NORMAL );
    (void) clear ();
    if ( sql04_tio_count > 0 )
    {
	(void) refresh ();
#ifdef	SCRLIB
	(void) d_sftkys (&vs_fd);    /* erase softkeys */
	(void) msg_mode ();          /* enter message mode (to_status_line) */
	(void) cbol ();		 /* cursor begin of line */
	(void) attrset ( A_NORMAL );
	/* Overwrite status line with blanks */
	for ( i = 0 ; i < sql04_cols ; i ++ ) (void) addch ( CHBLANK );
	(void) cbol ();		 /* cursor begin of line */
	(void) screen_mode ();       /* enter screen mode (from_status_line) */
#else	/*SCRLIB*/
	FILL ( sql04_save_sys_text , ' ' , sizeof(sql04_save_sys_text) );
	FILL ( sql04_save_sys_attr , 0   , sizeof(sql04_save_sys_attr) );
	FILL ( sql04_save_sk_text  , ' ' , sizeof(sql04_save_sk_text)  );
	sql04_write_sysline ( sql04_save_sys_text , sql04_save_sys_attr );
	sql04_write_softkeys ( sql04_save_sk_text );
#endif	/*SCRLIB*/
    }
#if OSF1 /* must call curses routines during curses mode */
    if ( sql04_term_initialized )
    {
        /*
         *  Reset the terminal.
         */
        PUTP ( keypad_local );
        if ( init_prog  ) (void) system ( init_prog );
        if ( reset_file ) (void) sql04_cat ( reset_file );
        PUTP ( reset_1string );
        PUTP ( reset_2string );
        PUTP ( reset_3string );
        (void) fflush ( stdout );

        sql04_term_initialized = FALSE ;

        /*
         *  Issue the user's reset command.
         */
        if ( sql04_env_DBTERMRESET )
            (void) system ( sql04_env_DBTERMRESET );
    }
#endif

    /*
     *  Reset the screen to the 'outside curses' state.
     *  'endwin' arranges for a later call to 'refresh'.
     *  None of the curses data structures is released.
     *  Calling 'refresh' again restores curses mode and
     *  redraws the last screen contents
     *  (here it will be cleared, since we called 'clear' some lines above).
     */
    (void) endwin ();

    /*
     *  On some systems 'endwin' leaves stdio in full buffered mode.
     */
    (void) setvbuf ( stdout , (char*) 0 , _IOLBF , BUFSIZ );
    (void) setvbuf ( stderr , (char*) 0 , _IONBF , BUFSIZ );

    /*
     *  Since we modified the termio values by ourself,
     *  we restore them completely to their previous state.
     */
    (void) SET_TERMIO ( 0 , &sql04_termio_extern );
    DBG1 (( MF__,"restored external terminal settings \n" ))
#ifndef	SAFE_CTRLKEY
    sql04_enable_ctrlkey = FALSE ;
#endif

#if ! OSF1 /* must call curses routines during curses mode */
    if ( sql04_term_initialized )
    {
	/*
	 *  Reset the terminal.
	 */
	PUTP ( keypad_local );
	if ( init_prog  ) (void) system ( init_prog );
	if ( reset_file ) (void) sql04_cat ( reset_file );
	PUTP ( reset_1string );
	PUTP ( reset_2string );
	PUTP ( reset_3string );
	(void) fflush ( stdout );

	sql04_term_initialized = FALSE ;

	/*
	 *  Issue the user's reset command.
	 */
	if ( sql04_env_DBTERMRESET )
	    (void) system ( sql04_env_DBTERMRESET );
    }
#endif

    /*
     *  Restore the original environment.
     */
    if ( sql04_envdef_TERM_extern )
	(void) putenv ( sql04_envdef_TERM_extern );
    if ( sql04_envdef_TERMINFO_extern )
	(void) putenv ( sql04_envdef_TERMINFO_extern );
}

/*==========================================================================*/

/*
 *  'sqlthold' resumes curses mode after a call to 'sqltrelease'.
 */

/*ARGSUSED*/ /* term_ref unused */
global	void	sqlthold ( term_ref , manual_input )

tsp00_Int4		term_ref ;
boolean			manual_input ;

{
    char            dummy [2];
#ifdef SCRLIB
    extern VS       vs_fd ;
#endif


    if ( ! sql04_released ) return ;
    sql04_released = FALSE ;
    DBG1 (( MF__,"sqlthold: called, manual_input %d \n", manual_input ))

    if ( manual_input && (sql04_tio_count > 0) )
    {
	(void) fprintf ( stdout , "Hit <CR> to return " );
	(void) fflush  ( stdout );
	(void) read ( 0 , dummy , 1 );
    }

    /*
     *  We released the terminal by calling 'endwin'.
     *  'endwin' restores shell mode and prepares the curses data
     *  for resuming curses mode after the next call to 'refresh'.
     *  This next call to refresh will be done with the next 'sqltio'.
     *  We suppress it here, since the component may run in batch mode.
     *  In this case we won't output anything.
     */

    /*
     *  Since we modified the termio values by ourself,
     *  we restore them completely to their previous state.
     */
    (void) SET_TERMIO ( 0 , &sql04_termio_intern );
    DBG1 (( MF__,"restored internal terminal settings \n" ))

    /*
     *  Force a refresh of the screen.
     */
    sql01_vt_clear = TRUE ;

    /*
     *  Set the internal environment.
     */
    if ( sql04_envdef_TERM )
	(void) putenv ( sql04_envdef_TERM );
    if ( sql04_envdef_TERMINFO )
	(void) putenv ( sql04_envdef_TERMINFO );
}

/*==========================================================================*/

/*
 *  'sqltermvar' returns the terminal-type (TERM or DBTERM) to the caller.
 *  If nothing is set, a blank-string is returned in term_type.
 */

global	void	sqltermvar ( term_type )

char    *term_type ;

{
    if ( ! sql04_env_TERM )
	FILL ( term_type , ' ' , sizeof(tsp00_C18) );
    else
	sql47_ctop ( term_type , sql04_env_TERM , sizeof(tsp00_C18) );

}

/*==========================================================================*/

#ifdef	OLD
/*
 *  'sqltmap' maps all non-printable characters in a character array
 *  to question marks.
 */

/*ARGSUSED*/ /* term_ref unused */
global	void	sqltmap ( term_ref , buf , startpos , length )

tsp00_Int4		term_ref ;
char			*buf ;
tsp00_Int2		startpos ;
tsp00_Int2		length ;

{
    register int             i ;
    register char            *spos ;


    spos = buf + startpos - 1 ;

    for ( i = 0 ; i < length ; i ++ , spos ++ )
    {
	 if ( ! sql04_isprint(*spos) ) *spos = '?' ;
    }
}
#endif	/*OLD*/

/*==========================================================================*/

/*
 *  Fill the table of available returnkeys.
 */

static	void	sql04_retkey_array ( returnkeys_array )

register char  *returnkeys_array ;

{
    struct key_info		*kip ;


    FILL ( returnkeys_array , 0 , VTKEY_LAST );

    /*
     *  The following keys are always available:
     *  some are available on all keyboards (e.g. RETURN/ENTER),
     *  others can be simulated by control sequences (e.g. Ctrl-L),
     *  others are generated by interrupt or special terminal modes.
     */
    returnkeys_array [ VTKEY_CHARACTER ]    = TRUE ; /* characters, e.g. 'a' */
    returnkeys_array [ VTKEY_ENTER ]        = TRUE ; /* Ctrl-D */
    returnkeys_array [ VTKEY_CLEAR ]        = TRUE ; /* Ctrl-F */
    returnkeys_array [ VTKEY_DO ]           = TRUE ; /* RETURN with VT_FORM */
    returnkeys_array [ VTKEY_CMD ]          = TRUE ; /* Ctrl-R */
    returnkeys_array [ VTKEY_CANCEL ]       = TRUE ; /* interrupt */
    returnkeys_array [ VTKEY_END ]          = TRUE ; /* Ctrl-E and/or Ctrl-Z */
    returnkeys_array [ VTKEY_NEXT_FIELD ]   = TRUE ; /* TAB with VT_FORM
							RETURN with VT_EDIT */
    returnkeys_array [ VTKEY_PREV_FIELD ]   = TRUE ; /* Ctrl-K with VT_FORM */
    returnkeys_array [ VTKEY_DEL_EOF ]      = TRUE ; /* Ctrl-X */
    returnkeys_array [ VTKEY_CONTROL ]      = TRUE ; /* Ctrl-A to Ctrl-Z when
							enabled as returnkey */

    for ( kip = sql04_key_list ; kip ; kip = kip->ki_next )
    {
	if ( kip->ki_function < VTKEY_LAST )
	    returnkeys_array [ kip->ki_function ] = TRUE ;
    }

#ifdef DEBUG_RTE
    debug_key_array ( "Returnkey:" , returnkeys_array );
#endif
}

/*==========================================================================*/

/*
 *  Fill the table of available attributes.
 */

static	void	sql04_attrib_array ( attributes_array )

register char  *attributes_array ;

{
    FILL ( attributes_array , FALSE , VTA_LAST );

    if ( enter_bold_mode      ) attributes_array[VTA_BRIGHT]    = TRUE ;
    if ( enter_reverse_mode   ) attributes_array[VTA_INVERSE]   = TRUE ;
    if ( enter_underline_mode ) attributes_array[VTA_UNDERLINE] = TRUE ;
    if ( enter_blink_mode     ) attributes_array[VTA_BLINK]     = TRUE ;

    attributes_array[VTA_INVISIBLE] = TRUE ;
    attributes_array[VTA_MIXED]     = TRUE ;

    DBG1 (( MF__,"bright      %d \n", attributes_array[VTA_BRIGHT]    ))
    DBG1 (( MF__,"inverse     %d \n", attributes_array[VTA_INVERSE]   ))
    DBG1 (( MF__,"underline   %d \n", attributes_array[VTA_UNDERLINE] ))
    DBG1 (( MF__,"blink       %d \n", attributes_array[VTA_BLINK]     ))
    DBG1 (( MF__,"invisible   %d \n", attributes_array[VTA_INVISIBLE] ))
    DBG1 (( MF__,"mixed       %d \n", attributes_array[VTA_MIXED]     ))
}

/*==========================================================================*/

/*
 *  Fill the table of available colors.
 */

static	void	sql04_colors_array ( colors_array )

register char  *colors_array ;

{
    int				idx ;


    colors_array[VTC_MONOCHROME] = TRUE ;
    for ( idx = VTC_WHITE ; idx < VTC_LAST ; idx ++ )
	colors_array[idx] = FALSE ;

#if A_COLOR
#ifdef A_BGCOLOR

    if ( bg_color0 && fg_color0 ) colors_array [ VTC_BLACK      ] = TRUE ;
    if ( bg_color1 && fg_color1 ) colors_array [ VTC_RED        ] = TRUE ;
    if ( bg_color2 && fg_color2 ) colors_array [ VTC_GREEN      ] = TRUE ;
    if ( bg_color3 && fg_color3 ) colors_array [ VTC_YELLOW     ] = TRUE ;
    if ( bg_color4 && fg_color4 ) colors_array [ VTC_BLUE       ] = TRUE ;
    if ( bg_color5 && fg_color5 ) colors_array [ VTC_PINK       ] = TRUE ;
    if ( bg_color6 && fg_color6 ) colors_array [ VTC_LIGHT_BLUE ] = TRUE ;
    if ( bg_color7 && fg_color7 ) colors_array [ VTC_WHITE      ] = TRUE ;

    for ( idx = VTC_WHITE ;
	  (idx <= VTC_LIGHT_BLUE) && ! colors_array[idx] ;
	  idx ++ );
    sql04_has_colors = (idx <= VTC_LIGHT_BLUE);

#else /*A_BGCOLOR*/

    DBG1 (( MF__,"COLORS     %d \n" , COLORS ))
    if ( COLORS > COLOR_BLACK   ) colors_array [ VTC_BLACK      ] = TRUE ;
    if ( COLORS > COLOR_RED     ) colors_array [ VTC_RED        ] = TRUE ;
    if ( COLORS > COLOR_GREEN   ) colors_array [ VTC_GREEN      ] = TRUE ;
    if ( COLORS > COLOR_YELLOW  ) colors_array [ VTC_YELLOW     ] = TRUE ;
    if ( COLORS > COLOR_BLUE    ) colors_array [ VTC_BLUE       ] = TRUE ;
    if ( COLORS > COLOR_MAGENTA ) colors_array [ VTC_PINK       ] = TRUE ;
    if ( COLORS > COLOR_CYAN    ) colors_array [ VTC_LIGHT_BLUE ] = TRUE ;
    if ( COLORS > COLOR_WHITE   ) colors_array [ VTC_WHITE      ] = TRUE ;

    sql04_has_colors = has_colors ();

#endif /*A_BGCOLOR*/
#endif /*A_COLOR*/

#ifdef DEBUG_RTE
    for ( idx = VTC_WHITE ; idx <= VTC_LIGHT_BLUE ; idx ++ )
	DBG1 (( MF__,"color[%d]: %d \n", idx , colors_array[idx] ))
    DBG1 (( MF__,"has colors: %d \n" , sql04_has_colors ))
#endif

}

/*==========================================================================*/

/*
 *  Clear screen and update curses's color map.
 */

static	void	sql04_update_colors ( )

{
    int				idx ;


    /*
     *  We need to clear the screen before using init_pair
     *  since init_pair immediately updates the screen with the new colors.
     *  This can lead to multiple screen updates just before a new
     *  screen layout is to be output.
     *  Clearing the screen completly (refresh is required!)
     *  results in a single re-write of the new colored screen layout.
     */
    (void) clear ();
    (void) refresh ();

    for ( idx = 0 ; idx < MAXATTRIBUTES ; idx ++ )
    {
	sql04_attrib_table[idx].att &= ~A_COLOR ;
	sql04_attrib_table[idx].att |= sql04_convert_color ( idx ,
	    sql04_attrib_table[idx].fg, sql04_attrib_table[idx].bg );
    }

    /*
     *  We need a complete re-write of the screen, since we cleared it.
     */
    sql01_vt_clear = TRUE ;
}

/*==========================================================================*/

/*
 *  Convert a foreground/background color pair to a curses attribute.
 */

/*ARGSUSED*/	/* elem unused with screenlib */

static	chtype	sql04_convert_color ( elem , fg , bg )

int			elem ;
enum1   		fg ;
enum1   		bg ;

{
    chtype                      color_attr = 0 ;
    short                       fg_color ;
    short                       bg_color ;


    if ( ! sql04_has_colors )
    {
	DBG1 (( MF__,"cvtcol: no colors, returning attr 0x%08lx\n",
						(long) color_attr ))
	return ( color_attr );
    }

    /*
     *  Use default b/w if all is monochrome
     */
    if ( (bg == VTC_MONOCHROME) && (fg == VTC_MONOCHROME) )
    {
	DBG1 (( MF__,"cvtcol: b/w requested, returning attr 0x%08lx\n",
						(long) color_attr ))
	return ( color_attr );
    }

#if A_COLOR
#ifdef A_BGCOLOR

    switch ( bg )
    {
    case VTC_WHITE      : color_attr = BG_COL7 ; break ;
    case VTC_BLACK      : color_attr = BG_COL0 ; break ;
    case VTC_RED        : color_attr = BG_COL1 ; break ;
    case VTC_GREEN      : color_attr = BG_COL2 ; break ;
    case VTC_YELLOW     : color_attr = BG_COL3 ; break ;
    case VTC_BLUE       : color_attr = BG_COL4 ; break ;
    case VTC_PINK       : color_attr = BG_COL5 ; break ;
    case VTC_LIGHT_BLUE : color_attr = BG_COL6 ; break ;
    }

    switch ( fg )
    {
    case VTC_WHITE      : color_attr |= FG_COL0 ; break ;
    case VTC_BLACK      : color_attr |= FG_COL7 ; break ;
    case VTC_RED        : color_attr |= FG_COL1 ; break ;
    case VTC_GREEN      : color_attr |= FG_COL2 ; break ;
    case VTC_YELLOW     : color_attr |= FG_COL3 ; break ;
    case VTC_BLUE       : color_attr |= FG_COL4 ; break ;
    case VTC_PINK       : color_attr |= FG_COL5 ; break ;
    case VTC_LIGHT_BLUE : color_attr |= FG_COL6 ; break ;
    }

#else /*A_BGCOLOR*/

    switch ( fg )
    {
    case VTC_WHITE      : fg_color = COLOR_WHITE   ; break ;
    case VTC_BLACK      : fg_color = COLOR_BLACK   ; break ;
    case VTC_RED        : fg_color = COLOR_RED     ; break ;
    case VTC_GREEN      : fg_color = COLOR_GREEN   ; break ;
    case VTC_YELLOW     : fg_color = COLOR_YELLOW  ; break ;
    case VTC_BLUE       : fg_color = COLOR_BLUE    ; break ;
    case VTC_PINK       : fg_color = COLOR_MAGENTA ; break ;
    case VTC_LIGHT_BLUE : fg_color = COLOR_CYAN    ; break ;
    }

    switch ( bg )
    {
    case VTC_WHITE      : bg_color = COLOR_WHITE   ; break ;
    case VTC_BLACK      : bg_color = COLOR_BLACK   ; break ;
    case VTC_RED        : bg_color = COLOR_RED     ; break ;
    case VTC_GREEN      : bg_color = COLOR_GREEN   ; break ;
    case VTC_YELLOW     : bg_color = COLOR_YELLOW  ; break ;
    case VTC_BLUE       : bg_color = COLOR_BLUE    ; break ;
    case VTC_PINK       : bg_color = COLOR_MAGENTA ; break ;
    case VTC_LIGHT_BLUE : bg_color = COLOR_CYAN    ; break ;
    }

    if ( fg_color <  0      ) fg_color = 0 ;
    if ( fg_color >  COLORS ) fg_color = (short) COLORS ;
    if ( bg_color <  0      ) bg_color = 0 ;
    if ( bg_color >  COLORS ) bg_color = (short) COLORS ;

    /*
     *  Curses uses pair number 0 for its own purposes.
     */
    elem ++ ;
    if ( elem <  1           ) elem = 1 ;
    if ( elem >= COLOR_PAIRS ) elem = COLOR_PAIRS - 1 ;

    (void) init_pair ( (short) elem , fg_color , bg_color );
    color_attr = COLOR_PAIR ( elem );

#endif /*A_BGCOLOR*/
#endif /*A_COLOR*/

    DBG1 (( MF__,"cvtcol: %2d fg/bg %d/%d (%s/%s) 0x%08lx \n", elem , fg , bg ,
	sql04_color_name[fg] , sql04_color_name[bg] , (long) color_attr ))
    return ( color_attr );
}

/*==========================================================================*/

/*
 *  Extract several options from an options arry.
 */

static	void	sql04_get_options ( c_vt_options )

char			*c_vt_options ;

{
#ifdef	APPL_BUG
    int				i ;
#endif


    sql04_wait_for_input  = (int) c_vt_options [0] ;
    sql04_usage_mode      = (int) c_vt_options [1] ;
    sql04_return_on_last  = (int) c_vt_options [2] ;
    sql04_return_on_first = (int) c_vt_options [3] ;
    sql04_ring_bell       = (int) c_vt_options [4] ;
    sql04_mark_option     = (int) c_vt_options [5] ;
    sql04_mark_option     =  1 ; /*TEST !!!!*/
    sql04_enable_charkey  = (int) c_vt_options [6] ;

    sql04_first_linechg   = ((c_vt_options [7]      ) & 0x00ff) |
			    ((c_vt_options [8]  << 8) & 0xff00) ;
    sql04_last_linechg    = ((c_vt_options [9]      ) & 0x00ff) |
			    ((c_vt_options [10] << 8) & 0xff00) ;

    sql04_enable_ctrlkey  = (int) c_vt_options [11] ;
#ifdef	TEST_CTRLKEY
    sql04_enable_ctrlkey  = TRUE ;
#endif

#ifdef	PRINT_LINES_CHANGED
    if ( (sql04_first_linechg != 1) || (sql04_last_linechg != sql04_lines) )
    {
	int			fst ;
	int			lst ;


	DBG1(( MF__,"(%3d) first %2d, last %2d, lines %2d \n",
	    sql04_tio_count , sql04_first_linechg , sql04_last_linechg ,
	    sql04_lines ))
	lst = sql04_lines * sql04_cols ;
	for ( fst = 0 ; fst < lst ; fst ++ )
	    if ( sql04_tio_screen[fst] != sql04_check_screen[fst] ) break ;
	for ( lst -- ; lst > fst ; lst -- )
	    if ( sql04_tio_screen[lst] != sql04_check_screen[lst] ) break ;
	if ( fst <= lst )
	{
	    DBG1(( MF__,
		"sqltio: first %2d, col %2d ; last %2d, col %2d \n",
		fst/sql04_cols , fst%sql04_cols ,
		lst/sql04_cols , lst%sql04_cols ))
	    DBG1(( MF__,
		"sqltio: screen f %02x l %02x, old f %02x l %02x \n",
		sql04_tio_screen[fst]&0xff, sql04_tio_screen[lst]&0xff,
		sql04_check_screen[fst]&0xff, sql04_check_screen[lst]&0xff ))
	}
    }
    COPY ( sql04_check_screen , sql04_tio_screen , sql04_lines * sql04_cols );
#endif /*PRINT_LINES_CHANGED*/

#ifdef	GET_ALL_LINES
    sql04_first_linechg = 1 ;
    sql04_last_linechg  = sql04_lines ;
#else /*GET_ALL_LINES*/
#ifdef	APPL_BUG
    if ( sql04_first_linechg < 1 ) sql04_first_linechg = 1 ;
    if ( sql04_first_linechg > sql04_lines ) sql04_first_linechg = sql04_lines ;
    if ( sql04_last_linechg < 1 ) sql04_last_linechg = 1 ;
    if ( sql04_last_linechg > sql04_lines ) sql04_last_linechg = sql04_lines ;
#else /*APPL_BUG*/
    if ( sql04_first_linechg < 1        ||
	 sql04_first_linechg > sql04_lines ||
	 sql04_last_linechg  < 1        ||
	 sql04_last_linechg  > sql04_lines    )
    {
	(void) endwin ();
	(void) SET_TERMIO ( 0 , &sql04_termio_extern);
	DBG1 (( MF__,"restored external terminal settings \n" ))
	DBG1(( MF__,
	    "sqltio: first/last line changed: %2d, %2d, lines: %2d \n",
		sql04_first_linechg , sql04_last_linechg , sql04_lines ))
	sqlabort ();
    }
#endif /*APPL_BUG*/
#endif /*GET_ALL_LINES*/

    DBG1 (( MF__,"wait_for_input     = %d\n", sql04_wait_for_input ))
    DBG1 (( MF__,"usage_mode         = %d\n", sql04_usage_mode ))
    DBG1 (( MF__,"return_on_last     = %d\n", sql04_return_on_last ))
    DBG1 (( MF__,"return_on_first    = %d\n", sql04_return_on_first ))
    DBG1 (( MF__,"ring_bell          = %d\n", sql04_ring_bell ))
    DBG1 (( MF__,"mark_option        = %d\n", sql04_mark_option ))
    DBG1 (( MF__,"enable_charkey     = %d\n", sql04_enable_charkey ))
    DBG1 (( MF__,"first_line_changed = %d\n", sql04_first_linechg ))
    DBG1 (( MF__,"last_line_changed  = %d\n", sql04_last_linechg ))
    DBG1 (( MF__,"enable_ctrlkey     = %d\n", sql04_enable_ctrlkey ))
}

/*==========================================================================*/

/*
 *  Write the full output screen.
 *  To optimize the output, a save screen is created,
 *  which contains the screen text and the correct attribute
 *  for each screen position. (sqltio gets a screen with the end of field
 *  delimiters determining the attribute for the following gap between
 *  the fields.)
 */

static	void	sql04_full_screen ( )

{
    register int		pos ;
    register int		eps ;
    register int		in_field ;
    register UCHAR		nscr ;
    register UCHAR		natt ;


    /*
     *  Get the positions in the screen/attrib buffers
     *  where the first and last changed characters are.
     */
    pos = 0 ;
    eps = sql04_screen_size ;
    in_field = FALSE ;
    natt = sql04_tio_attrib[0];

    /*
     *  Reset the line change values
     *  since 'part_screen' might be called later during input.
     *  It then should only update the modified positions.
     *  The modifying functions will lower 'first_linechg' and
     *  raise 'last_linechg' to the correct values.
     */
    sql04_first_linechg = sql04_lines ;
    sql04_last_linechg  = 1 ;

    /*
     *  Clear the curses buffers.
     */
    (void) clear ();


    for ( ; pos < eps ; pos ++ )
    {
	/*
	 *  Get the current character.
	 */
	nscr = sql04_tio_screen[pos];

	/*
	 *  Check for a field delimiter.
	 */
	if ( nscr < FIELD_DELIMITERS )
	{
	    /*
	     *  A field delimiter changes the in-field state.
	     */
	    if ( nscr == VT_EOF )
	    {
		/*
		 *  End of field delimiter gives the attribute for all
		 *  following out of field characters.
		 *  The delimiter is replaced by a blank.
		 */
		natt = sql04_tio_attrib[pos] ;
		in_field = FALSE ;
	    }
	    else
	    {
		/*
		 *  Start of field delimiter (VT_SONCF || VT_SOCF).
		 *  If previously in field, tis behaves like an eof delimiter.
		 *  Otherwise, it gets the attribute of the leading
		 *  eof delimiter.
		 */
		if ( in_field ) natt = sql04_tio_attrib[pos];
		in_field = TRUE ;
	    }
	    /*
	     *  A field delimiter is displayed as blank.
	     */
	    nscr = BLANK ;
	}
	else
	{
	    /*
	     *  No field delimiter.
	     *  Each character within a field has its own attribute.
	     *  Characters within fields might have been changed.
	     *  The corresponding bit is not set in the save buffers.
	     *  To compare equal, if only the bit is changed,
	     *  strip this bit from the register variable.
	     *  Outside a field, only blanks are displayed.
	     */
	    if ( in_field )
		natt = sql04_tio_attrib[pos] & ~BIT_CHANGED ;
	    else
		nscr = BLANK ;
	}
	/* if nscr < FIELD_DELIMITERS */

	sql04_save_screen[pos] = nscr ;
	sql04_save_attrib[pos] = natt ;
	sql04_addch ( nscr , natt );
    }
    /* for pos */
}

/*==========================================================================*/

/*
 *  Write a partial output screen.
 *  Only those screen positions with changes against the previous screen
 *  are output to curses.
 *  To optimize further output, the save screen is updated.
 *  (see the comments to 'full_screen').
 */

static	void	sql04_part_screen ( )

{
    register int		pos ;
    register int		eps ;
    register int		in_field ;
    register UCHAR		nscr ;
    register UCHAR		natt ;
    register UCHAR		*ptr ;


    /*
     *  Get the positions in the screen/attrib buffers
     *  where the first and last changed characters might be.
     */
    pos = (sql04_first_linechg - 1) * sql04_cols ;
    eps = sql04_last_linechg * sql04_cols ;
    DBG1 (( MF__,"part_screen: pos %d \n", pos ))
    DBG1 (( MF__,"part_screen: eps %d \n", eps ))

    /*
     *  If we start at screen begin, the first character's attribute
     *  is always correct and we are not in a field.
     *  If we don't start with the first character,
     *  we have to determine if we are in a field or not.
     *  In a field each position has its own valid attribute,
     *  while outside a field the end of field delimiter determines
     *  the attribute for all following positions.
     */
    if ( pos == 0 ) 
    {
	in_field = FALSE ;
	natt = sql04_tio_attrib[0];
    }
    else
    {
	/*
	 *  Start checking the position before the first changed position.
	 */
	pos -- ;
	ptr = sql04_tio_screen + pos ;
	while ( (pos > 0) && (*ptr >= FIELD_DELIMITERS) )
	{
	    pos -- ;
	    ptr -- ;
	}
	/*
	 *  If at a start of field, the starting attribute is insignificant
	 *  since each field position has its own attribute.
	 *  At an end of field, the attribute is correct for the new line.
	 */
	if ( (*ptr == VT_SONCF) || (*ptr == VT_SOCF) )
	    in_field = TRUE ;
	else
	    in_field = FALSE ;
	natt = sql04_tio_attrib[pos];
	DBG1 (( MF__,"part_screen: pos %d: 0x%02x %s in field \n",
		    pos , (*ptr)&0xff , in_field?"":"not" ))
	/*
	 *  Restart at the beginning of the new line.
	 */
	pos = (sql04_first_linechg - 1) * sql04_cols ;
    }
    DBG1 (( MF__,"part_screen: atb 0x%02x \n", natt&0xff ))

    /*
     *  Reset the line change values
     *  since 'part_screen' might be called later during input.
     *  It then should only update the modified positions.
     *  The modifying functions will lower 'first_linechg' and
     *  raise 'last_linechg' to the correct values.
     */
    sql04_first_linechg = sql04_lines ;
    sql04_last_linechg  = 1 ;


    for ( ; pos < eps ; pos ++ )
    {
	/*
	 *  Get the current character.
	 */
	nscr = sql04_tio_screen[pos];

	/*
	 *  Check for a field delimiter.
	 */
	if ( nscr < FIELD_DELIMITERS )
	{
	    /*
	     *  A field delimiter changes the in-field state.
	     */
	    if ( nscr == VT_EOF )
	    {
		/*
		 *  End of field delimiter gives the attribute for all
		 *  following out of field characters.
		 *  The delimiter is replaced by a blank.
		 */
		natt = sql04_tio_attrib[pos] ;
		in_field = FALSE ;
	    }
	    else
	    {
		/*
		 *  Start of field delimiter (VT_SONCF || VT_SOCF).
		 *  If previously in field, tis behaves like an eof delimiter.
		 *  Otherwise, it gets the attribute of the leading
		 *  eof delimiter.
		 */
		if ( in_field ) natt = sql04_tio_attrib[pos];
		in_field = TRUE ;
	    }
	    /*
	     *  A field delimiter is displayed as blank.
	     */
	    nscr = BLANK ;
	}
	else
	{
	    /*
	     *  No field delimiter.
	     *  Each character within a field has its own attribute.
	     *  Characters within fields might have been changed.
	     *  The corresponding bit is not set in the save buffers.
	     *  To compare equal, if only the bit is changed,
	     *  strip this bit from the register variable.
	     *  Outside a field, only blanks are displayed.
	     */
	    if ( in_field )
		natt = sql04_tio_attrib[pos] & ~BIT_CHANGED ;
	    else
		nscr = BLANK ;
	}
	/* if nscr < FIELD_DELIMITERS */

	if ( (sql04_save_screen[pos] != nscr) ||
	     (sql04_save_attrib[pos] != natt)    )
	{
#if DEBUG_DEBUG
	    DBG1 (( MF__,"part_screen: line %02d col %02d from '%c' to '%c' \n",
	          LINE(pos) , COLUMN(pos) , sql04_save_screen[pos] , nscr ))
#endif /*DEBUG_DEBUG*/
	    sql04_save_screen[pos] = nscr ;
	    sql04_save_attrib[pos] = natt ;
	    (void) move ( LINE(pos) , COLUMN(pos) );
	    sql04_addch ( nscr , natt );
	}
    }
    /* for pos */
}

/*==========================================================================*/

/* Ausgabe der Statuszeile */

static	void	sql04_write_sysline ( c_sys_text , c_sys_attr ) /* screenlib */

UCHAR  *c_sys_text ;
UCHAR  *c_sys_attr ;

{
    int				i ;
    int				syslgt ;


    /* Falls keine hardwaremaessige Message-Zeile existiert, wird diese hinter
       der letzten Terminal-Zeile ausgegeben. Die Position muss gegebenfalls
       noch geaendert werden, falls die Softkeys in dieser Zeile ausgegeben
       werden */

#ifdef SCRLIB

    chtype			blank_attrib ;


    (void) move (LINES - 2, 0);
    (void) refresh ();                  /* Macke in Scrlib f. vt220 ... */
    msg_mode ();                        /* In den Message-Mode schalten */
    (void) attrset ( A_NORMAL );        /* sure is sure */

    if ( sql04_has_colors )
	(void) addch ( CHBLANK );       /* otherwise we may have a colored
					   first character (very very bad) in
					   report ; my problem ??? */

    else
	(void) addch ( CHBLANK | ATTR(c_sys_attr[0]) );

    for (i = 1 ; (c_sys_text[i-1] != 1) && (i < sql04_cols - 1); i++)
	(void) addch ( CHBLANK | ATTR(c_sys_attr[0]) );

    while (i < sql04_cols /* - 1 */ )
    {

	for (; (i < sql04_cols - 1) && ( c_sys_text[i] & 0xfe ); i++)
	{
	    sql04_addch ( c_sys_text[i] , c_sys_attr[i] );
	}

	blank_attrib = ATTR(c_sys_attr[i]);

	if ( i >= sql04_cols - 1 )
	    break ;
	else
	    if (c_sys_text[i] == 1)
		(void) addch ( CHBLANK | ATTR(c_sys_attr[i++]) );
	    else  /* == 0 */
		for (; (c_sys_text[i] != 1) && (i < sql04_cols /* - 1 */ ); i++)
		    (void) addch ( CHBLANK | blank_attrib );
    }

    (void) attrset ( blank_attrib );
    clrtoeol ();
    (void) attrset ( A_NORMAL );      /* sure is sure */

    cbol ();
    (void) refresh ();
    screen_mode ();

#else /*SCRLIB*/

    if ( ! has_status_line || ! to_status_line || ! from_status_line ) return ;
    if ( (int) (width_status_line) > 0 )
	syslgt = width_status_line < sql04_cols ?
		 width_status_line : sql04_cols ;
    else
	syslgt = sql04_cols ;

    (void) vidattr ( A_NORMAL );
    (void) putp ( tparm ( to_status_line , 0L , /* column */
		    /* dummies: */ 0L , 0L , 0L , 0L , 0L , 0L , 0L , 0L ) );
    (void) vidattr ( ATTR(c_sys_attr[0]) );
    for ( i = 0 ; (i < syslgt) && (c_sys_text[i] != 1) ; i ++ )
	(void) putchar ( ' ' );
    if ( i < syslgt )
    {
	(void) putchar ( ' ' );	/* for the SOF character */
	i ++ ;			/* skip the SOF character */
    }

    while ( i < syslgt )
    {
				/* end if 0 or 1 found (EOF or SOF) */
	for ( ; (i < syslgt) && (c_sys_text[i] & 0xfe) ; i ++ )
	{
	    if ( c_sys_attr[i] != c_sys_attr[i-1] )
		(void) vidattr ( ATTR(c_sys_attr[i]) );
	    (void) putchar ( c_sys_text[i] );
	}

	if ( i >= syslgt ) break ;
	if ( c_sys_text[i] == 1 )	/* SOF */
	{
	    if ( c_sys_attr[i] != c_sys_attr[i-1] )
		(void) vidattr ( ATTR(c_sys_attr[i]) );
	    (void) putchar ( ' ' );
	    i ++ ;
	}
	else				/* == 0 (EOF) */
	{
	    if ( c_sys_attr[i] != c_sys_attr[i-1] )
		(void) vidattr ( ATTR(c_sys_attr[i]) );
	    for ( ; (i < syslgt) && (c_sys_text[i] != 1) ; i ++ )
		(void) putchar ( ' ' );
	}
    }

    if ( (i < syslgt) && (c_sys_attr[i] != c_sys_attr[i-1]) )
	(void) vidattr ( ATTR(c_sys_attr[i]) );
    for ( ; i < syslgt ; i ++ )
	(void) putchar ( ' ' );
    (void) vidattr ( A_NORMAL );
    (void) putp ( from_status_line );
    (void) fflush ( stdout );

#endif /*SCRLIB*/
}

/*==========================================================================*/

/* Schreiben der Softkeys */

static	void	sql04_write_softkeys ( c_sk_text )

UCHAR           *c_sk_text ;

{
#ifdef SCRLIB

    extern VS       vs_fd ;
    int             skanz ;
    int             sklen ;
    char            i ;
    struct softkeys sks ;


    (void) attrset ( A_NORMAL ); /* Softkeys mit eingeschalteten Attr. gibt
				  * offenbar Murks auf vt220 etc ... */

    (void) refresh ();           /* wegen color-pc etc. , Softkeys werden
				  * sonst sofort wieder geloescht */

    skanz = f_skanz ();
    sklen = f_sk_length ();

    DBG1 (( MF__,"write_softkeys :         skanz = %d\n", skanz))
    DBG1 (( MF__,"write_softkeys :         sklen = %d\n", sklen))

    sks.anzahl = (short) skanz ;

    for ( i = 0 ; i < skanz ; i++ )
    {
	sks.sk[i].softkeyno = (short) i ;

	/* zum Testen , laueft sonst nicht mit scrlib-Vers. > 1.2 */
	FILL ((char *) sks.sk[i].text, ' ', 17);

	(void) strncpy (sks.sk[i].text, c_sk_text + 16 * i, sklen);

	DBG1 (( MF__,"write_softkeys :         sks.sk[i].text = %s\n", sks.sk[i].text))
    }

    w_sftkys ( &vs_fd , &sks );
    (void) attrset ( A_NORMAL );      /* sure is sure */

#else /*SCRLIB*/

    if ( ! sql04_hif_softkeys ) return ;
    (void) putp ( tparm ( sql04_hif_softkeys ,
	    (long)c_sk_text    , (long)c_sk_text+16 , (long)c_sk_text+32 ,
	    (long)c_sk_text+48 , (long)c_sk_text+64 , (long)c_sk_text+80 ,
	    (long)c_sk_text+96 , (long)c_sk_text+112 , (long)c_sk_text+128 ) ); 
    (void) fflush ( stdout );

#endif /*SCRLIB*/
}

/*==========================================================================*/

/*
 *  Read a key or character from the keyboard.
 */

static	int	sql04_get_key ( )

{
    int				rc ;
    int				keyfunc ;
    int				ich ;
    int				seqpos ;
    struct key_info		**first_match ;
    struct key_info		**last_match ;
    struct key_info		**cur ;
    char			buf [ 2 ];


    DBG1 (( MF__,"get_key: called \n" ))

    /*
     *  -1 is an illegal key function value. A key sequence is
     *  not matched as long as this value is negative.
     *  key_value is a global variable holding the secondary value
     *  for the key functions VTKEY_CHARACTER and VTKEY_CONTROL.
     */
    keyfunc         = -1 ;
    sql04_key_value = 0 ;

    /*
     *  'first_match' points to the first key that matches all
     *  characters of the key sequence as it is currently received.
     *  'last_match' points to the first key after 'first_match'
     *  that does not match all of the characters received.
     *  'first_match' will never exceed 'last_match'.
     *  If both are equal, there is no key matching the received
     *  sequence.
     *
     *  Initially, 'first_match' points to the first key in the list
     *  and 'last_match' points behind the last key in the list.
     *  In this way, the first character received can match all of
     *  the keys in the list.
     *
     *  'first_match' and 'last_match' are pointers to the
     *  list-linkage pointers 'ki_next'.
     *  The last key in the list points to NULL.
     *  'last_match' will then initially point to the linkage-pointer
     *  of the last key in the list.
     *  'cur' is used as a running variable.
     */
    for ( cur = &sql04_key_list ; *cur ; cur = &(*cur)->ki_next );
    first_match = &sql04_key_list ;
    last_match  = cur ;

    /*
     *  Search the key sequence in the key list.
     *  Key sequences may be multi-byte strings.
     *  The first character read from STDIN is compared against the
     *  first characters of the key sequences in the key list.
     *  Since there may be more list entries starting with the same
     *  character, the list is sorted by key sequences and the variables
     *  'first_match' and 'last_match' reflect the positions in the
     *  list where the first character matched.
     *  The second character read form STDIN is then compared
     *  against the second characters of the key sequences in the
     *  list. During this process the first/last match variables
     *  may narrow the range for the next search.
     *  This process continues until the search range shrinked to
     *  a single list entry.
     */
    for ( seqpos = 0 ; ; seqpos ++ )
    {
	DBGG (( "get_key: seqpos    %d \n", seqpos ))

	/*
	 *  Read a character from STDIN.
	 */
	rc = read ( 0 , buf , 1 );
	if ( rc < 0 )
	{
	    DBG1(( MF__, "get_key: read error: %s \n", sqlerrs() ))
	    if ( errno == EINTR )
		keyfunc = VTKEY_CANCEL ;
	    else
		keyfunc = VTKEY_END ;
	    break ;
	}
	if ( rc == 0 )
	{
	    DBG1 (( MF__,"get_key: end of file during read \n" ))
	    keyfunc = VTKEY_END ;
	    break ;
	}
	ich = buf[0] & 0xff ;
	DBGG (( "get_key: got character 0x%02x \n", ich ))

	/*
	 *  tic(1M) converts '\0' to '\200'.
	 */
	if ( ich == 0 ) ich = 0200 ;

	/*
	 *  Find the first list entry matching the character
	 *  at the current position of the key sequence.
	 */
	for ( cur = first_match ; cur != last_match ; cur = &(*cur)->ki_next )
	{
	    if ( ((*cur)->ki_sequence[seqpos]&0xff) >= ich ) break ;
	}
	first_match = cur ;

	/*
	 *  Find the first list entry after 'first_match' NOT matching
	 *  the character at the current position of the key sequence.
	 */
	for ( ; cur != last_match ; cur = &(*cur)->ki_next )
	{
	    if ( ((*cur)->ki_sequence[seqpos]&0xff) > ich ) break ;
	}
	last_match = cur ;

	/*
	 *  'last_match' points always to the first list entry that does
	 *  not match. If 'first_match' points to the same entry,
	 *  the received sequence is not in the list.
	 */
	if ( first_match == last_match ) break ;

	/*
	 *  If there is more than one list entry left,
	 *  continue the search with the next character.
	 */
	if ( (*first_match)->ki_next != *last_match ) continue ;

	/*
	 *  A single list entry is left and it matches the
	 *  currently received character.
	 *  If this is the last character in the list entry's
	 *  key sequence the key sequence is completely
	 *  received and the match is perfect.
	 */
	cur = first_match ;
	if ( (*cur)->ki_sequence[seqpos+1] == 0 )
	{
	    keyfunc = (*cur)->ki_function ;
	    break ;
	}

	/*
	 *  Continue to read characters until the key sequence
	 *  is complete, or a mismatching character is received.
	 */
    }

    /*
     *  If the key has already been determined in the loop,
     *  the work is finished.
     */
    if ( keyfunc >= 0 )
    {
	if ( sql04_usage_mode != VT_EDIT )
	{
	    switch ( keyfunc )
	    {
	    case VTKEY_TAB :
		keyfunc = VTKEY_NEXT_FIELD ;
		break ;
	    case VTKEY_BACK_TAB :
		keyfunc = VTKEY_PREV_FIELD ;
		break ;
	    }
	}
	DBG1 (( MF__,"get_key: returning key: %s \n", sql04_key_name(keyfunc) ))
	return ( keyfunc );
    }

    /*
     *  We received a character that did not match any of the
     *  keys in the list.
     *  If it was NOT the first character, the begin of one or more
     *  key sequences had been matched by previously
     *  received characters. The current characters belongs to a
     *  key sequence similar to those in the list.
     *  Thus the received sequence comes from an undefined key.
     */
    if ( seqpos != 0 )
    {
	keyfunc = VTKEY_UNKNOWN ;
	DBG1 (( MF__,"get_key: returning key: %s \n", sql04_key_name(keyfunc) ))
	return ( keyfunc );
    }

/* MAP CHARACTERS HERE (IBM -> ISO) */

    /*
     *  We received a character, not a key.
     *  If it is printable, return it in the global variable key_value.
     */
    if ( sql04_isprint(ich) )
    {
	keyfunc = VTKEY_CHARACTER ;
	sql04_key_value = ich ;
	DBG1 (( MF__,"get_key: returning key: %s \n", sql04_key_name(keyfunc) ))
	return ( keyfunc );
    }

    if ( sql04_enable_ctrlkey && (ich >= CTRL('A')) && (ich <= CTRL('Z')) )
    {
	DBG1 (( MF__,"get_key: control_key '%c' \n", ich + 'A' - CTRL('A') ))
	switch ( ich )
	{
	case CTRL('C') :
	case CTRL('Y') :
	    (void) kill ( getpid() , (ich == CTRL('C')) ? SIGINT : SIGQUIT );
	    keyfunc = VTKEY_UNKNOWN ;
	    DBG1 (( MF__,"get_key: returning key: %s \n", sql04_key_name(keyfunc) ))
	    return ( keyfunc );

	case CTRL('H') :	/* identical with BACKSPACE key */
	case CTRL('I') :	/* identical with TAB key */
	case CTRL('M') :	/* identical with RETURN key */
	    break ;

	default :
	    keyfunc = VTKEY_CONTROL ;
	    sql04_key_value = ich - CTRL('A') + 'A' ;
	    DBG1 (( MF__,"get_key: returning key: %s \n", sql04_key_name(keyfunc) ))
	    return ( keyfunc );
	}
    }

    keyfunc = VTKEY_UNKNOWN ;

    switch ( ich )
    {
    /*
     *  Some Control Characters have natural equivalences
     *  in the set of VTKEYs.
     */

    case '\b' :                     /* BACKSPACE */
	keyfunc = VTKEY_RUBOUT ;
	break ;

    case '\t' :                     /* TAB */
	if ( sql04_usage_mode == VT_EDIT )
	    keyfunc = VTKEY_TAB ;
	else
	    keyfunc = VTKEY_NEXT_FIELD ;
	break ;

    case '\n' :                     /* NEWLINE */
    case '\r' :                     /* RETURN */
	if ( sql04_usage_mode == VT_EDIT )
	    keyfunc = VTKEY_NEXT_FIELD ;
	else
	    keyfunc = VTKEY_DO ;
	break ;

    case 0x7f :                     /* DEL */
	keyfunc = VTKEY_DELETE_CHAR ;
	break ;

    /*
     *  The Control Characters below simulate some important keys
     *  which are not present on all keyboards.
     */

    case CTRL('D') :
	keyfunc = VTKEY_ENTER ;
	break ;

    case CTRL('E') :		/* see also CTRL('Z') */
	keyfunc = VTKEY_END ;
	break ;

    case CTRL('F') :
	keyfunc = VTKEY_CLEAR ;
	break ;

    case CTRL('K') :
	if ( sql04_usage_mode == VT_EDIT )
	    keyfunc = VTKEY_BACK_TAB ;
	else
	    keyfunc = VTKEY_PREV_FIELD ;
	break ;

    case CTRL('L') :
	keyfunc = VTKEY_REFRESH ;
	break ;

    case CTRL('R') :
	keyfunc = VTKEY_CMD ;
	break ;

    case CTRL('X') :
	keyfunc = VTKEY_DEL_EOF ;
	break ;

    case CTRL('Z') :		/* see also CTRL('E') */
	keyfunc = VTKEY_END ;
	break ;

    }

    DBG1 (( MF__,"get_key: returning key: %s \n", sql04_key_name(keyfunc) ))
    return ( keyfunc );
}

/*==========================================================================*/

/*
 *  Get a character and put it to the screen buffer.
 */

static	int	sql04_input_character ( )

{
    int				keyfunc ;
    int				lgt ;
    char			buf [ 16 ];


    keyfunc = sql04_get_key ();
    if ( keyfunc != VTKEY_CHARACTER ) 
    {
	return ( keyfunc );
    }

    lgt = 0 ;
    buf[lgt ++] = (char) sql04_key_value ;

#ifdef KANJI
    /*
     *  Collect a complete (Multi-Byte-) character.
     */
    {
	tsp00_Int4		len ;

	if ( sql04_encoding_ptr && sql04_encoding_cnt )
	{
	    while (    (lgt < sizeof(buf))
		    && (len = lgt , s80uni_chartype ( buf , &len , 
					sql04_codeset ) == uni_is_incomplete) )
	    {
		keyfunc = sql04_get_key ();
		if ( keyfunc != VTKEY_CHARACTER ) 
		{
		    MSGD (( -11004, ERR_TYPE, "VTERM   ",
				"inputchr: key within kanji sequence \n" ));
		    sql04_beep_flash ();
		    return ( keyfunc );
		}
		buf[lgt ++] = (char) sql04_key_value ;
	    }
	    if ( lgt >= sizeof(buf) )
	    {
		    MSGD (( -11004, ERR_TYPE, "VTERM   ",
				 "inputchr: kanji sequence too long %d \n", lgt ));
			sql04_beep_flash ();
			return ( keyfunc );
	    }
	}
    }
#endif

    sql04_put_charstring ( buf , lgt );

    return ( VTKEY_CHARACTER );
}

/*==========================================================================*/

/*
 *  Put a character which may be built by multiple bytes (e.g. Kanji).
 */

static	void	sql04_put_charstring ( buf , lgt )

char			*buf ;
int			lgt ;

{
    int				idx ;
    int				high_pos ;


#ifdef DEBUG_RTE
    DBG1 (( MF__,"putstr: at pos %d put 0x%02x ", sql04_position , buf[0]&0xff ))
    for ( idx = 1 ; idx < lgt ; idx ++ ) DBG1 (( MF__,"0x%02x ", buf[idx]&0xff ))
    DBG1 (( MF__,"\n" ))
#endif

    if ( ! sql04_in_field(sql04_position) )
    {
	DBG1 (( MF__,"putstr: not in field \n" ))
	sql04_beep_flash ();
	return ;
    }

    /*
     *  Cannot write to protected positions.
     */
    if ( is_protect(sql04_save_attrib[sql04_position]) )
    {
	DBG1 (( MF__,"putstr: at protected position \n" ))
	sql04_beep_flash ();
	/*
	 *  In a mixed field advance cursor to next unprotected position.
	 */
	if ( is_mixed(sql04_save_attrib[sql04_position]) )
	{
	    sql04_next_unprot ();
	    DBG1 (( MF__,"putstr: (mixed) found position %d \n", sql04_position ))
	}
	return ;
    }

    /*
     *  If in overtype mode, the character at the current position
     *  is removed before inserting the new one.
     */
    if ( ! sql04_insert_mode )
    {
	sql04_delete ();
    }

    /*
     *  Shift characters to the right.
     */
    for ( idx = 0 ; idx < lgt ; idx ++ )
    {
	high_pos = sql04_shift_right ( sql04_position );
	if ( high_pos < 0 )
	{
	    /*
	     *  The input field is already full.
	     */
	    while ( idx -- ) sql04_shift_left ( sql04_position );
	    /*IST XXX insert label should be switched to blink !*/
	    sql04_beep_flash ();
	    return ;
	}
    }
    /*
     *  This is the highest position, where a character has been modified.
     */
    sql04_position_changed ( high_pos );

    /*
     *  Update buffers.
     */
    for ( idx = 0 ; idx < lgt ; idx ++ )
    {
	sql04_tio_screen[sql04_position+idx] = (UCHAR) buf[idx];
	sql04_tio_attrib[sql04_position+idx] |= BIT_CHANGED ;
#ifdef KANJI
	sql04_charmodes[sql04_position+idx] = idx ? 1 : 0 ;
#endif
    }
    sql04_screen_changed = TRUE ;
    sql04_position_changed ( sql04_position );
#ifdef KANJI
    /*
     *  Position on the last byte of the character.
     */
    sql04_position += lgt - 1 ;
#endif

    /*
     *  Automatically advance the cursor to the next unprotected
     *  position. This may move "behind last".
     */
    sql04_next_unprot ();
    DBG1 (( MF__,"putstr: returning position %d \n", sql04_position ))
}

/*==========================================================================*/

/*
 *  Determine the insert mode for the current 'sqltio'.
 *  'insert_mode' is normally saved over several calls to 'sqltio'.
 *  If, however, 'sqltio' is called with an empty insert label,
 *  insert is initially switched off for this call.
 */

static	void	sql04_init_ins ( insert_pos , insert_text , insert_opt )

tsp00_Int2		*insert_pos ;
UCHAR			*insert_text ;
UCHAR			*insert_opt ;

{
    register int		pos ;


    sql04_insert_save = sql04_insert_mode ;
    pos = (insert_pos[0] - 1) * sql04_cols + (insert_pos[1] - 1);

    /*
     *  If there is no insert label, temporarily switch insert mode off.
     */
    if ( (pos <= 0) ||
	 (pos + VT_LABEL_SIZE >= sql04_screen_size) )
    {
	sql04_insert_mode = FALSE ;
    }
    DBG1 (( MF__,"iniins: old %d, pos %d, new %d \n",
	sql04_insert_save , pos , sql04_insert_mode ))

    /*
     *  If insert mode is active, display the insert label.
     */
    if ( sql04_insert_mode )
    {
	sql04_insert_on ( insert_pos , insert_text , insert_opt );
    }
}

/*==========================================================================*/

/*
 *  Save the insert mode for the next 'sqltio'.
 *  'insert_mode' is normally saved over several calls to 'sqltio'.
 *  If, however, 'sqltio' has been called with an empty insert label,
 *  insert has been switched off for this call and will be reset to its
 *  original state.
 */

static	void	sql04_reset_ins ( insert_pos )

tsp00_Int2		*insert_pos ;

{
    register int		pos ;


    pos = (insert_pos[0] - 1) * sql04_cols + (insert_pos[1] - 1);
    DBG1 (( MF__,"resins: new %d, pos %d, old %d \n",
	sql04_insert_mode , pos , sql04_insert_save ))

    /*
     *  If there is no insert label, reset insert mode.
     */
    if ( (pos <= 0) ||
	 (pos + VT_LABEL_SIZE >= sql04_screen_size) )
    {
	sql04_insert_mode = sql04_insert_save ;
    }
    else
    {
	/*
	 *  If insert mode is active, clear the insert label.
	 *  (It might be displayed elsewhere at the next 'sqltio')
	 */
	if ( sql04_insert_mode )
	{
	    sql04_insert_off ( insert_pos );
	    /* insert_mode is cleared by sql04_insert_off */
	    sql04_insert_mode = TRUE ;
	}
    }
}

/*==========================================================================*/

/*
 *  Switch the insert mode on and display the insert label.
 */

static	void	sql04_insert_on ( insert_pos , insert_text , insert_opt )

tsp00_Int2		*insert_pos ;
UCHAR			*insert_text ;
UCHAR			*insert_opt ;

{
    register int		pos ;
    register int		i ;
    register UCHAR		*ptr ;
    register UCHAR		atb ;


    sql04_insert_mode = TRUE ;

    pos = (insert_pos[0] - 1) * sql04_cols + (insert_pos[1] - 1);
    DBG1 (( MF__,"inson:  pos %d, label '%.8s' \n", pos , insert_text ))

    if ( (pos > 0) &&
	 (pos + VT_LABEL_SIZE < sql04_screen_size) )
    {
	ptr = insert_text ;
	atb = *insert_opt ;
	(void) move ( LINE(pos) , COLUMN(pos) );

	for ( i = 0 ; i < VT_LABEL_SIZE ; i ++ )
	{
	    sql04_addch ( *(ptr++) , atb );
	}
    }
}

/*==========================================================================*/

/*
 *  Switch the insert mode on and replace the insert label
 *  with the original screen contents.
 */

static	void	sql04_insert_off ( insert_pos )

tsp00_Int2		*insert_pos ;

{
    register int		pos ;
    register int		i ;
    register UCHAR		*ptr ;
    register UCHAR		*atp ;


    sql04_insert_mode = FALSE ;

    pos = (insert_pos[0] - 1) * sql04_cols + (insert_pos[1] - 1);
    DBG1 (( MF__,"insoff: pos %d, oldscreen '", pos ))

    if ( (pos > 0) &&
	 (pos + VT_LABEL_SIZE < sql04_screen_size) )
    {
	ptr = sql04_save_screen + pos ;
	atp = sql04_save_attrib + pos ;
	(void) move ( LINE(pos) , COLUMN(pos) );

	for ( i = 0 ; i < VT_LABEL_SIZE ; i ++ )
	{
	    DBG1 (( MF__,"%c" , *ptr ))
	    sql04_addch ( *(ptr++) , *(atp++) );
	}
    }
    DBG1 (( MF__,"' \n" ))
}

/*==========================================================================*/

static	void	sql04_local_keys ( keyfunc )

int			keyfunc ;

{
    register int		pos ;
    register int		col ;


    pos = sql04_position ;

    switch ( keyfunc )
    {
    case VTKEY_CURSOR_UP:
	pos -= sql04_cols ;
	break ;

    case VTKEY_CURSOR_DOWN:
	pos += sql04_cols ;
	break ;

    case VTKEY_CURSOR_RIGHT:
	pos ++ ;
	break ;

    case VTKEY_CURSOR_LEFT:
	pos -- ;
	break ;

    case VTKEY_CURSOR_HOME:
	col = sql04_position ;	/* save old position */
	sql04_position = 0 ;
	pos = sql04_next_field ();
	sql04_position = col ;	/* restore old position */
	break ;

    case VTKEY_CURSOR_END:
	col = sql04_position ;	/* save old position */
	sql04_position = sql04_screen_size-1 ;
	pos = sql04_prev_field ();
	sql04_position = col ;	/* restore old position */
	break ;

    case VTKEY_NEXT_FIELD:
	pos = sql04_next_field ();
	break ;

    case VTKEY_PREV_FIELD :
	pos = sql04_prev_field ();
	break ;

    case VTKEY_DELETE_CHAR :
	sql04_delete ();
	break ;

    case VTKEY_RUBOUT:
	pos = sql04_rubout ();
	break ;

    case VTKEY_DEL_EOF:
	sql04_erase_to_eof ();
	break ;

    case VTKEY_TAB:
	col = COLUMN(pos);
	if ( col + DELTA_TAB >= sql04_cols )
	    pos += sql04_cols - col ; /* start of next line */
	else
	    pos += (col / DELTA_TAB + 1) * DELTA_TAB - col ;
	break ;

    case VTKEY_BACK_TAB:
	col = COLUMN(pos);
	if ( col - DELTA_TAB < 0 )
	{
	    pos -= col ;
	    col = sql04_cols ; /* past end of previous line */
	}
	pos -= col - (col - 1) / DELTA_TAB * DELTA_TAB ;
	break ;

    default:
	sql04_beep_flash ();
	break ;
    }

#ifdef KANJI
    /*
     *  Except when trying to move one character right,
     *  position at the beginning of a character by moving left.
     *  This prevents curses from optimizing by outputting only
     *  a part of the character.
     */
    if ( pos == sql04_position + 1 )
	col = 1 ;
    else
	col = -1 ;
    while ( (pos > 0) && (pos <= sql04_screen_size) && sql04_charmodes[pos] )
    {
	pos += col ;
    }
#endif

    /*
     *  Don't allow movements behind the last field,
     *  if 'return_on_last' is requested.
     */
    if ( sql04_return_on_last )
    {
	if ( pos >= sql04_screen_size )
	{
	    /* tried to move behind screen */
	    sql04_behind_last = TRUE ;
	    return ;
	}
	if ( (pos >= 0) &&
	     !sql04_in_field(pos) &&
	     (sql04_find_next(pos , sql04_screen_size) < 0) )
	{
	    /* tried to move behind last field */
	    sql04_behind_last = TRUE ;
	    return ;
	}
    }

    /*
     *  Don't allow movements before the first field,
     *  if 'return_on_first' is requested.
     */
    if ( sql04_return_on_first )
    {
	if ( pos < 0 )
	{
	    /* tried to move before screen */
	    sql04_before_first = TRUE ;
	    return ;
	}
	if ( (pos < sql04_screen_size) &&
	     !sql04_in_field(pos) &&
	     (sql04_find_prev(pos , -1 ) < 0) )
	{
	    /* tried to move before first field */
	    sql04_before_first = TRUE ;
	    return ;
	}
    }

    /*
     *  Some local key functions may wrap around the screen.
     */
    if ( pos < 0 ) pos += sql04_screen_size ;
    if ( pos >= sql04_screen_size ) pos -= sql04_screen_size ;

    /*
     *  If the position changed, we have to update the global 'position'
     *  and probably 'displpos'.
     */
    if ( pos != sql04_position )
    {
	/*
	 *  If both positions are the same,
	 *  or if the new position is outside a field,
	 *  or if the new position is visible,
	 *  or if the new position is in a different field
	 *  then set the display cursor to the same new position
	 *  as the buffer cursor.
	 */
	if ( (sql04_displpos == sql04_position) ||
	     ! sql04_in_field(pos) ||
	     ! is_invisible(sql04_tio_attrib[pos]) ||
	     (sql04_find_eof(sql04_displpos) != sql04_find_eof(pos)) )
	{
	    sql04_displpos = pos ;
	}
	sql04_position = pos ;
    }
}

/*==========================================================================*/

/*
 *  Erase the character at the cursor position and
 *  shift the characters right from the cursor position left.
 */

static	void	sql04_delete ( )

{
    register int		pos ;
    register UCHAR		*atp ;
#ifdef KANJI
    int				cnt ;
#endif


    pos = sql04_position ;
    atp = sql04_tio_attrib + pos ;

    if ( !sql04_in_field(pos) || is_protect(*atp) )
    {
	sql04_beep_flash ();
	return ;
    }

    /*
     *  This position is the lowest one to be modified by 'delete'.
     */
    sql04_position_changed ( pos );

#ifdef KANJI
    cnt = 0 ;
    do
    {
	pos = sql04_position ;
#endif

	/*
	 *  Shift the characters right from this position to the left.
	 */
	pos = sql04_shift_left ( pos );

	/*
	 *  This position is the highest one to be modified by 'delete'.
	 */
	sql04_position_changed ( pos );

	/*
	 *  Blank the specified position out.
	 */
	sql04_tio_screen[pos] = BLANK ;
	sql04_tio_attrib[pos] |= BIT_CHANGED ;
	sql04_screen_changed = TRUE ;

#ifdef KANJI
	sql04_charmodes[pos] = 0 ;
    }
    while (    (++cnt < sql04_screen_size) /* avoid infinite loop */
	    && sql04_charmodes[sql04_position] );
#endif
}

/*==========================================================================*/

/*
 *  Erase the character to the left of the cursor.
 *  This is also allowed if cursor is at the end of field delimiter
 *  or at the first position of a continuation field.
 *  If in insert mode, the characters right from the new cursor
 *  position are shifted left.
 */

static	int	sql04_rubout ( )

{
    register int		pos ;
    register int		eps ;
    register UCHAR		*ptr ;
    register UCHAR		*atp ;
    int				rubout_pos ;


    pos = sql04_position ;
    eps = -1 ;

#ifdef KANJI
    /*
     *  Find the first byte of the current character.
     */
    do
    {
#endif

	pos -- ;
	ptr = sql04_tio_screen + pos ;
	atp = sql04_tio_attrib + pos ;

	if ( pos <= eps )
	{
	    sql04_beep_flash ();
	    return ( sql04_position );
	}

	/*
	 *  If the cursor was at the first position of a continuation field,
	 *  delete the last character of the previous field.
	 */
	if ( (*ptr == VT_SOCF) &&
	     (*(ptr+1) >= FIELD_DELIMITERS) &&
	     is_unprot(*(atp+1)) )
	{
	    pos = sql04_find_prev ( pos , eps );
	    if ( pos < eps )
	    {
		sql04_beep_flash ();
		return ( sql04_position );
	    }
	    pos = sql04_find_eof ( pos );
	    ptr = sql04_tio_screen + pos ;
	    atp = sql04_tio_attrib + pos ;
	}

	/*
	 *  If neither before nor now in field, there is nothing to delete.
	 */
	if ( ! sql04_in_field(pos) || is_protect(*atp) )
	{
	    sql04_beep_flash ();
	    return ( sql04_position );
	}

#ifdef KANJI
    }
    while ( sql04_charmodes[pos] );
#endif

    /*
     *  This is the lowest position to be modified by 'rubout'.
     */
    sql04_position_changed ( pos );

    /*
     *  Position at the first byte of the character
     *  and delete the whole character.
     */
    rubout_pos = pos ;
    pos = sql04_position ;
    sql04_position = rubout_pos ;
    sql04_delete ();

    /*
     *  If not in insert mode, the current position is overtyped
     *  with a blank instead of being removed.
     *  After having removed a character, insert a blank here.
     */
    if ( ! sql04_insert_mode )
    {
	sql04_insert_mode = TRUE ;
	sql04_put_charstring ( " " , 1 );
	sql04_insert_mode = FALSE ;
    }

    sql04_position = pos ;
    return ( rubout_pos );
}

/*==========================================================================*/

/*
 *  Fill the rest of the current field with blanks.
 *  If a mixed field contains a protected position, stop at it.
 *  Don't erase continuation fields.
 */

static	void	sql04_erase_to_eof ( )

{
    register int		pos ;
    register int		eps ;
    register UCHAR		*atp ;
    register UCHAR		*ptr ;


    pos = sql04_position ;
    eps = sql04_screen_size ;
    ptr = sql04_tio_screen + pos ;
    atp = sql04_tio_attrib + pos ;

    if ( ! sql04_in_field(pos) || is_protect(*atp) )
    {
	sql04_beep_flash ();
	return ;
    }

    sql04_position_changed ( pos );
    while ( (pos < eps) && (*ptr >= FIELD_DELIMITERS) && is_unprot(*atp) )
    {
	*ptr = BLANK ;
	*atp |= BIT_CHANGED ;
#ifdef KANJI
	sql04_charmodes[pos] = 0 ;
#endif
	pos ++ ;
	ptr ++ ;
	atp ++ ;
    }
    sql04_screen_changed = TRUE ;
    sql04_position_changed ( pos );
}

/*==========================================================================*/

/*
 *  Shift the characters right of 'position' one position to the left.
 *  Shift through all continuation fields.
 *  Stop at a protected position.
 *  Update the 'tio_screen' buffer only.
 *  Return the position of the last unprotected character of the fields.
 */

static	int	sql04_shift_left ( start_position )

int			start_position ;

{
    register int		pos ;
    register int		eps ;
    register UCHAR		*ptr ;
    register UCHAR		*atp ;
    int				lastpos ;


    pos = start_position ;
    eps = sql04_screen_size ;
    ptr = sql04_tio_screen + pos ;
    atp = sql04_tio_attrib + pos ;

    /*
     *  We may have to shift characters through several continuation fields.
     */
    for ( ; ; )
    {
	/*
	 *  Start with the first character which is to be shifted left.
	 */
	pos ++ ;
	ptr ++ ;
	atp ++ ;
	lastpos = pos ;

	/*
	 *  Shift all characters in the field left.
	 */
	while ( (pos < eps) && (*ptr >= FIELD_DELIMITERS) && is_unprot(*atp) )
	{
	    *(ptr-1) = *ptr ;
	    *(atp-1) |= BIT_CHANGED ;
#ifdef KANJI
	    sql04_charmodes[pos-1] = sql04_charmodes[pos] ;
#endif
	    pos ++ ;
	    ptr ++ ;
	    atp ++ ;
	}
	if ( pos != lastpos ) sql04_screen_changed = TRUE ;

	/*
	 *  Stop at screen end or at a protected character in the field.
	 */
	if ( (pos >= eps) || ((*ptr >= FIELD_DELIMITERS) && is_protect(*atp)) )
	{
	    return ( pos - 1 );
	}

	/*
	 *  We found an end of field delimiter.
	 *  Store the position of the last unprotected character.
	 *  Look for a non-empty continuation field.
	 */
	lastpos = pos - 1 ;
	pos = sql04_find_next ( pos , eps );
	ptr = sql04_tio_screen + pos ;
	atp = sql04_tio_attrib + pos ;

	/*
	 *  Return, if there are no more fields or
	 *  if at a non-continuation field
	 *  or at a protected character at the first position.
	 */
	if ( (pos < 0) || (*(ptr-1) != VT_SOCF) || is_protect(*atp) )
	{
	    return ( lastpos );
	}

	/*
	 *  Move the first character from the continuation field
	 *  to the last position of the previous field.
	 */
	sql04_tio_screen[lastpos] = *ptr ;
	sql04_tio_attrib[lastpos] |= BIT_CHANGED ;
#ifdef KANJI
	sql04_charmodes[lastpos] = sql04_charmodes[pos] ;
#endif
	sql04_screen_changed = TRUE ;

	/*
	 *  Continue with shifting characters within this continuation field.
	 */
    }
    /* for(;;) */
    /*NOTREACHED*/
}

/*==========================================================================*/

/*
 *  Shift the characters from 'position' on right one position to the right.
 *  Shift through all continuation fields.
 *  Stop at a protected position.
 *  Update the 'tio_screen' buffer only.
 *  Return the position of the last unprotected character of the fields.
 */

static	int	sql04_shift_right ( start_position )

int			start_position ;

{
    register int		pos ;
    register int		eps ;
    register UCHAR		*ptr ;
    register UCHAR		*atp ;
    int				lastpos ;
    int				end_pos ;


    DBG1 (( MF__,"shftrigt: called    %d \n", start_position ))

    pos = start_position ;
    eps = sql04_screen_size ;
    ptr = sql04_tio_screen + pos ;
    atp = sql04_tio_attrib + pos ;

    /*
     *  Search for the last unprotected position in the (continued) field.
     */
    for ( ; ; )
    {
	/*
	 *  Find the end of the current field or a protected character.
	 */
	while ( (pos < eps) && (*ptr >= FIELD_DELIMITERS) && is_unprot(*atp) )
	{
	    pos ++ ;
	    ptr ++ ;
	    atp ++ ;
	}

	/*
	 *  The current position is one character position behind
	 *  the last writable position of this field.
	 */
	end_pos = pos ;

	/*
	 *  Stop at screen end
	 *  or at a protected character in the field.
	 */
	if ( (pos >= eps) || ((*ptr >= FIELD_DELIMITERS) && is_protect(*atp)) )
	{
	    break ;
	}

	/*
	 *  Look for a non-empty continuation field.
	 */
	pos = sql04_find_next ( pos , eps );
	ptr = sql04_tio_screen + pos ;
	atp = sql04_tio_attrib + pos ;

	/*
	 *  Stop, if there are no more fields or
	 *  if at a non-continuation field
	 *  or at a protected character at the first position.
	 */
	if ( (pos < 0) || (*(ptr-1) != VT_SOCF) || is_protect(*atp) )
	{
	    break ;
	}
    }
    /* for(;;) */

    /*
     *  Get pointers to the last writable position in the field.
     */
    pos = end_pos - 1 ;
    eps = start_position ;
    ptr = sql04_tio_screen + pos ;
    DBG1 (( MF__,"shftrigt: end pos   %d \n", end_pos ))

    /*
     *  Insert is possible only if there is at least one space
     *  at the end of the field.
     */
    if ( *ptr != ' ' )
    {
	DBG1 (( MF__,"shftrigt: not blank %d \n", end_pos ))
	return ( -1 );
    }

    /*
     *  Go to the first character to be shifted right.
     */
    pos -- ;
    ptr -- ;

    /*
     *  Shift the characters in the field(s) to the right.
     */
    while ( pos >= eps )
    {
	/*
	 *  Shift the characters within the current field.
	 */
	atp = sql04_tio_attrib + pos ;
	while ( (pos >= eps) && (*ptr >= FIELD_DELIMITERS) )
	{
	    *(ptr+1) = *ptr ;
	    *(atp+1) |= BIT_CHANGED ;
#ifdef KANJI
	    sql04_charmodes[pos+1] = sql04_charmodes[pos] ;
#endif
	    pos -- ;
	    ptr -- ;
	    atp -- ;
	}

	/*
	 *  Stop at insert position.
	 */
	if ( pos < eps ) break ;

	/*
	 *  Save the position, where to put the last character from
	 *  the previous continuation field.
	 */
	lastpos = pos + 1 ;
	DBG1 (( MF__,"shftrigt: lastpos   %d \n", lastpos ))

	/*
	 *  Find the end of the previous field.
	 */
	pos = sql04_find_prev ( pos , -1 );
	if ( pos < 0 ) break ; /* MUST NEVER HAPPEN ! */
	pos = sql04_find_eof ( pos );
	ptr = sql04_tio_screen + pos ;

	/*
	 *  Move the last character of this field to the saved position.
	 */
	sql04_tio_screen[lastpos] = *ptr ;
	sql04_tio_attrib[lastpos] |= BIT_CHANGED ;
#ifdef KANJI
	sql04_charmodes[lastpos] = sql04_charmodes[pos] ;
#endif
	sql04_screen_changed = TRUE ;
	DBG1 (( MF__,"shftrigt: movepos   %d \n", pos ))

	/*
	 *  Go to the first character of this field to be shifted right.
	 */
	pos -- ;
	ptr -- ;
    }
    /* while */

    DBG1 (( MF__,"shftrigt: returning %d \n", end_pos ))
    return ( end_pos );
}

/*==========================================================================*/

/*
 *  Set 'sql04_position' to the first unprotected position
 *  of the current or of the next following field.
 *  Wrap around the end of the screen.
 *  If no unprotected position exists, beep and leave 'sql04_position'
 *  unchanged.
 */

static	void	sql04_next_unprot ( )

{
    register int		pos ;
    register int		went_next_field = FALSE ;


    /*
     *  Try the next unprotected position in the current field.
     */
    pos = sql04_find_unprot ( sql04_position );

    /*
     *  If none, search for the next field with an unprotected position.
     */
    if ( pos < 0 )
    {
	pos = sql04_next_field ();
	if ( pos != sql04_position ) went_next_field = TRUE ;
    }

    /*
     *  The search might have exceeded the last field.
     */
    if ( pos >= sql04_screen_size )
    {
	sql04_behind_last = TRUE ;
	return ;
    }

    /*
     *  In invisible fields, the display cursor remains on the first
     *  character of the field when typing characters.
     *  If the new position is visible,
     *  or the old position was visible,
     *  or the position changed to a new field
     *  then the display cursor should follow the buffer cursor.
     */
    if ( ! is_invisible(sql04_tio_attrib[pos]) ||
	 ! is_invisible(sql04_tio_attrib[sql04_displpos]) ||
	 went_next_field )
    {
	sql04_displpos = pos ;
    }

    sql04_position = pos ;
}

/*==========================================================================*/

/*
 *  Return the first unprotected position of the next following field.
 *  Wrap around the end of the screen.
 *  If no unprotected position exists, beep and return 'sql04_position'.
 */

static	int	sql04_next_field ( )

{
    register int		fpos ;
    register int		pos ;


    /*
     *  Go to the first unprotected position of the next field.
     */
    for ( pos = sql04_position ; ; )
    {
	pos = sql04_find_next ( pos , sql04_screen_size );
	if ( (pos < 0) || is_unprot(sql04_tio_attrib[pos]) ) break ;
	fpos = pos ;
	pos = sql04_find_unprot ( pos );
	if ( pos > 0 ) break ;
	pos = fpos ;
    }

    /*
     *  If none found, restart from the beginning of the screen.
     *  If, however, 'return_on_last' is active, return a position
     *  past the end of the screen.
     */
    if ( pos < 0 )
    {
	if ( sql04_return_on_last ) return ( sql04_screen_size );
	for ( pos = 0 ; ; )
	{
	    pos = sql04_find_next ( pos , sql04_position + 1 );
	    if ( (pos < 0) || is_unprot(sql04_tio_attrib[pos]) ) break ;
	    fpos = pos ;
	    pos = sql04_find_unprot ( pos );
	    if ( pos > 0 ) break ;
	    pos = fpos ;
	}
    }

    if ( pos >= 0 ) return ( pos );
    sql04_beep_flash ();
    return ( sql04_position );
}

/*==========================================================================*/

/*
 *  Return the first unprotected position of the next previous field.
 *  Wrap around the beginning of the screen.
 *  If no unprotected position exists, beep and return 'sql04_position'.
 */

static	int	sql04_prev_field ( )

{
    register int		fpos ;
    register int		pos ;


    /*
     *  Go to the first unprotected position of the previous field.
     */
    for ( pos = sql04_position ; ; )
    {
	pos = sql04_find_prev ( pos , -1 );
	if ( (pos < 0) || is_unprot(sql04_tio_attrib[pos]) ) break ;
	fpos = pos ;
	pos = sql04_find_unprot ( pos );
	if ( pos > 0 ) break ;
	pos = fpos ;
    }

    /*
     *  If none found, restart from the end of the screen.
     *  If, however, 'return_on_first' is active, return a position
     *  before the beginning of the screen.
     */
    if ( pos < 0 )
    {
	if ( sql04_return_on_first ) return ( -1 );
	for ( pos = sql04_screen_size-1 ; ; )
	{
	    pos = sql04_find_prev ( pos , sql04_position );
	    if ( (pos < 0) || is_unprot(sql04_tio_attrib[pos]) ) break ;
	    fpos = pos ;
	    pos = sql04_find_unprot ( pos );
	    if ( pos > 0 ) break ;
	    pos = fpos ;
	}
    }

    if ( pos >= 0 ) return ( pos );
    sql04_beep_flash ();
    return ( sql04_position );
}

/*==========================================================================*/

static	void	sql04_position_changed ( position )

int			position ;

{
    register int		lno ;


    /*
     *  'first_linechg' and 'last_linechg' count from 1 to sql04_lines.
     */
    lno = LINE(position) + 1 ;

    if ( lno < sql04_first_linechg ) sql04_first_linechg = lno ;
    if ( lno > sql04_last_linechg  ) sql04_last_linechg  = lno ;
}

/*==========================================================================*/

/*
 *  We are in a field, if not at a field delimiter and the
 *  next previous delimiter is a start of field and the
 *  current position is either unprotected or mixed.
 */

static	int	sql04_in_field ( start_position )

{
    register int		pos ;
    register UCHAR		*ptr ;
    register UCHAR		*atp ;


    /*
     *  Get a pointer to the current character.
     */
    pos = start_position ;
    ptr = sql04_tio_screen + pos ;

    /*
     *  If the current character is a field delimiter,
     *  we are not in a field.
     */
    if ( *ptr < FIELD_DELIMITERS ) return ( FALSE );

    /*
     *  Step from the current character backwards
     *  until a field delimiter is found.
     */
    do
    {
	pos -- ;
	ptr -- ;
    }
    while ( (pos >= 0) && (*ptr >= FIELD_DELIMITERS) );

    /*
     *  If no field delimiter found or
     *  the current character is a end of field delimiter,
     *  we are not in a field.
     */
    if ( (pos < 0) || (*ptr == VT_EOF) ) return ( FALSE );

    /*
     *  Step into the field and get its attribute.
     */
    pos ++ ;
    ptr ++ ;
    atp = sql04_tio_attrib + pos ;

    if ( is_unprot(*atp) || is_mixed(*atp) )
	return ( TRUE );
    else
	return ( FALSE );
}

/*==========================================================================*/

/*
 *  Return the position of the first character
 *  of the next following unprotected or mixed field.
 *  If no field follows, return -1.
 */

static	int	sql04_find_next ( start_position , stop_position )

int			start_position ;
int			stop_position ;

{
    register int		pos ;
    register int		eps ;
    register UCHAR		*ptr ;
    register UCHAR		*atp ;


    DBG1 (( MF__,"find_next: start     %d \n", start_position ))
    DBG1 (( MF__,"find_next: stop      %d \n", stop_position ))

    pos = start_position ;
    eps = stop_position ;
    ptr = sql04_tio_screen + pos ;

    /*
     *  Loop until an unprotected or mixed field is found.
     */
    for ( ; pos < eps ; )
    {
	/*
	 *  Step from the current character forward
	 *  until a start of field delimiter is found.
	 */
	while ( (pos < eps) &&
		(*ptr != VT_SONCF) &&
		(*ptr != VT_SOCF) )
	{
	    pos ++ ;
	    ptr ++ ;
	}

	/*
	 *  If no field found, give up.
	 */
	if ( pos >= eps ) break ;

	/*
	 *  We found a start of field delimiter.
	 *  Move into that field and get its attribute.
	 */
	pos ++ ;
	ptr ++ ;
	atp = sql04_tio_attrib + pos ;

	/*
	 *  If we found an unprotected or mixed field, return.
	 */
	if ( (pos < eps) &&
	     (*ptr >= FIELD_DELIMITERS) &&
	     (is_unprot(*atp) || is_mixed(*atp)) )
	{
	    DBG1 (( MF__,"find_next: returning %d \n", pos ))
	    return ( pos );
	}
    }

    DBG1 (( MF__,"find_next: returning %d \n", -1 ))
    return ( -1 );
}

/*==========================================================================*/

/*
 *  Return the position of the first character
 *  of the next previous unprotected or mixed field.
 *  If no field leads, return -1.
 */

static	int	sql04_find_prev ( start_position , stop_position )

int			start_position ;
int			stop_position ;

{
    register int		pos ;
    register int		eps ;
    register UCHAR		*ptr ;
    register UCHAR		*atp ;


    DBG1 (( MF__,"find_prev: start     %d \n", start_position ))
    DBG1 (( MF__,"find_prev: stop      %d \n", stop_position ))

    pos = start_position ;
    eps = stop_position ;
    ptr = sql04_tio_screen + pos ;

    /*
     *  Step from the current character backwards
     *  until a field delimiter is found.
     */
    while ( (pos > eps) && (*ptr >= FIELD_DELIMITERS) )
    {
	pos -- ;
	ptr -- ;
    }

    /*
     *  The field delimiter may be an end of field or a start of field.
     *  In the first case we were outside a field and have to find
     *  the beginning of the field.
     *  In the second case we were inside a field and found its own
     *  beginning and have to find the beginning of the previous field.
     */
    if ( pos > eps )
    {
	pos -- ;
	ptr -- ;
    }

    /*
     *  Loop until an unprotected or mixed field is found.
     */
    for ( ; pos > eps ; )
    {
	/*
	 *  Find the next previous start of field.
	 */
	while ( (pos > eps) && (*ptr != VT_SONCF) && (*ptr != VT_SOCF) )
	{
	    pos -- ;
	    ptr -- ;
	}

	/*
	 *  If no field found, give up.
	 */
	if ( pos <= eps ) break ;

	/*
	 *  We found a start of field delimiter.
	 *  Move into that field and get its attribute.
	 */
	pos ++ ;
	ptr ++ ;
	atp = sql04_tio_attrib + pos ;

	/*
	 *  If we found an unprotected or mixed field, return.
	 */
	if ( (*ptr >= FIELD_DELIMITERS) &&
	     (is_unprot(*atp) || is_mixed(*atp)) )
	{
	    DBG1 (( MF__,"find_prev: returning %d \n", pos ))
	    return ( pos );
	}

	/*
	 *  We are at the first character of a protected field.
	 *  Move before its start of field delimiter so that the next loop
	 *  execution does not find the same field again.
	 */
	pos -= 2 ;
	ptr -= 2 ;
    }

    DBG1 (( MF__,"find_prev: returning %d \n", -1 ))
    return ( -1 );
}

/*==========================================================================*/

/*
 *  Return the next following unprotected position within the same field.
 *  If no unprotected position follows in this field, return -1.
 */

static	int	sql04_find_unprot ( start_position )

int			start_position ;

{
    register int		pos ;
    register int		eps ;
    register UCHAR		*ptr ;
    register UCHAR		*atp ;


    pos = start_position ;
    pos ++ ; /* don't find the current position */
    eps = sql04_screen_size ;
    ptr = sql04_tio_screen + pos ;
    atp = sql04_tio_attrib + pos ;

    /*
     *  We start always in a field.
     */
    while ( (pos < eps) && (*ptr >= FIELD_DELIMITERS) && is_protect(*atp) )
    {
	pos ++ ;
	ptr ++ ;
	atp ++ ;
    }
    if ( (pos < eps) && (*ptr >= FIELD_DELIMITERS) && is_unprot(*atp) )
    {
	return ( pos );
    }

    return ( -1 );
}

/*==========================================================================*/

/*
 *  Return the position of the last character of the field.
 */

static	int	sql04_find_eof ( start_position )

int			start_position ;

{
    register int		pos ;
    register int		eps ;
    register UCHAR		*ptr ;


    pos = start_position ;
    eps = sql04_screen_size ;
    ptr = sql04_tio_screen + pos ;

    /*
     *  We start always in a field.
     */
    while ( (pos < eps) && (*ptr >= FIELD_DELIMITERS) )
    {
	pos ++ ;
	ptr ++ ;
    }

    return ( pos - 1 );
}

#ifdef MARK_NOCH_ZU_TUN
/*==========================================================================*/

/*
 *   Display a full (normalized) vt-screen on the terminal.
 *   Used ONLY(!) for the mark-functionality
 */

static	void	sql04_write_marked ( )

{
    register int		pos ;
    register UCHAR		*ptr = sql04_save_screen ;
    register UCHAR		*atp = sql04_save_attrib ;


    DBGSCREEN ( ptr , atp , sql04_screen_size , "write_marked" )

    (void) attron ( sql04_mark_attrib );
    for ( pos = 0 ; pos < sql04_screen_size ; pos ++ , ptr ++ , atp ++ )
    {
	/* don't change graphics and non-input fields */
	if ( (*ptr >= ' ') && sql04_in_field(pos) )
	{
	    sql04_addch ( *ptr , *atp );
	}
    }
    (void) attroff ( sql04_mark_attrib );

}
#endif /* MARK_NOCH_ZU_TUN */

#ifdef MARK_NOCH_ZU_TUN
/*==========================================================================*/

static	boolean	sql04_in_marked_area (pos)
int     pos ;
{

    return FALSE ;      /* bis zur ausgetesteten Version ! */

    if ( pos == sql04_mark_apos )
	return TRUE ;

    switch ( sql04_mark_option )
    {
	case VTM_MARK_BLOCK :
	{

	    int     acol ;
	    int     aline ;
	    int     ecol ;
	    int     eline ;

	    int     poscol ;
	    int     posline ;

	    int     links,rechts,oben,unten ;

	    acol    = sql04_mark_apos % sql04_cols ;
	    aline   = sql04_mark_apos / sql04_cols ;
	    ecol    = sql04_mark_epos % sql04_cols ;
	    eline   = sql04_mark_epos / sql04_cols ;

	    poscol  = pos % sql04_cols ;
	    posline = pos / sql04_cols ;

	    links   = smaller ( acol , ecol );
	    rechts  = greater ( acol , ecol );
	    oben    = smaller ( aline , eline );
	    unten   = greater ( aline , eline );

	    return ( poscol >= links && poscol <= links &&
		 posline <= unten && posline >= oben );

	}

	case VTM_MARK_LINE :
	    return ( ( sql04_mark_apos / sql04_cols ) == ( pos / sql04_cols ) );

	case VTM_MARK_CONTINUE :
	    if ( sql04_mark_apos <= sql04_mark_epos )
		return ( pos >= sql04_mark_apos && pos <= sql04_mark_epos );
	    else
		return ( pos >= sql04_mark_epos && pos <= sql04_mark_apos );

	 default :
	    return  ( FALSE );

    }
}
#endif /* MARK_NOCH_ZU_TUN */

#ifdef MARK_NOCH_ZU_TUN
/*==========================================================================*/

/* Markieren eines Bildschirmbereichs durch Darstellung der ersten
   Markierungs-Position durch Blink und Underline (wie Rand-Editor) */

#endif /* MARK_NOCH_ZU_TUN */

/*==========================================================================*/

static	void	sql04_addch ( uchr , uatt )

register UCHAR		uchr ;
register UCHAR		uatt ;

{
    register chtype		cchr ;
    register chtype		catt ;


    catt = ATTR(uatt);

    if ( uchr < MAXGRAPHIC )
    {
	/*
	 *  Graphic character. Strip all non-color attributes.
	 *  Some terminals get crazy from graphic with attributes.
	 */
	cchr = sql04_graphic[uchr];
	catt &= A_COLOR ;
	DBGG (( "addch: graphic 0x%02x -> 0x%08lx \n", uchr , cchr | catt ))
    }
    else
    {
	if ( is_invisible(uatt) )
	{
	    cchr = CHBLANK ;
	}
	else
	{
	    if ( sql04_isprint((int) uchr) )
	    {
		cchr = (chtype) uchr ;
	    }
	    else
	    {
		cchr = (chtype) '?' ;
	    }
	    /* if is print */
	}
	/* if is invisible */
    }
    /* if is graphic */

#if SCO || SVR4 || LINUX
    /*
     *  On some systems 'addch' fails with characters > 0x7f.
     */
    if ( (uchr < ' ') || (uchr > '~') )
    {
	register int		curlin ;
	register int		curcol ;
	chtype			cstr [ 1 ];

	cstr[0] = cchr | catt ;
	(void) addchnstr ( cstr , 1 );
	getyx ( stdscr , curlin , curcol );
	curcol ++ ;
	if ( curcol >= sql04_cols )
	{
	    curcol = 0 ;
	    curlin ++ ;
	    if ( curlin >= sql04_lines ) curlin = 0 ;
	}
	(void) move ( curlin , curcol );
    }
    else
#endif	/*SCO || SVR4*/
    {
	(void) addch ( cchr | catt );
    }
}

/*==========================================================================*/

static	void	sql04_beep_flash ( )

{
    /*
     *  Sound terminal's bell.
     *  Some terminals can't generate an audible signal, but may be able
     *  to flash the screen (light it up for a short time).
     */
    (void) beep ();
    (void) flash ();
}

/*==========================================================================*/

#ifdef DEBUG_RTE
static	void	debug_init ()

{
    /*
     *  In the DEBUG mode, the virtual terminal can be left by Ctrl-C.
     */
    (void) signal ( SIGINT , debug_catch );

    debugfp = fopen ( DEBUGFILE , "w" );
    if ( ! debugfp )
    {
	DBG1(( MF__, "cannot open '%s': %s \n", DEBUGFILE , sqlerrs() ))
	exit ( 1 );
    }
}
#endif /* DEBUG_RTE */

/*==========================================================================*/

#ifdef DEBUG_RTE
/*
 *  In the DEBUG mode, the virtual terminal can be left by Ctrl-C.
 */

/*ARGSUSED*/
static	SIGNALFUNCTYPE	debug_catch ( sig )

int			sig ;

{
    char           *msg = "" ;


    sqlctoff ( &msg , &msg , msg );
    (void) fclose ( debugfp ); /* 91-Aug-20 J.Bruehe: force a buffer flush */
    exit ( 0 );
}
#endif /* DEBUG_RTE */

/*==========================================================================*/

#ifdef	DEBUG_RTE
/*PRINTFLIKE1*/
global	void	sqldbgvt ( char *text , ... )
{
    va_list			args ;



    if ( ! debugfp ) debug_init ();

    va_start ( args, text );
    (void) vfprintf ( debugfp , text , args );
    (void) fflush ( debugfp );
    va_end ( args );
}
#endif /* DEBUG_RTE */

/*==========================================================================*/

#ifdef	DEBUG_RTE
static	void	debug_screen ( screen , attrib , length , header )

UCHAR			*screen ;
UCHAR			*attrib ;
int			length ;
char			*header ;

{
    int             i ;



    if ( ! debugfp ) debug_init ();


    (void) fprintf ( debugfp , "\n\n%s\n", header );
    for ( i = 0 ; header[i] ; i ++ ) (void) putc ( '=' , debugfp );
    (void) fprintf ( debugfp , "\n\n" );

    for ( i = 0 ; i < length / LINEVALUES ; i++ )
    {
	debug_hexline  ( attrib , i * LINEVALUES , LINEVALUES , 'a' );
	debug_hexline  ( screen , i * LINEVALUES , LINEVALUES , 's' );
	debug_charline ( screen , i * LINEVALUES , LINEVALUES , 's' );
	(void) putc ( '\n', debugfp );
    }
    debug_hexline  ( attrib , i * LINEVALUES , length % LINEVALUES , 'a' );
    debug_hexline  ( screen , i * LINEVALUES , length % LINEVALUES , 's' );
    debug_charline ( screen , i * LINEVALUES , length % LINEVALUES , 's' );
    (void) putc ( '\n', debugfp );
    (void) fflush (debugfp);
}
#endif /* DEBUG_RTE */

/*==========================================================================*/

#ifdef	DEBUG_RTE
static	void	debug_hexline ( buf , startpos , length , label )

UCHAR			*buf ;
int			startpos ;
int			length ;
char			label ;

{
    register int		i ;


    (void) fprintf ( debugfp , " %c : %4d   ", label , startpos );
    for ( i = 0 ; i < length ; i ++ )
    {
	if ( i % 4 == 0 ) (void) putc ( ' ' , debugfp );
	(void) fprintf ( debugfp , "%02x ", (unsigned) buf[i + startpos] );
    }
    (void) putc ( '\n', debugfp );
}
#endif /* DEBUG_RTE */

/*==========================================================================*/

#ifdef	DEBUG_RTE
static	void	debug_charline ( buf , startpos , length , label )

UCHAR			*buf ;
int			startpos ;
int			length ;
char			label ;

{
    register int		i ;
    register UCHAR		uch ;


    (void) fprintf ( debugfp , " %c : %4d   ", label , startpos );
    for ( i = 0 ; i < length ; i++ )
    {
	if ( i % 4 == 0 ) (void) putc ( ' ' , debugfp );
	(void) putc ( ' ' , debugfp );
	uch = buf[i+startpos];
	if ( sql04_isprint((int) uch) )
	    (void) putc ( uch , debugfp );
	else
	    (void) putc ( ' ' , debugfp );
	(void) putc ( ' ' , debugfp );
    }
    (void) putc ( '\n', debugfp );
}
#endif /* DEBUG_RTE */

/*==========================================================================*/

#ifdef	DEBUG_RTE
static	void	debug_key_array ( name , keyarr )

char			*name ;
char			*keyarr ;

{
    int				idx ;


    for ( idx = 0 ; idx < VTKEY_LAST ; idx ++ )
	DBG1 (( MF__,"%s %-18s=%d \n", name , sql04_key_name(idx) , keyarr[idx] ))
}
#endif /* DEBUG_RTE */

/*==========================================================================*/

#ifdef	lint
static	void	sql04_lint_dummy ()
{
    if( sql04_mark_apos && sql04_mark_epos && sql04_mark_attrib )
	sql04_lint_dummy ();
}
#endif	/*lint*/
