#include <data.h>
#if OPT_WIDE_CHARS
#include <menu.h>
#endif
#if defined(EAGAIN) && defined(EWOULDBLOCK)
#define E_TEST(err) ((err) == EAGAIN || (err) == EWOULDBLOCK)
#else
#ifdef EAGAIN
#define E_TEST(err) ((err) == EAGAIN)
#else
#define E_TEST(err) ((err) == EWOULDBLOCK)
#endif
#endif
#if OPT_WIDE_CHARS
Bool
decodeUtf8(PtyData * data)
{
int i;
int length = data->last - data->next;
int utf_count = 0;
IChar utf_char = 0;
data->utf_size = 0;
for (i = 0; i < length; i++) {
unsigned c = data->next[i];
if (c < 0x80) {
if (utf_count > 0) {
data->utf_data = UCS_REPL;
data->utf_size = (i + 1);
} else {
data->utf_data = c;
data->utf_size = 1;
}
break;
} else if (c < 0xc0) {
if (utf_count < 1) {
data->utf_data = UCS_REPL;
data->utf_size = (i + 1);
break;
} else {
if (!utf_char && !((c & 0x7f) >> (7 - utf_count))) {
utf_char = UCS_REPL;
}
utf_char <<= 6;
utf_char |= (c & 0x3f);
if ((utf_char >= 0xd800 &&
utf_char <= 0xdfff) ||
(utf_char == 0xfffe) ||
(utf_char == HIDDEN_CHAR)) {
utf_char = UCS_REPL;
}
utf_count--;
if (utf_count == 0) {
if (utf_char > 0xffff) {
TRACE(("using replacement for %#x\n", utf_char));
utf_char = UCS_REPL;
}
data->utf_data = utf_char;
data->utf_size = (i + 1);
break;
}
}
} else {
if (utf_count > 0) {
data->utf_data = UCS_REPL;
data->utf_size = (i + 1);
break;
}
if (c < 0xe0) {
utf_count = 1;
utf_char = (c & 0x1f);
if (!(c & 0x1e))
utf_char = UCS_REPL;
} else if (c < 0xf0) {
utf_count = 2;
utf_char = (c & 0x0f);
} else if (c < 0xf8) {
utf_count = 3;
utf_char = (c & 0x07);
} else if (c < 0xfc) {
utf_count = 4;
utf_char = (c & 0x03);
} else if (c < 0xfe) {
utf_count = 5;
utf_char = (c & 0x01);
} else {
data->utf_data = UCS_REPL;
data->utf_size = (i + 1);
break;
}
}
}
#if OPT_TRACE > 1
TRACE(("UTF-8 char %04X [%d..%d]\n",
data->utf_data,
data->next - data->buffer,
data->next - data->buffer + data->utf_size - 1));
#endif
return (data->utf_size != 0);
}
#endif
int
readPtyData(TScreen * screen, PtySelect * select_mask, PtyData * data)
{
int size = 0;
#ifdef VMS
if (*select_mask & pty_mask) {
trimPtyData(screen, data);
if (read_queue.flink != 0) {
size = tt_read(data->next);
if (size == 0) {
Panic("input: read returned zero\n", 0);
}
} else {
sys$hiber();
}
}
#else
if (FD_ISSET(screen->respond, select_mask)) {
trimPtyData(screen, data);
size = read(screen->respond, (char *) data->last, (unsigned) FRG_SIZE);
if (size <= 0) {
#if (defined(i386) && defined(SVR4) && defined(sun)) || defined(__CYGWIN__)
if (errno == EIO || errno == 0)
#else
if (errno == EIO)
#endif
Cleanup(0);
else if (!E_TEST(errno))
Panic("input: read returned unexpected error (%d)\n", errno);
size = 0;
} else if (size == 0) {
#if defined(__UNIXOS2__)
Cleanup(0);
#else
Panic("input: read returned zero\n", 0);
#endif
}
}
#endif
if (size) {
#if OPT_TRACE
int i;
TRACE(("read %d bytes from pty\n", size));
for (i = 0; i < size; i++) {
if (!(i % 16))
TRACE(("%s", i ? "\n " : "READ"));
TRACE((" %02X", data->last[i]));
}
TRACE(("\n"));
#endif
data->last += size;
#ifdef ALLOWLOGGING
term->screen.logstart = VTbuffer->next;
#endif
}
return (size);
}
#if OPT_WIDE_CHARS
Bool
morePtyData(TScreen * screen, PtyData * data)
{
Bool result = (data->last > data->next);
if (result && screen->utf8_inparse) {
if (!data->utf_size)
result = decodeUtf8(data);
}
TRACE2(("morePtyData returns %d\n", result));
return result;
}
#endif
#if OPT_WIDE_CHARS
IChar
nextPtyData(TScreen * screen, PtyData * data)
{
IChar result;
if (screen->utf8_inparse) {
result = skipPtyData(data);
} else {
result = *((data)->next++);
if (!screen->output_eight_bits)
result &= 0x7f;
}
TRACE2(("nextPtyData returns %#x\n", result));
return result;
}
IChar
skipPtyData(PtyData * data)
{
IChar result = data->utf_data;
data->next += data->utf_size;
data->utf_size = 0;
return result;
}
#endif
#if OPT_WIDE_CHARS
void
switchPtyData(TScreen * screen, int flag)
{
if (screen->utf8_mode != flag) {
screen->utf8_mode = flag;
screen->utf8_inparse = (Boolean) (flag != 0);
TRACE(("turning UTF-8 mode %s\n", BtoS(flag)));
update_font_utf8_mode();
}
}
#endif
void
initPtyData(PtyData ** result)
{
PtyData *data;
TRACE(("initPtyData given minBufSize %d, maxBufSize %d\n",
FRG_SIZE, BUF_SIZE));
if (FRG_SIZE < 64)
FRG_SIZE = 64;
if (BUF_SIZE < FRG_SIZE)
BUF_SIZE = FRG_SIZE;
if (BUF_SIZE % FRG_SIZE)
BUF_SIZE = BUF_SIZE + FRG_SIZE - (BUF_SIZE % FRG_SIZE);
TRACE(("initPtyData using minBufSize %d, maxBufSize %d\n",
FRG_SIZE, BUF_SIZE));
data = (PtyData *) XtMalloc(sizeof(*data) + (unsigned) (BUF_SIZE + FRG_SIZE));
memset(data, 0, sizeof(*data));
data->next = data->buffer;
data->last = data->buffer;
*result = data;
}
#if OPT_WIDE_CHARS
PtyData *
fakePtyData(PtyData * result, Char * next, Char * last)
{
PtyData *data = result;
memset(data, 0, sizeof(*data));
data->next = next;
data->last = last;
return data;
}
#endif
void
trimPtyData(TScreen * screen GCC_UNUSED, PtyData * data)
{
int i;
FlushLog(screen);
if (data->next != data->buffer) {
int n = (data->last - data->next);
TRACE(("shifting buffer down by %d\n", n));
for (i = 0; i < n; ++i) {
data->buffer[i] = data->next[i];
}
data->next = data->buffer;
data->last = data->next + n;
}
}
void
fillPtyData(TScreen * screen, PtyData * data, char *value, int length)
{
int size;
int n;
trimPtyData(screen, data);
VTbuffer->last += length;
size = VTbuffer->last - VTbuffer->next;
for (n = size; n >= length; --n)
VTbuffer->next[n] = VTbuffer->next[n - length];
for (n = 0; n < length; n++)
VTbuffer->next[n] = CharOf(value[n]);
}
#if OPT_WIDE_CHARS
Char *
convertToUTF8(Char * lp, unsigned c)
{
if (c < 0x80) {
*lp++ = (Char) (c);
} else if (c < 0x800) {
*lp++ = (Char) (0xc0 | (c >> 6));
*lp++ = (Char) (0x80 | (c & 0x3f));
} else {
*lp++ = (Char) (0xe0 | (c >> 12));
*lp++ = (Char) (0x80 | ((c >> 6) & 0x3f));
*lp++ = (Char) (0x80 | (c & 0x3f));
}
return lp;
}
void
writePtyData(int f, IChar * d, unsigned len)
{
unsigned n = (len << 1);
if (VTbuffer->write_len <= len) {
VTbuffer->write_len = n;
VTbuffer->write_buf = (Char *) XtRealloc((char *)
VTbuffer->write_buf, VTbuffer->write_len);
}
for (n = 0; n < len; n++)
VTbuffer->write_buf[n] = (Char) d[n];
TRACE(("writePtyData %d:%s\n", n,
visibleChars(PAIRED_CHARS(VTbuffer->write_buf, 0), n)));
v_write(f, VTbuffer->write_buf, n);
}
#endif
#ifdef NO_LEAKS
void
noleaks_ptydata(void)
{
if (VTbuffer != 0) {
#if OPT_WIDE_CHARS
if (VTbuffer->write_buf != 0)
free(VTbuffer->write_buf);
#endif
free(VTbuffer);
VTbuffer = 0;
}
}
#endif