Commit 06921364 authored by Jason 'Eraserhead' Felice's avatar Jason 'Eraserhead' Felice
Browse files

Some API cleanup and rewrite of the save screen/restore screen code.

parent 08e8f9b6
......@@ -39,5 +39,14 @@
key handler under the 'default' clause, we get two decimal 410s. Why?
</bug>
<bug>
<date>99.12.19.23.13.00</date>
<owner email="jasonf@nacs.net">Jay 'Eraserhead' Felice</owner>
Determining which line is the message line (and setting it) is horribly
broken. We should sort all this out. I don't think we're using the right
line in most cases.
</bug>
</bugs>
<!-- vi:set sts=2 sw=2 autoindent: -->
1999-12-19 Jay 'Eraserhead' Felice <jasonf@nacs.net>
- CC1/CC2 bytes processed for Read MDT Fields and Read Input Fields commands
as they should be (previously only processed for Write to Display command).
- save/restore screen rewrite seems to work now - added wtd.c and wtd.h which
manage a ``WTD Context'' which can be used for generating commands and WTD
orders for creating a particular display and format table. This is designed
so that we can later do differentials (as in, for the 5250 server).
1999-12-17 Jay 'Eraserhead' Felice <jasonf@nacs.net>
- Partial work on save/restore screen rewrite finished.
......
......@@ -51,5 +51,12 @@
handing the 400 a unique identifier.
</item>
<item>
We are currently ignoring some useful information in the format table
header (given to us with the SOH order). This includes the `Operator
Error Line' and a list of function keys which should be ignored (because
they aren't applicable for a particular screen).
</item>
</todo>
<!-- vi:set sts=2 sw=2 autoindent: -->
......@@ -2,7 +2,7 @@ dnl ** Process this file with autoconf to produce a configure script.
AC_INIT(src/tn5250.c)
dnl ** Automake Intialization
AM_INIT_AUTOMAKE(tn5250, 0.15.3)
AM_INIT_AUTOMAKE(tn5250, 0.15.4)
AM_CONFIG_HEADER(src/config.h)
dnl ** Checks for programs.
......
......@@ -415,11 +415,13 @@ void tn5250_display_set_cursor_prev_field(Tn5250Display * 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)
void tn5250_display_make_wtd_data (Tn5250Display *This, Tn5250Buffer *buf,
Tn5250DBuffer *src_dbuffer, Tn5250Table *src_table)
{
Tn5250WTDContext *ctx;
if ((ctx = tn5250_wtd_context_new (This, buf)) == NULL)
if ((ctx = tn5250_wtd_context_new (buf, src_dbuffer, src_table,
This->display_buffers, This->format_tables)) == NULL)
return;
tn5250_wtd_context_convert (ctx);
......@@ -836,7 +838,6 @@ void tn5250_display_kf_dup(Tn5250Display * This)
int y, x, i;
Tn5250Field *field;
unsigned char *data;
int curfield;
field = tn5250_display_current_field (This);
if (field == NULL || tn5250_field_is_bypass (field)) {
......
......@@ -100,7 +100,9 @@ extern void tn5250_display_set_pending_insert (Tn5250Display *This,
int y,
int x);
extern void tn5250_display_make_wtd_data (Tn5250Display *This,
struct _Tn5250Buffer *b);
struct _Tn5250Buffer *b,
struct _Tn5250DBuffer *,
struct _Tn5250Table *);
/* Key functions */
extern void tn5250_display_do_key (Tn5250Display *This,int);
......@@ -149,8 +151,8 @@ extern void tn5250_display_kf_delete (Tn5250Display *This);
(tn5250_dbuffer_roll((This)->display_buffers,(top),(bottom),(lines)))
#define tn5250_display_set_ic(This,y,x) \
(tn5250_dbuffer_set_ic((This)->display_buffers,(y),(x)))
#define tn5250_display_set_message_line(This,y) \
(tn5250_table_set_message_line((This)->format_tables,(y)))
#define tn5250_display_set_header_data(This,data,len) \
(tn5250_table_set_header_data((This)->format_tables,(data),(len)))
#define tn5250_display_clear_pending_insert(This) \
(void)((This)->pending_insert = 0)
#define tn5250_display_pending_insert(This) \
......
......@@ -37,7 +37,8 @@ Tn5250Table *tn5250_table_new()
This->numfields = 0;
This->field_list = NULL;
This->MasterMDT = 0;
This->message_line = 25;
This->header_data = NULL;
This->header_length = 0;
This->next = This->prev = NULL;
return This;
}
......@@ -51,12 +52,35 @@ Tn5250Table *tn5250_table_copy(Tn5250Table *table)
memcpy(This,table,sizeof(Tn5250Table));
This->next = This->prev = NULL;
This->field_list = tn5250_field_list_copy (table->field_list);
This->header_length = table->header_length;
if (table->header_data != NULL) {
This->header_data = (unsigned char *)malloc (This->header_length);
TN5250_ASSERT (This->header_data != NULL);
memcpy (This->header_data, table->header_data, table->header_length);
} else
This->header_data = NULL;
return This;
}
void tn5250_table_set_header_data(Tn5250Table *This, unsigned char *data, int len)
{
This->header_length = len;
if (This->header_data != NULL)
free (This->header_data);
if (This->header_length == 0)
This->header_data = NULL;
else {
This->header_data = (unsigned char *)malloc (This->header_length);
TN5250_ASSERT (This->header_data != NULL);
memcpy (This->header_data, data, len);
}
}
void tn5250_table_destroy(Tn5250Table * This)
{
(void)tn5250_field_list_destroy(This->field_list);
if (This->header_data)
free (This->header_data);
free (This);
}
......@@ -86,7 +110,11 @@ void tn5250_table_clear(Tn5250Table * This)
This->numfields = 0;
This->MasterMDT = 0;
This->message_line = 24;
This->header_length = 0;
if (This->header_data) {
free (This->header_data);
This->header_data = NULL;
}
TN5250_LOG(("FormatTable::Clear: entered.\n"));
}
......
......@@ -31,14 +31,19 @@ extern "C" {
Tn5250Field /*@null@*/ *field_list;
int numfields;
int MasterMDT;
int message_line;
int curfield;
/* Header data (from SOH order) is saved here. We even save data that
* we don't understand here so we can insert that into our generated
* WTD orders for save/restore screen. */
unsigned char *header_data;
int header_length;
};
typedef struct _Tn5250Table Tn5250Table;
extern Tn5250Table *tn5250_table_new(void);
extern Tn5250Table *tn5250_table_copy(Tn5250Table *table);
extern void tn5250_table_set_header_data(Tn5250Table *This, unsigned char *data, int len);
extern void tn5250_table_destroy(Tn5250Table /*@only@*/ * This);
extern void tn5250_table_add_field(Tn5250Table * This, Tn5250Field * field);
......@@ -51,11 +56,9 @@ extern "C" {
#define tn5250_table_mdt(This) ((This)->MasterMDT)
#define tn5250_table_set_mdt(This) (void) ((This)->MasterMDT = 1)
#define tn5250_table_clear_mdt(This) (void) ((This)->MasterMDT = 0)
#define tn5250_table_set_message_line(This,row) (void) ((This)->message_line = (row))
#define tn5250_table_field_count(This) ((This)->numfields)
#define tn5250_table_mdt(This) ((This)->MasterMDT)
#define tn5250_table_message_line(This) ((This)->message_line)
#ifdef __cplusplus
}
......
......@@ -54,7 +54,6 @@ static void tn5250_session_system_request(Tn5250Session * This);
static void tn5250_session_attention(Tn5250Session * This);
static void tn5250_session_output_only(Tn5250Session * This);
static void tn5250_session_save_screen(Tn5250Session * This);
static void tn5250_session_restore_screen(Tn5250Session * This);
static void tn5250_session_message_on(Tn5250Session * This);
static void tn5250_session_message_off(Tn5250Session * This);
static void tn5250_session_roll(Tn5250Session * This);
......@@ -69,6 +68,8 @@ static void tn5250_session_read_input_fields(Tn5250Session * This);
static void tn5250_session_read_mdt_fields(Tn5250Session * This);
static int tn5250_session_valid_wtd_data_char (unsigned char c);
static int tn5250_session_handle_aidkey (Tn5250Session *This, int key);
static void tn5250_session_handle_cc1 (Tn5250Session *This, unsigned char cc1);
static void tn5250_session_handle_cc2 (Tn5250Session *This, unsigned char cc2);
Tn5250Session *tn5250_session_new()
{
......@@ -435,7 +436,11 @@ static void tn5250_session_process_stream(Tn5250Session * This)
while (!tn5250_record_is_chain_end(This->record)) {
cur_command = tn5250_record_get_byte(This->record);
TN5250_ASSERT(cur_command == ESC);
if (cur_command != ESC) {
TN5250_LOG (("cur_command != ESC; cur_pos = %d\n",
This->record->cur_pos));
TN5250_ASSERT(0);
}
cur_command = tn5250_record_get_byte(This->record);
TN5250_LOG(("ProcessStream: cur_command = 0x%02X\n", cur_command));
......@@ -470,9 +475,6 @@ static void tn5250_session_process_stream(Tn5250Session * This)
case (CMD_SAVE_SCREEN):
tn5250_session_save_screen(This);
break;
case (CMD_RESTORE_SCREEN):
tn5250_session_restore_screen(This);
break;
case (CMD_WRITE_ERROR_CODE):
tn5250_session_write_error_code(This);
break;
......@@ -685,6 +687,14 @@ static void tn5250_session_write_to_display(Tn5250Session * This)
tn5250_display_set_cursor(This->display, 0, 0);
}
tn5250_session_handle_cc2 (This, CC2);
tn5250_display_update(This->display);
}
static void tn5250_session_handle_cc2 (Tn5250Session *This, unsigned char CC2)
{
if (CC2 & TN5250_SESSION_CTL_MESSAGE_ON)
tn5250_display_indicator_set(This->display, TN5250_DISPLAY_IND_MESSAGE_WAITING);
if ((CC2 & TN5250_SESSION_CTL_MESSAGE_OFF) && !(CC2 & TN5250_SESSION_CTL_MESSAGE_ON))
......@@ -702,8 +712,6 @@ static void tn5250_session_write_to_display(Tn5250Session * This)
tn5250_display_beep (This->display);
if ((CC2 & TN5250_SESSION_CTL_UNLOCK) != 0)
tn5250_display_indicator_clear(This->display, TN5250_DISPLAY_IND_X_SYSTEM);
tn5250_display_update(This->display);
}
static void tn5250_session_clear_unit(Tn5250Session * This)
......@@ -823,51 +831,22 @@ static void tn5250_session_save_screen(Tn5250Session * This)
TN5250_LOG(("SaveScreen: entered.\n"));
tn5250_buffer_init (&buffer);
tn5250_display_make_wtd_data (This->display, &buffer, NULL, NULL);
/* Okay, now if we were in a Read MDT Fields or a Read Input Fields,
* we need to append a command which would put us back in the appropriate
* read. */
if (This->read_opcode != 0) {
tn5250_buffer_append_byte (&buffer, ESC);
tn5250_buffer_append_byte (&buffer, This->read_opcode);
tn5250_buffer_append_byte (&buffer, 0x00); /* FIXME: ? CC1 */
tn5250_buffer_append_byte (&buffer, 0x00); /* FIXME: ? CC2 */
}
/* Append dummy CC1/CC2 bytes for write_to_display later. */
tn5250_buffer_append_byte (&buffer, 0);
tn5250_buffer_append_byte (&buffer, 0);
tn5250_display_make_wtd_data (This->display, &buffer);
tn5250_stream_send_packet (This->stream, tn5250_buffer_length (&buffer),
TN5250_RECORD_FLOW_DISPLAY, TN5250_RECORD_H_NONE,
TN5250_RECORD_OPCODE_SAVE_SCR, tn5250_buffer_data (&buffer));
tn5250_buffer_free (&buffer);
/* unsigned char outbuf[2 + sizeof(Tn5250DBuffer*) + sizeof(Tn5250Table*)];
int n;
outbuf[0] = 0x04;
outbuf[1] = 0x12;
*((Tn5250DBuffer**)&outbuf[2]) = tn5250_display_push_dbuffer(This->display);
*((Tn5250Table**)&outbuf[2+sizeof(Tn5250DBuffer*)]) =
tn5250_display_push_table(This->display);
tn5250_stream_send_packet(This->stream, sizeof(outbuf),
TN5250_RECORD_FLOW_DISPLAY, TN5250_RECORD_H_NONE,
TN5250_RECORD_OPCODE_SAVE_SCR, outbuf); */
}
static void tn5250_session_restore_screen(Tn5250Session * This)
{/*
int screen, format;
int i;
unsigned char rdata[sizeof (Tn5250DBuffer*) + sizeof (Tn5250Table*)];
TN5250_LOG(("RestoreScreen: entered.\n"));
for (i = 0; i < sizeof(rdata); i++)
rdata[i] = tn5250_record_get_byte(This->record);
TN5250_LOG(("RestoreScreen: screen = %d; format = %d\n", screen, format));
tn5250_display_restore_dbuffer (This->display, *((Tn5250DBuffer**)rdata));
tn5250_display_restore_table (This->display,
*((Tn5250Table**)(rdata + sizeof(Tn5250DBuffer*)))); */
tn5250_session_write_to_display (This);
tn5250_display_update(This->display);
}
static void tn5250_session_message_on(Tn5250Session * This)
......@@ -1022,28 +1001,30 @@ static void tn5250_session_start_of_field(Tn5250Session * This)
}
}
/*
* Clear the format table, get the table header data, and copy it to the
* table. This includes the operator error line (byte 4).
*/
static void tn5250_session_start_of_header(Tn5250Session * This)
{
int length;
int count;
unsigned char temp;
TN5250_LOG(("StartOfHeader: entered.\n"));
int i, n;
unsigned char *ptr = NULL;
TN5250_LOG (("StartOfHeader: entered.\n"));
tn5250_table_clear(tn5250_display_table(This->display));
tn5250_display_indicator_set(This->display, TN5250_DISPLAY_IND_X_SYSTEM);
length = tn5250_record_get_byte(This->record);
TN5250_LOG(("StartOfHeader: length = %d\nStartOfHeader: data = ", length));
for (count = 0; count < length; count++) {
temp = tn5250_record_get_byte(This->record);
TN5250_LOG(("0x%02X ", temp));
if (count == 3)
tn5250_display_set_message_line(This->display, temp);
n = tn5250_record_get_byte (This->record);
if (n > 0) {
ptr = (unsigned char *)malloc (n);
TN5250_ASSERT (ptr != NULL);
}
TN5250_LOG(("\n"));
tn5250_table_clear(tn5250_display_table(This->display));
for (i = 0; i < n; i++)
ptr[i] = tn5250_record_get_byte (This->record);
tn5250_display_set_header_data (This->display, ptr, n);
if (ptr != NULL)
free (ptr);
}
/*
......@@ -1168,7 +1149,10 @@ static void tn5250_session_read_input_fields(Tn5250Session * This)
This->read_opcode = CMD_READ_INPUT_FIELDS;
CC1 = tn5250_record_get_byte(This->record);
tn5250_session_handle_cc1 (This, CC1);
CC2 = tn5250_record_get_byte(This->record);
tn5250_session_handle_cc2 (This, CC2);
TN5250_LOG(("ReadInputFields: CC1 = 0x%02X; CC2 = 0x%02X\n", CC1, CC2));
tn5250_display_indicator_clear(This->display,
......@@ -1187,13 +1171,17 @@ static void tn5250_session_read_mdt_fields(Tn5250Session * This)
This->read_opcode = CMD_READ_MDT_FIELDS;
CC1 = tn5250_record_get_byte(This->record);
tn5250_session_handle_cc1 (This, CC1);
CC2 = tn5250_record_get_byte(This->record);
tn5250_session_handle_cc2 (This, CC2);
TN5250_LOG(("ReadMDTFields: CC1 = 0x%02X; CC2 = 0x%02X\n", CC1, CC2));
tn5250_display_indicator_clear(This->display,
TN5250_DISPLAY_IND_X_SYSTEM
| TN5250_DISPLAY_IND_X_CLOCK
| TN5250_DISPLAY_IND_INHIBIT);
tn5250_display_update(This->display);
}
......
/* tn5250 -- an implentation of the 5250 telnet protocol.
* Copyright (C) 1997 Michael Madore
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "config.h"
#include <string.h>
#include <stdio.h>
#include <malloc.h>
#include "utility.h"
#include "dbuffer.h"
#include "field.h"
#include "formattable.h"
#include "display.h"
#include "terminal.h"
#include "buffer.h"
#include "record.h"
#include "stream.h"
#include "session.h"
#include "codes5250.h"
#include "wtd.h"
static void tn5250_wtd_context_putc (Tn5250WTDContext *This, unsigned char c);
static void tn5250_wtd_context_ra_putc (Tn5250WTDContext *This, unsigned char c);
static void tn5250_wtd_context_ra_flush (Tn5250WTDContext *This);
static void tn5250_wtd_context_write_field (Tn5250WTDContext *This, Tn5250Field *field, unsigned char attr);
static void tn5250_wtd_context_convert_nosrc (Tn5250WTDContext *This);
static Tn5250Field *tn5250_wtd_context_peek_field (Tn5250WTDContext *This);
/*
* Create a new instance of our WTD context object and initialize it.
*/
Tn5250WTDContext *tn5250_wtd_context_new (Tn5250Buffer *buffer, Tn5250DBuffer *sd, Tn5250Table *st, Tn5250DBuffer *dd, Tn5250Table *dt)
{
Tn5250WTDContext *This;
TN5250_ASSERT(dd != NULL);
TN5250_ASSERT(dt != NULL);
TN5250_ASSERT(buffer != NULL);
if ((This = tn5250_new (Tn5250WTDContext, 1)) == NULL)
return NULL;
This->buffer = buffer;
This->src_dbuffer = sd;
This->src_table = st;
This->dst_dbuffer = dd;
This->dst_table = dt;
This->ra_count = 0;
This->ra_char = 0x00;
This->clear_unit = 0;
return This;
}
/*
* Destroy a WTD context object.
*/
void tn5250_wtd_context_destroy (Tn5250WTDContext *This)
{
TN5250_ASSERT (This != NULL);
free (This);
}
/*
* Convert the display info to WTD data.
*/
void tn5250_wtd_context_convert (Tn5250WTDContext *This)
{
/* The differential conversion is not yet implemented, and probably
* won't be until we implement the 5250 server. */
TN5250_ASSERT (This->src_dbuffer == NULL && This->src_table == NULL);
tn5250_wtd_context_convert_nosrc (This);
}
/*
* This is our routine which is used when we don't know the prior state
* of the format table or display buffer.
*/
static void tn5250_wtd_context_convert_nosrc (Tn5250WTDContext *This)
{
unsigned char c;
Tn5250Field *field;
int fy, fx;
TN5250_LOG (("wtd_context_convert entered.\n"));
/* Since we don't know the unit's prior state, we clear the unit. */
tn5250_wtd_context_putc (This, ESC);
if (tn5250_dbuffer_width (This->dst_dbuffer) != 80) {
tn5250_wtd_context_putc (This, CMD_CLEAR_UNIT_ALTERNATE);
tn5250_wtd_context_putc (This, 0x00);
} else
tn5250_wtd_context_putc (This, CMD_CLEAR_UNIT);
This->clear_unit = 1;
tn5250_wtd_context_putc (This, ESC);
tn5250_wtd_context_putc (This, CMD_WRITE_TO_DISPLAY);
/* FIXME: We will want to use different CC1/CC2 codes sometimes... */
tn5250_wtd_context_putc (This, 0x00); /* CC1 */
tn5250_wtd_context_putc (This, 0x00); /* CC2 */
/* If we have header data, start with a SOH order. */
if (This->dst_table->header_length != 0) {
int i;
tn5250_wtd_context_putc (This, SOH);
tn5250_wtd_context_putc (This, This->dst_table->header_length);
for (i = 0; i < This->dst_table->header_length; i++)
tn5250_wtd_context_putc (This, This->dst_table->header_data[i]);
}
/* FIXME: Set the insert-cursor address using IC if necessary. */
for (This->y = 0; This->y < tn5250_dbuffer_height(This->dst_dbuffer);
This->y++) {
for (This->x = 0; This->x < tn5250_dbuffer_width(This->dst_dbuffer);
This->x++) {
c = tn5250_dbuffer_char_at (This->dst_dbuffer, This->y, This->x);
field = tn5250_wtd_context_peek_field (This);
if (field != NULL) {
/* Start of a field, write an SF order. We have to remove
* the last byte we put on the buffer (since its the attribute,
* which is taken care of here. */
tn5250_wtd_context_write_field (This, field, c);
} else
tn5250_wtd_context_ra_putc (This, c);
}
}
TN5250_LOG_BUFFER (This->buffer);
}
/*
* Return a pointer to the field that _starts_ at the next position on the
* display, or NULL if no field starts there.
*/
static Tn5250Field *tn5250_wtd_context_peek_field (Tn5250WTDContext *This)
{
int nx = This->x, ny = This->y;
Tn5250Field *field;
if (++nx == tn5250_dbuffer_width (This->dst_dbuffer)) {
if (++ny == tn5250_dbuffer_height (This->dst_dbuffer))
return NULL;
}
field = tn5250_table_field_yx (This->dst_table, ny, nx);
if (field == NULL)
return NULL;
if (tn5250_field_start_row (field) != ny
|| tn5250_field_start_col (field) != nx)
return NULL;
return field;
}
/*
* Put a character (which may be an attribute or a parameter for an order)
* directly into the buffer. Flush the RA buffer if necessary.
*/
static void tn5250_wtd_context_putc (Tn5250WTDContext *This, unsigned char c)
{
tn5250_wtd_context_ra_flush (This);
tn5250_buffer_append_byte (This->buffer, c);
}
static void tn5250_wtd_context_ra_putc (Tn5250WTDContext *This, unsigned char c)
{
if (This->ra_char != c)
tn5250_wtd_context_ra_flush (This);
This->ra_char = c;
This->ra_count++;
}
static void tn5250_wtd_context_ra_flush (Tn5250WTDContext *This)
{
if (This->ra_count == 0)
return;
/* Determine which is smaller, the RA/SBA order or just repeating the
* bytes. */
if (This->ra_count <= 4 &&
!(This->ra_count == 3 && This->ra_char == 0x00 && This->clear_unit)) {
/* Just repeating the bytes won. */
while (This->ra_count > 0) {
tn5250_buffer_append_byte (This->buffer, This->ra_char);
This->ra_count--;
}
} else {
/* We can just use an SBA if the character is a NUL and we've just
* cleared the unit. Yes, I'm being picky over saving one byte. */
if (This->clear_unit && This->ra_char == 0x00) {
tn5250_buffer_append_byte (This->buffer, SBA);
tn5250_buffer_append_byte (This->buffer, This->y + 1);
tn5250_buffer_append_byte (This->buffer, This->x + 1);
} else {
int px = This->x, py = This->y;
if (px == 0) {
px = tn5250_dbuffer_width (This->dst_dbuffer) - 1;
TN5250_ASSERT (py != 0);
py--;
} else
px--;
tn5250_buffer_append_byte (This->buffer, RA);
tn5250_buffer_append_byte (This->buffer, py + 1);
tn5250_buffer_append_byte (This->buffer, px + 1);
tn5250_buffer_append_byte (This->buffer, This->ra_char);
}
}
This->ra_count = 0;
}
/*
* Write the SF order and the field's information.
*/
static void tn5250_wtd_context_write_field (Tn5250WTDContext *This, Tn5250Field *field, unsigned char attr)
{
TN5250_LOG (("Writing SF order in stream data.\n"));
tn5250_wtd_context_putc (This, SF);