1175 lines
36 KiB
C
1175 lines
36 KiB
C
|
/****************************************************************
|
||
|
* *
|
||
|
* Copyright 2001, 2009 Fidelity Information Services, Inc *
|
||
|
* *
|
||
|
* This source code contains the intellectual property *
|
||
|
* of its copyright holder(s), and is made available *
|
||
|
* under a license. If you do not know the terms of *
|
||
|
* the license, please stop and do not read further. *
|
||
|
* *
|
||
|
****************************************************************/
|
||
|
|
||
|
#include "mdef.h"
|
||
|
|
||
|
#include <errno.h>
|
||
|
#include <wctype.h>
|
||
|
#include <wchar.h>
|
||
|
#include "gtm_string.h"
|
||
|
|
||
|
#include "iotcp_select.h"
|
||
|
#include "io_params.h"
|
||
|
#include "io.h"
|
||
|
#include "trmdef.h"
|
||
|
#include "iotimer.h"
|
||
|
#include "gt_timer.h"
|
||
|
#include "iottdef.h"
|
||
|
#include "iott_edit.h"
|
||
|
#include "stringpool.h"
|
||
|
#include "gtmio.h"
|
||
|
#include "eintr_wrappers.h"
|
||
|
#include "send_msg.h"
|
||
|
#include "outofband.h"
|
||
|
#include "error.h"
|
||
|
#include "std_dev_outbndset.h"
|
||
|
#include "wake_alarm.h"
|
||
|
#include "min_max.h"
|
||
|
#ifdef UNICODE_SUPPORTED
|
||
|
#include "gtm_icu_api.h"
|
||
|
#include "gtm_utf8.h"
|
||
|
#endif
|
||
|
|
||
|
GBLDEF int4 spc_inp_prc; /* dummy: not used currently */
|
||
|
GBLDEF bool ctrlu_occurred; /* dummy: not used currently */
|
||
|
GBLDEF int term_error_line; /* record for cores */
|
||
|
|
||
|
GBLREF io_pair io_curr_device;
|
||
|
GBLREF io_pair io_std_device;
|
||
|
GBLREF bool prin_in_dev_failure;
|
||
|
GBLREF spdesc stringpool;
|
||
|
GBLREF volatile int4 outofband;
|
||
|
GBLREF mv_stent *mv_chain;
|
||
|
GBLREF stack_frame *frame_pointer;
|
||
|
GBLREF unsigned char *msp, *stackbase, *stacktop, *stackwarn;
|
||
|
GBLREF boolean_t dollar_zininterrupt;
|
||
|
GBLREF int4 ctrap_action_is;
|
||
|
GBLREF boolean_t gtm_utf8_mode;
|
||
|
|
||
|
#ifdef UNICODE_SUPPORTED
|
||
|
LITREF UChar32 u32_line_term[];
|
||
|
#endif
|
||
|
|
||
|
GBLREF int AUTO_RIGHT_MARGIN, EAT_NEWLINE_GLITCH;
|
||
|
GBLREF char *CURSOR_UP, *CURSOR_DOWN, *CURSOR_LEFT, *CURSOR_RIGHT, *CLR_EOL;
|
||
|
GBLREF char *KEY_BACKSPACE, *KEY_DC;
|
||
|
GBLREF char *KEY_DOWN, *KEY_LEFT, *KEY_RIGHT, *KEY_UP;
|
||
|
GBLREF char *KEY_INSERT;
|
||
|
GBLREF char *KEYPAD_LOCAL, *KEYPAD_XMIT;
|
||
|
|
||
|
#ifdef __MVS__
|
||
|
# define SEND_KEYPAD_LOCAL
|
||
|
#else
|
||
|
# define SEND_KEYPAD_LOCAL \
|
||
|
if (edit_mode && NULL != KEYPAD_LOCAL && (keypad_len = STRLEN(KEYPAD_LOCAL))) /* embedded assignment */ \
|
||
|
DOWRITE(tt_ptr->fildes, KEYPAD_LOCAL, keypad_len);
|
||
|
#endif
|
||
|
|
||
|
LITREF unsigned char lower_to_upper_table[];
|
||
|
|
||
|
/* dc1 & dc3 have the same value in ASCII and EBCDIC */
|
||
|
static readonly char dc1 = 17;
|
||
|
static readonly char dc3 = 19;
|
||
|
static readonly unsigned char eraser[3] = { NATIVE_BS, NATIVE_SP, NATIVE_BS };
|
||
|
|
||
|
#ifdef UNICODE_SUPPORTED
|
||
|
|
||
|
/* Maintenance of $ZB on a badchar error and returning partial data (if any) */
|
||
|
void iott_readfl_badchar(mval *vmvalptr, wint_t *dataptr32, int datalen,
|
||
|
int delimlen, unsigned char *delimptr, unsigned char *strend, unsigned char *buffer_start)
|
||
|
{
|
||
|
int i, tmplen, len;
|
||
|
unsigned char *delimend, *outptr, *outtop;
|
||
|
wint_t *curptr32;
|
||
|
io_desc *iod;
|
||
|
|
||
|
if (0 < datalen && NULL != dataptr32)
|
||
|
{ /* Return how much input we got */
|
||
|
if (gtm_utf8_mode)
|
||
|
{
|
||
|
outptr = buffer_start;
|
||
|
outtop = ((unsigned char *)dataptr32);
|
||
|
curptr32 = dataptr32;
|
||
|
for (i = 0; i < datalen && outptr < outtop; i++, curptr32++)
|
||
|
outptr = UTF8_WCTOMB(*curptr32, outptr);
|
||
|
vmvalptr->str.len = INTCAST(outptr - buffer_start);
|
||
|
} else
|
||
|
vmvalptr->str.len = datalen;
|
||
|
vmvalptr->str.addr = (char *)buffer_start;
|
||
|
if (buffer_start == stringpool.free)
|
||
|
stringpool.free += vmvalptr->str.len; /* The BADCHAR error after this won't do this for us */
|
||
|
}
|
||
|
if (NULL != strend && NULL != delimptr)
|
||
|
{ /* First find the end of the delimiter (max of 4 bytes) */
|
||
|
if (0 == delimlen)
|
||
|
{
|
||
|
for (delimend = delimptr; 4 >= delimlen && delimend < strend; ++delimend, ++delimlen)
|
||
|
{
|
||
|
if (UTF8_VALID(delimend, strend, tmplen))
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (0 < delimlen)
|
||
|
{ /* Set $ZB with the failing badchar */
|
||
|
iod = io_curr_device.in;
|
||
|
memcpy(iod->dollar.zb, delimptr, MIN(delimlen, ESC_LEN - 1));
|
||
|
iod->dollar.zb[MIN(delimlen, ESC_LEN - 1)] = '\0';
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
int iott_readfl(mval *v, int4 length, int4 timeout) /* timeout in seconds */
|
||
|
{
|
||
|
boolean_t ret, nonzerotimeout, timed, insert_mode, edit_mode, utf8_active, zint_restart, buffer_moved;
|
||
|
uint4 mask;
|
||
|
wint_t inchar, *current_32_ptr, *buffer_32_start, switch_char;
|
||
|
unsigned char inbyte, *outptr, *outtop;
|
||
|
#ifdef __MVS__
|
||
|
wint_t asc_inchar;
|
||
|
#endif
|
||
|
unsigned char more_buf[GTM_MB_LEN_MAX + 1], *more_ptr; /* to build up multi byte for character */
|
||
|
unsigned char *current_ptr; /* insert next character into buffer here */
|
||
|
unsigned char *buffer_start; /* beginning of non UTF8 buffer */
|
||
|
int msk_in, msk_num, rdlen, save_errno, selstat, status, ioptr_width, i, utf8_more;
|
||
|
int exp_length;
|
||
|
int inchar_width; /* display width of inchar */
|
||
|
int delchar_width; /* display width of deleted char */
|
||
|
int delta_width; /* display width change for replaced char */
|
||
|
int dx, dx_start; /* local dollar X, starting value */
|
||
|
int dx_instr, dx_outlen; /* wcwidth of string to insert point, whole string */
|
||
|
int dx_prev, dx_cur, dx_next;/* wcwidth of string to char BEFORE, AT and AFTER the insert point */
|
||
|
int instr; /* insert point in input string */
|
||
|
int outlen; /* total characters in line so far */
|
||
|
int keypad_len, backspace, delete;
|
||
|
int up, down, right, left, insert_key;
|
||
|
boolean_t escape_edit;
|
||
|
int4 msec_timeout; /* timeout in milliseconds */
|
||
|
io_desc *io_ptr;
|
||
|
d_tt_struct *tt_ptr;
|
||
|
io_terminator outofbands;
|
||
|
io_termmask mask_term;
|
||
|
tt_interrupt *tt_state;
|
||
|
mv_stent *mvc, *mv_zintdev;
|
||
|
unsigned char *zb_ptr, *zb_top;
|
||
|
ABS_TIME cur_time, end_time;
|
||
|
fd_set input_fd;
|
||
|
struct timeval input_timeval;
|
||
|
struct timeval save_input_timeval;
|
||
|
|
||
|
error_def(ERR_CTRAP);
|
||
|
error_def(ERR_IOEOF);
|
||
|
error_def(ERR_NOPRINCIO);
|
||
|
error_def(ERR_ZINTRECURSEIO);
|
||
|
error_def(ERR_STACKOFLOW);
|
||
|
error_def(ERR_STACKCRIT);
|
||
|
|
||
|
assert(stringpool.free >= stringpool.base);
|
||
|
assert(stringpool.free <= stringpool.top);
|
||
|
io_ptr = io_curr_device.in;
|
||
|
tt_ptr = (d_tt_struct *)(io_ptr->dev_sp);
|
||
|
assert(dev_open == io_ptr->state);
|
||
|
iott_flush(io_curr_device.out);
|
||
|
insert_mode = !(TT_NOINSERT & tt_ptr->ext_cap); /* get initial mode */
|
||
|
ioptr_width = io_ptr->width;
|
||
|
utf8_active = gtm_utf8_mode ? (CHSET_M != io_ptr->ichset) : FALSE;
|
||
|
/* if utf8_active, need room for multi byte characters plus wint_t buffer */
|
||
|
exp_length = utf8_active ? (int)(((SIZEOF(wint_t) * length) + (GTM_MB_LEN_MAX * length) + SIZEOF(gtm_int64_t))) : length;
|
||
|
zint_restart = FALSE;
|
||
|
if (tt_ptr->mupintr)
|
||
|
{ /* restore state to before job interrupt */
|
||
|
tt_state = &tt_ptr->tt_state_save;
|
||
|
if (ttwhichinvalid == tt_state->who_saved)
|
||
|
GTMASSERT;
|
||
|
if (dollar_zininterrupt)
|
||
|
{
|
||
|
tt_ptr->mupintr = FALSE;
|
||
|
tt_state->who_saved = ttwhichinvalid;
|
||
|
rts_error(VARLSTCNT(1) ERR_ZINTRECURSEIO);
|
||
|
}
|
||
|
assert(length == tt_state->length);
|
||
|
if (ttread != tt_state->who_saved)
|
||
|
GTMASSERT; /* ZINTRECURSEIO should have caught */
|
||
|
mv_zintdev = io_find_mvstent(io_ptr, FALSE);
|
||
|
if (NULL != mv_zintdev && mv_zintdev->mv_st_cont.mvs_zintdev.buffer_valid)
|
||
|
{ /* looks good so use it */
|
||
|
buffer_start = (unsigned char *)mv_zintdev->mv_st_cont.mvs_zintdev.curr_sp_buffer.addr;
|
||
|
current_ptr = buffer_start;
|
||
|
mv_zintdev->mv_st_cont.mvs_zintdev.buffer_valid = FALSE;
|
||
|
mv_zintdev->mv_st_cont.mvs_zintdev.io_ptr = NULL;
|
||
|
if (mv_chain == mv_zintdev)
|
||
|
POP_MV_STENT(); /* pop if top of stack */
|
||
|
buffer_moved = (buffer_start != tt_state->buffer_start);
|
||
|
if (utf8_active)
|
||
|
{ /* need to properly align U32 buffer */
|
||
|
assert(exp_length == tt_state->exp_length);
|
||
|
buffer_32_start = (wint_t *)ROUND_UP2((INTPTR_T)(buffer_start + (GTM_MB_LEN_MAX * length)),
|
||
|
SIZEOF(gtm_int64_t));
|
||
|
if (buffer_moved && (((unsigned char *)buffer_32_start - buffer_start)
|
||
|
!= ((unsigned char *)tt_state->buffer_32_start - tt_state->buffer_start)))
|
||
|
memmove(buffer_32_start, buffer_start + ((unsigned char *)tt_state->buffer_32_start
|
||
|
- tt_state->buffer_start), (SIZEOF(wint_t) * length));
|
||
|
current_32_ptr = buffer_32_start;
|
||
|
utf8_more = tt_state->utf8_more;
|
||
|
more_ptr = tt_state->more_ptr;
|
||
|
memcpy(more_buf, tt_state->more_buf, SIZEOF(more_buf));
|
||
|
}
|
||
|
instr = tt_state->instr;
|
||
|
outlen = tt_state->outlen;
|
||
|
dx = tt_state->dx;
|
||
|
dx_start = tt_state->dx_start;
|
||
|
dx_instr = tt_state->dx_instr;
|
||
|
dx_outlen = tt_state->dx_outlen;
|
||
|
insert_mode = tt_state->insert_mode;
|
||
|
end_time = tt_state->end_time;
|
||
|
zb_ptr = tt_state->zb_ptr;
|
||
|
zb_top = tt_state->zb_top;
|
||
|
tt_state->who_saved = ttwhichinvalid;
|
||
|
tt_ptr->mupintr = FALSE;
|
||
|
zint_restart = TRUE;
|
||
|
}
|
||
|
}
|
||
|
if (!zint_restart)
|
||
|
{
|
||
|
ENSURE_STP_FREE_SPACE(exp_length);
|
||
|
buffer_start = current_ptr = stringpool.free;
|
||
|
if (utf8_active)
|
||
|
{
|
||
|
buffer_32_start = (wint_t *)ROUND_UP2((INTPTR_T)(stringpool.free + (GTM_MB_LEN_MAX * length)),
|
||
|
SIZEOF(gtm_int64_t));
|
||
|
current_32_ptr = buffer_32_start;
|
||
|
}
|
||
|
instr = outlen = 0;
|
||
|
dx_instr = dx_outlen = 0;
|
||
|
utf8_more = 0;
|
||
|
/* ---------------------------------------------------------
|
||
|
* zb_ptr is used to fill-in the value of $zb as we go
|
||
|
* If we drop-out with error or otherwise permaturely,
|
||
|
* consider $zb to be null.
|
||
|
* ---------------------------------------------------------
|
||
|
*/
|
||
|
zb_ptr = io_ptr->dollar.zb;
|
||
|
zb_top = zb_ptr + SIZEOF(io_ptr->dollar.zb) - 1;
|
||
|
*zb_ptr = 0;
|
||
|
io_ptr->esc_state = START;
|
||
|
io_ptr->dollar.za = 0;
|
||
|
io_ptr->dollar.zeof = FALSE;
|
||
|
dx_start = (int)io_ptr->dollar.x;
|
||
|
}
|
||
|
v->str.len = 0;
|
||
|
ret = TRUE;
|
||
|
mask = tt_ptr->term_ctrl;
|
||
|
mask_term = tt_ptr->mask_term;
|
||
|
/* keep test in next line in sync with test in iott_rdone.c */
|
||
|
edit_mode = (0 != (TT_EDITING & tt_ptr->ext_cap) && !((TRM_NOECHO|TRM_PASTHRU) & mask));
|
||
|
if (!zint_restart)
|
||
|
{
|
||
|
if (mask & TRM_NOTYPEAHD)
|
||
|
TCFLUSH(tt_ptr->fildes, TCIFLUSH, status);
|
||
|
if (mask & TRM_READSYNC)
|
||
|
{
|
||
|
DOWRITERC(tt_ptr->fildes, &dc1, 1, status);
|
||
|
if (0 != status)
|
||
|
{
|
||
|
io_ptr->dollar.za = 9;
|
||
|
rts_error(VARLSTCNT(1) status);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (edit_mode)
|
||
|
{ /* remove ESC and editing control characters from terminator list */
|
||
|
mask_term.mask[ESC / NUM_BITS_IN_INT4] &= ~(1 << ESC);
|
||
|
mask_term.mask[EDIT_SOL / NUM_BITS_IN_INT4] &= ~(1 << EDIT_SOL);
|
||
|
mask_term.mask[EDIT_EOL / NUM_BITS_IN_INT4] &= ~(1 << EDIT_EOL);
|
||
|
mask_term.mask[EDIT_DEOL / NUM_BITS_IN_INT4] &= ~(1 << EDIT_DEOL);
|
||
|
mask_term.mask[EDIT_DELETE / NUM_BITS_IN_INT4] &= ~(1 << EDIT_DELETE);
|
||
|
mask_term.mask[EDIT_LEFT / NUM_BITS_IN_INT4] &= ~(1 << EDIT_LEFT);
|
||
|
mask_term.mask[EDIT_RIGHT / NUM_BITS_IN_INT4] &= ~(1 << EDIT_RIGHT);
|
||
|
mask_term.mask[EDIT_ERASE / NUM_BITS_IN_INT4] &= ~(1 << EDIT_ERASE);
|
||
|
if (!zint_restart)
|
||
|
{
|
||
|
/* to turn keypad on if possible */
|
||
|
#ifndef __MVS__
|
||
|
if (NULL != KEYPAD_XMIT && (keypad_len = STRLEN(KEYPAD_XMIT))) /* embedded assignment */
|
||
|
{
|
||
|
DOWRITERC(tt_ptr->fildes, KEYPAD_XMIT, keypad_len, status);
|
||
|
if (0 != status)
|
||
|
{
|
||
|
io_ptr->dollar.za = 9;
|
||
|
rts_error(VARLSTCNT(1) status);
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
dx_start = (dx_start + ioptr_width) % ioptr_width; /* normalize within width */
|
||
|
}
|
||
|
}
|
||
|
if (!zint_restart)
|
||
|
dx = dx_start;
|
||
|
nonzerotimeout = FALSE;
|
||
|
if (NO_M_TIMEOUT == timeout)
|
||
|
{
|
||
|
timed = FALSE;
|
||
|
input_timeval.tv_sec = 100;
|
||
|
msec_timeout = NO_M_TIMEOUT;
|
||
|
} else
|
||
|
{
|
||
|
timed = TRUE;
|
||
|
input_timeval.tv_sec = timeout;
|
||
|
msec_timeout = timeout2msec(timeout);
|
||
|
if (!msec_timeout)
|
||
|
{
|
||
|
if (!zint_restart)
|
||
|
iott_mterm(io_ptr);
|
||
|
} else
|
||
|
{
|
||
|
nonzerotimeout = TRUE;
|
||
|
sys_get_curr_time(&cur_time);
|
||
|
if (!zint_restart)
|
||
|
add_int_to_abs_time(&cur_time, msec_timeout, &end_time);
|
||
|
}
|
||
|
}
|
||
|
input_timeval.tv_usec = 0;
|
||
|
do
|
||
|
{
|
||
|
if (outofband)
|
||
|
{
|
||
|
if (jobinterrupt == outofband)
|
||
|
{ /* save state if jobinterrupt */
|
||
|
tt_state = &tt_ptr->tt_state_save;
|
||
|
tt_state->who_saved = ttread;
|
||
|
tt_state->length = length;
|
||
|
tt_state->buffer_start = buffer_start;
|
||
|
PUSH_MV_STENT(MVST_ZINTDEV);
|
||
|
mv_chain->mv_st_cont.mvs_zintdev.curr_sp_buffer.addr = (char *)buffer_start;
|
||
|
mv_chain->mv_st_cont.mvs_zintdev.curr_sp_buffer.len = exp_length;
|
||
|
mv_chain->mv_st_cont.mvs_zintdev.buffer_valid = TRUE;
|
||
|
mv_chain->mv_st_cont.mvs_zintdev.io_ptr = io_ptr;
|
||
|
if (utf8_active)
|
||
|
{
|
||
|
tt_state->exp_length = exp_length;
|
||
|
tt_state->buffer_32_start = buffer_32_start;
|
||
|
tt_state->utf8_more = utf8_more;
|
||
|
tt_state->more_ptr = more_ptr;
|
||
|
memcpy(tt_state->more_buf, more_buf, SIZEOF(more_buf));
|
||
|
}
|
||
|
if (buffer_start == stringpool.free)
|
||
|
stringpool.free += exp_length; /* reserve space */
|
||
|
tt_state->instr = instr;
|
||
|
tt_state->outlen = outlen;
|
||
|
tt_state->dx = dx;
|
||
|
tt_state->dx_start = dx_start;
|
||
|
tt_state->dx_instr = dx_instr;
|
||
|
tt_state->dx_outlen = dx_outlen;
|
||
|
tt_state->insert_mode = insert_mode;
|
||
|
tt_state->end_time = end_time;
|
||
|
tt_state->zb_ptr = zb_ptr;
|
||
|
tt_state->zb_top = zb_top;
|
||
|
tt_ptr->mupintr = TRUE;
|
||
|
} else
|
||
|
{
|
||
|
instr = outlen = 0;
|
||
|
SEND_KEYPAD_LOCAL
|
||
|
if (!msec_timeout)
|
||
|
iott_rterm(io_ptr);
|
||
|
}
|
||
|
outofband_action(FALSE);
|
||
|
break;
|
||
|
}
|
||
|
errno = 0;
|
||
|
FD_ZERO(&input_fd);
|
||
|
FD_SET(tt_ptr->fildes, &input_fd);
|
||
|
assert(0 != FD_ISSET(tt_ptr->fildes, &input_fd));
|
||
|
/* the checks for EINTR below are valid and should not be converted to EINTR
|
||
|
* wrapper macros, since the select/read is not retried on EINTR.
|
||
|
*/
|
||
|
save_input_timeval = input_timeval; /* take a copy and pass it because select() below might change it */
|
||
|
selstat = select(tt_ptr->fildes + 1, (void *)&input_fd, (void *)NULL, (void *)NULL, &save_input_timeval);
|
||
|
if (selstat < 0)
|
||
|
{
|
||
|
if (EINTR != errno)
|
||
|
{
|
||
|
term_error_line = __LINE__;
|
||
|
goto term_error;
|
||
|
}
|
||
|
} else if (0 == selstat)
|
||
|
{
|
||
|
if (timed)
|
||
|
{
|
||
|
ret = FALSE;
|
||
|
break;
|
||
|
}
|
||
|
continue; /* select() timeout; keep going */
|
||
|
} else if (0 < (rdlen = (int)(read(tt_ptr->fildes, &inbyte, 1)))) /* This read is protected */
|
||
|
{
|
||
|
assert(0 != FD_ISSET(tt_ptr->fildes, &input_fd));
|
||
|
/* --------------------------------------------------
|
||
|
* set prin_in_dev_failure to FALSE to indicate that
|
||
|
* input device is working now.
|
||
|
* --------------------------------------------------
|
||
|
*/
|
||
|
prin_in_dev_failure = FALSE;
|
||
|
if (tt_ptr->canonical)
|
||
|
{
|
||
|
if (0 == inbyte)
|
||
|
{
|
||
|
/* --------------------------------------
|
||
|
* This means that the device has hungup
|
||
|
* --------------------------------------
|
||
|
*/
|
||
|
io_ptr->dollar.zeof = TRUE;
|
||
|
io_ptr->dollar.x = 0;
|
||
|
io_ptr->dollar.za = 9;
|
||
|
io_ptr->dollar.y++;
|
||
|
tt_ptr->discard_lf = FALSE;
|
||
|
if (io_ptr->error_handler.len > 0)
|
||
|
rts_error(VARLSTCNT(1) ERR_IOEOF);
|
||
|
break;
|
||
|
} else
|
||
|
io_ptr->dollar.zeof = FALSE;
|
||
|
}
|
||
|
#ifdef UNICODE_SUPPORTED
|
||
|
if (utf8_active)
|
||
|
{
|
||
|
if (tt_ptr->discard_lf)
|
||
|
{ /* saw CR last time so ignore following LF */
|
||
|
tt_ptr->discard_lf = FALSE;
|
||
|
if (NATIVE_LF == inbyte)
|
||
|
continue;
|
||
|
}
|
||
|
if (utf8_more)
|
||
|
{ /* needed extra bytes */
|
||
|
*more_ptr++ = inbyte;
|
||
|
if (--utf8_more)
|
||
|
continue; /* get next byte */
|
||
|
UTF8_MBTOWC(more_buf, more_ptr, inchar);
|
||
|
if (WEOF == inchar)
|
||
|
{ /* invalid char */
|
||
|
io_ptr->dollar.za = 9;
|
||
|
iott_readfl_badchar(v, buffer_32_start, outlen,
|
||
|
(int)(more_ptr - more_buf), more_buf, more_ptr, buffer_start);
|
||
|
utf8_badchar((int)(more_ptr - more_buf), more_buf, more_ptr, 0, NULL); /* BADCHAR */
|
||
|
break;
|
||
|
}
|
||
|
} else if (0 < (utf8_more = UTF8_MBFOLLOW(&inbyte))) /* assignment */
|
||
|
{
|
||
|
more_ptr = more_buf;
|
||
|
if (0 > utf8_more)
|
||
|
{ /* invalid character */
|
||
|
io_ptr->dollar.za = 9;
|
||
|
*more_ptr++ = inbyte;
|
||
|
iott_readfl_badchar(v, buffer_32_start, outlen,
|
||
|
1, more_buf, more_ptr, buffer_start);
|
||
|
utf8_badchar(1, more_buf, more_ptr, 0, NULL); /* ERR_BADCHAR */
|
||
|
break;
|
||
|
} else if (GTM_MB_LEN_MAX < utf8_more)
|
||
|
{ /* too big to be valid */
|
||
|
io_ptr->dollar.za = 9;
|
||
|
*more_ptr++ = inbyte;
|
||
|
iott_readfl_badchar(v, buffer_32_start, outlen,
|
||
|
1, more_buf, more_ptr, buffer_start);
|
||
|
utf8_badchar(1, more_buf, more_ptr, 0, NULL); /* ERR_BADCHAR */
|
||
|
break;
|
||
|
} else
|
||
|
{
|
||
|
*more_ptr++ = inbyte;
|
||
|
continue; /* get next byte */
|
||
|
}
|
||
|
} else
|
||
|
{ /* single byte */
|
||
|
more_ptr = more_buf;
|
||
|
*more_ptr++ = inbyte;
|
||
|
UTF8_MBTOWC(more_buf, more_ptr, inchar);
|
||
|
if (WEOF == inchar)
|
||
|
{ /* invalid char */
|
||
|
io_ptr->dollar.za = 9;
|
||
|
iott_readfl_badchar(v, buffer_32_start, outlen,
|
||
|
1, more_buf, more_ptr, buffer_start);
|
||
|
utf8_badchar(1, more_buf, more_ptr, 0, NULL); /* ERR_BADCHAR */
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (!tt_ptr->done_1st_read)
|
||
|
{
|
||
|
tt_ptr->done_1st_read = TRUE;
|
||
|
if (BOM_CODEPOINT == inchar)
|
||
|
continue;
|
||
|
}
|
||
|
if (mask & TRM_CONVERT)
|
||
|
inchar = u_toupper(inchar);
|
||
|
GTM_IO_WCWIDTH(inchar, inchar_width);
|
||
|
} else
|
||
|
{
|
||
|
#endif
|
||
|
if (mask & TRM_CONVERT)
|
||
|
NATIVE_CVT2UPPER(inbyte, inbyte);
|
||
|
inchar = inbyte;
|
||
|
inchar_width = 1;
|
||
|
#ifdef UNICODE_SUPPORTED
|
||
|
}
|
||
|
#endif
|
||
|
GETASCII(asc_inchar,inchar);
|
||
|
if (!edit_mode && (dx >= ioptr_width) && io_ptr->wrap && !(mask & TRM_NOECHO))
|
||
|
{
|
||
|
DOWRITE(tt_ptr->fildes, NATIVE_TTEOL, strlen(NATIVE_TTEOL));
|
||
|
dx = 0;
|
||
|
}
|
||
|
if ((' ' > INPUT_CHAR) && (tt_ptr->enbld_outofbands.mask & (1 << INPUT_CHAR)))
|
||
|
{ /* ctrap supercedes editing so check first */
|
||
|
instr = outlen = 0;
|
||
|
io_ptr->dollar.za = 9;
|
||
|
std_dev_outbndset(INPUT_CHAR); /* it needs ASCII? */
|
||
|
SEND_KEYPAD_LOCAL
|
||
|
if (!msec_timeout)
|
||
|
iott_rterm(io_ptr);
|
||
|
rts_error(VARLSTCNT(3) ERR_CTRAP, 1, ctrap_action_is);
|
||
|
break;
|
||
|
}
|
||
|
if (((0 != (mask & TRM_ESCAPE)) || edit_mode)
|
||
|
&& ((NATIVE_ESC == inchar) || (START != io_ptr->esc_state)))
|
||
|
{
|
||
|
if (zb_ptr >= zb_top UNICODE_ONLY(|| (utf8_active && ASCII_MAX < inchar)))
|
||
|
{ /* $zb overflow or not ASCII in utf8 mode */
|
||
|
io_ptr->dollar.za = 2;
|
||
|
break;
|
||
|
}
|
||
|
*zb_ptr++ = (unsigned char)inchar;
|
||
|
iott_escape(zb_ptr - 1, zb_ptr, io_ptr);
|
||
|
*(zb_ptr - 1) = (unsigned char)INPUT_CHAR; /* need to store ASCII value */
|
||
|
if (FINI == io_ptr->esc_state && !edit_mode)
|
||
|
break;
|
||
|
if (BADESC == io_ptr->esc_state)
|
||
|
{ /* Escape sequence failed parse */
|
||
|
io_ptr->dollar.za = 2;
|
||
|
break;
|
||
|
}
|
||
|
/* --------------------------------------------------------------------
|
||
|
* In escape sequence...do not process further, but get next character
|
||
|
* --------------------------------------------------------------------
|
||
|
*/
|
||
|
} else
|
||
|
{ /* SIMPLIFY THIS! */
|
||
|
if (!utf8_active || ASCII_MAX >= INPUT_CHAR)
|
||
|
{ /* may need changes to allow terminator > MAX_ASCII and/or LS and PS if default_mask_term */
|
||
|
msk_num = (uint4)INPUT_CHAR / NUM_BITS_IN_INT4;
|
||
|
msk_in = (1 << ((uint4)INPUT_CHAR % NUM_BITS_IN_INT4));
|
||
|
if (msk_in & mask_term.mask[msk_num])
|
||
|
{
|
||
|
*zb_ptr++ = (unsigned char)INPUT_CHAR;
|
||
|
if (utf8_active && ASCII_CR == INPUT_CHAR)
|
||
|
tt_ptr->discard_lf = TRUE;
|
||
|
break;
|
||
|
}
|
||
|
} else if (utf8_active && tt_ptr->default_mask_term && (u32_line_term[U32_LT_NL] == INPUT_CHAR ||
|
||
|
u32_line_term[U32_LT_LS] == INPUT_CHAR || u32_line_term[U32_LT_PS] == INPUT_CHAR))
|
||
|
{ /* UTF and default terminators and Unicode terminators above ASCII_MAX */
|
||
|
zb_ptr = UTF8_WCTOMB(INPUT_CHAR, zb_ptr);
|
||
|
break;
|
||
|
}
|
||
|
assert(0 <= instr);
|
||
|
assert(!edit_mode || 0 <= dx);
|
||
|
assert(outlen >= instr);
|
||
|
if ((int)inchar == tt_ptr->ttio_struct->c_cc[VERASE]
|
||
|
&& !(mask & TRM_PASTHRU))
|
||
|
{
|
||
|
if (0 < instr && (edit_mode || 0 < dx))
|
||
|
{
|
||
|
dx_prev = compute_dx(BUFF_ADDR(0), instr - 1, ioptr_width, dx_start);
|
||
|
delchar_width = dx_instr - dx_prev;
|
||
|
if (edit_mode)
|
||
|
{
|
||
|
if (!(mask & TRM_NOECHO))
|
||
|
move_cursor_left(dx, delchar_width);
|
||
|
dx = (dx - delchar_width + ioptr_width) % ioptr_width;
|
||
|
} else
|
||
|
dx -= delchar_width;
|
||
|
instr--;
|
||
|
dx_instr -= delchar_width;
|
||
|
STORE_OFF(' ', outlen);
|
||
|
outlen--;
|
||
|
if (!(mask & TRM_NOECHO) && edit_mode)
|
||
|
{
|
||
|
IOTT_COMBINED_CHAR_CHECK;
|
||
|
}
|
||
|
MOVE_BUFF(instr, BUFF_ADDR(instr + 1), outlen - instr);
|
||
|
if (!(mask & TRM_NOECHO))
|
||
|
{
|
||
|
if (!edit_mode)
|
||
|
{
|
||
|
for (i = 0; i < delchar_width; i++)
|
||
|
{
|
||
|
DOWRITERC(tt_ptr->fildes, eraser,
|
||
|
SIZEOF(eraser), status)
|
||
|
if (0 != status)
|
||
|
break;
|
||
|
}
|
||
|
} else
|
||
|
{ /* First write spaces on all the display columns that
|
||
|
* the current string occupied. Then overwrite that
|
||
|
* with the new string. This way we are guaranteed all
|
||
|
* display columns are clean.
|
||
|
*/
|
||
|
status = write_str_spaces(dx_outlen - dx_instr, dx, FALSE);
|
||
|
if (0 == status)
|
||
|
status = write_str(BUFF_ADDR(instr),
|
||
|
outlen - instr, dx, FALSE, FALSE);
|
||
|
}
|
||
|
if (0 != status)
|
||
|
{
|
||
|
term_error_line = __LINE__;
|
||
|
goto term_error;
|
||
|
}
|
||
|
}
|
||
|
dx_outlen = compute_dx(BUFF_ADDR(0), outlen, ioptr_width, dx_start);
|
||
|
}
|
||
|
} else
|
||
|
{
|
||
|
if (!edit_mode)
|
||
|
switch_char = 'A'; /* force to default case */
|
||
|
else
|
||
|
switch_char = inchar;
|
||
|
switch (switch_char)
|
||
|
{
|
||
|
case EDIT_SOL: /* ctrl A start of line */
|
||
|
{
|
||
|
int num_lines_above;
|
||
|
int num_chars_left;
|
||
|
|
||
|
num_lines_above = (dx_instr + dx_start) /
|
||
|
ioptr_width;
|
||
|
num_chars_left = dx - dx_start;
|
||
|
if (!(mask & TRM_NOECHO))
|
||
|
{
|
||
|
if (0 != move_cursor(tt_ptr->fildes, num_lines_above,
|
||
|
num_chars_left))
|
||
|
{
|
||
|
term_error_line = __LINE__;
|
||
|
goto term_error;
|
||
|
}
|
||
|
}
|
||
|
instr = dx_instr = 0;
|
||
|
dx = dx_start;
|
||
|
break;
|
||
|
}
|
||
|
case EDIT_EOL: /* ctrl E end of line */
|
||
|
{
|
||
|
int num_lines_above;
|
||
|
int num_chars_left;
|
||
|
|
||
|
num_lines_above =
|
||
|
(dx_instr + dx_start) / ioptr_width -
|
||
|
(dx_outlen + dx_start) / ioptr_width;
|
||
|
/* For some reason, a CURSOR_DOWN ("\n") seems to reposition the cursor
|
||
|
* at the beginning of the next line rather than maintain the vertical
|
||
|
* position. Therefore if we are moving down, we need to calculate
|
||
|
* the num_chars_left differently to accommodate this.
|
||
|
*/
|
||
|
if (0 <= num_lines_above)
|
||
|
num_chars_left = dx - (dx_outlen + dx_start) % ioptr_width;
|
||
|
else
|
||
|
num_chars_left = - ((dx_outlen + dx_start) % ioptr_width);
|
||
|
if (!(mask & TRM_NOECHO))
|
||
|
{
|
||
|
if (0 != move_cursor(tt_ptr->fildes, num_lines_above,
|
||
|
num_chars_left))
|
||
|
{
|
||
|
term_error_line = __LINE__;
|
||
|
goto term_error;
|
||
|
}
|
||
|
}
|
||
|
instr = outlen;
|
||
|
dx_instr = dx_outlen;
|
||
|
dx = (dx_outlen + dx_start) % ioptr_width;
|
||
|
break;
|
||
|
}
|
||
|
case EDIT_LEFT: /* ctrl B left one */
|
||
|
{
|
||
|
if (instr != 0)
|
||
|
{
|
||
|
dx_prev = compute_dx(BUFF_ADDR(0), instr - 1,
|
||
|
ioptr_width, dx_start);
|
||
|
inchar_width = dx_instr - dx_prev;
|
||
|
if (!(mask & TRM_NOECHO))
|
||
|
{
|
||
|
if (0 != move_cursor_left(dx, inchar_width))
|
||
|
{
|
||
|
term_error_line = __LINE__;
|
||
|
goto term_error;
|
||
|
}
|
||
|
}
|
||
|
instr--;
|
||
|
dx = (dx - inchar_width + ioptr_width) % ioptr_width;
|
||
|
dx_instr -= inchar_width;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
case EDIT_RIGHT: /* ctrl F right one */
|
||
|
{
|
||
|
if (instr < outlen)
|
||
|
{
|
||
|
dx_next = compute_dx(BUFF_ADDR(0), instr + 1,
|
||
|
ioptr_width, dx_start);
|
||
|
inchar_width = dx_next - dx_instr;
|
||
|
if (!(mask & TRM_NOECHO))
|
||
|
{
|
||
|
if (0 != move_cursor_right(dx, inchar_width))
|
||
|
{
|
||
|
term_error_line = __LINE__;
|
||
|
goto term_error;
|
||
|
}
|
||
|
}
|
||
|
instr++;
|
||
|
dx = (dx + inchar_width) % ioptr_width;
|
||
|
dx_instr += inchar_width;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
case EDIT_DEOL: /* ctrl K delete to end of line */
|
||
|
{
|
||
|
if (!(mask & TRM_NOECHO))
|
||
|
{
|
||
|
if (0 != write_str_spaces(dx_outlen - dx_instr, dx, FALSE))
|
||
|
{
|
||
|
term_error_line = __LINE__;
|
||
|
goto term_error;
|
||
|
}
|
||
|
}
|
||
|
SET_BUFF(instr, ' ', outlen - instr);
|
||
|
outlen = instr;
|
||
|
dx_outlen = dx_instr;
|
||
|
break;
|
||
|
}
|
||
|
case EDIT_ERASE: /* ctrl U delete whole line */
|
||
|
{
|
||
|
int num_lines_above;
|
||
|
int num_chars_left;
|
||
|
|
||
|
num_lines_above = (dx_instr + dx_start) /
|
||
|
ioptr_width;
|
||
|
num_chars_left = dx - dx_start;
|
||
|
SET_BUFF(0, ' ', outlen);
|
||
|
if (!(mask & TRM_NOECHO))
|
||
|
{
|
||
|
status = move_cursor(tt_ptr->fildes,
|
||
|
num_lines_above, num_chars_left);
|
||
|
if (0 != status
|
||
|
|| 0 != write_str_spaces(dx_outlen, dx_start, FALSE))
|
||
|
{
|
||
|
term_error_line = __LINE__;
|
||
|
goto term_error;
|
||
|
}
|
||
|
}
|
||
|
instr = 0;
|
||
|
outlen = 0;
|
||
|
dx = dx_start;
|
||
|
dx_instr = dx_outlen = 0;
|
||
|
break;
|
||
|
}
|
||
|
case EDIT_DELETE: /* ctrl D delete char */
|
||
|
{
|
||
|
if (instr < outlen)
|
||
|
{
|
||
|
STORE_OFF(' ', outlen);
|
||
|
outlen--;
|
||
|
if (!(mask & TRM_NOECHO))
|
||
|
{
|
||
|
IOTT_COMBINED_CHAR_CHECK;
|
||
|
}
|
||
|
MOVE_BUFF(instr, BUFF_ADDR(instr + 1), outlen - instr);
|
||
|
if (!(mask & TRM_NOECHO))
|
||
|
{ /* First write spaces on all the display columns that
|
||
|
* the current string occupied. Then overwrite that
|
||
|
* with the new string. This way we are guaranteed all
|
||
|
* display columns are clean.
|
||
|
*/
|
||
|
if (0 != write_str_spaces(dx_outlen - dx_instr, dx, FALSE))
|
||
|
{
|
||
|
term_error_line = __LINE__;
|
||
|
goto term_error;
|
||
|
}
|
||
|
if (0 != write_str(BUFF_ADDR(instr), outlen - instr,
|
||
|
dx, FALSE, FALSE))
|
||
|
{
|
||
|
term_error_line = __LINE__;
|
||
|
goto term_error;
|
||
|
}
|
||
|
}
|
||
|
dx_outlen = compute_dx(BUFF_ADDR(0), outlen,
|
||
|
ioptr_width, dx_start);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
default:
|
||
|
{
|
||
|
if (outlen > instr)
|
||
|
{
|
||
|
if (insert_mode)
|
||
|
MOVE_BUFF(instr + 1, BUFF_ADDR(instr), outlen - instr)
|
||
|
else if (edit_mode && !insert_mode)
|
||
|
{ /* only needed if edit && !insert_mode && not at end */
|
||
|
GTM_IO_WCWIDTH(GET_OFF(instr), delchar_width);
|
||
|
delta_width = inchar_width - delchar_width;
|
||
|
}
|
||
|
}
|
||
|
STORE_OFF(inchar, instr);
|
||
|
if (!(mask & TRM_NOECHO))
|
||
|
{
|
||
|
if (!edit_mode)
|
||
|
{
|
||
|
term_error_line = __LINE__;
|
||
|
status = iott_write_raw(tt_ptr->fildes,
|
||
|
BUFF_ADDR(instr), 1);
|
||
|
if (0 <= status)
|
||
|
status = 0;
|
||
|
else
|
||
|
status = errno;
|
||
|
} else if (instr == outlen)
|
||
|
{
|
||
|
term_error_line = __LINE__;
|
||
|
status = write_str(BUFF_ADDR(instr), 1, dx, FALSE, FALSE);
|
||
|
} else
|
||
|
{ /* First write spaces on all the display columns that the
|
||
|
* current string occupied. Then overwrite that with the
|
||
|
* new string. This way we are guaranteed all display
|
||
|
* columns are clean. Note that this space overwrite is
|
||
|
* needed even in case of insert mode because due to
|
||
|
* differing wide-character alignments before and after
|
||
|
* the insert, it is possible that a column might be left
|
||
|
* empty in the post insert write of the new string even
|
||
|
* though it had something displayed before.
|
||
|
*/
|
||
|
term_error_line = __LINE__;
|
||
|
status = write_str_spaces(dx_outlen - dx_instr, dx, FALSE);
|
||
|
if (0 == status)
|
||
|
{
|
||
|
term_error_line = __LINE__;
|
||
|
status = write_str(BUFF_ADDR(instr),
|
||
|
outlen - instr + (insert_mode ? 1 : 0),
|
||
|
dx, FALSE, FALSE);
|
||
|
}
|
||
|
}
|
||
|
if (0 != status)
|
||
|
goto term_error;
|
||
|
}
|
||
|
if (insert_mode || instr == outlen)
|
||
|
outlen++;
|
||
|
instr++;
|
||
|
if (edit_mode)
|
||
|
{ /* Compute value of dollarx at the new cursor position */
|
||
|
dx_cur = compute_dx(BUFF_ADDR(0), instr, ioptr_width, dx_start);
|
||
|
inchar_width = dx_cur - dx_instr;
|
||
|
if (!(mask & TRM_NOECHO))
|
||
|
{
|
||
|
term_error_line = __LINE__;
|
||
|
status = move_cursor_right(dx, inchar_width);
|
||
|
if (0 != status)
|
||
|
goto term_error;
|
||
|
}
|
||
|
}
|
||
|
if (!edit_mode)
|
||
|
{
|
||
|
dx += inchar_width;
|
||
|
dx_instr += inchar_width;
|
||
|
dx_outlen += inchar_width;
|
||
|
} else if (insert_mode || instr >= outlen)
|
||
|
{ /* at end or insert */
|
||
|
dx = (dx + inchar_width) % ioptr_width;
|
||
|
dx_instr = dx_cur;
|
||
|
dx_outlen = compute_dx(BUFF_ADDR(0), outlen,
|
||
|
ioptr_width, dx_start);
|
||
|
} else
|
||
|
{ /* replaced character */
|
||
|
dx = (dx + inchar_width) % ioptr_width;
|
||
|
dx_instr = dx_cur;
|
||
|
dx_outlen = compute_dx(BUFF_ADDR(0), outlen,
|
||
|
ioptr_width, dx_start);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
/* Ensure that the actual display position of the current character matches the computed value */
|
||
|
assert(!edit_mode || dx_instr == compute_dx(BUFF_ADDR(0), instr, ioptr_width, dx_start));
|
||
|
assert(!edit_mode || dx_outlen == compute_dx(BUFF_ADDR(0), outlen, ioptr_width, dx_start));
|
||
|
} else if (0 == rdlen)
|
||
|
{
|
||
|
if (0 < selstat)
|
||
|
{ /* this should be the only possibility */
|
||
|
io_ptr->dollar.zeof = TRUE;
|
||
|
io_ptr->dollar.x = 0;
|
||
|
io_ptr->dollar.za = 0;
|
||
|
io_ptr->dollar.y++;
|
||
|
if (io_curr_device.in == io_std_device.in)
|
||
|
{
|
||
|
if (!prin_in_dev_failure)
|
||
|
prin_in_dev_failure = TRUE;
|
||
|
else
|
||
|
{
|
||
|
send_msg(VARLSTCNT(1) ERR_NOPRINCIO);
|
||
|
stop_image_no_core();
|
||
|
}
|
||
|
}
|
||
|
if (io_ptr->dollar.zeof)
|
||
|
{
|
||
|
io_ptr->dollar.za = 9;
|
||
|
SEND_KEYPAD_LOCAL
|
||
|
rts_error(VARLSTCNT(1) ERR_IOEOF);
|
||
|
} else
|
||
|
{
|
||
|
io_ptr->dollar.zeof = TRUE;
|
||
|
io_ptr->dollar.za = 0;
|
||
|
SEND_KEYPAD_LOCAL
|
||
|
if (0 < io_ptr->error_handler.len)
|
||
|
rts_error(VARLSTCNT(1) ERR_IOEOF);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
if (0 == errno)
|
||
|
{ /* eof */
|
||
|
io_ptr->dollar.zeof = TRUE;
|
||
|
io_ptr->dollar.x = 0;
|
||
|
io_ptr->dollar.za = 0;
|
||
|
io_ptr->dollar.y++;
|
||
|
SEND_KEYPAD_LOCAL
|
||
|
if (0 < io_ptr->error_handler.len)
|
||
|
rts_error(VARLSTCNT(1) ERR_IOEOF);
|
||
|
break;
|
||
|
}
|
||
|
} else if (EINTR != errno) /* rdlen < 0 */
|
||
|
{
|
||
|
term_error_line = __LINE__;
|
||
|
goto term_error;
|
||
|
}
|
||
|
if (FINI == io_ptr->esc_state)
|
||
|
{
|
||
|
int zb_len = (int)(zb_ptr - io_ptr->dollar.zb);
|
||
|
|
||
|
escape_edit = FALSE;
|
||
|
down = strncmp((const char *)io_ptr->dollar.zb, KEY_DOWN, zb_len);
|
||
|
up = strncmp((const char *)io_ptr->dollar.zb, KEY_UP, zb_len);
|
||
|
right = strncmp((const char *)io_ptr->dollar.zb, KEY_RIGHT, zb_len);
|
||
|
left = strncmp((const char *)io_ptr->dollar.zb, KEY_LEFT, zb_len);
|
||
|
backspace = delete = insert_key = -1;
|
||
|
|
||
|
if (KEY_BACKSPACE != NULL)
|
||
|
backspace = strncmp((const char *)io_ptr->dollar.zb, KEY_BACKSPACE, zb_len);
|
||
|
if (KEY_DC != NULL)
|
||
|
delete = strncmp((const char *)io_ptr->dollar.zb, KEY_DC, zb_len);
|
||
|
if (KEY_INSERT != NULL && '\0' != KEY_INSERT[0])
|
||
|
insert_key = strncmp((const char *)io_ptr->dollar.zb, KEY_INSERT, zb_len);
|
||
|
|
||
|
if (backspace == 0 || delete == 0)
|
||
|
{
|
||
|
if (instr > 0)
|
||
|
{
|
||
|
dx_prev = compute_dx(BUFF_ADDR(0), instr - 1, ioptr_width, dx_start);
|
||
|
delchar_width = dx_instr - dx_prev;
|
||
|
if (!(mask & TRM_NOECHO))
|
||
|
{
|
||
|
term_error_line = __LINE__;
|
||
|
status = move_cursor_left(dx, delchar_width);
|
||
|
}
|
||
|
dx = (dx - delchar_width + ioptr_width) % ioptr_width;
|
||
|
instr--;
|
||
|
dx_instr -= delchar_width;
|
||
|
STORE_OFF(' ', outlen);
|
||
|
outlen--;
|
||
|
if (!(mask & TRM_NOECHO))
|
||
|
{
|
||
|
IOTT_COMBINED_CHAR_CHECK;
|
||
|
}
|
||
|
MOVE_BUFF(instr, BUFF_ADDR(instr + 1), outlen - instr);
|
||
|
if (!(mask & TRM_NOECHO))
|
||
|
{ /* First write spaces on all the display columns that the current string occupied.
|
||
|
* Then overwrite that with the new string. This way we are guaranteed all
|
||
|
* display columns are clean.
|
||
|
*/
|
||
|
if (0 == status)
|
||
|
{
|
||
|
term_error_line = __LINE__;
|
||
|
status = write_str_spaces(dx_outlen - dx_instr, dx, FALSE);
|
||
|
}
|
||
|
if (0 == status)
|
||
|
{
|
||
|
term_error_line = __LINE__;
|
||
|
status = write_str(BUFF_ADDR(instr), outlen - instr, dx, FALSE, FALSE);
|
||
|
}
|
||
|
if (0 != status)
|
||
|
goto term_error;
|
||
|
}
|
||
|
dx_outlen = compute_dx(BUFF_ADDR(0), outlen, ioptr_width, dx_start);
|
||
|
}
|
||
|
escape_edit = TRUE;
|
||
|
}
|
||
|
if (up == 0 || down == 0)
|
||
|
{ /* move cursor to start of field */
|
||
|
if (0 < instr)
|
||
|
{
|
||
|
if (0 != move_cursor(tt_ptr->fildes, ((dx_instr + dx_start) / ioptr_width),
|
||
|
(dx - dx_start)))
|
||
|
{
|
||
|
term_error_line = __LINE__;
|
||
|
goto term_error;
|
||
|
}
|
||
|
}
|
||
|
instr = (int)tt_ptr->recall_buff.len;
|
||
|
if (length < instr)
|
||
|
instr = length; /* restrict to length of read */
|
||
|
if (0 != instr)
|
||
|
{ /* need to blank old output first */
|
||
|
SET_BUFF(instr, ' ', outlen);
|
||
|
if (0 != write_str_spaces(dx_outlen, dx_start, FALSE))
|
||
|
{
|
||
|
term_error_line = __LINE__;
|
||
|
goto term_error;
|
||
|
}
|
||
|
MOVE_BUFF(0, tt_ptr->recall_buff.addr, instr);
|
||
|
if (0 != write_str(BUFF_ADDR(0), instr, dx_start, TRUE, FALSE))
|
||
|
{
|
||
|
term_error_line = __LINE__;
|
||
|
goto term_error;
|
||
|
}
|
||
|
}
|
||
|
dx_instr = dx_outlen = tt_ptr->recall_width;
|
||
|
dx = (unsigned)(dx_instr + dx_start) % ioptr_width;
|
||
|
outlen = instr;
|
||
|
escape_edit = TRUE;
|
||
|
} else if ( !(mask & TRM_NOECHO)
|
||
|
&& !(right == 0 && instr == outlen)
|
||
|
&& !(left == 0 && instr == 0))
|
||
|
{
|
||
|
if (right == 0)
|
||
|
{
|
||
|
dx_next = compute_dx(BUFF_ADDR(0), instr + 1, ioptr_width, dx_start);
|
||
|
inchar_width = dx_next - dx_instr;
|
||
|
if (0 != move_cursor_right(dx, inchar_width))
|
||
|
{
|
||
|
term_error_line = __LINE__;
|
||
|
goto term_error;
|
||
|
}
|
||
|
instr++;
|
||
|
dx = (dx + inchar_width) % ioptr_width;
|
||
|
dx_instr += inchar_width;
|
||
|
}
|
||
|
if (left == 0)
|
||
|
{
|
||
|
dx_prev = compute_dx(BUFF_ADDR(0), instr - 1, ioptr_width, dx_start);
|
||
|
inchar_width = dx_instr - dx_prev;
|
||
|
if (0 != move_cursor_left(dx, inchar_width))
|
||
|
{
|
||
|
term_error_line = __LINE__;
|
||
|
goto term_error;
|
||
|
}
|
||
|
instr--;
|
||
|
dx = (dx - inchar_width + ioptr_width) % ioptr_width;
|
||
|
dx_instr -= inchar_width;
|
||
|
}
|
||
|
}
|
||
|
if (0 == insert_key)
|
||
|
insert_mode = !insert_mode; /* toggle */
|
||
|
if (0 == right || 0 == left || 0 == insert_key)
|
||
|
escape_edit = TRUE;
|
||
|
if (escape_edit || (0 == (TRM_ESCAPE & mask)))
|
||
|
{ /* reset dollar zb if editing function or not trm_escape */
|
||
|
memset(io_ptr->dollar.zb, '\0', SIZEOF(io_ptr->dollar.zb));
|
||
|
io_ptr->esc_state = START;
|
||
|
zb_ptr = io_ptr->dollar.zb;
|
||
|
zb_top = zb_ptr + SIZEOF(io_ptr->dollar.zb) - 1;
|
||
|
} else
|
||
|
break; /* not edit function and TRM_ESCAPE */
|
||
|
}
|
||
|
if (nonzerotimeout)
|
||
|
{
|
||
|
sys_get_curr_time(&cur_time);
|
||
|
cur_time = sub_abs_time(&end_time, &cur_time);
|
||
|
if (0 > cur_time.at_sec)
|
||
|
{
|
||
|
ret = FALSE;
|
||
|
break;
|
||
|
}
|
||
|
input_timeval.tv_sec = cur_time.at_sec;
|
||
|
input_timeval.tv_usec = (gtm_tv_usec_t)cur_time.at_usec;
|
||
|
}
|
||
|
} while (outlen < length);
|
||
|
*zb_ptr++ = 0;
|
||
|
if (!msec_timeout)
|
||
|
{
|
||
|
iott_rterm(io_ptr);
|
||
|
if (0 == outlen && ((io_ptr->dollar.zb + 1) == zb_ptr)) /* No input and no delimiter seen */
|
||
|
ret = FALSE;
|
||
|
}
|
||
|
if (mask & TRM_READSYNC)
|
||
|
{
|
||
|
DOWRITERC(tt_ptr->fildes, &dc3, 1, status);
|
||
|
if (0 != status)
|
||
|
{
|
||
|
io_ptr->dollar.za = 9;
|
||
|
rts_error(VARLSTCNT(1) status);
|
||
|
}
|
||
|
}
|
||
|
SEND_KEYPAD_LOCAL /* to turn keypad off if possible */
|
||
|
if (outofband && jobinterrupt != outofband)
|
||
|
{
|
||
|
v->str.len = 0;
|
||
|
io_ptr->dollar.za = 9;
|
||
|
return(FALSE);
|
||
|
}
|
||
|
#ifdef UNICODE_SUPPORTED
|
||
|
if (utf8_active)
|
||
|
{
|
||
|
outptr = buffer_start;
|
||
|
outtop = ((unsigned char *)buffer_32_start);
|
||
|
current_32_ptr = buffer_32_start;
|
||
|
for (i = 0; i < outlen && outptr < outtop; i++, current_32_ptr++)
|
||
|
outptr = UTF8_WCTOMB(*current_32_ptr, outptr);
|
||
|
v->str.len = INTCAST(outptr - buffer_start);
|
||
|
} else
|
||
|
#endif
|
||
|
v->str.len = outlen;
|
||
|
v->str.addr = (char *)buffer_start;
|
||
|
if (edit_mode)
|
||
|
{ /* store in recall buffer */
|
||
|
if ((BUFF_CHAR_SIZE * outlen) > tt_ptr->recall_size)
|
||
|
{
|
||
|
if (tt_ptr->recall_buff.addr)
|
||
|
free(tt_ptr->recall_buff.addr);
|
||
|
tt_ptr->recall_size = (int)(BUFF_CHAR_SIZE * outlen);
|
||
|
tt_ptr->recall_buff.addr = malloc(tt_ptr->recall_size);
|
||
|
}
|
||
|
tt_ptr->recall_width = dx_outlen;
|
||
|
tt_ptr->recall_buff.len = outlen;
|
||
|
memcpy(tt_ptr->recall_buff.addr, BUFF_ADDR(0), BUFF_CHAR_SIZE * outlen);
|
||
|
}
|
||
|
if (!(mask & TRM_NOECHO))
|
||
|
{
|
||
|
if ((io_ptr->dollar.x += dx_outlen) >= ioptr_width && io_ptr->wrap)
|
||
|
{
|
||
|
io_ptr->dollar.y += (io_ptr->dollar.x / ioptr_width);
|
||
|
if (io_ptr->length)
|
||
|
io_ptr->dollar.y %= io_ptr->length;
|
||
|
io_ptr->dollar.x %= ioptr_width;
|
||
|
if (0 == io_ptr->dollar.x)
|
||
|
DOWRITE(tt_ptr->fildes, NATIVE_TTEOL, strlen(NATIVE_TTEOL));
|
||
|
}
|
||
|
}
|
||
|
return ((short)ret);
|
||
|
|
||
|
term_error:
|
||
|
save_errno = errno;
|
||
|
io_ptr->dollar.za = 9;
|
||
|
tt_ptr->discard_lf = FALSE;
|
||
|
SEND_KEYPAD_LOCAL /* to turn keypad off if possible */
|
||
|
if (!msec_timeout)
|
||
|
iott_rterm(io_ptr);
|
||
|
rts_error(VARLSTCNT(1) save_errno);
|
||
|
return FALSE;
|
||
|
}
|