ptydata.c revision 956cc18d
1956cc18dSsnj/* $XTermId: ptydata.c,v 1.90 2009/08/09 17:22:05 tom Exp $ */ 2d522f475Smrg 3d522f475Smrg/************************************************************ 4d522f475Smrg 5956cc18dSsnjCopyright 1999-2008,2009 by Thomas E. Dickey 6d522f475Smrg 7d522f475Smrg All Rights Reserved 8d522f475Smrg 9d522f475SmrgPermission is hereby granted, free of charge, to any person obtaining a 10d522f475Smrgcopy of this software and associated documentation files (the 11d522f475Smrg"Software"), to deal in the Software without restriction, including 12d522f475Smrgwithout limitation the rights to use, copy, modify, merge, publish, 13d522f475Smrgdistribute, sublicense, and/or sell copies of the Software, and to 14d522f475Smrgpermit persons to whom the Software is furnished to do so, subject to 15d522f475Smrgthe following conditions: 16d522f475Smrg 17d522f475SmrgThe above copyright notice and this permission notice shall be included 18d522f475Smrgin all copies or substantial portions of the Software. 19d522f475Smrg 20d522f475SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 21d522f475SmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22d522f475SmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 23d522f475SmrgIN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY 24d522f475SmrgCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 25d522f475SmrgTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 26d522f475SmrgSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27d522f475Smrg 28d522f475SmrgExcept as contained in this notice, the name(s) of the above copyright 29d522f475Smrgholders shall not be used in advertising or otherwise to promote the 30d522f475Smrgsale, use or other dealings in this Software without prior written 31d522f475Smrgauthorization. 32d522f475Smrg 33d522f475Smrg********************************************************/ 34d522f475Smrg 35d522f475Smrg#include <data.h> 36d522f475Smrg 37d522f475Smrg#if OPT_WIDE_CHARS 38d522f475Smrg#include <menu.h> 39d522f475Smrg#endif 40d522f475Smrg 41d522f475Smrg/* 42d522f475Smrg * Check for both EAGAIN and EWOULDBLOCK, because some supposedly POSIX 43d522f475Smrg * systems are broken and return EWOULDBLOCK when they should return EAGAIN. 44d522f475Smrg * Note that this macro may evaluate its argument more than once. 45d522f475Smrg */ 46d522f475Smrg#if defined(EAGAIN) && defined(EWOULDBLOCK) 47d522f475Smrg#define E_TEST(err) ((err) == EAGAIN || (err) == EWOULDBLOCK) 48d522f475Smrg#else 49d522f475Smrg#ifdef EAGAIN 50d522f475Smrg#define E_TEST(err) ((err) == EAGAIN) 51d522f475Smrg#else 52d522f475Smrg#define E_TEST(err) ((err) == EWOULDBLOCK) 53d522f475Smrg#endif 54d522f475Smrg#endif 55d522f475Smrg 56d522f475Smrg#if OPT_WIDE_CHARS 57d522f475Smrg/* 58d522f475Smrg * Convert the 8-bit codes in data->buffer[] into Unicode in data->utf_data. 59d522f475Smrg * The number of bytes converted will be nonzero iff there is data. 60d522f475Smrg */ 61d522f475SmrgBool 62d522f475SmrgdecodeUtf8(PtyData * data) 63d522f475Smrg{ 64d522f475Smrg int i; 65d522f475Smrg int length = data->last - data->next; 66d522f475Smrg int utf_count = 0; 67956cc18dSsnj unsigned utf_char = 0; 68d522f475Smrg 69d522f475Smrg data->utf_size = 0; 70d522f475Smrg for (i = 0; i < length; i++) { 71d522f475Smrg unsigned c = data->next[i]; 72d522f475Smrg 73d522f475Smrg /* Combine UTF-8 into Unicode */ 74d522f475Smrg if (c < 0x80) { 75d522f475Smrg /* We received an ASCII character */ 76d522f475Smrg if (utf_count > 0) { 77d522f475Smrg data->utf_data = UCS_REPL; /* prev. sequence incomplete */ 78d522f475Smrg data->utf_size = (i + 1); 79d522f475Smrg } else { 80956cc18dSsnj data->utf_data = (IChar) c; 81d522f475Smrg data->utf_size = 1; 82d522f475Smrg } 83d522f475Smrg break; 84d522f475Smrg } else if (c < 0xc0) { 85d522f475Smrg /* We received a continuation byte */ 86d522f475Smrg if (utf_count < 1) { 87d522f475Smrg /* 88d522f475Smrg * We received a continuation byte before receiving a sequence 89d522f475Smrg * state. Or an attempt to use a C1 control string. Either 90d522f475Smrg * way, it is mapped to the replacement character. 91d522f475Smrg */ 92d522f475Smrg data->utf_data = UCS_REPL; /* ... unexpectedly */ 93d522f475Smrg data->utf_size = (i + 1); 94d522f475Smrg break; 95d522f475Smrg } else { 96d522f475Smrg /* Check for overlong UTF-8 sequences for which a shorter 97d522f475Smrg * encoding would exist and replace them with UCS_REPL. 98d522f475Smrg * An overlong UTF-8 sequence can have any of the following 99d522f475Smrg * forms: 100d522f475Smrg * 1100000x 10xxxxxx 101d522f475Smrg * 11100000 100xxxxx 10xxxxxx 102d522f475Smrg * 11110000 1000xxxx 10xxxxxx 10xxxxxx 103d522f475Smrg * 11111000 10000xxx 10xxxxxx 10xxxxxx 10xxxxxx 104d522f475Smrg * 11111100 100000xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 105d522f475Smrg */ 106d522f475Smrg if (!utf_char && !((c & 0x7f) >> (7 - utf_count))) { 107d522f475Smrg utf_char = UCS_REPL; 108d522f475Smrg } 109d522f475Smrg utf_char <<= 6; 110d522f475Smrg utf_char |= (c & 0x3f); 111d522f475Smrg if ((utf_char >= 0xd800 && 112d522f475Smrg utf_char <= 0xdfff) || 113d522f475Smrg (utf_char == 0xfffe) || 114d522f475Smrg (utf_char == HIDDEN_CHAR)) { 115d522f475Smrg utf_char = UCS_REPL; 116d522f475Smrg } 117d522f475Smrg utf_count--; 118d522f475Smrg if (utf_count == 0) { 119956cc18dSsnj#if !OPT_WIDER_ICHAR 120d522f475Smrg /* characters outside UCS-2 become UCS_REPL */ 121d522f475Smrg if (utf_char > 0xffff) { 122d522f475Smrg TRACE(("using replacement for %#x\n", utf_char)); 123d522f475Smrg utf_char = UCS_REPL; 124d522f475Smrg } 125956cc18dSsnj#endif 126956cc18dSsnj data->utf_data = (IChar) utf_char; 127d522f475Smrg data->utf_size = (i + 1); 128d522f475Smrg break; 129d522f475Smrg } 130d522f475Smrg } 131d522f475Smrg } else { 132d522f475Smrg /* We received a sequence start byte */ 133d522f475Smrg if (utf_count > 0) { 134d522f475Smrg data->utf_data = UCS_REPL; /* prev. sequence incomplete */ 135d522f475Smrg data->utf_size = (i + 1); 136d522f475Smrg break; 137d522f475Smrg } 138d522f475Smrg if (c < 0xe0) { 139d522f475Smrg utf_count = 1; 140d522f475Smrg utf_char = (c & 0x1f); 141d522f475Smrg if (!(c & 0x1e)) 142d522f475Smrg utf_char = UCS_REPL; /* overlong sequence */ 143d522f475Smrg } else if (c < 0xf0) { 144d522f475Smrg utf_count = 2; 145d522f475Smrg utf_char = (c & 0x0f); 146d522f475Smrg } else if (c < 0xf8) { 147d522f475Smrg utf_count = 3; 148d522f475Smrg utf_char = (c & 0x07); 149d522f475Smrg } else if (c < 0xfc) { 150d522f475Smrg utf_count = 4; 151d522f475Smrg utf_char = (c & 0x03); 152d522f475Smrg } else if (c < 0xfe) { 153d522f475Smrg utf_count = 5; 154d522f475Smrg utf_char = (c & 0x01); 155d522f475Smrg } else { 156d522f475Smrg data->utf_data = UCS_REPL; 157d522f475Smrg data->utf_size = (i + 1); 158d522f475Smrg break; 159d522f475Smrg } 160d522f475Smrg } 161d522f475Smrg } 162d522f475Smrg#if OPT_TRACE > 1 163d522f475Smrg TRACE(("UTF-8 char %04X [%d..%d]\n", 164d522f475Smrg data->utf_data, 165d522f475Smrg data->next - data->buffer, 166d522f475Smrg data->next - data->buffer + data->utf_size - 1)); 167d522f475Smrg#endif 168d522f475Smrg 169d522f475Smrg return (data->utf_size != 0); 170d522f475Smrg} 171d522f475Smrg#endif 172d522f475Smrg 173d522f475Smrgint 174d522f475SmrgreadPtyData(TScreen * screen, PtySelect * select_mask, PtyData * data) 175d522f475Smrg{ 176d522f475Smrg int size = 0; 177d522f475Smrg 178d522f475Smrg#ifdef VMS 179d522f475Smrg if (*select_mask & pty_mask) { 180d522f475Smrg trimPtyData(screen, data); 181d522f475Smrg if (read_queue.flink != 0) { 182d522f475Smrg size = tt_read(data->next); 183d522f475Smrg if (size == 0) { 184d522f475Smrg Panic("input: read returned zero\n", 0); 185d522f475Smrg } 186d522f475Smrg } else { 187d522f475Smrg sys$hiber(); 188d522f475Smrg } 189d522f475Smrg } 190d522f475Smrg#else /* !VMS */ 191d522f475Smrg if (FD_ISSET(screen->respond, select_mask)) { 192956cc18dSsnj int save_err; 193d522f475Smrg trimPtyData(screen, data); 194d522f475Smrg 195d522f475Smrg size = read(screen->respond, (char *) data->last, (unsigned) FRG_SIZE); 196956cc18dSsnj save_err = errno; 197d522f475Smrg#if (defined(i386) && defined(SVR4) && defined(sun)) || defined(__CYGWIN__) 198956cc18dSsnj /* 199956cc18dSsnj * Yes, I know this is a majorly f*ugly hack, however it seems to 200956cc18dSsnj * be necessary for Solaris x86. DWH 11/15/94 201956cc18dSsnj * Dunno why though.. 202956cc18dSsnj * (and now CYGWIN, alanh@xfree86.org 08/15/01 203956cc18dSsnj */ 204956cc18dSsnj if (size <= 0) { 205956cc18dSsnj if (save_err == EIO || save_err == 0) 206956cc18dSsnj Cleanup(0); 207956cc18dSsnj else if (!E_TEST(save_err)) 208956cc18dSsnj Panic("input: read returned unexpected error (%d)\n", save_err); 209956cc18dSsnj size = 0; 210956cc18dSsnj } 211956cc18dSsnj#else /* !f*ugly */ 212956cc18dSsnj if (size < 0) { 213956cc18dSsnj if (save_err == EIO) 214d522f475Smrg Cleanup(0); 215956cc18dSsnj else if (!E_TEST(save_err)) 216956cc18dSsnj Panic("input: read returned unexpected error (%d)\n", save_err); 217d522f475Smrg size = 0; 218d522f475Smrg } else if (size == 0) { 219956cc18dSsnj#if defined(__UNIXOS2__) || defined(__FreeBSD__) 220d522f475Smrg Cleanup(0); 221d522f475Smrg#else 222d522f475Smrg Panic("input: read returned zero\n", 0); 223d522f475Smrg#endif 224d522f475Smrg } 225956cc18dSsnj#endif /* f*ugly */ 226d522f475Smrg } 227d522f475Smrg#endif /* VMS */ 228d522f475Smrg 229d522f475Smrg if (size) { 230d522f475Smrg#if OPT_TRACE 231d522f475Smrg int i; 232d522f475Smrg 233d522f475Smrg TRACE(("read %d bytes from pty\n", size)); 234d522f475Smrg for (i = 0; i < size; i++) { 235d522f475Smrg if (!(i % 16)) 236d522f475Smrg TRACE(("%s", i ? "\n " : "READ")); 237d522f475Smrg TRACE((" %02X", data->last[i])); 238d522f475Smrg } 239d522f475Smrg TRACE(("\n")); 240d522f475Smrg#endif 241d522f475Smrg data->last += size; 242d522f475Smrg#ifdef ALLOWLOGGING 243d522f475Smrg term->screen.logstart = VTbuffer->next; 244d522f475Smrg#endif 245d522f475Smrg } 246d522f475Smrg 247d522f475Smrg return (size); 248d522f475Smrg} 249d522f475Smrg 250d522f475Smrg/* 251d522f475Smrg * Return the next value from the input buffer. Note that morePtyData() is 252d522f475Smrg * always called before this function, so we can do the UTF-8 input conversion 253d522f475Smrg * in that function and simply return the result here. 254d522f475Smrg */ 255d522f475Smrg#if OPT_WIDE_CHARS 256d522f475SmrgIChar 257d522f475SmrgnextPtyData(TScreen * screen, PtyData * data) 258d522f475Smrg{ 259d522f475Smrg IChar result; 260d522f475Smrg if (screen->utf8_inparse) { 261d522f475Smrg result = skipPtyData(data); 262d522f475Smrg } else { 263d522f475Smrg result = *((data)->next++); 264956cc18dSsnj if (!screen->output_eight_bits) { 265956cc18dSsnj result = (IChar) (result & 0x7f); 266956cc18dSsnj } 267d522f475Smrg } 268d522f475Smrg TRACE2(("nextPtyData returns %#x\n", result)); 269d522f475Smrg return result; 270d522f475Smrg} 271d522f475Smrg 272d522f475Smrg/* 273d522f475Smrg * Simply return the data and skip past it. 274d522f475Smrg */ 275d522f475SmrgIChar 276d522f475SmrgskipPtyData(PtyData * data) 277d522f475Smrg{ 278d522f475Smrg IChar result = data->utf_data; 279d522f475Smrg 280d522f475Smrg data->next += data->utf_size; 281d522f475Smrg data->utf_size = 0; 282d522f475Smrg 283d522f475Smrg return result; 284d522f475Smrg} 285d522f475Smrg#endif 286d522f475Smrg 287d522f475Smrg#if OPT_WIDE_CHARS 288d522f475Smrg/* 289d522f475Smrg * Called when UTF-8 mode has been turned on/off. 290d522f475Smrg */ 291d522f475Smrgvoid 292d522f475SmrgswitchPtyData(TScreen * screen, int flag) 293d522f475Smrg{ 294d522f475Smrg if (screen->utf8_mode != flag) { 295d522f475Smrg screen->utf8_mode = flag; 296956cc18dSsnj screen->utf8_inparse = (Boolean) (flag != 0); 297d522f475Smrg 298d522f475Smrg TRACE(("turning UTF-8 mode %s\n", BtoS(flag))); 299d522f475Smrg update_font_utf8_mode(); 300d522f475Smrg } 301d522f475Smrg} 302d522f475Smrg#endif 303d522f475Smrg 304d522f475Smrg/* 305d522f475Smrg * Allocate a buffer. 306d522f475Smrg */ 307d522f475Smrgvoid 308d522f475SmrginitPtyData(PtyData ** result) 309d522f475Smrg{ 310d522f475Smrg PtyData *data; 311d522f475Smrg 312d522f475Smrg TRACE(("initPtyData given minBufSize %d, maxBufSize %d\n", 313d522f475Smrg FRG_SIZE, BUF_SIZE)); 314d522f475Smrg 315d522f475Smrg if (FRG_SIZE < 64) 316d522f475Smrg FRG_SIZE = 64; 317d522f475Smrg if (BUF_SIZE < FRG_SIZE) 318d522f475Smrg BUF_SIZE = FRG_SIZE; 319d522f475Smrg if (BUF_SIZE % FRG_SIZE) 320d522f475Smrg BUF_SIZE = BUF_SIZE + FRG_SIZE - (BUF_SIZE % FRG_SIZE); 321d522f475Smrg 322d522f475Smrg TRACE(("initPtyData using minBufSize %d, maxBufSize %d\n", 323d522f475Smrg FRG_SIZE, BUF_SIZE)); 324d522f475Smrg 325956cc18dSsnj data = (PtyData *) XtMalloc(sizeof(*data) + (unsigned) (BUF_SIZE + FRG_SIZE)); 326d522f475Smrg 327d522f475Smrg memset(data, 0, sizeof(*data)); 328d522f475Smrg data->next = data->buffer; 329d522f475Smrg data->last = data->buffer; 330d522f475Smrg *result = data; 331d522f475Smrg} 332d522f475Smrg 333d522f475Smrg/* 334d522f475Smrg * Initialize a buffer for the caller, using its data in 'source'. 335d522f475Smrg */ 336d522f475Smrg#if OPT_WIDE_CHARS 337d522f475SmrgPtyData * 338d522f475SmrgfakePtyData(PtyData * result, Char * next, Char * last) 339d522f475Smrg{ 340d522f475Smrg PtyData *data = result; 341d522f475Smrg 342d522f475Smrg memset(data, 0, sizeof(*data)); 343d522f475Smrg data->next = next; 344d522f475Smrg data->last = last; 345d522f475Smrg 346d522f475Smrg return data; 347d522f475Smrg} 348d522f475Smrg#endif 349d522f475Smrg 350d522f475Smrg/* 351d522f475Smrg * Remove used data by shifting the buffer down, to make room for more data, 352d522f475Smrg * e.g., a continuation-read. 353d522f475Smrg */ 354d522f475Smrgvoid 355d522f475SmrgtrimPtyData(TScreen * screen GCC_UNUSED, PtyData * data) 356d522f475Smrg{ 357d522f475Smrg int i; 358d522f475Smrg 359d522f475Smrg FlushLog(screen); 360d522f475Smrg 361d522f475Smrg if (data->next != data->buffer) { 362d522f475Smrg int n = (data->last - data->next); 363d522f475Smrg 364d522f475Smrg TRACE(("shifting buffer down by %d\n", n)); 365d522f475Smrg for (i = 0; i < n; ++i) { 366d522f475Smrg data->buffer[i] = data->next[i]; 367d522f475Smrg } 368d522f475Smrg data->next = data->buffer; 369d522f475Smrg data->last = data->next + n; 370d522f475Smrg } 371d522f475Smrg 372d522f475Smrg} 373d522f475Smrg 374d522f475Smrg/* 375d522f475Smrg * Insert new data into the input buffer so the next calls to morePtyData() 376d522f475Smrg * and nextPtyData() will return that. 377d522f475Smrg */ 378d522f475Smrgvoid 379d522f475SmrgfillPtyData(TScreen * screen, PtyData * data, char *value, int length) 380d522f475Smrg{ 381d522f475Smrg int size; 382d522f475Smrg int n; 383d522f475Smrg 384d522f475Smrg /* remove the used portion of the buffer */ 385d522f475Smrg trimPtyData(screen, data); 386d522f475Smrg 387d522f475Smrg VTbuffer->last += length; 388d522f475Smrg size = VTbuffer->last - VTbuffer->next; 389d522f475Smrg 390d522f475Smrg /* shift the unused portion up to make room */ 391d522f475Smrg for (n = size; n >= length; --n) 392d522f475Smrg VTbuffer->next[n] = VTbuffer->next[n - length]; 393d522f475Smrg 394d522f475Smrg /* insert the new bytes to interpret */ 395d522f475Smrg for (n = 0; n < length; n++) 396d522f475Smrg VTbuffer->next[n] = CharOf(value[n]); 397d522f475Smrg} 398d522f475Smrg 399d522f475Smrg#if OPT_WIDE_CHARS 400d522f475SmrgChar * 401d522f475SmrgconvertToUTF8(Char * lp, unsigned c) 402d522f475Smrg{ 403d522f475Smrg if (c < 0x80) { /* 0******* */ 404956cc18dSsnj *lp++ = (Char) (c); 405d522f475Smrg } else if (c < 0x800) { /* 110***** 10****** */ 406956cc18dSsnj *lp++ = (Char) (0xc0 | (c >> 6)); 407956cc18dSsnj *lp++ = (Char) (0x80 | (c & 0x3f)); 408d522f475Smrg } else { /* 1110**** 10****** 10****** */ 409956cc18dSsnj *lp++ = (Char) (0xe0 | (c >> 12)); 410956cc18dSsnj *lp++ = (Char) (0x80 | ((c >> 6) & 0x3f)); 411956cc18dSsnj *lp++ = (Char) (0x80 | (c & 0x3f)); 412d522f475Smrg } 413d522f475Smrg /* 414d522f475Smrg * UTF-8 is defined for words of up to 31 bits, but we need only 16 415d522f475Smrg * bits here, since that's all that X11R6 supports. 416d522f475Smrg */ 417d522f475Smrg return lp; 418d522f475Smrg} 419d522f475Smrg 420d522f475Smrg/* 421d522f475Smrg * Write data back to the PTY 422d522f475Smrg */ 423d522f475Smrgvoid 424d522f475SmrgwritePtyData(int f, IChar * d, unsigned len) 425d522f475Smrg{ 426d522f475Smrg unsigned n = (len << 1); 427d522f475Smrg 428d522f475Smrg if (VTbuffer->write_len <= len) { 429d522f475Smrg VTbuffer->write_len = n; 430d522f475Smrg VTbuffer->write_buf = (Char *) XtRealloc((char *) 431d522f475Smrg VTbuffer->write_buf, VTbuffer->write_len); 432d522f475Smrg } 433d522f475Smrg 434d522f475Smrg for (n = 0; n < len; n++) 435956cc18dSsnj VTbuffer->write_buf[n] = (Char) d[n]; 436d522f475Smrg 437d522f475Smrg TRACE(("writePtyData %d:%s\n", n, 438956cc18dSsnj visibleChars(VTbuffer->write_buf, n))); 439d522f475Smrg v_write(f, VTbuffer->write_buf, n); 440d522f475Smrg} 441d522f475Smrg#endif /* OPT_WIDE_CHARS */ 442d522f475Smrg 443d522f475Smrg#ifdef NO_LEAKS 444d522f475Smrgvoid 445d522f475Smrgnoleaks_ptydata(void) 446d522f475Smrg{ 447d522f475Smrg if (VTbuffer != 0) { 448d522f475Smrg#if OPT_WIDE_CHARS 449d522f475Smrg if (VTbuffer->write_buf != 0) 450d522f475Smrg free(VTbuffer->write_buf); 451d522f475Smrg#endif 452d522f475Smrg free(VTbuffer); 453d522f475Smrg VTbuffer = 0; 454d522f475Smrg } 455d522f475Smrg} 456d522f475Smrg#endif 457