root/foundation-apps/mxterm-maxx/ptydata.c

Revision 8, 11.2 KB (checked in by emasson, 3 years ago)

initial import for the community edition

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