/* TN5250
* Copyright (C) 1997 Michael Madore
*
* This file is part of TN5250.
*
* TN5250 is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1, or (at your option)
* any later version.
*
* TN5250 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this software; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307 USA
*
*/
#include "tn5250-private.h"
static void tn5250_display_add_dbuffer (Tn5250Display * display,
Tn5250DBuffer * dbuffer);
void tn5250_display_kf_macro (Tn5250Display * This, int Ch);
void tn5250_display_set_cursor_next_progression_field (Tn5250Display *
This, int nextfield);
void tn5250_display_set_cursor_prev_progression_field (Tn5250Display *
This,
int currentfield);
void tn5250_display_wordwrap_delete (Tn5250Display * This);
void tn5250_display_wordwrap_insert (Tn5250Display * This, unsigned char c,
int shiftcount);
void tn5250_display_wordwrap_addch (Tn5250Display * This, unsigned char c);
/****f* lib5250/tn5250_display_new
* NAME
* tn5250_display_new
* SYNOPSIS
* ret = tn5250_display_new ();
* INPUTS
* None
* DESCRIPTION
* DOCUMENT ME!!!
*****/
Tn5250Display *
tn5250_display_new ()
{
Tn5250Display *This;
if ((This = tn5250_new (Tn5250Display, 1)) == NULL)
{
return NULL;
}
This->display_buffers = NULL;
This->macro = NULL;
This->terminal = NULL;
This->config = NULL;
This->indicators = 0;
This->indicators_dirty = 0;
This->pending_insert = 0;
This->sign_key_hack = 1;
This->session = NULL;
This->key_queue_head = This->key_queue_tail = 0;
This->saved_msg_line = NULL;
This->msg_line = NULL;
This->map = NULL;
This->keystate = TN5250_KEYSTATE_UNLOCKED;
This->keySRC = TN5250_KBDSRC_NONE;
tn5250_display_add_dbuffer (This, tn5250_dbuffer_new (80, 24));
return This;
}
/****f* lib5250/tn5250_display_destroy
* NAME
* tn5250_display_destroy
* SYNOPSIS
* tn5250_display_destroy (This);
* INPUTS
* Tn5250Display * This -
* DESCRIPTION
* DOCUMENT ME!!!
*****/
void
tn5250_display_destroy (Tn5250Display * This)
{
Tn5250DBuffer *diter, *dnext;
if ((diter = This->display_buffers) != NULL)
{
do
{
dnext = diter->next;
tn5250_dbuffer_destroy (diter);
diter = dnext;
}
while (diter != This->display_buffers);
}
if (This->terminal != NULL)
{
tn5250_terminal_destroy (This->terminal);
}
if (This->saved_msg_line != NULL)
{
free (This->saved_msg_line);
}
if (This->msg_line != NULL)
{
free (This->msg_line);
}
if (This->config != NULL)
{
tn5250_config_unref (This->config);
}
free (This);
return;
}
/****f* lib5250/tn5250_display_config
* NAME
* tn5250_display_config
* SYNOPSIS
* tn5250_display_config (This, config);
* INPUTS
* Tn5250Display * This -
* Tn5250Config * config -
* DESCRIPTION
* Applies configuration to the display.
*****/
int
tn5250_display_config (Tn5250Display * This, Tn5250Config * config)
{
const char *v;
const char *termtype;
tn5250_config_ref (config);
if (This->config != NULL)
{
tn5250_config_unref (This->config);
}
This->config = config;
/* check if the +/- sign keyboard hack should be enabled */
if (tn5250_config_get (config, "sign_key_hack"))
{
This->sign_key_hack = tn5250_config_get_bool (config, "sign_key_hack");
}
/* Set a terminal type if necessary */
termtype = tn5250_config_get (config, "env.TERM");
if (termtype == NULL)
{
tn5250_config_set (config, "env.TERM", "IBM-3179-2");
}
/* Set the new character map. */
if (This->map != NULL)
{
tn5250_char_map_destroy (This->map);
}
if ((v = tn5250_config_get (config, "map")) == NULL)
{
tn5250_config_set (config, "map", "37");
v = tn5250_config_get (config, "map");
}
This->map = tn5250_char_map_new (v);
if (This->map == NULL)
{
return -1; /* FIXME: An error message would be nice. */
}
return 0;
}
/****f* lib5250/tn5250_display_set_session
* NAME
* tn5250_display_set_session
* SYNOPSIS
* tn5250_display_set_session (This, s);
* INPUTS
* Tn5250Display * This -
* struct _Tn5250Session * s -
* DESCRIPTION
* DOCUMENT ME!!!
*****/
void
tn5250_display_set_session (Tn5250Display * This, struct _Tn5250Session *s)
{
This->session = s;
if (This->session != NULL)
{
This->session->display = This;
}
return;
}
/****f* lib5250/tn5250_display_push_dbuffer
* NAME
* tn5250_display_push_dbuffer
* SYNOPSIS
* ret = tn5250_display_push_dbuffer (This);
* INPUTS
* Tn5250Display * This -
* DESCRIPTION
* Create a new display buffer and assign the old one an id so we can
* later restore it. Return the id which must be > 0.
*****/
Tn5250DBuffer *
tn5250_display_push_dbuffer (Tn5250Display * This)
{
Tn5250DBuffer *dbuf;
dbuf = tn5250_dbuffer_copy (This->display_buffers);
tn5250_display_add_dbuffer (This, dbuf);
return dbuf; /* Pointer is used as unique identifier in data stream. */
}
/****f* lib5250/tn5250_display_restore_dbuffer
* NAME
* tn5250_display_restore_dbuffer
* SYNOPSIS
* tn5250_display_restore_dbuffer (This, id);
* INPUTS
* Tn5250Display * This -
* Tn5250DBuffer * id -
* DESCRIPTION
* Delete the current dbuffer and replace it with the one with id `id'.
*****/
void
tn5250_display_restore_dbuffer (Tn5250Display * This, Tn5250DBuffer * id)
{
Tn5250DBuffer *iter;
/* Sanity check to make sure that the display buffer is for real and
* that it isn't the one which is currently active. */
if ((iter = This->display_buffers) != NULL)
{
do
{
if (iter == id && iter != This->display_buffers)
{
break;
}
iter = iter->next;
}
while (iter != This->display_buffers);
if (iter != id || iter == This->display_buffers)
{
return;
}
}
else
{
return;
}
This->display_buffers->prev->next = This->display_buffers->next;
This->display_buffers->next->prev = This->display_buffers->prev;
tn5250_dbuffer_destroy (This->display_buffers);
This->display_buffers = iter;
return;
}
/****i* lib5250/tn5250_display_add_dbuffer
* NAME
* tn5250_display_add_dbuffer
* SYNOPSIS
* tn5250_display_add_dbuffer (This, dbuffer);
* INPUTS
* Tn5250Display * This -
* Tn5250DBuffer * dbuffer -
* DESCRIPTION
* Add a display buffer into this display's circularly linked list of
* display buffers.
*****/
static void
tn5250_display_add_dbuffer (Tn5250Display * This, Tn5250DBuffer * dbuffer)
{
TN5250_ASSERT (dbuffer != NULL);
if (This->display_buffers == NULL)
{
This->display_buffers = dbuffer;
dbuffer->next = dbuffer->prev = dbuffer;
}
else
{
dbuffer->next = This->display_buffers;
dbuffer->prev = This->display_buffers->prev;
dbuffer->next->prev = dbuffer;
dbuffer->prev->next = dbuffer;
}
return;
}
/****f* lib5250/tn5250_display_set_terminal
* NAME
* tn5250_display_set_terminal
* SYNOPSIS
* tn5250_display_set_terminal (This, term);
* INPUTS
* Tn5250Display * This -
* Tn5250Terminal * term -
* DESCRIPTION
* Set the terminal associated with this display.
*****/
void
tn5250_display_set_terminal (Tn5250Display * This, Tn5250Terminal * term)
{
if (This->terminal != NULL)
{
tn5250_terminal_destroy (This->terminal);
}
This->terminal = term;
This->indicators_dirty = 1;
tn5250_terminal_update (This->terminal, This);
tn5250_terminal_update_indicators (This->terminal, This);
return;
}
/****f* lib5250/tn5250_display_update
* NAME
* tn5250_display_update
* SYNOPSIS
* tn5250_display_update (This);
* INPUTS
* Tn5250Display * This -
* DESCRIPTION
* Update the terminal's representation of the display.
*****/
void
tn5250_display_update (Tn5250Display * This)
{
if (This->msg_line != NULL)
{
int l;
l = tn5250_dbuffer_msg_line (This->display_buffers);
memcpy (This->display_buffers->data +
tn5250_display_width (This) * l, This->msg_line, This->msg_len);
}
if (This->terminal != NULL)
{
tn5250_terminal_update (This->terminal, This);
if (This->indicators_dirty)
{
tn5250_terminal_update_indicators (This->terminal, This);
This->indicators_dirty = 0;
}
}
return;
}
/****f* lib5250/tn5250_display_waitevent
* NAME
* tn5250_display_waitevent
* SYNOPSIS
* ret = tn5250_display_waitevent (This);
* INPUTS
* Tn5250Display * This -
* DESCRIPTION
* Wait for a terminal event. Handle keystrokes while we're at it
* and don't return those to the session (what would it do with them?)
*****/
int
tn5250_display_waitevent (Tn5250Display * This)
{
int is_x_system, r, handled_key = 0;
if (This->terminal == NULL)
{
return 0;
}
while (1)
{
is_x_system = (This->keystate == TN5250_KEYSTATE_LOCKED);
/* Handle keys from our key queue if we aren't X SYSTEM. */
if (This->key_queue_head != This->key_queue_tail && !is_x_system)
{
TN5250_LOG (("Handling buffered key.\n"));
tn5250_display_do_key (This, This->key_queue[This->key_queue_head]);
if (++This->key_queue_head == TN5250_DISPLAY_KEYQ_SIZE)
{
This->key_queue_head = 0;
}
handled_key = 1;
continue;
}
/* don't make the user press HELP to see what the error is */
if (This->keystate == TN5250_KEYSTATE_PREHELP)
{
tn5250_display_do_key (This, K_HELP);
handled_key = 1;
}
if (handled_key)
{
tn5250_display_update (This);
handled_key = 0;
}
r = tn5250_terminal_waitevent (This->terminal);
if ((r & TN5250_TERMINAL_EVENT_KEY) != 0)
{
tn5250_display_do_keys (This);
}
if ((r & ~TN5250_TERMINAL_EVENT_KEY) != 0)
{
return r;
}
}
}
/****f* lib5250/tn5250_display_getkey
* NAME
* tn5250_display_getkey
* SYNOPSIS
* ret = tn5250_display_getkey (This);
* INPUTS
* Tn5250Display * This -
* DESCRIPTION
* Get the next keystroke in the keyboard buffer.
*****/
int
tn5250_display_getkey (Tn5250Display * This)
{
if (This->terminal == NULL)
{
return -1;
}
return tn5250_terminal_getkey (This->terminal);
}
/****f* lib5250/tn5250_display_beep
* NAME
* tn5250_display_beep
* SYNOPSIS
* tn5250_display_beep (This);
* INPUTS
* Tn5250Display * This -
* DESCRIPTION
* The required beep function.
*****/
void
tn5250_display_beep (Tn5250Display * This)
{
const char *cmd;
int ec;
if ((cmd = tn5250_config_get (This->config, "beep_command")) != NULL)
{
ec = system (cmd);
if (ec == -1)
{
TN5250_LOG (("system() for beep command failed: %s\n",
strerror (errno)));
}
else if (ec != 0)
{
TN5250_LOG (("beep command exited with errno %d\n", ec));
}
return;
}
if (This->terminal == NULL)
return;
tn5250_terminal_beep (This->terminal);
return;
}
/****f* lib5250/tn5250_display_set_pending_insert
* NAME
* tn5250_display_set_pending_insert
* SYNOPSIS
* tn5250_display_set_pending_insert (This, y, x);
* INPUTS
* Tn5250Display * This -
* int y -
* int x -
* DESCRIPTION
* Set the pending insert flag and the insert cursor position.
*****/
void
tn5250_display_set_pending_insert (Tn5250Display * This, int y, int x)
{
This->pending_insert = 1;
tn5250_dbuffer_set_ic (This->display_buffers, y, x);
return;
}
/****f* lib5250/tn5250_display_field_at
* NAME
* tn5250_display_field_at
* SYNOPSIS
* ret = tn5250_display_field_at (This, y, x);
* INPUTS
* Tn5250Display * This -
* int y -
* int x -
* DESCRIPTION
* DOCUMENT ME!!!
*****/
Tn5250Field *
tn5250_display_field_at (Tn5250Display * This, int y, int x)
{
return tn5250_dbuffer_field_yx (This->display_buffers, y, x);
}
/****f* lib5250/tn5250_display_current_field
* NAME
* tn5250_display_current_field
* SYNOPSIS
* ret = tn5250_display_current_field (This);
* INPUTS
* Tn5250Display * This -
* DESCRIPTION
* Find the field currently under the cursor. The answer might be NULL
* if there is no field under the cursor.
*****/
Tn5250Field *
tn5250_display_current_field (Tn5250Display * This)
{
return tn5250_display_field_at (This,
tn5250_display_cursor_y (This),
tn5250_display_cursor_x (This));
}
/****f* lib5250/tn5250_display_next_field
* NAME
* tn5250_display_next_field
* SYNOPSIS
* ret = tn5250_display_next_field (This);
* INPUTS
* Tn5250Display * This -
* DESCRIPTION
* Return a pointer to the next field after the current one which is not
* a bypass field.
*****/
Tn5250Field *
tn5250_display_next_field (Tn5250Display * This)
{
Tn5250Field *iter = NULL, *next;
int y, x;
y = tn5250_display_cursor_y (This);
x = tn5250_display_cursor_x (This);
iter = tn5250_display_field_at (This, y, x);
if (iter == NULL)
{
/* Find the first field on the display after the cursor, wrapping if we
* hit the bottom of the display. */
while (iter == NULL)
{
if ((iter = tn5250_display_field_at (This, y, x)) == NULL)
{
if (++x == tn5250_dbuffer_width (This->display_buffers))
{
x = 0;
if (++y == tn5250_dbuffer_height (This->display_buffers))
{
y = 0;
}
}
if (y == tn5250_display_cursor_y (This) &&
x == tn5250_display_cursor_x (This))
{
return NULL; /* No fields on display */
}
}
}
}
else
{
iter = iter->next;
}
next = iter;
while (tn5250_field_is_bypass (next))
{
next = next->next; /* Hehe */
if (next == iter && tn5250_field_is_bypass (next))
{
return NULL; /* No non-bypass fields. */
}
}
return next;
}
/****f* lib5250/tn5250_display_prev_field
* NAME
* tn5250_display_prev_field
* SYNOPSIS
* ret = tn5250_display_prev_field (This);
* INPUTS
* Tn5250Display * This -
* DESCRIPTION
* Return a pointer to the first preceding field which is not a bypass
* field.
*****/
Tn5250Field *
tn5250_display_prev_field (Tn5250Display * This)
{
Tn5250Field *iter = NULL, *prev;
int y, x;
y = tn5250_display_cursor_y (This);
x = tn5250_display_cursor_x (This);
iter = tn5250_display_field_at (This, y, x);
if (iter == NULL)
{
/* Find the first field on the display after the cursor, wrapping if we
* hit the bottom of the display. */
while (iter == NULL)
{
if ((iter = tn5250_display_field_at (This, y, x)) == NULL)
{
if (x-- == 0)
{
x = tn5250_dbuffer_width (This->display_buffers) - 1;
if (y-- == 0)
{
y = tn5250_dbuffer_height (This->display_buffers) - 1;
}
}
if (y == tn5250_display_cursor_y (This) &&
x == tn5250_display_cursor_x (This))
{
return NULL; /* No fields on display */
}
}
}
}
else
{
iter = iter->prev;
}
prev = iter;
while (tn5250_field_is_bypass (prev))
{
prev = prev->prev; /* Hehe */
if (prev == iter && tn5250_field_is_bypass (prev))
{
return NULL; /* No non-bypass fields. */
}
}
return prev;
}
/****f* lib5250/tn5250_display_set_cursor_home
* NAME
* tn5250_display_set_cursor_home
* SYNOPSIS
* tn5250_display_set_cursor_home (This);
* INPUTS
* Tn5250Display * This -
* DESCRIPTION
* Set the cursor to the home position on the current display buffer.
* The home position is:
* 1) the IC position, if we have one.
* 2) the first position of the first non-bypass field, if we have on.
* 3) 0,0
*****/
void
tn5250_display_set_cursor_home (Tn5250Display * This)
{
if (This->pending_insert)
{
tn5250_dbuffer_goto_ic (This->display_buffers);
/* This->pending_insert = 0; */
}
else
{
int y = 0, x = 0;
Tn5250Field *iter = This->display_buffers->field_list;
if (iter != NULL)
{
do
{
if (!tn5250_field_is_bypass (iter))
{
y = tn5250_field_start_row (iter);
x = tn5250_field_start_col (iter);
break;
}
iter = iter->next;
}
while (iter != This->display_buffers->field_list);
}
tn5250_display_set_cursor (This, y, x);
}
return;
}
/****f* lib5250/tn5250_display_set_cursor_field
* NAME
* tn5250_display_set_cursor_field
* SYNOPSIS
* tn5250_display_set_cursor_field (This, field);
* INPUTS
* Tn5250Display * This -
* Tn5250Field * field -
* DESCRIPTION
* Set the cursor position on the current display buffer to the home
* position of the specified field.
*****/
void
tn5250_display_set_cursor_field (Tn5250Display * This, Tn5250Field * field)
{
if (field == NULL)
{
tn5250_display_set_cursor_home (This);
return;
}
tn5250_dbuffer_cursor_set (This->display_buffers,
tn5250_field_start_row (field),
tn5250_field_start_col (field));
return;
}
/****f* lib5250/tn5250_display_set_cursor_next_field
* NAME
* tn5250_display_set_cursor_next_field
* SYNOPSIS
* tn5250_display_set_cursor_next_field (This);
* INPUTS
* Tn5250Display * This -
* DESCRIPTION
* Move the cursor to the next non-bypass field. This will move the
* cursor to the home position if there are no non-bypass fields.
*****/
void
tn5250_display_set_cursor_next_field (Tn5250Display * This)
{
Tn5250Field *currentfield = tn5250_display_current_field (This);
Tn5250Field *field;
if ((currentfield != NULL) && (currentfield->nextfieldprogressionid != 0))
{
tn5250_display_set_cursor_next_progression_field (This,
currentfield->
nextfieldprogressionid);
}
else
{
field = tn5250_display_next_field (This);
tn5250_display_set_cursor_field (This, field);
}
return;
}
/****f* lib5250/tn5250_display_set_cursor_next_progression_field
* NAME
* tn5250_display_set_cursor_next_progression_field
* SYNOPSIS
* tn5250_display_set_cursor_next_progression_field (This);
* INPUTS
* Tn5250Display * This -
* DESCRIPTION
* Move the cursor to the next specified field. This will move the
* cursor to the next non-bypass field if no field is specified.
*****/
void
tn5250_display_set_cursor_next_progression_field (Tn5250Display * This,
int nextfield)
{
Tn5250Field *field;
if (nextfield == 0)
{
tn5250_display_set_cursor_next_field (This);
return;
}
while ((field = tn5250_display_next_field (This)) != NULL)
{
tn5250_display_set_cursor_field (This, field);
if (field->entry_id == nextfield)
{
break;
}
}
return;
}
/****f* lib5250/tn5250_display_set_cursor_next_logical_field
* NAME
* tn5250_display_set_cursor_next_logical_field
* SYNOPSIS
* tn5250_display_set_cursor_next_logical_field (This);
* INPUTS
* Tn5250Display * This -
* DESCRIPTION
* Move the cursor to the next non-bypass field not of the same
* continuous field set. This will move the cursor to the home
* position if there are no non-bypass fields.
*****/
void
tn5250_display_set_cursor_next_logical_field (Tn5250Display * This)
{
Tn5250Field *currentfield = tn5250_display_current_field (This);
int currentid, origid;
if (currentfield != NULL)
{
currentid = currentfield->entry_id;
origid = currentfield->id;
while (currentid == currentfield->entry_id)
{
tn5250_display_set_cursor_next_field (This);
currentfield = tn5250_display_current_field (This);
if ((currentfield == NULL) || (origid == currentfield->id))
{
break;
}
}
}
else
{
tn5250_display_set_cursor_next_field (This);
}
return;
}
/****f* lib5250/tn5250_display_set_cursor_prev_field
* NAME
* tn5250_display_set_cursor_prev_field
* SYNOPSIS
* tn5250_display_set_cursor_prev_field (This);
* INPUTS
* Tn5250Display * This -
* DESCRIPTION
* Move the cursor to the previous non-bypass field. This will move the
* cursor to the home position if there are no non-bypass fields.
*****/
void
tn5250_display_set_cursor_prev_field (Tn5250Display * This)
{
Tn5250Field *currentfield = tn5250_display_current_field (This);
Tn5250Field *field;
if ((currentfield != NULL) && (currentfield->entry_id != 0))
{
tn5250_display_set_cursor_prev_progression_field (This,
currentfield->
entry_id);
}
else
{
field = tn5250_display_prev_field (This);
tn5250_display_set_cursor_field (This, field);
}
return;
}
/****f* lib5250/tn5250_display_set_cursor_prev_progression_field
* NAME
* tn5250_display_set_cursor_prev_progression_field
* SYNOPSIS
* tn5250_display_set_cursor_prev_progression_field (This);
* INPUTS
* Tn5250Display * This -
* DESCRIPTION
* Move the cursor to the previous progression field.
*
*****/
void
tn5250_display_set_cursor_prev_progression_field (Tn5250Display * This,
int currentfield)
{
Tn5250Field *field;
Tn5250Field *origfield;
int orig_id;
int differentfieldfound;
if (currentfield == 0)
{
return;
}
origfield = tn5250_display_current_field (This);
orig_id = origfield->id;
differentfieldfound = 0;
while ((field = tn5250_display_prev_field (This)) != NULL)
{
tn5250_display_set_cursor_field (This, field);
if (field->entry_id == currentfield)
{
if (field->id == orig_id)
{
field = tn5250_display_prev_field (This);
tn5250_display_set_cursor_field (This, field);
break;
}
if (!differentfieldfound)
{
break;
}
}
else
{
differentfieldfound = 1;
}
if (field->nextfieldprogressionid == currentfield)
{
break;
}
}
return;
}
/****f* lib5250/tn5250_display_set_cursor_prev_logical_field
* NAME
* tn5250_display_set_cursor_prev_logical_field
* SYNOPSIS
* tn5250_display_set_cursor_prev_logical_field (This);
* INPUTS
* Tn5250Display * This -
* DESCRIPTION
* Move the cursor to the previous non-bypass field not of the same
* continuous field set. This will move the cursor to the home
* position if there are no non-bypass fields.
*****/
void
tn5250_display_set_cursor_prev_logical_field (Tn5250Display * This)
{
Tn5250Field *currentfield;
int currentid, origid;
tn5250_display_set_cursor_prev_field (This);
currentfield = tn5250_display_current_field (This);
if (currentfield == NULL)
{
return;
}
currentid = currentfield->entry_id;
origid = currentfield->id;
while (currentid == currentfield->entry_id)
{
tn5250_display_set_cursor_prev_field (This);
currentfield = tn5250_display_current_field (This);
if ((currentfield == NULL) || (origid == currentfield->id))
{
break;
}
}
tn5250_display_set_cursor_next_field (This);
return;
}
/*
* Reconstruct WTD data as it might be sent from a host. We use this
* to save our format table and display buffer. We assume the buffer
* has been initialized, and we append to it.
*/
void
tn5250_display_make_wtd_data (Tn5250Display * This, Tn5250Buffer * buf,
Tn5250DBuffer * src_dbuffer)
{
Tn5250WTDContext *ctx;
if ((ctx = tn5250_wtd_context_new (buf, src_dbuffer,
This->display_buffers)) == NULL)
{
return;
}
/*
These coordinates will be used in an IC order when the screen is
restored
*/
tn5250_wtd_context_set_ic (ctx,
tn5250_display_cursor_y (This) + 1,
tn5250_display_cursor_x (This) + 1);
tn5250_wtd_context_convert (ctx);
tn5250_wtd_context_destroy (ctx);
return;
}
/****f* lib5250/tn5250_display_interactive_addch
* NAME
* tn5250_display_interactive_addch
* SYNOPSIS
* tn5250_display_interactive_addch (This, ch);
* INPUTS
* Tn5250Display * This -
* unsigned char ch -
* DESCRIPTION
* Add a character to the display, and set the field's MDT flag. This
* is meant to be called by the keyboard handler when the user is
* entering data.
*****/
void
tn5250_display_interactive_addch (Tn5250Display * This, unsigned char ch)
{
Tn5250Field *field = tn5250_display_current_field (This);
Tn5250Field *contfield;
int end_of_field = 0;
int nextfieldprogressionid = 0;
if (field == NULL || tn5250_field_is_bypass (field))
{
This->keystate = TN5250_KEYSTATE_PREHELP;
This->keySRC = TN5250_KBDSRC_PROTECT;
tn5250_display_inhibit (This);
return;
}
/* Upcase the character if this is a monocase field. */
if (tn5250_field_is_monocase (field) && isalpha (ch))
{
ch = toupper (ch);
}
/* '+' and '-' keys activate field exit/field minus for numeric fields. */
if (This->sign_key_hack && (tn5250_field_is_num_only (field)
|| tn5250_field_is_signed_num (field)))
{
switch (ch)
{
case '+':
tn5250_display_kf_field_plus (This);
return;
case '-':
tn5250_display_kf_field_minus (This);
return;
}
}
/* Make sure this is a valid data character for this field type. */
if (!tn5250_field_valid_char (field, ch, &(This->keySRC)))
{
TN5250_LOG (("Inhibiting: invalid character for field type.\n"));
This->keystate = TN5250_KEYSTATE_PREHELP;
tn5250_display_inhibit (This);
return;
}
/* Are we at the last character of the field? */
if (tn5250_display_cursor_y (This) == tn5250_field_end_row (field) &&
tn5250_display_cursor_x (This) == tn5250_field_end_col (field))
{
end_of_field = 1;
if (field->nextfieldprogressionid != 0)
{
nextfieldprogressionid = field->nextfieldprogressionid;
}
}
/* Don't allow the user to enter data in the sign portion of a signed
* number field. */
if (end_of_field && tn5250_field_is_signed_num (field))
{
TN5250_LOG (("Inhibiting: last character of signed num field.\n"));
This->keystate = TN5250_KEYSTATE_PREHELP;
This->keySRC = TN5250_KBDSRC_SIGNPOS;
tn5250_display_inhibit (This);
return;
}
/* Add or insert the character (depending on whether insert mode is on). */
if ((tn5250_display_indicators (This) & TN5250_DISPLAY_IND_INSERT) != 0)
{
int ofs = tn5250_field_length (field) - 1;
unsigned char *data = tn5250_display_field_data (This, field);
if (tn5250_field_is_continued (field))
{
contfield = field;
while (!tn5250_field_is_continued_last (contfield))
{
contfield = contfield->next;
}
ofs = tn5250_field_length (contfield) - 1;
data = tn5250_display_field_data (This, contfield);
}
if (tn5250_field_is_signed_num (field))
{
ofs--;
}
if ((data[ofs] != '\0')
&& (tn5250_char_map_to_local (This->map, data[ofs]) != ' ')
&& (data[ofs] != TN5250_DISPLAY_WORD_WRAP_SPACE))
{
This->keystate = TN5250_KEYSTATE_PREHELP;
This->keySRC = TN5250_KBDSRC_NOROOM;
tn5250_display_inhibit (This);
return;
}
if (tn5250_field_is_wordwrap (field))
{
tn5250_display_wordwrap_insert (This,
tn5250_char_map_to_remote (This->
map, ch),
tn5250_field_count_right (field,
tn5250_display_cursor_y
(This),
tn5250_display_cursor_x
(This)));
}
else
{
tn5250_dbuffer_ins (This->display_buffers, field->id,
tn5250_char_map_to_remote (This->map, ch),
tn5250_field_count_right (field,
tn5250_display_cursor_y
(This),
tn5250_display_cursor_x
(This)));
}
}
else
{
if (tn5250_field_is_wordwrap (field)
|| (tn5250_field_is_continued_last (field)
&& tn5250_field_is_wordwrap (field->prev)))
{
tn5250_display_wordwrap_addch (This,
tn5250_char_map_to_remote (This->map,
ch));
}
else
{
if (This->terminal->putkey != NULL)
{
tn5250_terminal_putkey (This->terminal, This, ch,
tn5250_display_cursor_y (This),
tn5250_display_cursor_x (This));
}
tn5250_dbuffer_addch (This->display_buffers,
tn5250_char_map_to_remote (This->map, ch));
}
}
tn5250_field_set_mdt (field);
/* If at the end of the field and not a fer field and not a word wrap
* field advance to the next field.
*/
if (end_of_field && !tn5250_field_is_wordwrap (field))
{
if (tn5250_field_is_fer (field))
{
tn5250_display_indicator_set (This, TN5250_DISPLAY_IND_FER);
tn5250_display_set_cursor (This,
tn5250_field_end_row (field),
tn5250_field_end_col (field));
}
else
{
tn5250_display_field_adjust (This, field);
if (tn5250_field_is_auto_enter (field))
{
tn5250_display_do_aidkey (This, TN5250_SESSION_AID_ENTER);
return;
}
if (nextfieldprogressionid != 0)
{
tn5250_display_set_cursor_next_progression_field (This,
nextfieldprogressionid);
}
else
{
/* If we are at the end of the field tn5250_dbuffer_addch()
* above may have moved the cursor beyond the end of the
* field. That screws us up in the case of continuous fields
* because each individual field does not have a progression
* ID set. Since continuous fields may not be the next
* field to the right we need to be sure that the cursor
* is currently in the field, not to the right of it. Doing
* so will ensure that the following call puts us in the
* next continuous field. This has the side effect that
* inserting into a single character field does not move
* the cursor to the next field. Maybe that's a bug, maybe
* that's a feature :)
*/
tn5250_dbuffer_left (This->display_buffers);
tn5250_display_set_cursor_next_field (This);
}
}
}
return;
}
/****f* lib5250/tn5250_display_shift_right
* NAME
* tn5250_display_shift_right
* SYNOPSIS
* tn5250_display_shift_right (This, field, fill);
* INPUTS
* Tn5250Display * This -
* Tn5250Field * field -
* unsigned char fill -
* DESCRIPTION
* Move all the data characters in the field to the right-hand side of
* the field and left-fill the field with `fill' characters.
*****/
void
tn5250_display_shift_right (Tn5250Display * This, Tn5250Field * field,
unsigned char fill)
{
int n, end;
unsigned char *ptr;
ptr = tn5250_display_field_data (This, field);
end = tn5250_field_length (field) - 1;
tn5250_field_set_mdt (field);
/* Don't adjust the sign position of signed num type fields. */
if (tn5250_field_is_signed_num (field))
{
end--;
}
/* Left fill the field until the first non-null or non-blank character. */
for (n = 0; n <= end && (ptr[n] == 0 || ptr[n] == 0x40); n++)
{
ptr[n] = fill;
}
/* If the field is entirely blank and we don't do this, we spin forever. */
if (n > end)
{
return;
}
/* Shift the contents of the field right one place and put the fill char in
* position 0 until the data is right-justified in the field. */
while (ptr[end] == 0 || ptr[end] == 0x40)
{
for (n = end; n > 0; n--)
{
ptr[n] = ptr[n - 1];
}
ptr[0] = fill;
}
return;
}
/****f* lib5250/tn5250_display_field_adjust
* NAME
* tn5250_display_field_adjust
* SYNOPSIS
* tn5250_display_field_adjust (This, field);
* INPUTS
* Tn5250Display * This -
* Tn5250Field * field -
* DESCRIPTION
* Adjust the field data as required by the Field Format Word. This is
* called from tn5250_display_kf_field_exit.
*****/
void
tn5250_display_field_adjust (Tn5250Display * This, Tn5250Field * field)
{
int mand_fill_type;
/* Because of special processing during transmit and other weirdness,
* we need to shift signed number fields right regardless. */
mand_fill_type = tn5250_field_mand_fill_type (field);
if (tn5250_field_type (field) == TN5250_FIELD_SIGNED_NUM)
{
mand_fill_type = TN5250_FIELD_RIGHT_BLANK;
}
switch (mand_fill_type)
{
case TN5250_FIELD_NO_ADJUST:
case TN5250_FIELD_MANDATORY_FILL:
break;
case TN5250_FIELD_RIGHT_ZERO:
tn5250_display_shift_right (This, field,
tn5250_char_map_to_remote (This->map, '0'));
break;
case TN5250_FIELD_RIGHT_BLANK:
tn5250_display_shift_right (This, field,
tn5250_char_map_to_remote (This->map, ' '));
break;
}
tn5250_field_set_mdt (field);
return;
}
/****f* lib5250/tn5250_display_do_keys
* NAME
* tn5250_display_do_keys
* SYNOPSIS
* tn5250_display_do_keys (This);
* INPUTS
* Tn5250Display * This -
* DESCRIPTION
* Handle keys from the terminal until we run out or are in the X SYSTEM
* state.
*****/
void
tn5250_display_do_keys (Tn5250Display * This)
{
int cur_key;
char Last;
int dokey;
TN5250_LOG (("display_do_keys!\n"));
do
{
cur_key = tn5250_macro_getkey (This, &Last);
if (Last)
{
tn5250_display_indicator_clear (This, TN5250_DISPLAY_IND_MACRO);
}
if (cur_key == 0)
{
cur_key = tn5250_display_getkey (This);
}
if (cur_key != -1)
{
tn5250_macro_reckey (This, cur_key);
dokey = 0;
switch (This->keystate)
{
case TN5250_KEYSTATE_UNLOCKED:
dokey = 1;
break;
case TN5250_KEYSTATE_HARDWARE:
if (cur_key == K_RESET)
{
TN5250_LOG (("doing key %d in hw error state.\n", cur_key));
}
dokey = 1;
break;
case TN5250_KEYSTATE_LOCKED:
switch (cur_key)
{
case K_SYSREQ:
case K_ATTENTION:
TN5250_LOG (("doing key %d in locked state.\n", cur_key));
dokey = 1;
break;
}
break;
case TN5250_KEYSTATE_PREHELP:
switch (cur_key)
{
case K_RESET:
case K_HELP:
case K_ATTENTION:
dokey = 1;
TN5250_LOG (("Doing key %d in prehelp state\n", cur_key));
break;
}
break;
break;
case TN5250_KEYSTATE_POSTHELP:
switch (cur_key)
{
case K_RESET:
case K_ATTENTION:
TN5250_LOG (("Doing key %d in posthelp state.\n", cur_key));
dokey = 1;
break;
}
}
if (!dokey)
{
if ((This->key_queue_tail + 1 == This->key_queue_head) ||
(This->key_queue_head == 0 &&
This->key_queue_tail == TN5250_DISPLAY_KEYQ_SIZE - 1))
{
TN5250_LOG (("Beep: Key queue full.\n"));
tn5250_display_beep (This);
}
This->key_queue[This->key_queue_tail] = cur_key;
if (++This->key_queue_tail == TN5250_DISPLAY_KEYQ_SIZE)
{
This->key_queue_tail = 0;
}
}
else
{
/* if we're hitting a special keypress (such as error reset)
in a state where typeahead is not allowed, then clear
the key queue */
if (This->key_queue_head != This->key_queue_tail)
{
This->key_queue_head = This->key_queue_tail = 0;
}
tn5250_display_do_key (This, cur_key);
}
}
}
while (cur_key != -1);
tn5250_display_update (This);
return;
}
/****f* lib5250/tn5250_display_do_key
* NAME
* tn5250_display_do_key
* SYNOPSIS
* tn5250_display_do_key (This, key);
* INPUTS
* Tn5250Display * This -
* int key -
* DESCRIPTION
* Translate a keystroke and handle it.
*****/
void
tn5250_display_do_key (Tn5250Display * This, int key)
{
int pre_FER_clear = 0;
TN5250_LOG (("@key %d\n", key));
/* FIXME: Translate from terminal key via keyboard map to 5250 key. */
switch (This->keystate)
{
case TN5250_KEYSTATE_UNLOCKED:
TN5250_ASSERT (!tn5250_display_inhibited (This));
/* normal processing can continue */
break;
case TN5250_KEYSTATE_HARDWARE:
if (key != K_RESET)
{
TN5250_LOG (("Denying key %d in hw err state.\n", key));
tn5250_display_beep (This);
return;
}
break;
case TN5250_KEYSTATE_LOCKED:
if (key != K_SYSREQ && key != K_PRINT && key != K_ATTENTION)
{
TN5250_LOG (("Denying key %d in locked state.\n", key));
tn5250_display_beep (This);
return;
}
break;
case TN5250_KEYSTATE_PREHELP:
if (key != K_RESET && key != K_HELP
&& key != K_PRINT && key != K_ATTENTION)
{
TN5250_LOG (("Denying key %d in prehelp state.\n", key));
tn5250_display_beep (This);
return;
}
break;
case TN5250_KEYSTATE_POSTHELP:
if (key != K_RESET && key != K_ATTENTION)
{
TN5250_LOG (("Denying key %d in posthelp state.\n", key));
tn5250_display_beep (This);
return;
}
break;
}
/* In the case we are in the field exit required state, we inhibit on
* everything except left arrow, backspace, field exit, field+, and
* field- */
if ((tn5250_display_indicators (This) & TN5250_DISPLAY_IND_FER) != 0)
{
switch (key)
{
case K_LEFT:
case K_BACKSPACE:
tn5250_display_indicator_clear (This, TN5250_DISPLAY_IND_FER);
return;
case K_UP:
case K_DOWN:
case K_RIGHT:
tn5250_display_indicator_clear (This, TN5250_DISPLAY_IND_FER);
break;
case K_ENTER:
case K_FIELDEXIT:
case K_FIELDMINUS:
case K_FIELDPLUS:
case K_TAB:
case K_BACKTAB:
case K_RESET:
pre_FER_clear = 1;
break;
default:
This->keystate = TN5250_KEYSTATE_PREHELP;
This->keySRC = TN5250_KBDSRC_FER;
tn5250_display_inhibit (This);
TN5250_LOG (("Denying key %d in FER state.\n", key));
return;
}
}
switch (key)
{
case K_RESET:
tn5250_display_uninhibit (This);
This->keystate = TN5250_KEYSTATE_UNLOCKED;
break;
case K_BACKSPACE:
tn5250_display_kf_backspace (This);
break;
case K_LEFT:
tn5250_display_kf_left (This);
break;
case K_RIGHT:
tn5250_display_kf_right (This);
break;
case K_UP:
tn5250_display_kf_up (This);
break;
case K_DOWN:
tn5250_display_kf_down (This);
break;
case K_HELP:
tn5250_display_do_aidkey (This, TN5250_SESSION_AID_HELP);
break;
case K_HOME:
tn5250_display_kf_home (This);
break;
case K_END:
tn5250_display_kf_end (This);
break;
case K_DELETE:
tn5250_display_kf_delete (This);
break;
case K_INSERT:
tn5250_display_kf_insert (This);
break;
case K_TAB:
tn5250_display_kf_tab (This);
break;
case K_BACKTAB:
tn5250_display_kf_backtab (This);
break;
case K_ENTER:
tn5250_display_do_aidkey (This, TN5250_SESSION_AID_ENTER);
break;
case K_ROLLDN:
tn5250_display_do_aidkey (This, TN5250_SESSION_AID_PGUP);
break;
case K_ROLLUP:
tn5250_display_do_aidkey (This, TN5250_SESSION_AID_PGDN);
break;
case K_FIELDEXIT:
tn5250_display_kf_field_exit (This);
break;
case K_FIELDPLUS:
tn5250_display_kf_field_plus (This);
break;
case K_FIELDMINUS:
tn5250_display_kf_field_minus (This);
break;
case K_TESTREQ:
tn5250_display_do_aidkey (This, TN5250_SESSION_AID_TESTREQ);
break;
case K_SYSREQ:
tn5250_display_do_aidkey (This, TN5250_SESSION_AID_SYSREQ);
break;
case K_ATTENTION:
tn5250_display_uninhibit (This);
This->keystate = TN5250_KEYSTATE_UNLOCKED;
tn5250_display_do_aidkey (This, TN5250_SESSION_AID_ATTN);
break;
case K_PRINT:
tn5250_display_do_aidkey (This, TN5250_SESSION_AID_PRINT);
break;
case K_DUPLICATE:
tn5250_display_kf_dup (This);
break;
case K_NEXTWORD:
tn5250_display_kf_nextword (This);
break;
case K_PREVWORD:
tn5250_display_kf_prevword (This);
break;
case K_NEXTFLD:
tn5250_display_kf_nextfld (This);
break;
case K_PREVFLD:
tn5250_display_kf_prevfld (This);
break;
case K_FIELDHOME:
tn5250_display_kf_fieldhome (This);
break;
case K_NEWLINE:
tn5250_display_kf_newline (This);
break;
case K_MEMO:
tn5250_display_kf_macro (This, K_MEMO);
break;
case K_EXEC:
tn5250_display_kf_macro (This, K_EXEC);
break;
default:
/* Handle function/command keys. */
if (key >= K_F1 && key <= K_F24)
{
if ((!tn5250_macro_recfunct (This, key)) &&
(!tn5250_macro_execfunct (This, key)))
{
if (key <= K_F12)
{
TN5250_LOG (("Key = %d; K_F1 = %d; Key - K_F1 = %d\n",
key, K_F1, key - K_F1));
TN5250_LOG (("AID_F1 = %d; Result = %d\n",
TN5250_SESSION_AID_F1,
key - K_F1 + TN5250_SESSION_AID_F1));
tn5250_display_do_aidkey (This,
key - K_F1 +
TN5250_SESSION_AID_F1);
}
else
{
tn5250_display_do_aidkey (This,
key - K_F13 +
TN5250_SESSION_AID_F13);
}
}
break;
}
/* Handle data keys. */
if (key >= ' ' && key <= 255)
{
TN5250_LOG (("HandleKey: key = %c\n", key));
tn5250_display_interactive_addch (This, key);
}
else
{
TN5250_LOG (("HandleKey: Weird key ignored: %d\n", key));
}
}
if (pre_FER_clear)
{
tn5250_display_indicator_clear (This, TN5250_DISPLAY_IND_FER);
}
return;
}
/****f* lib5250/tn5250_display_field_pad_and_adjust
* NAME
* tn5250_display_field_pad_and_adjust
* SYNOPSIS
* tn5250_display_field_pad_and_adjust(This, field);
* INPUTS
* Tn5250Display * This -
* Tn5250Display * field -
* DESCRIPTION
* This nulls out the remainder of the field (after the
* cursor position) except for the +/- sign, and then right
* adjusts the field. Does NOT do auto-enter, and does NOT
* advance to the next field.
*****/
void
tn5250_display_field_pad_and_adjust (Tn5250Display * This,
Tn5250Field * field)
{
Tn5250Field *iter;
unsigned char *data;
int i, l;
/* NULL out remainder of field from cursor position. For signed numeric
* fields, we do *not* want to null out the sign position - Field+ and
* Field- will do this for us. We do not do this when the FER indicator
* is set.
*/
if ((tn5250_display_indicators (This) & TN5250_DISPLAY_IND_FER) == 0)
{
data = tn5250_display_field_data (This, field);
i = tn5250_field_count_left (field, tn5250_display_cursor_y (This),
tn5250_display_cursor_x (This));
l = tn5250_field_length (field);
if (tn5250_field_is_signed_num (field))
{
l--;
}
for (; i < l; i++)
{
data[i] = 0;
}
if (tn5250_field_is_continued (field)
&& (!tn5250_field_is_continued_last (field)))
{
iter = field->next;
while (tn5250_field_is_continued (iter))
{
data = tn5250_display_field_data (This, iter);
l = tn5250_field_length (iter);
for (i = 0; i < l; i++)
{
data[i] = 0;
}
if (tn5250_field_is_continued_last (iter))
{
break;
}
iter = iter->next;
}
}
}
tn5250_display_field_adjust (This, field);
return;
}
/****f* lib5250/tn5250_display_kf_field_exit
* NAME
* tn5250_display_kf_field_exit
* SYNOPSIS
* tn5250_display_kf_field_exit (This);
* INPUTS
* Tn5250Display * This -
* DESCRIPTION
* Process a field exit function.
*****/
void
tn5250_display_kf_field_exit (Tn5250Display * This)
{
Tn5250Field *field;
field = tn5250_display_current_field (This);
if (field == NULL || tn5250_field_is_bypass (field))
{
This->keystate = TN5250_KEYSTATE_PREHELP;
This->keySRC = TN5250_KBDSRC_PROTECT;
tn5250_display_inhibit (This);
return;
}
tn5250_display_field_pad_and_adjust (This, field);
if (tn5250_field_is_auto_enter (field))
{
tn5250_display_do_aidkey (This, TN5250_SESSION_AID_ENTER);
return;
}
tn5250_display_set_cursor_next_logical_field (This);
return;
}
/****f* lib5250/tn5250_display_kf_field_plus
* NAME
* tn5250_display_kf_field_plus
* SYNOPSIS
* tn5250_display_kf_field_plus (This);
* INPUTS
* Tn5250Display * This -
* DESCRIPTION
* Process a field plus function.
*****/
void
tn5250_display_kf_field_plus (Tn5250Display * This)
{
Tn5250Field *field;
unsigned char *data;
TN5250_LOG (("Field+ entered.\n"));
field = tn5250_display_current_field (This);
if (field == NULL || tn5250_field_is_bypass (field))
{
This->keystate = TN5250_KEYSTATE_PREHELP;
This->keySRC = TN5250_KBDSRC_PROTECT;
tn5250_display_inhibit (This);
return;
}
tn5250_display_field_pad_and_adjust (This, field);
/* NOTE: Field+ should act like field exit on a non-numeric field. */
if ((field != NULL) &&
((tn5250_field_type (field) == TN5250_FIELD_SIGNED_NUM) ||
(tn5250_field_type (field) == TN5250_FIELD_NUM_ONLY)))
{
/* We don't do anything for number only fields. For signed numeric
* fields, we change the sign position to a '+'. */
data = tn5250_display_field_data (This, field);
if (tn5250_field_type (field) != TN5250_FIELD_NUM_ONLY)
{
data[tn5250_field_length (field) - 1] = 0;
}
}
if (tn5250_field_is_auto_enter (field))
{
tn5250_display_do_aidkey (This, TN5250_SESSION_AID_ENTER);
return;
}
tn5250_display_set_cursor_next_logical_field (This);
return;
}
/****f* lib5250/tn5250_display_kf_field_minus
* NAME
* tn5250_display_kf_field_minus
* SYNOPSIS
* tn5250_display_kf_field_minus (This);
* INPUTS
* Tn5250Display * This -
* DESCRIPTION
* Process a field minus function.
*****/
void
tn5250_display_kf_field_minus (Tn5250Display * This)
{
Tn5250Field *field;
unsigned char *data;
TN5250_LOG (("Field- entered.\n"));
field = tn5250_display_current_field (This);
if ((field == NULL) ||
((tn5250_field_type (field) != TN5250_FIELD_SIGNED_NUM) &&
(tn5250_field_type (field) != TN5250_FIELD_NUM_ONLY)))
{
This->keystate = TN5250_KEYSTATE_PREHELP;
This->keySRC = TN5250_KBDSRC_FLDM_DISALLOWED;
tn5250_display_inhibit (This);
return;
}
tn5250_display_field_pad_and_adjust (This, field);
/* For numeric only fields, we shift the data one character to the
* left and change the zone to negative. i.e. 0xf0 becomes 0xd0,
* 0xf1 becomes 0xd1, etc. in the rightmost position. For
* signed numeric fields, we change the sign position to a '-'. */
data = tn5250_display_field_data (This, field);
if (tn5250_field_type (field) == TN5250_FIELD_NUM_ONLY)
{
int i = tn5250_field_length (field) - 1;
data[i] = (data[i] & 0x0F) | 0xd0;
}
else
{
data[tn5250_field_length (field) - 1] =
tn5250_char_map_to_remote (This->map, '-');
}
if (tn5250_field_is_auto_enter (field))
{
tn5250_display_do_aidkey (This, TN5250_SESSION_AID_ENTER);
return;
}
tn5250_display_set_cursor_next_logical_field (This);
return;
}
/****f* lib5250/tn5250_display_do_aidkey
* NAME
* tn5250_display_do_aidkey
* SYNOPSIS
* tn5250_display_do_aidkey (This, aidcode);
* INPUTS
* Tn5250Display * This -
* int aidcode -
* DESCRIPTION
* Handle an aid code.
*****/
void
tn5250_display_do_aidkey (Tn5250Display * This, int aidcode)
{
TN5250_LOG (("tn5250_display_do_aidkey (0x%02X) called.\n", aidcode));
/* Aidcodes less than zero are pseudo-aid-codes (see session.h) */
if (This->session->read_opcode || aidcode < 0)
{
/* FIXME: If this returns zero, we need to stop processing. */
(*(This->session->handle_aidkey)) (This->session, aidcode);
}
return;
}
/****f* lib5250/tn5250_display_kf_dup
* NAME
* tn5250_display_kf_dup
* SYNOPSIS
* tn5250_display_kf_dup (This);
* INPUTS
* Tn5250Display * This -
* DESCRIPTION
* Process a DUP key function.
*****/
void
tn5250_display_kf_dup (Tn5250Display * This)
{
int i;
Tn5250Field *field;
unsigned char *data;
field = tn5250_display_current_field (This);
if (field == NULL || tn5250_field_is_bypass (field))
{
This->keystate = TN5250_KEYSTATE_PREHELP;
This->keySRC = TN5250_KBDSRC_PROTECT;
tn5250_display_inhibit (This);
return;
}
tn5250_field_set_mdt (field);
if (!tn5250_field_is_dup_enable (field))
{
This->keystate = TN5250_KEYSTATE_PREHELP;
This->keySRC = TN5250_KBDSRC_DUP_DISALLOWED;
tn5250_display_inhibit (This);
return;
}
i = tn5250_field_count_left (field, tn5250_display_cursor_y (This),
tn5250_display_cursor_x (This));
data = tn5250_display_field_data (This, field);
for (; i < tn5250_field_length (field); i++)
{
data[i] = 0x1c;
}
if (tn5250_field_is_fer (field))
{
tn5250_display_indicator_set (This, TN5250_DISPLAY_IND_FER);
tn5250_dbuffer_cursor_set (This->display_buffers,
tn5250_field_end_row (field),
tn5250_field_end_col (field));
}
else
{
tn5250_display_field_adjust (This, field);
if (tn5250_field_is_auto_enter (field))
{
tn5250_display_do_aidkey (This, TN5250_SESSION_AID_ENTER);
return;
}
tn5250_display_set_cursor_next_field (This);
}
return;
}
/****f* lib5250/tn5250_display_indicator_set
* NAME
* tn5250_display_indicator_set
* SYNOPSIS
* tn5250_display_indicator_set (This, inds);
* INPUTS
* Tn5250Display * This -
* int inds -
* DESCRIPTION
* Set the specified indicators and set a flag noting that the indicators
* must be refreshed.
*****/
void
tn5250_display_indicator_set (Tn5250Display * This, int inds)
{
This->indicators |= inds;
This->indicators_dirty = 1;
return;
}
/****f* lib5250/tn5250_display_indicator_clear
* NAME
* tn5250_display_indicator_clear
* SYNOPSIS
* tn5250_display_indicator_clear (This, inds);
* INPUTS
* Tn5250Display * This -
* int inds -
* DESCRIPTION
* Clear the specified indicators and set a flag noting that the indicators
* must be refreshed.
*****/
void
tn5250_display_indicator_clear (Tn5250Display * This, int inds)
{
This->indicators &= ~inds;
This->indicators_dirty = 1;
/* Restore the message line if we are clearing the X II indicator */
if ((inds & TN5250_DISPLAY_IND_INHIBIT) != 0
&& This->saved_msg_line != NULL)
{
int l = tn5250_dbuffer_msg_line (This->display_buffers);
memcpy (This->display_buffers->data +
l * tn5250_display_width (This), This->saved_msg_line,
tn5250_display_width (This));
free (This->saved_msg_line);
This->saved_msg_line = NULL;
free (This->msg_line);
This->msg_line = NULL;
}
return;
}
/****f* lib5250/tn5250_display_clear_unit
* NAME
* tn5250_display_clear_unit
* SYNOPSIS
* tn5250_display_clear_unit (This);
* INPUTS
* Tn5250Display * This -
* DESCRIPTION
* Clear the display and set the display size to 24x80.
*****/
void
tn5250_display_clear_unit (Tn5250Display * This)
{
tn5250_dbuffer_set_size (This->display_buffers, 24, 80);
tn5250_display_indicator_set (This, TN5250_DISPLAY_IND_X_SYSTEM);
This->keystate = TN5250_KEYSTATE_LOCKED;
tn5250_display_indicator_clear (This,
TN5250_DISPLAY_IND_INSERT |
TN5250_DISPLAY_IND_INHIBIT |
TN5250_DISPLAY_IND_FER);
This->pending_insert = 0;
tn5250_dbuffer_set_ic (This->display_buffers, 0, 0);
if (This->saved_msg_line != NULL)
{
free (This->saved_msg_line);
This->saved_msg_line = NULL;
}
if (This->msg_line != NULL)
{
free (This->msg_line);
This->msg_line = NULL;
}
return;
}
/****f* lib5250/tn5250_display_clear_unit_alternate
* NAME
* tn5250_display_clear_unit_alternate
* SYNOPSIS
* tn5250_display_clear_unit_alternate (This);
* INPUTS
* Tn5250Display * This -
* DESCRIPTION
* Clear the display and set the display size to 27x132.
*****/
void
tn5250_display_clear_unit_alternate (Tn5250Display * This)
{
tn5250_dbuffer_set_size (This->display_buffers, 27, 132);
tn5250_display_indicator_set (This, TN5250_DISPLAY_IND_X_SYSTEM);
This->keystate = TN5250_KEYSTATE_LOCKED;
tn5250_display_indicator_clear (This,
TN5250_DISPLAY_IND_INSERT |
TN5250_DISPLAY_IND_INHIBIT |
TN5250_DISPLAY_IND_FER);
This->pending_insert = 0;
tn5250_dbuffer_set_ic (This->display_buffers, 0, 0);
if (This->saved_msg_line != NULL)
{
free (This->saved_msg_line);
This->saved_msg_line = NULL;
}
if (This->msg_line != NULL)
{
free (This->msg_line);
This->msg_line = NULL;
}
return;
}
/****f* lib5250/tn5250_display_clear_format_table
* NAME
* tn5250_display_clear_format_table
* SYNOPSIS
* tn5250_display_clear_format_table (This);
* INPUTS
* Tn5250Display * This -
* DESCRIPTION
* Clear the format table.
*****/
void
tn5250_display_clear_format_table (Tn5250Display * This)
{
tn5250_dbuffer_clear_table (This->display_buffers);
tn5250_display_set_cursor (This, 0, 0);
tn5250_display_indicator_set (This, TN5250_DISPLAY_IND_X_SYSTEM);
This->keystate = TN5250_KEYSTATE_LOCKED;
tn5250_display_indicator_clear (This, TN5250_DISPLAY_IND_INSERT);
return;
}
/****f* lib5250/tn5250_display_kf_backspace
* NAME
* tn5250_display_kf_backspace
* SYNOPSIS
* tn5250_display_kf_backspace (This);
* INPUTS
* Tn5250Display * This -
* DESCRIPTION
* Move the cursor left one position unless on the first position of
* field, in which case we move to the last position of the previous
* field. (Or inhibit if we aren't on a field).
*****/
void
tn5250_display_kf_backspace (Tn5250Display * This)
{
Tn5250Field *field = tn5250_display_current_field (This);
if (field == NULL)
{
This->keystate = TN5250_KEYSTATE_PREHELP;
This->keySRC = TN5250_KBDSRC_PROTECT;
tn5250_display_inhibit (This);
return;
}
/* If in first position of field, set cursor position to last position
* of previous field. */
if (tn5250_display_cursor_x (This) == tn5250_field_start_col (field) &&
tn5250_display_cursor_y (This) == tn5250_field_start_row (field))
{
field = tn5250_display_prev_field (This);
if (field == NULL)
{
return; /* Should never happen */
}
tn5250_display_set_cursor_field (This, field);
if (tn5250_field_length (field) - 1 > 0)
{
tn5250_dbuffer_right (This->display_buffers,
tn5250_field_length (field) - 1);
}
return;
}
tn5250_dbuffer_left (This->display_buffers);
return;
}
/****f* lib5250/tn5250_display_kf_left
* NAME
* tn5250_display_kf_left
* SYNOPSIS
* tn5250_display_kf_left (This);
* INPUTS
* Tn5250Display * This -
* DESCRIPTION
* Move the cursor left.
*****/
void
tn5250_display_kf_left (Tn5250Display * This)
{
tn5250_dbuffer_left (This->display_buffers);
return;
}
/****f* lib5250/tn5250_display_kf_right
* NAME
* tn5250_display_kf_right
* SYNOPSIS
* tn5250_display_kf_right (This);
* INPUTS
* Tn5250Display * This -
* DESCRIPTION
* Move the cursor right.
*****/
void
tn5250_display_kf_right (Tn5250Display * This)
{
tn5250_dbuffer_right (This->display_buffers, 1);
return;
}
/****f* lib5250/tn5250_display_kf_up
* NAME
* tn5250_display_kf_up
* SYNOPSIS
* tn5250_display_kf_up (This);
* INPUTS
* Tn5250Display * This -
* DESCRIPTION
* Move the cursor up.
*****/
void
tn5250_display_kf_up (Tn5250Display * This)
{
tn5250_dbuffer_up (This->display_buffers);
return;
}
/****f* lib5250/tn5250_display_kf_down
* NAME
* tn5250_display_kf_down
* SYNOPSIS
* tn5250_display_kf_down (This);
* INPUTS
* Tn5250Display * This -
* DESCRIPTION
* Move the cursor down.
*****/
void
tn5250_display_kf_down (Tn5250Display * This)
{
tn5250_dbuffer_down (This->display_buffers);
return;
}
/****f* lib5250/tn5250_display_kf_insert
* NAME
* tn5250_display_kf_insert
* SYNOPSIS
* tn5250_display_kf_insert (This);
* INPUTS
* Tn5250Display * This -
* DESCRIPTION
* Toggle the insert indicator.
*****/
void
tn5250_display_kf_insert (Tn5250Display * This)
{
if ((tn5250_display_indicators (This) & TN5250_DISPLAY_IND_INSERT) != 0)
{
tn5250_display_indicator_clear (This, TN5250_DISPLAY_IND_INSERT);
}
else
{
tn5250_display_indicator_set (This, TN5250_DISPLAY_IND_INSERT);
}
return;
}
/****f* lib5250/tn5250_display_kf_tab
* NAME
* tn5250_display_kf_tab
* SYNOPSIS
* tn5250_display_kf_tab (This);
* INPUTS
* Tn5250Display * This -
* DESCRIPTION
* Tab function.
*****/
void
tn5250_display_kf_tab (Tn5250Display * This)
{
tn5250_display_set_cursor_next_logical_field (This);
return;
}
/****f* lib5250/tn5250_display_kf_backtab
* NAME
* tn5250_display_kf_backtab
* SYNOPSIS
* tn5250_display_kf_backtab (This);
* INPUTS
* Tn5250Display * This -
* DESCRIPTION
* Backwards tab function.
*****/
void
tn5250_display_kf_backtab (Tn5250Display * This)
{
/* Backtab: Move to start of this field, or start of previous field if
* already there.
*/
Tn5250Field *field = tn5250_display_current_field (This);
if (field == NULL || tn5250_field_count_left (field,
tn5250_display_cursor_y
(This),
tn5250_display_cursor_x
(This)) == 0)
{
tn5250_display_set_cursor_prev_logical_field (This);
return;
}
if (field != NULL)
{
tn5250_display_set_cursor_field (This, field);
}
else
{
tn5250_display_set_cursor_home (This);
}
return;
}
/****f* lib5250/tn5250_display_kf_end
* NAME
* tn5250_display_kf_end
* SYNOPSIS
* tn5250_display_kf_end (This);
* INPUTS
* Tn5250Display * This -
* DESCRIPTION
* End key function.
*****/
void
tn5250_display_kf_end (Tn5250Display * This)
{
Tn5250Field *field = tn5250_display_current_field (This);
if (field != NULL && !tn5250_field_is_bypass (field))
{
unsigned char *data = tn5250_display_field_data (This, field);
int i = tn5250_field_length (field) - 1;
int y = tn5250_field_start_row (field);
int x = tn5250_field_start_col (field);
if (data[i] == '\0')
{
while (i > 0 && data[i] == '\0')
{
i--;
}
while (i >= 0)
{
if (++x == tn5250_display_width (This))
{
x = 0;
if (++y == tn5250_display_height (This))
{
y = 0;
}
}
i--;
}
}
else
{
y = tn5250_field_end_row (field);
x = tn5250_field_end_col (field);
}
tn5250_display_set_cursor (This, y, x);
}
else
{
This->keystate = TN5250_KEYSTATE_PREHELP;
This->keySRC = TN5250_KBDSRC_PROTECT;
tn5250_display_inhibit (This);
}
return;
}
/****f* lib5250/tn5250_display_kf_home
* NAME
* tn5250_display_kf_home
* SYNOPSIS
* tn5250_display_kf_home (This);
* INPUTS
* Tn5250Display * This -
* DESCRIPTION
* Home key function.
*****/
void
tn5250_display_kf_home (Tn5250Display * This)
{
Tn5250Field *field;
int gx, gy;
if (This->pending_insert)
{
gy = This->display_buffers->tcy;
gx = This->display_buffers->tcx;
}
else
{
field = tn5250_dbuffer_first_non_bypass (This->display_buffers);
if (field != NULL)
{
gy = tn5250_field_start_row (field);
gx = tn5250_field_start_col (field);
}
else
{
gx = gy = 0;
}
}
if (gy == tn5250_display_cursor_y (This)
&& gx == tn5250_display_cursor_x (This))
{
tn5250_display_do_aidkey (This, TN5250_SESSION_AID_RECORD_BS);
}
else
{
tn5250_display_set_cursor (This, gy, gx);
}
return;
}
/****f* lib5250/tn5250_display_kf_delete
* NAME
* tn5250_display_kf_delete
* SYNOPSIS
* tn5250_display_kf_delete (This);
* INPUTS
* Tn5250Display * This -
* DESCRIPTION
* Delete key function.
*****/
void
tn5250_display_kf_delete (Tn5250Display * This)
{
Tn5250Field *field = tn5250_display_current_field (This);
if (field == NULL || tn5250_field_is_bypass (field))
{
This->keystate = TN5250_KEYSTATE_PREHELP;
This->keySRC = TN5250_KBDSRC_PROTECT;
tn5250_display_inhibit (This);
}
else
{
tn5250_field_set_mdt (field);
/* If this field is word wrap handle it differently */
if (tn5250_field_is_wordwrap (field))
{
tn5250_display_wordwrap_delete (This);
return;
}
tn5250_dbuffer_del (This->display_buffers, field->id,
tn5250_field_count_right (field,
tn5250_display_cursor_y
(This),
tn5250_display_cursor_x
(This)));
}
return;
}
/****f* lib5250/tn5250_display_kf_prevword
* NAME
* tn5250_display_kf_prevword
* SYNOPSIS
* tn5250_display_kf_prevword (This);
* INPUTS
* Tn5250Display * This -
* DESCRIPTION
* Move cursor to the last non-blank character.
*****/
void
tn5250_display_kf_prevword (Tn5250Display * This)
{
tn5250_dbuffer_prevword (This->display_buffers);
return;
}
/****f* lib5250/tn5250_display_kf_nextword
* NAME
* tn5250_display_kf_nextword
* SYNOPSIS
* tn5250_display_kf_nextword (This);
* INPUTS
* Tn5250Display * This -
* DESCRIPTION
* Move cursor to the next non-blank character.
*****/
void
tn5250_display_kf_nextword (Tn5250Display * This)
{
tn5250_dbuffer_nextword (This->display_buffers);
return;
}
/****f* lib5250/tn5250_display_kf_prevfld
* NAME
* tn5250_display_kf_prevfld
* SYNOPSIS
* tn5250_display_kf_prevfld (This);
* INPUTS
* Tn5250Display * This -
* DESCRIPTION
* Move the cursor backward to the beginning of the previous non-blank
* or input field. The intent is to emulate the dbuffer_prevword function
* and add the additional functionality of stopping at a (possibly blank)
* input-capable field as well.
*****/
void
tn5250_display_kf_prevfld (Tn5250Display * This)
{
int state = 0;
int maxiter;
Tn5250Field *field;
TN5250_LOG (("dbuffer_prevfld: entered.\n"));
maxiter = (This->display_buffers->w * This->display_buffers->h);
TN5250_ASSERT (maxiter > 0);
while (--maxiter)
{
tn5250_dbuffer_left (This->display_buffers);
/* If at the start of a field, exit */
field = tn5250_display_current_field (This);
if ((field != NULL) &&
(tn5250_field_start_row (field) == This->display_buffers->cy) &&
(tn5250_field_start_col (field) == This->display_buffers->cx))
{
break;
}
switch (state)
{
case 0:
if (This->display_buffers->data[This->display_buffers->cy *
This->display_buffers->w +
This->display_buffers->cx] <= 0x40)
{
state++;
}
break;
case 1:
if (This->display_buffers->data[This->display_buffers->cy *
This->display_buffers->w +
This->display_buffers->cx] > 0x40)
{
state++;
}
break;
case 2:
if (This->display_buffers->data[This->display_buffers->cy *
This->display_buffers->w +
This->display_buffers->cx] <= 0x40)
{
tn5250_dbuffer_right (This->display_buffers, 1);
return;
}
break;
}
}
return;
}
/****f* lib5250/tn5250_display_kf_nextfld
* NAME
* tn5250_display_kf_nextfld
* SYNOPSIS
* tn5250_display_kf_nextfld (This);
* INPUTS
* Tn5250Display * This -
* DESCRIPTION
* Move the cursor forward to the beginning of the next non-blank
* or input field. The intent is to emulate the dbuffer_nextword function
* and add the additional functionality of stopping at a (possibly blank)
* input-capable field as well.
*****/
void
tn5250_display_kf_nextfld (Tn5250Display * This)
{
int foundblank = 0;
int maxiter;
Tn5250Field *field;
TN5250_LOG (("dbuffer_nextfld: entered.\n"));
maxiter = (This->display_buffers->w * This->display_buffers->h);
TN5250_ASSERT (maxiter > 0);
while (--maxiter)
{
tn5250_dbuffer_right (This->display_buffers, 1);
if (This->display_buffers->data[This->display_buffers->cy *
This->display_buffers->w +
This->display_buffers->cx] <= 0x40)
{
foundblank++;
}
/* If found a blank previously and a non-blank now, exit */
if ((foundblank)
&& (This->display_buffers->
data[This->display_buffers->cy * This->display_buffers->w +
This->display_buffers->cx] > 0x40))
{
break;
}
/* If at the start of a field, exit */
field = tn5250_display_current_field (This);
if ((field != NULL) &&
(tn5250_field_start_row (field) == This->display_buffers->cy) &&
(tn5250_field_start_col (field) == This->display_buffers->cx))
{
break;
}
}
return;
}
/****f* lib5250/tn5250_display_kf_fieldhome
* NAME
* tn5250_display_kf_fieldhome
* SYNOPSIS
* tn5250_display_kf_fieldhome (This);
* INPUTS
* Tn5250Display * This -
* DESCRIPTION
* Move cursor to the next non-blank character.
*****/
void
tn5250_display_kf_fieldhome (Tn5250Display * This)
{
Tn5250Field *field = tn5250_display_current_field (This);
if (field != NULL && !tn5250_field_is_bypass (field))
{
int y = tn5250_field_start_row (field);
int x = tn5250_field_start_col (field);
tn5250_display_set_cursor (This, y, x);
}
else
{
This->keystate = TN5250_KEYSTATE_PREHELP;
This->keySRC = TN5250_KBDSRC_PROTECT;
tn5250_display_inhibit (This);
}
return;
}
/****f* lib5250/tn5250_display_kf_newline
* NAME
* tn5250_display_kf_newline
* SYNOPSIS
* tn5250_display_kf_newline (This);
* INPUTS
* Tn5250Display * This -
* DESCRIPTION
* Move cursor to the first field on the next line.
*****/
void
tn5250_display_kf_newline (Tn5250Display * This)
{
int y;
Tn5250Field *f;
y = tn5250_display_cursor_y (This);
tn5250_display_set_cursor (This, y, 0);
tn5250_dbuffer_down (This->display_buffers);
f = tn5250_display_current_field (This);
if (f == NULL || tn5250_field_is_bypass (f))
{
tn5250_display_set_cursor_next_field (This);
}
return;
}
/****f* lib5250/tn5250_display_kf_macro
* NAME
* tn5250_display_kf_macro
* SYNOPSIS
* tn5250_display_kf_macro (This);
* INPUTS
* Tn5250Display * This -
* int Ch - choice : K_MEMO | K_EXEC
* DESCRIPTION
* Toggle the memo/exec indicator.
*****/
void
tn5250_display_kf_macro (Tn5250Display * This, int Ch)
{
TN5250_LOG (("K_MEMO/EXEC\n"));
if ((Ch == K_MEMO) && (!tn5250_macro_estate (This)))
{
if (!tn5250_macro_rstate (This))
{
if (tn5250_macro_startdef (This))
{
tn5250_display_indicator_set (This, TN5250_DISPLAY_IND_MACRO);
}
}
else
{
tn5250_macro_enddef (This);
tn5250_display_indicator_clear (This, TN5250_DISPLAY_IND_MACRO);
}
}
if ((Ch == K_EXEC) && (!tn5250_macro_rstate (This)))
{
if (!tn5250_macro_estate (This))
{
if (tn5250_macro_startexec (This))
{
tn5250_display_indicator_set (This, TN5250_DISPLAY_IND_MACRO);
}
}
else
{
tn5250_macro_endexec (This);
tn5250_display_indicator_clear (This, TN5250_DISPLAY_IND_MACRO);
}
}
return;
}
/****f* lib5250/tn5250_display_save_msg_line
* NAME
* tn5250_display_save_msg_line
* SYNOPSIS
* tn5250_display_save_msg_line (This);
* INPUTS
* Tn5250Display * This -
* DESCRIPTION
* Save the current message line.
*****/
void
tn5250_display_save_msg_line (Tn5250Display * This)
{
int l;
if (This->saved_msg_line != NULL)
{
free (This->saved_msg_line);
}
This->saved_msg_line =
(unsigned char *) malloc (tn5250_display_width (This));
l = tn5250_dbuffer_msg_line (This->display_buffers);
memcpy (This->saved_msg_line, This->display_buffers->data +
tn5250_display_width (This) * l, tn5250_display_width (This));
return;
}
/****f* lib5250/tn5250_display_set_msg_line
* NAME
* tn5250_display_set_msg_line
* SYNOPSIS
* tn5250_display_set_msg_line (This);
* INPUTS
* Tn5250Display * This -
* const unsigned char *msgline -
* int msglen -
* DESCRIPTION
* Set a new message line.
*****/
void
tn5250_display_set_msg_line (Tn5250Display * This,
const unsigned char *msgline, int msglen)
{
int l;
if (This->msg_line != NULL)
{
free (This->msg_line);
}
This->msg_line = (unsigned char *) malloc (tn5250_display_width (This));
memset (This->msg_line, 0x00, tn5250_display_width (This));
memcpy (This->msg_line, msgline, msglen);
This->msg_len = msglen;
l = tn5250_dbuffer_msg_line (This->display_buffers);
memcpy (This->display_buffers->data + tn5250_display_width (This) * l,
This->msg_line, This->msg_len);
return;
}
/****f* lib5250/tn5250_display_set_char_map
* NAME
* tn5250_display_set_char_map
* SYNOPSIS
* tn5250_display_set_char_map (display, "37");
* INPUTS
* Tn5250Display * display - Pointer to the display object.
* const char * name - Name of translation map to use.
* DESCRIPTION
* Save the current message line.
*****/
void
tn5250_display_set_char_map (Tn5250Display * This, const char *name)
{
Tn5250CharMap *map = tn5250_char_map_new (name);
TN5250_ASSERT (map != NULL);
if (This->map != NULL)
{
tn5250_char_map_destroy (This->map);
}
This->map = map;
return;
}
/****f* lib5250/tn5250_display_erase_region
* NAME
* tn5250_display_erase_region
* SYNOPSIS
* tn5250_display_erase_region (This, startrow, startcol, endrow, endcol,
* leftedge, rightedge);
* INPUTS
* Tn5250Display * This -
* unsigned int startrow -
* unsigned int startcol -
* unsigned int endrow -
* unsigned int endcol -
* unsigned int leftedge -
* unsigned int rightedge -
* DESCRIPTION
* Erase a region of the buffer
*****/
void
tn5250_display_erase_region (Tn5250Display * This, unsigned int startrow,
unsigned int startcol, unsigned int endrow,
unsigned int endcol, unsigned int leftedge,
unsigned int rightedge)
{
int i, j;
if (startrow == endrow)
{
for (j = startcol - 1; j < endcol; j++)
{
This->display_buffers->
data[((startrow - 1) * This->display_buffers->w) + j] =
tn5250_char_map_to_remote (This->map, ' ');
}
}
else
{
for (i = startrow - 1; i < endrow; i++)
{
if (i == (startrow - 1))
{
for (j = startcol - 1; j < rightedge; j++)
{
This->display_buffers->data[(i * This->display_buffers->w) +
j] =
tn5250_char_map_to_remote (This->map, ' ');
}
}
else if (i == (endrow - 1))
{
for (j = leftedge - 1; j < endcol; j++)
{
This->display_buffers->data[(i * This->display_buffers->w) +
j] =
tn5250_char_map_to_remote (This->map, ' ');
}
}
else
{
for (j = leftedge - 1; j < rightedge; j++)
{
This->display_buffers->data[(i * This->display_buffers->w) +
j] =
tn5250_char_map_to_remote (This->map, ' ');
}
}
}
}
return;
}
/****f* lib5250/tn5250_display_wordwrap_delete
* NAME
* tn5250_display_wordwrap_delete
* SYNOPSIS
* tn5250_display_wordwrap_delete (This);
* INPUTS
* Tn5250Display * This -
* DESCRIPTION
* Delete key function.
*****/
void
tn5250_display_wordwrap_delete (Tn5250Display * This)
{
Tn5250Field *field = tn5250_display_current_field (This);
Tn5250Field *iter;
int buflen;
unsigned char *text, *ptr;
unsigned char *data;
unsigned char espace = TN5250_DISPLAY_WORD_WRAP_SPACE;
/* Use code from x5250 (with permission). The basic idea here is to
* copy all the fields starting with the field we are currently in
* until the last field in this wordwrap group (the last field isn't
* marked continuous - but will always be the next field, or so say
* the docs). Delete the character at the current cursor location for
* only the current field. Then copy the result and concatenate the
* remaining fields into a single buffer. Once that is done, word wrap
* the result and copy it back into the field buffers.
*/
tn5250_dbuffer_del_this_field_only (This->display_buffers,
tn5250_field_count_right (field,
tn5250_display_cursor_y
(This),
tn5250_display_cursor_x
(This)));
/* First allocate enough space to do the copying. This will be sum of
* the lengths of the word wrap fields in this group starting from the
* current field.
*/
/* Find out how much to allocate (do this separately so we can do the
* actual allocation in one step).
*/
buflen = 0;
for (iter = field; tn5250_field_is_wordwrap (iter); iter = iter->next)
{
buflen = buflen + tn5250_field_length (iter) + 1;
}
buflen = buflen + tn5250_field_length (iter);
/* Now allocate */
text = (unsigned char *) malloc (buflen * sizeof (unsigned char));
ptr = text;
/* Now repeat the loop above and this time copy the data over. Insert
* a space after the end of each field since spaces are implied at the
* ends of word wrap fields.
*/
for (iter = field; tn5250_field_is_wordwrap (iter); iter = iter->next)
{
data = tn5250_display_field_data (This, iter);
memcpy (ptr, data, tn5250_field_length (iter) * sizeof (unsigned char));
ptr = ptr + (tn5250_field_length (iter) * sizeof (unsigned char));
memcpy (ptr, &espace, sizeof (unsigned char));
ptr = ptr + sizeof (unsigned char);
}
data = tn5250_display_field_data (This, iter);
memcpy (ptr, data, tn5250_field_length (iter) * sizeof (unsigned char));
tn5250_display_wordwrap (This, text, buflen, tn5250_field_length (field),
field);
free (text);
return;
}
/****f* lib5250/tn5250_display_wordwrap_insert
* NAME
* tn5250_display_wordwrap_insert
* SYNOPSIS
* tn5250_display_wordwrap_insert (This);
* INPUTS
* Tn5250Display * This -
* DESCRIPTION
* Insert key function.
*****/
void
tn5250_display_wordwrap_insert (Tn5250Display * This, unsigned char c,
int shiftcount)
{
Tn5250Field *field = tn5250_display_current_field (This);
Tn5250Field *iter;
int x, y, i;
unsigned char c2;
int buflen;
unsigned char *text, *ptr;
unsigned char *data;
unsigned char espace = TN5250_DISPLAY_WORD_WRAP_SPACE;
/* First allocate enough space to do the copying. This will be sum of
* the lengths of the word wrap fields in this group starting from the
* current field.
*/
/* Find out how much to allocate (do this separately so we can do the
* actual allocation in one step).
*/
buflen = 0;
/* If we just inserted a space near the beginning of a word wrap field
* that is not the first of a group, we may need to word wrap the prior
* field as well since we may have just made a word short enough that it
* should be on the previous line. All word wrap fields are continuous
* fields so a check to see if the previous field is a middle field
* should do the trick.
*/
if (!tn5250_field_is_continued_first (field))
{
iter = field->prev;
}
else
{
iter = field;
}
for (; tn5250_field_is_wordwrap (iter); iter = iter->next)
{
buflen = buflen + tn5250_field_length (iter) + 1;
}
buflen = buflen + tn5250_field_length (iter);
/* Now allocate */
text = (unsigned char *) malloc (buflen * sizeof (unsigned char));
ptr = text;
if (!tn5250_field_is_continued_first (field))
{
iter = field->prev;
data = tn5250_display_field_data (This, iter);
memcpy (ptr, data, tn5250_field_length (iter) * sizeof (unsigned char));
ptr = ptr + (tn5250_field_length (iter) * sizeof (unsigned char));
memcpy (ptr, &espace, sizeof (unsigned char));
ptr = ptr + sizeof (unsigned char);
}
/* Use our own version of tn5250_dbuffer_ins(). We can't use the real
* version because the insert may cause the current field data to be
* wider than the field. That's ok because we're going to word wrap it
* and that will fit the data to the field(s).
*
* We need to put the entire field into the buffer, so start at the
* beginning of the field, then copy the inserted data.
*/
x = tn5250_field_start_col (field);
y = tn5250_field_start_row (field);
for (i = 0; i < tn5250_field_length (field) - shiftcount - 1; i++)
{
c2 = This->display_buffers->data[y * This->display_buffers->w + x];
memcpy (ptr, &c2, sizeof (unsigned char));
ptr = ptr + sizeof (unsigned char);
if (++x == This->display_buffers->w)
{
x = 0;
y++;
}
}
x = This->display_buffers->cx;
y = This->display_buffers->cy;
for (; i < tn5250_field_length (field); i++)
{
c2 = This->display_buffers->data[y * This->display_buffers->w + x];
memcpy (ptr, &c, sizeof (unsigned char));
ptr = ptr + sizeof (unsigned char);
c = c2;
if (++x == This->display_buffers->w)
{
x = 0;
y++;
}
}
memcpy (ptr, &c, sizeof (unsigned char));
ptr = ptr + sizeof (unsigned char);
memcpy (ptr, &espace, sizeof (unsigned char));
ptr = ptr + sizeof (unsigned char);
/* Now repeat the loop above starting with the next field and this time
* copy the data over. Insert a space after the end of each field since
* spaces are implied at the ends of word wrap fields.
*/
for (iter = field->next; tn5250_field_is_wordwrap (iter); iter = iter->next)
{
data = tn5250_display_field_data (This, iter);
memcpy (ptr, data, tn5250_field_length (iter) * sizeof (unsigned char));
ptr = ptr + (tn5250_field_length (iter) * sizeof (unsigned char));
memcpy (ptr, &espace, sizeof (unsigned char));
ptr = ptr + sizeof (unsigned char);
}
data = tn5250_display_field_data (This, iter);
memcpy (ptr, data, tn5250_field_length (iter) * sizeof (unsigned char));
if (!tn5250_field_is_continued_first (field))
{
tn5250_display_wordwrap (This, text, buflen,
tn5250_field_length (field), field->prev);
}
else
{
tn5250_display_wordwrap (This, text, buflen,
tn5250_field_length (field), field);
}
tn5250_dbuffer_right (This->display_buffers, 1);
/* We have to adjust the cursor position ourselves in the case of the
* cursor being outside the end of the field.
*
* Note that we *have* to handle all cursor placement ourselves because
* tn5250_display_wordwrap() can possibly put the cursor anywhere
* (don't worry, it is supposed to). But our caller doesn't have enough
* info to intelligently place the cursor.
*/
if (tn5250_display_cursor_x (This) > tn5250_field_end_col (field))
{
tn5250_dbuffer_left (This->display_buffers);
tn5250_display_set_cursor_next_field (This);
}
free (text);
return;
}
/****f* lib5250/tn5250_display_wordwrap_addch
* NAME
* tn5250_display_wordwrap_addch
* SYNOPSIS
* tn5250_display_wordwrap_addch (This);
* INPUTS
* Tn5250Display * This -
* DESCRIPTION
* Addch key function.
*****/
void
tn5250_display_wordwrap_addch (Tn5250Display * This, unsigned char c)
{
Tn5250Field *field = tn5250_display_current_field (This);
Tn5250Field *iter;
int buflen;
unsigned char *text, *ptr;
unsigned char *data;
unsigned char espace = TN5250_DISPLAY_WORD_WRAP_SPACE;
/* Use our own version of tn5250_dbuffer_addch(). We can't use the real
* version because we don't want to advance the cursor position.
*/
This->display_buffers->
data[(This->display_buffers->cy * This->display_buffers->w) +
This->display_buffers->cx] = c;
/* First allocate enough space to do the copying. This will be sum of
* the lengths of the word wrap fields in this group starting from the
* current field.
*/
/* Find out how much to allocate (do this separately so we can do the
* actual allocation in one step).
*/
buflen = 0;
/* If we just added a space near the beginning of a word wrap field
* that is not the first of a group, we may need to word wrap the prior
* field as well since we may have just made a word short enough that it
* should be on the previous line. All word wrap fields are continuous
* fields so a check to see if the previous field is a middle field
* should do the trick.
*/
if (!tn5250_field_is_continued_first (field))
{
iter = field->prev;
}
else
{
iter = field;
}
for (; tn5250_field_is_wordwrap (iter); iter = iter->next)
{
buflen = buflen + tn5250_field_length (iter) + 1;
}
buflen = buflen + tn5250_field_length (iter);
/* Now allocate */
text = (unsigned char *) malloc (buflen * sizeof (unsigned char));
ptr = text;
if (!tn5250_field_is_continued_first (field))
{
data = tn5250_display_field_data (This, field->prev);
memcpy (ptr, data,
tn5250_field_length (field->prev) * sizeof (unsigned char));
ptr =
ptr + (tn5250_field_length (field->prev) * sizeof (unsigned char));
memcpy (ptr, &espace, sizeof (unsigned char));
ptr = ptr + sizeof (unsigned char);
}
/* Now repeat the loop above starting with the next field and this time
* copy the data over. Insert a space after the end of each field since
* spaces are implied at the ends of word wrap fields.
*/
for (iter = field; tn5250_field_is_wordwrap (iter); iter = iter->next)
{
data = tn5250_display_field_data (This, iter);
memcpy (ptr, data, tn5250_field_length (iter) * sizeof (unsigned char));
ptr = ptr + (tn5250_field_length (iter) * sizeof (unsigned char));
memcpy (ptr, &espace, sizeof (unsigned char));
ptr = ptr + sizeof (unsigned char);
}
data = tn5250_display_field_data (This, iter);
memcpy (ptr, data, tn5250_field_length (iter) * sizeof (unsigned char));
if (!tn5250_field_is_continued_first (field))
{
tn5250_display_wordwrap (This, text, buflen,
tn5250_field_length (field), field->prev);
}
else
{
tn5250_display_wordwrap (This, text, buflen,
tn5250_field_length (field), field);
}
tn5250_dbuffer_right (This->display_buffers, 1);
/* We have to adjust the cursor position ourselves in the case of the
* cursor being outside the end of the field.
*
* Note that we *have* to handle all cursor placement ourselves because
* tn5250_display_wordwrap() can possibly put the cursor anywhere
* (don't worry, it is supposed to). But our caller doesn't have enough
* info to intelligently place the cursor.
*/
if (tn5250_display_cursor_x (This) > tn5250_field_end_col (field))
{
tn5250_dbuffer_left (This->display_buffers);
tn5250_display_set_cursor_next_field (This);
}
free (text);
return;
}
void
tn5250_display_wordwrap (Tn5250Display * This, unsigned char *text,
int totallen, int fieldlen, Tn5250Field * field)
{
Tn5250Field *iter;
int origcursorcol = tn5250_dbuffer_cursor_x (This->display_buffers);
int nonnullcheck, nonnullcount = 0;
int cursorset;
int origentryid = field->entry_id;
int i, j;
unsigned char c, c2;
int curlinelength = 0;
int wordlength = 0;
char word[3564 + 1] = { '\0' };
char line[3564 + 1] = { '\0' };
/* First find out how many non-null character are between the start
* of the field and the current cursor position. This will be used
* later to set the cursor to the right place after wrapping.
*
* Note that the 'i < fieldlen + 1' in the for loop below is because
* we add an extra character to each field before calling this function.
*/
j = 0;
for (iter = field; iter != tn5250_display_current_field (This);
iter = iter->next)
{
for (i = 0; i < fieldlen + 1; i++)
{
if (text[i + j] != TN5250_DISPLAY_WORD_WRAP_SPACE)
{
nonnullcount++;
}
}
j = i;
}
for (i = 0; i < origcursorcol - tn5250_field_start_col (iter); i++)
{
if (text[i + j] != TN5250_DISPLAY_WORD_WRAP_SPACE)
{
nonnullcount++;
}
}
/* After playing a bit with a real IBM terminal I discovered that it
* treats every space as a word. Thus everytime we encounter a space
* complete the current word and add it and a space to the buffer.
*/
/* We need to be able to distinguish between spaces the user typed in
* and spaces we add here to pad the end of lines. Spaces the user
* typed in should always remain and are treated as one word per space.
* Spaces we add here for padding should be adjustable.
*
* Right now the best way I can think of to do this is to use a special
* character for spaces we pad with. Since TN5250_DISPLAY_WORD_WRAP_SPACE
* is not a valid character in EBCDIC or ASCII I'll use that here.
*/
iter = field;
for (i = 0; i < totallen; i++)
{
c = text[i];
if (c != TN5250_DISPLAY_WORD_WRAP_SPACE)
{
c2 = tn5250_char_map_to_local (This->map, c);
}
if ((c2 != ' ') && (c != TN5250_DISPLAY_WORD_WRAP_SPACE))
{
word[wordlength] = c2;
wordlength++;
word[wordlength] = '\0';
curlinelength++;
}
else
{
if (strlen (line) == 0)
{
if (c == TN5250_DISPLAY_WORD_WRAP_SPACE)
{
sprintf (line, "%s", word);
}
else
{
sprintf (line, "%s ", word);
}
}
else
{
if ((curlinelength + 1) > fieldlen)
{
tn5250_dbuffer_cursor_set (This->display_buffers,
tn5250_field_start_row (iter),
tn5250_field_start_col (iter));
for (j = 0; j < strlen (line); j++)
{
tn5250_dbuffer_addch (This->display_buffers,
tn5250_char_map_to_remote (This->
map,
line
[j]));
}
for (; j < tn5250_field_length (iter); j++)
{
tn5250_dbuffer_addch (This->display_buffers,
TN5250_DISPLAY_WORD_WRAP_SPACE);
}
if (tn5250_field_is_wordwrap (iter))
{
iter = iter->next;
}
memset (line, '\0', 133);
if (c == TN5250_DISPLAY_WORD_WRAP_SPACE)
{
sprintf (line, "%s", word);
}
else
{
sprintf (line, "%s ", word);
}
curlinelength = strlen (line);
}
else
{
if (c == TN5250_DISPLAY_WORD_WRAP_SPACE)
{
sprintf (line, "%s%s", line, word);
}
else
{
sprintf (line, "%s%s ", line, word);
}
curlinelength = strlen (line);
}
}
memset (word, '\0', 133);
wordlength = 0;
}
}
/* Add or clear any trailing text */
tn5250_dbuffer_cursor_set (This->display_buffers,
tn5250_field_start_row (iter),
tn5250_field_start_col (iter));
if (strlen (word) > 0)
{
sprintf (line, "%s%s", line, word);
}
for (j = 0; j < strlen (line); j++)
{
tn5250_dbuffer_addch (This->display_buffers,
tn5250_char_map_to_remote (This->map, line[j]));
}
for (; j < tn5250_field_length (iter); j++)
{
tn5250_dbuffer_addch (This->display_buffers,
TN5250_DISPLAY_WORD_WRAP_SPACE);
}
/* And finally clear any old text that might be in fields after the last
* field we just wrote to in this same word wrap group.
*
* It would probably be easier to use the field entry ID here instead of
* checking to see if the field is continuous and not outside the current
* word wrap group.
*/
if (tn5250_field_is_continued_last (iter->next)
|| (tn5250_field_is_wordwrap (iter->next)
&& !tn5250_field_is_continued_first (iter->next)))
{
for (iter = iter->next; tn5250_field_is_wordwrap (iter);
iter = iter->next)
{
tn5250_dbuffer_cursor_set (This->display_buffers,
tn5250_field_start_row (iter),
tn5250_field_start_col (iter));
for (j = 0; j < tn5250_field_length (iter); j++)
{
tn5250_dbuffer_addch (This->display_buffers,
TN5250_DISPLAY_WORD_WRAP_SPACE);
}
}
if (tn5250_field_is_continued_last (iter))
{
tn5250_dbuffer_cursor_set (This->display_buffers,
tn5250_field_start_row (iter),
tn5250_field_start_col (iter));
for (j = 0; j < tn5250_field_length (iter); j++)
{
tn5250_dbuffer_addch (This->display_buffers,
TN5250_DISPLAY_WORD_WRAP_SPACE);
}
}
}
/* And finally put the cursor where it should be. */
nonnullcheck = 0;
cursorset = 0;
for (iter = field; iter->entry_id == origentryid; iter = iter->next)
{
i = tn5250_field_start_row (iter);
for (j = tn5250_field_start_col (iter);
j <= tn5250_field_end_col (iter); j++)
{
if (j == This->display_buffers->w)
{
j = 0;
i++;
}
if (tn5250_display_char_at (This, i, j) !=
TN5250_DISPLAY_WORD_WRAP_SPACE)
{
if (nonnullcheck >= nonnullcount)
{
tn5250_dbuffer_cursor_set (This->display_buffers, i, j);
cursorset = 1;
break;
}
nonnullcheck++;
}
}
if (cursorset)
{
break;
}
}
return;
}
syntax highlighted by Code2HTML, v. 0.9.1