ptydata.c revision 894e0ac8
1894e0ac8Smrg/* $XTermId: ptydata.c,v 1.104 2014/05/26 14:46:18 tom Exp $ */
2d522f475Smrg
30bd37d32Smrg/*
4894e0ac8Smrg * Copyright 1999-2013,2014 by Thomas E. Dickey
50bd37d32Smrg *
60bd37d32Smrg *                         All Rights Reserved
70bd37d32Smrg *
80bd37d32Smrg * Permission is hereby granted, free of charge, to any person obtaining a
90bd37d32Smrg * copy of this software and associated documentation files (the
100bd37d32Smrg * "Software"), to deal in the Software without restriction, including
110bd37d32Smrg * without limitation the rights to use, copy, modify, merge, publish,
120bd37d32Smrg * distribute, sublicense, and/or sell copies of the Software, and to
130bd37d32Smrg * permit persons to whom the Software is furnished to do so, subject to
140bd37d32Smrg * the following conditions:
150bd37d32Smrg *
160bd37d32Smrg * The above copyright notice and this permission notice shall be included
170bd37d32Smrg * in all copies or substantial portions of the Software.
180bd37d32Smrg *
190bd37d32Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
200bd37d32Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
210bd37d32Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
220bd37d32Smrg * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
230bd37d32Smrg * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
240bd37d32Smrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
250bd37d32Smrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
260bd37d32Smrg *
270bd37d32Smrg * Except as contained in this notice, the name(s) of the above copyright
280bd37d32Smrg * holders shall not be used in advertising or otherwise to promote the
290bd37d32Smrg * sale, use or other dealings in this Software without prior written
300bd37d32Smrg * authorization.
310bd37d32Smrg */
32d522f475Smrg
33d522f475Smrg#include <data.h>
34d522f475Smrg
35d522f475Smrg#if OPT_WIDE_CHARS
36d522f475Smrg#include <menu.h>
37d522f475Smrg#endif
38d522f475Smrg
39d522f475Smrg/*
40d522f475Smrg * Check for both EAGAIN and EWOULDBLOCK, because some supposedly POSIX
41d522f475Smrg * systems are broken and return EWOULDBLOCK when they should return EAGAIN.
42d522f475Smrg * Note that this macro may evaluate its argument more than once.
43d522f475Smrg */
44d522f475Smrg#if defined(EAGAIN) && defined(EWOULDBLOCK)
45d522f475Smrg#define E_TEST(err) ((err) == EAGAIN || (err) == EWOULDBLOCK)
46d522f475Smrg#else
47d522f475Smrg#ifdef EAGAIN
48d522f475Smrg#define E_TEST(err) ((err) == EAGAIN)
49d522f475Smrg#else
50d522f475Smrg#define E_TEST(err) ((err) == EWOULDBLOCK)
51d522f475Smrg#endif
52d522f475Smrg#endif
53d522f475Smrg
54d522f475Smrg#if OPT_WIDE_CHARS
55d522f475Smrg/*
56d522f475Smrg * Convert the 8-bit codes in data->buffer[] into Unicode in data->utf_data.
57d522f475Smrg * The number of bytes converted will be nonzero iff there is data.
58d522f475Smrg */
59d522f475SmrgBool
60894e0ac8SmrgdecodeUtf8(TScreen *screen, PtyData *data)
61d522f475Smrg{
62d522f475Smrg    int i;
6320d2c4d2Smrg    int length = (int) (data->last - data->next);
64d522f475Smrg    int utf_count = 0;
65956cc18dSsnj    unsigned utf_char = 0;
66d522f475Smrg
67d522f475Smrg    data->utf_size = 0;
68d522f475Smrg    for (i = 0; i < length; i++) {
69d522f475Smrg	unsigned c = data->next[i];
70d522f475Smrg
71d522f475Smrg	/* Combine UTF-8 into Unicode */
72d522f475Smrg	if (c < 0x80) {
73d522f475Smrg	    /* We received an ASCII character */
74d522f475Smrg	    if (utf_count > 0) {
75d522f475Smrg		data->utf_data = UCS_REPL;	/* prev. sequence incomplete */
76a1f3da82Smrg		data->utf_size = i;
77d522f475Smrg	    } else {
78956cc18dSsnj		data->utf_data = (IChar) c;
79d522f475Smrg		data->utf_size = 1;
80d522f475Smrg	    }
81d522f475Smrg	    break;
82d522f475Smrg	} else if (c < 0xc0) {
83d522f475Smrg	    /* We received a continuation byte */
84d522f475Smrg	    if (utf_count < 1) {
85d522f475Smrg		/*
86d522f475Smrg		 * We received a continuation byte before receiving a sequence
87d522f475Smrg		 * state.  Or an attempt to use a C1 control string.  Either
88894e0ac8Smrg		 * way, it is mapped to the replacement character, unless
89894e0ac8Smrg		 * allowed by optional feature.
90d522f475Smrg		 */
91894e0ac8Smrg		data->utf_data = (IChar) (screen->c1_printable ? c : UCS_REPL);
92d522f475Smrg		data->utf_size = (i + 1);
93d522f475Smrg		break;
94d522f475Smrg	    } else {
95d522f475Smrg		/* Check for overlong UTF-8 sequences for which a shorter
96d522f475Smrg		 * encoding would exist and replace them with UCS_REPL.
97d522f475Smrg		 * An overlong UTF-8 sequence can have any of the following
98d522f475Smrg		 * forms:
99d522f475Smrg		 *   1100000x 10xxxxxx
100d522f475Smrg		 *   11100000 100xxxxx 10xxxxxx
101d522f475Smrg		 *   11110000 1000xxxx 10xxxxxx 10xxxxxx
102d522f475Smrg		 *   11111000 10000xxx 10xxxxxx 10xxxxxx 10xxxxxx
103d522f475Smrg		 *   11111100 100000xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
104d522f475Smrg		 */
105d522f475Smrg		if (!utf_char && !((c & 0x7f) >> (7 - utf_count))) {
106d522f475Smrg		    utf_char = UCS_REPL;
107d522f475Smrg		}
108d522f475Smrg		utf_char <<= 6;
109d522f475Smrg		utf_char |= (c & 0x3f);
110d522f475Smrg		if ((utf_char >= 0xd800 &&
111d522f475Smrg		     utf_char <= 0xdfff) ||
112d522f475Smrg		    (utf_char == 0xfffe) ||
113d522f475Smrg		    (utf_char == HIDDEN_CHAR)) {
114d522f475Smrg		    utf_char = UCS_REPL;
115d522f475Smrg		}
116d522f475Smrg		utf_count--;
117d522f475Smrg		if (utf_count == 0) {
118956cc18dSsnj#if !OPT_WIDER_ICHAR
119d522f475Smrg		    /* characters outside UCS-2 become UCS_REPL */
120d522f475Smrg		    if (utf_char > 0xffff) {
121d522f475Smrg			TRACE(("using replacement for %#x\n", utf_char));
122d522f475Smrg			utf_char = UCS_REPL;
123d522f475Smrg		    }
124956cc18dSsnj#endif
125956cc18dSsnj		    data->utf_data = (IChar) utf_char;
126d522f475Smrg		    data->utf_size = (i + 1);
127d522f475Smrg		    break;
128d522f475Smrg		}
129d522f475Smrg	    }
130d522f475Smrg	} else {
131d522f475Smrg	    /* We received a sequence start byte */
132d522f475Smrg	    if (utf_count > 0) {
133d522f475Smrg		data->utf_data = UCS_REPL;	/* prev. sequence incomplete */
134d522f475Smrg		data->utf_size = (i + 1);
135d522f475Smrg		break;
136d522f475Smrg	    }
137d522f475Smrg	    if (c < 0xe0) {
138d522f475Smrg		utf_count = 1;
139d522f475Smrg		utf_char = (c & 0x1f);
140a1f3da82Smrg		if (!(c & 0x1e)) {
141d522f475Smrg		    utf_char = UCS_REPL;	/* overlong sequence */
142a1f3da82Smrg		}
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,
165894e0ac8Smrg	   (int) (data->next - data->buffer),
166894e0ac8Smrg	   (int) (data->next - data->buffer + data->utf_size - 1)));
167d522f475Smrg#endif
168d522f475Smrg
169d522f475Smrg    return (data->utf_size != 0);
170d522f475Smrg}
171d522f475Smrg#endif
172d522f475Smrg
173d522f475Smrgint
174894e0ac8SmrgreadPtyData(XtermWidget xw, PtySelect * select_mask, PtyData *data)
175d522f475Smrg{
17620d2c4d2Smrg    TScreen *screen = TScreenOf(xw);
177d522f475Smrg    int size = 0;
178d522f475Smrg
179d522f475Smrg#ifdef VMS
180d522f475Smrg    if (*select_mask & pty_mask) {
18120d2c4d2Smrg	trimPtyData(xw, data);
182d522f475Smrg	if (read_queue.flink != 0) {
183d522f475Smrg	    size = tt_read(data->next);
184d522f475Smrg	    if (size == 0) {
185d522f475Smrg		Panic("input: read returned zero\n", 0);
186d522f475Smrg	    }
187d522f475Smrg	} else {
188d522f475Smrg	    sys$hiber();
189d522f475Smrg	}
190d522f475Smrg    }
191d522f475Smrg#else /* !VMS */
192d522f475Smrg    if (FD_ISSET(screen->respond, select_mask)) {
193956cc18dSsnj	int save_err;
19420d2c4d2Smrg	trimPtyData(xw, data);
195d522f475Smrg
19620d2c4d2Smrg	size = (int) read(screen->respond, (char *) data->last, (size_t) FRG_SIZE);
197956cc18dSsnj	save_err = errno;
198d522f475Smrg#if (defined(i386) && defined(SVR4) && defined(sun)) || defined(__CYGWIN__)
199956cc18dSsnj	/*
200956cc18dSsnj	 * Yes, I know this is a majorly f*ugly hack, however it seems to
201956cc18dSsnj	 * be necessary for Solaris x86.  DWH 11/15/94
202956cc18dSsnj	 * Dunno why though..
203956cc18dSsnj	 * (and now CYGWIN, alanh@xfree86.org 08/15/01
204956cc18dSsnj	 */
205956cc18dSsnj	if (size <= 0) {
206956cc18dSsnj	    if (save_err == EIO || save_err == 0)
2070bd37d32Smrg		NormalExit();
208956cc18dSsnj	    else if (!E_TEST(save_err))
209956cc18dSsnj		Panic("input: read returned unexpected error (%d)\n", save_err);
210956cc18dSsnj	    size = 0;
211956cc18dSsnj	}
212956cc18dSsnj#else /* !f*ugly */
213956cc18dSsnj	if (size < 0) {
214956cc18dSsnj	    if (save_err == EIO)
2150bd37d32Smrg		NormalExit();
216956cc18dSsnj	    else if (!E_TEST(save_err))
217956cc18dSsnj		Panic("input: read returned unexpected error (%d)\n", save_err);
218d522f475Smrg	    size = 0;
219d522f475Smrg	} else if (size == 0) {
2200bd37d32Smrg#if defined(__FreeBSD__)
2210bd37d32Smrg	    NormalExit();
222d522f475Smrg#else
223d522f475Smrg	    Panic("input: read returned zero\n", 0);
224d522f475Smrg#endif
225d522f475Smrg	}
226956cc18dSsnj#endif /* f*ugly */
227d522f475Smrg    }
228d522f475Smrg#endif /* VMS */
229d522f475Smrg
230d522f475Smrg    if (size) {
231d522f475Smrg#if OPT_TRACE
232d522f475Smrg	int i;
233d522f475Smrg
234d522f475Smrg	TRACE(("read %d bytes from pty\n", size));
235d522f475Smrg	for (i = 0; i < size; i++) {
236d522f475Smrg	    if (!(i % 16))
237d522f475Smrg		TRACE(("%s", i ? "\n    " : "READ"));
238d522f475Smrg	    TRACE((" %02X", data->last[i]));
239d522f475Smrg	}
240d522f475Smrg	TRACE(("\n"));
241d522f475Smrg#endif
242d522f475Smrg	data->last += size;
243d522f475Smrg#ifdef ALLOWLOGGING
24420d2c4d2Smrg	TScreenOf(term)->logstart = VTbuffer->next;
245d522f475Smrg#endif
246d522f475Smrg    }
247d522f475Smrg
248d522f475Smrg    return (size);
249d522f475Smrg}
250d522f475Smrg
251d522f475Smrg/*
252d522f475Smrg * Return the next value from the input buffer.  Note that morePtyData() is
253d522f475Smrg * always called before this function, so we can do the UTF-8 input conversion
254d522f475Smrg * in that function and simply return the result here.
255d522f475Smrg */
256d522f475Smrg#if OPT_WIDE_CHARS
257d522f475SmrgIChar
258894e0ac8SmrgnextPtyData(TScreen *screen, PtyData *data)
259d522f475Smrg{
260d522f475Smrg    IChar result;
261d522f475Smrg    if (screen->utf8_inparse) {
262d522f475Smrg	result = skipPtyData(data);
263d522f475Smrg    } else {
264d522f475Smrg	result = *((data)->next++);
265956cc18dSsnj	if (!screen->output_eight_bits) {
266956cc18dSsnj	    result = (IChar) (result & 0x7f);
267956cc18dSsnj	}
268d522f475Smrg    }
269d522f475Smrg    TRACE2(("nextPtyData returns %#x\n", result));
270d522f475Smrg    return result;
271d522f475Smrg}
272d522f475Smrg
273d522f475Smrg/*
274d522f475Smrg * Simply return the data and skip past it.
275d522f475Smrg */
276d522f475SmrgIChar
277894e0ac8SmrgskipPtyData(PtyData *data)
278d522f475Smrg{
279d522f475Smrg    IChar result = data->utf_data;
280d522f475Smrg
281d522f475Smrg    data->next += data->utf_size;
282d522f475Smrg    data->utf_size = 0;
283d522f475Smrg
284d522f475Smrg    return result;
285d522f475Smrg}
286d522f475Smrg#endif
287d522f475Smrg
288d522f475Smrg#if OPT_WIDE_CHARS
289d522f475Smrg/*
290d522f475Smrg * Called when UTF-8 mode has been turned on/off.
291d522f475Smrg */
292d522f475Smrgvoid
293894e0ac8SmrgswitchPtyData(TScreen *screen, int flag)
294d522f475Smrg{
295d522f475Smrg    if (screen->utf8_mode != flag) {
296d522f475Smrg	screen->utf8_mode = flag;
297956cc18dSsnj	screen->utf8_inparse = (Boolean) (flag != 0);
298d522f475Smrg
299d522f475Smrg	TRACE(("turning UTF-8 mode %s\n", BtoS(flag)));
300d522f475Smrg	update_font_utf8_mode();
301d522f475Smrg    }
302d522f475Smrg}
303d522f475Smrg#endif
304d522f475Smrg
305d522f475Smrg/*
306d522f475Smrg * Allocate a buffer.
307d522f475Smrg */
308d522f475Smrgvoid
309894e0ac8SmrginitPtyData(PtyData **result)
310d522f475Smrg{
311d522f475Smrg    PtyData *data;
312d522f475Smrg
313d522f475Smrg    TRACE(("initPtyData given minBufSize %d, maxBufSize %d\n",
314d522f475Smrg	   FRG_SIZE, BUF_SIZE));
315d522f475Smrg
316d522f475Smrg    if (FRG_SIZE < 64)
317d522f475Smrg	FRG_SIZE = 64;
318d522f475Smrg    if (BUF_SIZE < FRG_SIZE)
319d522f475Smrg	BUF_SIZE = FRG_SIZE;
320d522f475Smrg    if (BUF_SIZE % FRG_SIZE)
321d522f475Smrg	BUF_SIZE = BUF_SIZE + FRG_SIZE - (BUF_SIZE % FRG_SIZE);
322d522f475Smrg
323d522f475Smrg    TRACE(("initPtyData using minBufSize %d, maxBufSize %d\n",
324d522f475Smrg	   FRG_SIZE, BUF_SIZE));
325d522f475Smrg
326a1f3da82Smrg    data = TypeXtMallocX(PtyData, (BUF_SIZE + FRG_SIZE));
327d522f475Smrg
328d522f475Smrg    memset(data, 0, sizeof(*data));
329d522f475Smrg    data->next = data->buffer;
330d522f475Smrg    data->last = data->buffer;
331d522f475Smrg    *result = data;
332d522f475Smrg}
333d522f475Smrg
334d522f475Smrg/*
33520d2c4d2Smrg * Initialize a buffer for the caller, using its data in 'next'.
336d522f475Smrg */
337d522f475Smrg#if OPT_WIDE_CHARS
338d522f475SmrgPtyData *
339894e0ac8SmrgfakePtyData(PtyData *result, Char *next, Char *last)
340d522f475Smrg{
341d522f475Smrg    PtyData *data = result;
342d522f475Smrg
343d522f475Smrg    memset(data, 0, sizeof(*data));
344d522f475Smrg    data->next = next;
345d522f475Smrg    data->last = last;
346d522f475Smrg
347d522f475Smrg    return data;
348d522f475Smrg}
349d522f475Smrg#endif
350d522f475Smrg
351d522f475Smrg/*
352d522f475Smrg * Remove used data by shifting the buffer down, to make room for more data,
353d522f475Smrg * e.g., a continuation-read.
354d522f475Smrg */
355d522f475Smrgvoid
356894e0ac8SmrgtrimPtyData(XtermWidget xw GCC_UNUSED, PtyData *data)
357d522f475Smrg{
358d522f475Smrg    int i;
359d522f475Smrg
36020d2c4d2Smrg    FlushLog(xw);
361d522f475Smrg
362d522f475Smrg    if (data->next != data->buffer) {
36320d2c4d2Smrg	int n = (int) (data->last - data->next);
364d522f475Smrg
365d522f475Smrg	TRACE(("shifting buffer down by %d\n", n));
366d522f475Smrg	for (i = 0; i < n; ++i) {
367d522f475Smrg	    data->buffer[i] = data->next[i];
368d522f475Smrg	}
369d522f475Smrg	data->next = data->buffer;
370d522f475Smrg	data->last = data->next + n;
371d522f475Smrg    }
372d522f475Smrg
373d522f475Smrg}
374d522f475Smrg
375d522f475Smrg/*
376d522f475Smrg * Insert new data into the input buffer so the next calls to morePtyData()
377d522f475Smrg * and nextPtyData() will return that.
378d522f475Smrg */
379d522f475Smrgvoid
380894e0ac8SmrgfillPtyData(XtermWidget xw, PtyData *data, const char *value, int length)
381d522f475Smrg{
382d522f475Smrg    int size;
383d522f475Smrg    int n;
384d522f475Smrg
385d522f475Smrg    /* remove the used portion of the buffer */
38620d2c4d2Smrg    trimPtyData(xw, data);
387d522f475Smrg
388d522f475Smrg    VTbuffer->last += length;
38920d2c4d2Smrg    size = (int) (VTbuffer->last - VTbuffer->next);
390d522f475Smrg
391d522f475Smrg    /* shift the unused portion up to make room */
392d522f475Smrg    for (n = size; n >= length; --n)
393d522f475Smrg	VTbuffer->next[n] = VTbuffer->next[n - length];
394d522f475Smrg
395d522f475Smrg    /* insert the new bytes to interpret */
396d522f475Smrg    for (n = 0; n < length; n++)
397d522f475Smrg	VTbuffer->next[n] = CharOf(value[n]);
398d522f475Smrg}
399d522f475Smrg
400d522f475Smrg#if OPT_WIDE_CHARS
401d522f475SmrgChar *
402894e0ac8SmrgconvertToUTF8(Char *lp, unsigned c)
403d522f475Smrg{
40420d2c4d2Smrg#define CH(n) (Char)((c) >> ((n) * 8))
40520d2c4d2Smrg    if (c < 0x80) {
40620d2c4d2Smrg	/*  0*******  */
40720d2c4d2Smrg	*lp++ = (Char) CH(0);
40820d2c4d2Smrg    } else if (c < 0x800) {
40920d2c4d2Smrg	/*  110***** 10******  */
41020d2c4d2Smrg	*lp++ = (Char) (0xc0 | (CH(0) >> 6) | ((CH(1) & 0x07) << 2));
41120d2c4d2Smrg	*lp++ = (Char) (0x80 | (CH(0) & 0x3f));
41220d2c4d2Smrg    } else if (c < 0x00010000) {
41320d2c4d2Smrg	/*  1110**** 10****** 10******  */
41420d2c4d2Smrg	*lp++ = (Char) (0xe0 | ((int) (CH(1) & 0xf0) >> 4));
41520d2c4d2Smrg	*lp++ = (Char) (0x80 | (CH(0) >> 6) | ((CH(1) & 0x0f) << 2));
41620d2c4d2Smrg	*lp++ = (Char) (0x80 | (CH(0) & 0x3f));
41720d2c4d2Smrg    } else if (c < 0x00200000) {
41820d2c4d2Smrg	*lp++ = (Char) (0xf0 | ((int) (CH(2) & 0x1f) >> 2));
41920d2c4d2Smrg	*lp++ = (Char) (0x80 |
42020d2c4d2Smrg			((int) (CH(1) & 0xf0) >> 4) |
42120d2c4d2Smrg			((int) (CH(2) & 0x03) << 4));
42220d2c4d2Smrg	*lp++ = (Char) (0x80 | (CH(0) >> 6) | ((CH(1) & 0x0f) << 2));
42320d2c4d2Smrg	*lp++ = (Char) (0x80 | (CH(0) & 0x3f));
42420d2c4d2Smrg    } else if (c < 0x04000000) {
42520d2c4d2Smrg	*lp++ = (Char) (0xf8 | (CH(3) & 0x03));
42620d2c4d2Smrg	*lp++ = (Char) (0x80 | (CH(2) >> 2));
42720d2c4d2Smrg	*lp++ = (Char) (0x80 |
42820d2c4d2Smrg			((int) (CH(1) & 0xf0) >> 4) |
42920d2c4d2Smrg			((int) (CH(2) & 0x03) << 4));
43020d2c4d2Smrg	*lp++ = (Char) (0x80 | (CH(0) >> 6) | ((CH(1) & 0x0f) << 2));
43120d2c4d2Smrg	*lp++ = (Char) (0x80 | (CH(0) & 0x3f));
43220d2c4d2Smrg    } else {
43320d2c4d2Smrg	*lp++ = (Char) (0xfc | ((int) (CH(3) & 0x40) >> 6));
43420d2c4d2Smrg	*lp++ = (Char) (0x80 | (CH(3) & 0x3f));
43520d2c4d2Smrg	*lp++ = (Char) (0x80 | (CH(2) >> 2));
43620d2c4d2Smrg	*lp++ = (Char) (0x80 | (CH(1) >> 4) | ((CH(2) & 0x03) << 4));
43720d2c4d2Smrg	*lp++ = (Char) (0x80 | (CH(0) >> 6) | ((CH(1) & 0x0f) << 2));
43820d2c4d2Smrg	*lp++ = (Char) (0x80 | (CH(0) & 0x3f));
439d522f475Smrg    }
440d522f475Smrg    return lp;
44120d2c4d2Smrg#undef CH
442d522f475Smrg}
443d522f475Smrg
444d522f475Smrg/*
445d522f475Smrg * Write data back to the PTY
446d522f475Smrg */
447d522f475Smrgvoid
448894e0ac8SmrgwritePtyData(int f, IChar *d, unsigned len)
449d522f475Smrg{
450d522f475Smrg    unsigned n = (len << 1);
451d522f475Smrg
452d522f475Smrg    if (VTbuffer->write_len <= len) {
453d522f475Smrg	VTbuffer->write_len = n;
454d522f475Smrg	VTbuffer->write_buf = (Char *) XtRealloc((char *)
455d522f475Smrg						 VTbuffer->write_buf, VTbuffer->write_len);
456d522f475Smrg    }
457d522f475Smrg
458d522f475Smrg    for (n = 0; n < len; n++)
459956cc18dSsnj	VTbuffer->write_buf[n] = (Char) d[n];
460d522f475Smrg
461d522f475Smrg    TRACE(("writePtyData %d:%s\n", n,
462956cc18dSsnj	   visibleChars(VTbuffer->write_buf, n)));
463d522f475Smrg    v_write(f, VTbuffer->write_buf, n);
464d522f475Smrg}
465d522f475Smrg#endif /* OPT_WIDE_CHARS */
466d522f475Smrg
467d522f475Smrg#ifdef NO_LEAKS
468d522f475Smrgvoid
469d522f475Smrgnoleaks_ptydata(void)
470d522f475Smrg{
471d522f475Smrg    if (VTbuffer != 0) {
472d522f475Smrg#if OPT_WIDE_CHARS
473d522f475Smrg	if (VTbuffer->write_buf != 0)
474d522f475Smrg	    free(VTbuffer->write_buf);
475d522f475Smrg#endif
476d522f475Smrg	free(VTbuffer);
477d522f475Smrg	VTbuffer = 0;
478d522f475Smrg    }
479d522f475Smrg}
480d522f475Smrg#endif
481