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