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