term.c 127 KB
Newer Older
1
/* Terminal control module for terminals described by TERMCAP
Paul Eggert's avatar
Paul Eggert committed
2
   Copyright (C) 1985-1987, 1993-1995, 1998, 2000-2016 Free Software
3
   Foundation, Inc.
Jim Blandy's avatar
Jim Blandy committed
4 5 6

This file is part of GNU Emacs.

7
GNU Emacs is free software: you can redistribute it and/or modify
Jim Blandy's avatar
Jim Blandy committed
8
it under the terms of the GNU General Public License as published by
9 10
the Free Software Foundation, either version 3 of the License, or (at
your option) any later version.
Jim Blandy's avatar
Jim Blandy committed
11 12 13 14 15 16 17

GNU Emacs is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
18
along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
Jim Blandy's avatar
Jim Blandy committed
19

20
/* New redisplay, TTY faces by Gerd Moellmann <gerd@gnu.org>.  */
Jim Blandy's avatar
Jim Blandy committed
21

22
#include <config.h>
23
#include <errno.h>
24 25
#include <fcntl.h>
#include <stdio.h>
26
#include <sys/file.h>
27
#include <sys/time.h>
28
#include <unistd.h>
29

30
#include "lisp.h"
Jim Blandy's avatar
Jim Blandy committed
31
#include "termchar.h"
Paul Eggert's avatar
Paul Eggert committed
32
#include "tparam.h"
33
#include "character.h"
34
#include "buffer.h"
Karl Heuer's avatar
Karl Heuer committed
35 36
#include "charset.h"
#include "coding.h"
Kenichi Handa's avatar
Kenichi Handa committed
37
#include "composite.h"
38
#include "keyboard.h"
Jim Blandy's avatar
Jim Blandy committed
39
#include "frame.h"
Jim Blandy's avatar
Jim Blandy committed
40 41
#include "disptab.h"
#include "termhooks.h"
Andreas Schwab's avatar
Andreas Schwab committed
42
#include "dispextern.h"
Gerd Moellmann's avatar
Gerd Moellmann committed
43
#include "window.h"
Stefan Monnier's avatar
Stefan Monnier committed
44
#include "keymap.h"
YAMAMOTO Mitsuharu's avatar
YAMAMOTO Mitsuharu committed
45
#include "blockinput.h"
46
#include "syssignal.h"
Eli Zaretskii's avatar
Eli Zaretskii committed
47 48 49 50
#ifdef MSDOS
#include "msdos.h"
static int been_here = -1;
#endif
Gerd Moellmann's avatar
Gerd Moellmann committed
51

52 53 54 55
#ifdef USE_X_TOOLKIT
#include "../lwlib/lwlib.h"
#endif

56
#include "cm.h"
57
#include "menu.h"
Kenichi Handa's avatar
Kenichi Handa committed
58

59 60 61
/* The name of the default console device.  */
#ifdef WINDOWSNT
#define DEV_TTY  "CONOUT$"
62
#include "w32term.h"
63 64 65
#else
#define DEV_TTY  "/dev/tty"
#endif
Gerd Moellmann's avatar
Gerd Moellmann committed
66

67 68 69
static void tty_set_scroll_region (struct frame *f, int start, int stop);
static void turn_on_face (struct frame *, int face_id);
static void turn_off_face (struct frame *, int face_id);
70
static void tty_turn_off_highlight (struct tty_display_info *);
71 72 73 74 75 76 77
static void tty_show_cursor (struct tty_display_info *);
static void tty_hide_cursor (struct tty_display_info *);
static void tty_background_highlight (struct tty_display_info *tty);
static void clear_tty_hooks (struct terminal *terminal);
static void set_tty_hooks (struct terminal *terminal);
static void dissociate_if_controlling_tty (int fd);
static void delete_tty (struct terminal *);
78 79
static _Noreturn void maybe_fatal (bool, struct terminal *,
				   const char *, const char *, ...)
80 81 82
  ATTRIBUTE_FORMAT_PRINTF (3, 5) ATTRIBUTE_FORMAT_PRINTF (4, 5);
static _Noreturn void vfatal (const char *str, va_list ap)
  ATTRIBUTE_FORMAT_PRINTF (1, 0);
83

Gerd Moellmann's avatar
Gerd Moellmann committed
84

85 86
#define OUTPUT(tty, a)                                          \
  emacs_tputs ((tty), a,                                        \
87
               FRAME_TOTAL_LINES (XFRAME (selected_frame)) - curY (tty),	\
88 89
               cmputc)

90 91
#define OUTPUT1(tty, a) emacs_tputs ((tty), a, 1, cmputc)
#define OUTPUTL(tty, a, lines) emacs_tputs ((tty), a, lines, cmputc)
Gerd Moellmann's avatar
Gerd Moellmann committed
92

93
#define OUTPUT_IF(tty, a)                                               \
94 95
  do {                                                                  \
    if (a)                                                              \
96
      OUTPUT (tty, a);							\
97
  } while (0)
98

99
#define OUTPUT1_IF(tty, a) do { if (a) emacs_tputs ((tty), a, 1, cmputc); } while (0)
100

101
/* Display space properties.  */
Jim Blandy's avatar
Jim Blandy committed
102

103
/* Chain of all tty device parameters.  */
104
struct tty_display_info *tty_list;
Jim Blandy's avatar
Jim Blandy committed
105

106 107 108 109 110 111 112 113
/* Meaning of bits in no_color_video.  Each bit set means that the
   corresponding attribute cannot be combined with colors.  */

enum no_color_bit
{
  NC_STANDOUT	 = 1 << 0,
  NC_UNDERLINE	 = 1 << 1,
  NC_REVERSE	 = 1 << 2,
114
  NC_ITALIC	 = 1 << 3,
115 116 117
  NC_DIM	 = 1 << 4,
  NC_BOLD	 = 1 << 5,
  NC_INVIS	 = 1 << 6,
118
  NC_PROTECT	 = 1 << 7
119 120
};

Jim Blandy's avatar
Jim Blandy committed
121 122
/* internal state */

123
/* The largest frame width in any call to calculate_costs.  */
Gerd Moellmann's avatar
Gerd Moellmann committed
124

125
static int max_frame_cols;
Gerd Moellmann's avatar
Gerd Moellmann committed
126

Jim Blandy's avatar
Jim Blandy committed
127

128

129
#ifdef HAVE_GPM
130 131
#include <sys/fcntl.h>

132 133
/* The device for which we have enabled gpm support (or NULL).  */
struct tty_display_info *gpm_tty = NULL;
134

135
/* Last recorded mouse coordinates.  */
136
static int last_mouse_x, last_mouse_y;
137
#endif /* HAVE_GPM */
138

139
/* Ring the bell on a tty. */
140

141
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
142
tty_ring_bell (struct frame *f)
143 144
{
  struct tty_display_info *tty = FRAME_TTY (f);
145

146 147 148 149 150 151
  if (tty->output)
    {
      OUTPUT (tty, (tty->TS_visible_bell && visible_bell
                    ? tty->TS_visible_bell
                    : tty->TS_bell));
      fflush (tty->output);
Jim Blandy's avatar
Jim Blandy committed
152 153 154
    }
}

155 156
/* Set up termcap modes for Emacs. */

157
static void
158
tty_send_additional_strings (struct terminal *terminal, Lisp_Object sym)
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
{
  Lisp_Object lisp_terminal;
  Lisp_Object extra_codes;
  struct tty_display_info *tty = terminal->display_info.tty;

  XSETTERMINAL (lisp_terminal, terminal);
  for (extra_codes = Fterminal_parameter (lisp_terminal, sym);
       CONSP (extra_codes);
       extra_codes = XCDR (extra_codes))
    {
      Lisp_Object string = XCAR (extra_codes);
      if (STRINGP (string))
        {
          fwrite (SDATA (string), 1, SBYTES (string), tty->output);
          if (tty->termscript)
            fwrite (SDATA (string), 1, SBYTES (string), tty->termscript);
        }
    }
}

179
static void
180
tty_set_terminal_modes (struct terminal *terminal)
Jim Blandy's avatar
Jim Blandy committed
181
{
182
  struct tty_display_info *tty = terminal->display_info.tty;
183

184
  if (tty->output)
Jim Blandy's avatar
Jim Blandy committed
185
    {
186 187
      if (tty->TS_termcap_modes)
        OUTPUT (tty, tty->TS_termcap_modes);
188
      else
189 190 191 192
        {
          /* Output enough newlines to scroll all the old screen contents
             off the screen, so it won't be overwritten and lost.  */
          int i;
193
          current_tty = tty;
194
          for (i = 0; i < FRAME_TOTAL_LINES (XFRAME (selected_frame)); i++)
195
            cmputc ('\n');
196 197
        }

198
      OUTPUT_IF (tty, visible_cursor ? tty->TS_cursor_visible : tty->TS_cursor_normal);
199 200
      OUTPUT_IF (tty, tty->TS_keypad_mode);
      losecursor (tty);
201
      tty_send_additional_strings (terminal, Qtty_mode_set_strings);
202
      fflush (tty->output);
Jim Blandy's avatar
Jim Blandy committed
203 204 205
    }
}

206 207
/* Reset termcap modes before exiting Emacs. */

208
static void
209
tty_reset_terminal_modes (struct terminal *terminal)
Jim Blandy's avatar
Jim Blandy committed
210
{
211
  struct tty_display_info *tty = terminal->display_info.tty;
212 213

  if (tty->output)
Jim Blandy's avatar
Jim Blandy committed
214
    {
215
      tty_send_additional_strings (terminal, Qtty_mode_reset_strings);
216 217
      tty_turn_off_highlight (tty);
      tty_turn_off_insert (tty);
218 219 220 221
      OUTPUT_IF (tty, tty->TS_end_keypad_mode);
      OUTPUT_IF (tty, tty->TS_cursor_normal);
      OUTPUT_IF (tty, tty->TS_end_termcap_modes);
      OUTPUT_IF (tty, tty->TS_orig_pair);
222
      /* Output raw CR so kernel can track the cursor hpos.  */
223
      current_tty = tty;
224
      cmputc ('\r');
225
      fflush (tty->output);
Jim Blandy's avatar
Jim Blandy committed
226 227 228
    }
}

229
/* Flag the end of a display update on a termcap terminal. */
Jim Blandy's avatar
Jim Blandy committed
230

231
static void
232
tty_update_end (struct frame *f)
Jim Blandy's avatar
Jim Blandy committed
233
{
234
  struct tty_display_info *tty = FRAME_TTY (f);
235

236 237
  if (!XWINDOW (selected_window)->cursor_off_p)
    tty_show_cursor (tty);
238 239
  tty_turn_off_insert (tty);
  tty_background_highlight (tty);
240
  fflush (tty->output);
Jim Blandy's avatar
Jim Blandy committed
241 242
}

243 244
/* The implementation of set_terminal_window for termcap frames. */

245
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
246
tty_set_terminal_window (struct frame *f, int size)
Jim Blandy's avatar
Jim Blandy committed
247
{
248 249
  struct tty_display_info *tty = FRAME_TTY (f);

250
  tty->specified_window = size ? size : FRAME_TOTAL_LINES (f);
251
  if (FRAME_SCROLL_REGION_OK (f))
252
    tty_set_scroll_region (f, 0, tty->specified_window);
Jim Blandy's avatar
Jim Blandy committed
253 254
}

255 256
static void
tty_set_scroll_region (struct frame *f, int start, int stop)
Jim Blandy's avatar
Jim Blandy committed
257 258
{
  char *buf;
259
  struct tty_display_info *tty = FRAME_TTY (f);
260

261
  if (tty->TS_set_scroll_region)
Paul Eggert's avatar
Paul Eggert committed
262
    buf = tparam (tty->TS_set_scroll_region, 0, 0, start, stop - 1, 0, 0);
263 264
  else if (tty->TS_set_scroll_region_1)
    buf = tparam (tty->TS_set_scroll_region_1, 0, 0,
265 266 267
		  FRAME_TOTAL_LINES (f), start,
		  FRAME_TOTAL_LINES (f) - stop,
		  FRAME_TOTAL_LINES (f));
Jim Blandy's avatar
Jim Blandy committed
268
  else
269
    buf = tparam (tty->TS_set_window, 0, 0, start, 0, stop, FRAME_COLS (f));
270

271
  OUTPUT (tty, buf);
272
  xfree (buf);
273
  losecursor (tty);
Jim Blandy's avatar
Jim Blandy committed
274
}
275

Jim Blandy's avatar
Jim Blandy committed
276

277
static void
278
tty_turn_on_insert (struct tty_display_info *tty)
Jim Blandy's avatar
Jim Blandy committed
279
{
280 281 282
  if (!tty->insert_mode)
    OUTPUT (tty, tty->TS_insert_mode);
  tty->insert_mode = 1;
Jim Blandy's avatar
Jim Blandy committed
283 284
}

Andreas Schwab's avatar
Andreas Schwab committed
285
void
286
tty_turn_off_insert (struct tty_display_info *tty)
Jim Blandy's avatar
Jim Blandy committed
287
{
288 289 290
  if (tty->insert_mode)
    OUTPUT (tty, tty->TS_end_insert_mode);
  tty->insert_mode = 0;
Jim Blandy's avatar
Jim Blandy committed
291 292
}

293
/* Handle highlighting.  */
Jim Blandy's avatar
Jim Blandy committed
294

295
static void
296
tty_turn_off_highlight (struct tty_display_info *tty)
Jim Blandy's avatar
Jim Blandy committed
297
{
298 299 300
  if (tty->standout_mode)
    OUTPUT_IF (tty, tty->TS_end_standout_mode);
  tty->standout_mode = 0;
Jim Blandy's avatar
Jim Blandy committed
301 302
}

303
static void
304
tty_turn_on_highlight (struct tty_display_info *tty)
Jim Blandy's avatar
Jim Blandy committed
305
{
306 307 308
  if (!tty->standout_mode)
    OUTPUT_IF (tty, tty->TS_standout_mode);
  tty->standout_mode = 1;
Jim Blandy's avatar
Jim Blandy committed
309 310
}

311
static void
312
tty_toggle_highlight (struct tty_display_info *tty)
313
{
314
  if (tty->standout_mode)
315
    tty_turn_off_highlight (tty);
316
  else
317
    tty_turn_on_highlight (tty);
318 319
}

Gerd Moellmann's avatar
Gerd Moellmann committed
320 321 322 323

/* Make cursor invisible.  */

static void
324
tty_hide_cursor (struct tty_display_info *tty)
Gerd Moellmann's avatar
Gerd Moellmann committed
325
{
326
  if (tty->cursor_hidden == 0)
327
    {
328
      tty->cursor_hidden = 1;
329 330 331
#ifdef WINDOWSNT
      w32con_hide_cursor ();
#else
332
      OUTPUT_IF (tty, tty->TS_cursor_invisible);
333
#endif
334
    }
Gerd Moellmann's avatar
Gerd Moellmann committed
335 336 337 338 339 340
}


/* Ensure that cursor is visible.  */

static void
341
tty_show_cursor (struct tty_display_info *tty)
Gerd Moellmann's avatar
Gerd Moellmann committed
342
{
343
  if (tty->cursor_hidden)
344
    {
345
      tty->cursor_hidden = 0;
346 347 348
#ifdef WINDOWSNT
      w32con_show_cursor ();
#else
349
      OUTPUT_IF (tty, tty->TS_cursor_normal);
350
      if (visible_cursor)
351
        OUTPUT_IF (tty, tty->TS_cursor_visible);
352
#endif
353
    }
Gerd Moellmann's avatar
Gerd Moellmann committed
354 355 356
}


Jim Blandy's avatar
Jim Blandy committed
357 358 359 360
/* Set standout mode to the state it should be in for
   empty space inside windows.  What this is,
   depends on the user option inverse-video.  */

361 362
static void
tty_background_highlight (struct tty_display_info *tty)
Jim Blandy's avatar
Jim Blandy committed
363 364
{
  if (inverse_video)
365
    tty_turn_on_highlight (tty);
Jim Blandy's avatar
Jim Blandy committed
366
  else
367
    tty_turn_off_highlight (tty);
Jim Blandy's avatar
Jim Blandy committed
368 369 370 371
}

/* Set standout mode to the mode specified for the text to be output.  */

Andreas Schwab's avatar
Andreas Schwab committed
372
static void
373
tty_highlight_if_desired (struct tty_display_info *tty)
Jim Blandy's avatar
Jim Blandy committed
374
{
375
  if (inverse_video)
376
    tty_turn_on_highlight (tty);
377
  else
378
    tty_turn_off_highlight (tty);
Jim Blandy's avatar
Jim Blandy committed
379 380 381
}


Gerd Moellmann's avatar
Gerd Moellmann committed
382 383
/* Move cursor to row/column position VPOS/HPOS.  HPOS/VPOS are
   frame-relative coordinates.  */
Jim Blandy's avatar
Jim Blandy committed
384

385
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
386
tty_cursor_to (struct frame *f, int vpos, int hpos)
Jim Blandy's avatar
Jim Blandy committed
387
{
388
  struct tty_display_info *tty = FRAME_TTY (f);
Jim Blandy's avatar
Jim Blandy committed
389

390 391
  /* Detect the case where we are called from reset_sys_modes
     and the costs have never been calculated.  Do nothing.  */
392
  if (! tty->costs_set)
393 394
    return;

395 396
  if (curY (tty) == vpos
      && curX (tty) == hpos)
Jim Blandy's avatar
Jim Blandy committed
397
    return;
398
  if (!tty->TF_standout_motion)
399
    tty_background_highlight (tty);
400
  if (!tty->TF_insmode_motion)
401
    tty_turn_off_insert (tty);
402
  cmgoto (tty, vpos, hpos);
Jim Blandy's avatar
Jim Blandy committed
403 404 405 406
}

/* Similar but don't take any account of the wasted characters.  */

407
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
408
tty_raw_cursor_to (struct frame *f, int row, int col)
Jim Blandy's avatar
Jim Blandy committed
409
{
410 411
  struct tty_display_info *tty = FRAME_TTY (f);

412 413
  if (curY (tty) == row
      && curX (tty) == col)
Jim Blandy's avatar
Jim Blandy committed
414
    return;
415
  if (!tty->TF_standout_motion)
416
    tty_background_highlight (tty);
417
  if (!tty->TF_insmode_motion)
418
    tty_turn_off_insert (tty);
419
  cmgoto (tty, row, col);
Jim Blandy's avatar
Jim Blandy committed
420 421 422 423
}

/* Erase operations */

424 425
/* Clear from cursor to end of frame on a termcap device. */

426
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
427
tty_clear_to_end (struct frame *f)
Jim Blandy's avatar
Jim Blandy committed
428 429
{
  register int i;
430
  struct tty_display_info *tty = FRAME_TTY (f);
Jim Blandy's avatar
Jim Blandy committed
431

432
  if (tty->TS_clr_to_bottom)
Jim Blandy's avatar
Jim Blandy committed
433
    {
434
      tty_background_highlight (tty);
435
      OUTPUT (tty, tty->TS_clr_to_bottom);
Jim Blandy's avatar
Jim Blandy committed
436 437 438
    }
  else
    {
439
      for (i = curY (tty); i < FRAME_TOTAL_LINES (f); i++)
Jim Blandy's avatar
Jim Blandy committed
440
	{
Karoly Lorentey's avatar
Karoly Lorentey committed
441 442
	  cursor_to (f, i, 0);
	  clear_end_of_line (f, FRAME_COLS (f));
Jim Blandy's avatar
Jim Blandy committed
443 444 445 446
	}
    }
}

447
/* Clear an entire termcap frame. */
Jim Blandy's avatar
Jim Blandy committed
448

449
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
450
tty_clear_frame (struct frame *f)
Jim Blandy's avatar
Jim Blandy committed
451
{
452
  struct tty_display_info *tty = FRAME_TTY (f);
453

454
  if (tty->TS_clr_frame)
Jim Blandy's avatar
Jim Blandy committed
455
    {
456
      tty_background_highlight (tty);
457
      OUTPUT (tty, tty->TS_clr_frame);
458
      cmat (tty, 0, 0);
Jim Blandy's avatar
Jim Blandy committed
459 460 461
    }
  else
    {
Karoly Lorentey's avatar
Karoly Lorentey committed
462 463
      cursor_to (f, 0, 0);
      clear_to_end (f);
Jim Blandy's avatar
Jim Blandy committed
464 465 466
    }
}

467
/* An implementation of clear_end_of_line for termcap frames.
Jim Blandy's avatar
Jim Blandy committed
468 469 470

   Note that the cursor may be moved, on terminals lacking a `ce' string.  */

471
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
472
tty_clear_end_of_line (struct frame *f, int first_unused_hpos)
Jim Blandy's avatar
Jim Blandy committed
473 474
{
  register int i;
475
  struct tty_display_info *tty = FRAME_TTY (f);
Jim Blandy's avatar
Jim Blandy committed
476

477 478
  /* Detect the case where we are called from reset_sys_modes
     and the costs have never been calculated.  Do nothing.  */
479
  if (! tty->costs_set)
480 481
    return;

482
  if (curX (tty) >= first_unused_hpos)
Jim Blandy's avatar
Jim Blandy committed
483
    return;
484
  tty_background_highlight (tty);
485
  if (tty->TS_clr_line)
Jim Blandy's avatar
Jim Blandy committed
486
    {
487
      OUTPUT1 (tty, tty->TS_clr_line);
Jim Blandy's avatar
Jim Blandy committed
488 489 490
    }
  else
    {			/* have to do it the hard way */
491
      tty_turn_off_insert (tty);
Jim Blandy's avatar
Jim Blandy committed
492

Gerd Moellmann's avatar
Gerd Moellmann committed
493
      /* Do not write in last row last col with Auto-wrap on. */
494
      if (AutoWrap (tty)
Karoly Lorentey's avatar
Karoly Lorentey committed
495 496
          && curY (tty) == FrameRows (tty) - 1
	  && first_unused_hpos == FrameCols (tty))
Jim Blandy's avatar
Jim Blandy committed
497 498
	first_unused_hpos--;

499
      for (i = curX (tty); i < first_unused_hpos; i++)
Jim Blandy's avatar
Jim Blandy committed
500
	{
501 502 503
	  if (tty->termscript)
	    fputc (' ', tty->termscript);
	  fputc (' ', tty->output);
Jim Blandy's avatar
Jim Blandy committed
504
	}
505
      cmplus (tty, first_unused_hpos - curX (tty));
Jim Blandy's avatar
Jim Blandy committed
506 507 508
    }
}

509 510 511 512
/* Buffers to store the source and result of code conversion for terminal.  */
static unsigned char *encode_terminal_src;
static unsigned char *encode_terminal_dst;
/* Allocated sizes of the above buffers.  */
513 514
static ptrdiff_t encode_terminal_src_size;
static ptrdiff_t encode_terminal_dst_size;
515 516 517 518 519

/* Encode SRC_LEN glyphs starting at SRC to terminal output codes.
   Set CODING->produced to the byte-length of the resulting byte
   sequence, and return a pointer to that byte sequence.  */

520
unsigned char *
521 522
encode_terminal_code (struct glyph *src, int src_len,
		      struct coding_system *coding)
Karl Heuer's avatar
Karl Heuer committed
523
{
524
  struct glyph *src_end = src + src_len;
525
  unsigned char *buf;
526 527
  ptrdiff_t nchars, nbytes, required;
  ptrdiff_t tlen = GLYPH_TABLE_LENGTH;
Karl Heuer's avatar
Karl Heuer committed
528
  register Lisp_Object *tbase = GLYPH_TABLE_BASE;
529
  Lisp_Object charset_list;
530

531 532
  /* Allocate sufficient size of buffer to store all characters in
     multibyte-form.  But, it may be enlarged on demand if
Kenichi Handa's avatar
Kenichi Handa committed
533 534
     Vglyph_table contains a string or a composite glyph is
     encountered.  */
535
  if (INT_MULTIPLY_WRAPV (src_len, MAX_MULTIBYTE_LENGTH, &required))
536
    memory_full (SIZE_MAX);
537
  if (encode_terminal_src_size < required)
538 539 540 541
    encode_terminal_src = xpalloc (encode_terminal_src,
				   &encode_terminal_src_size,
				   required - encode_terminal_src_size,
				   -1, sizeof *encode_terminal_src);
542

543
  charset_list = coding_charset_list (coding);
Karl Heuer's avatar
Karl Heuer committed
544

545 546 547
  buf = encode_terminal_src;
  nchars = 0;
  while (src < src_end)
Karl Heuer's avatar
Karl Heuer committed
548
    {
Kenichi Handa's avatar
Kenichi Handa committed
549 550
      if (src->type == COMPOSITE_GLYPH)
	{
551 552
	  struct composition *cmp IF_LINT (= NULL);
	  Lisp_Object gstring IF_LINT (= Qnil);
Kenichi Handa's avatar
Kenichi Handa committed
553 554 555
	  int i;

	  nbytes = buf - encode_terminal_src;
556 557 558
	  if (src->u.cmp.automatic)
	    {
	      gstring = composition_gstring_from_id (src->u.cmp.id);
559
	      required = src->slice.cmp.to - src->slice.cmp.from + 1;
560 561 562 563
	    }
	  else
	    {
	      cmp = composition_table[src->u.cmp.id];
564 565
	      required = cmp->glyph_len;
	      required *= MAX_MULTIBYTE_LENGTH;
566
	    }
Kenichi Handa's avatar
Kenichi Handa committed
567

568
	  if (encode_terminal_src_size - nbytes < required)
Kenichi Handa's avatar
Kenichi Handa committed
569
	    {
570 571 572 573
	      encode_terminal_src =
		xpalloc (encode_terminal_src, &encode_terminal_src_size,
			 required - (encode_terminal_src_size - nbytes),
			 -1, 1);
Kenichi Handa's avatar
Kenichi Handa committed
574 575 576
	      buf = encode_terminal_src + nbytes;
	    }

577
	  if (src->u.cmp.automatic)
578
	    for (i = src->slice.cmp.from; i <= src->slice.cmp.to; i++)
579 580 581 582 583
	      {
		Lisp_Object g = LGSTRING_GLYPH (gstring, i);
		int c = LGLYPH_CHAR (g);

		if (! char_charset (c, charset_list, NULL))
584
		  c = '?';
585 586 587 588 589 590 591 592
		buf += CHAR_STRING (c, buf);
		nchars++;
	      }
	  else
	    for (i = 0; i < cmp->glyph_len; i++)
	      {
		int c = COMPOSITION_GLYPH (cmp, i);

593 594
		/* TAB in a composition means display glyphs with
		   padding space on the left or right.  */
595 596 597 598 599 600 601 602 603 604 605 606 607 608
		if (c == '\t')
		  continue;
		if (char_charset (c, charset_list, NULL))
		  {
		    if (CHAR_WIDTH (c) == 0
			&& i > 0 && COMPOSITION_GLYPH (cmp, i - 1) == '\t')
		      /* Should be left-padded */
		      {
			buf += CHAR_STRING (' ', buf);
			nchars++;
		      }
		  }
		else
		  c = '?';
609 610 611
		buf += CHAR_STRING (c, buf);
		nchars++;
	      }
Kenichi Handa's avatar
Kenichi Handa committed
612
	}
Karl Heuer's avatar
Karl Heuer committed
613
      /* We must skip glyphs to be padded for a wide character.  */
Kenichi Handa's avatar
Kenichi Handa committed
614
      else if (! CHAR_GLYPH_PADDING_P (*src))
Karl Heuer's avatar
Karl Heuer committed
615
	{
616
	  GLYPH g;
617
	  int c IF_LINT (= 0);
618 619
	  Lisp_Object string;

620
	  string = Qnil;
621
	  SET_GLYPH_FROM_CHAR_GLYPH (g, src[0]);
622

623
	  if (GLYPH_INVALID_P (g) || GLYPH_SIMPLE_P (tbase, tlen, g))
624
	    {
625
	      /* This glyph doesn't have an entry in Vglyph_table.  */
626 627
	      c = src->u.ch;
	    }
628
	  else
Karl Heuer's avatar
Karl Heuer committed
629
	    {
630
	      /* This glyph has an entry in Vglyph_table,
Karl Heuer's avatar
Karl Heuer committed
631 632
		 so process any alias before testing for simpleness.  */
	      GLYPH_FOLLOW_ALIASES (tbase, tlen, g);
633 634

	      if (GLYPH_SIMPLE_P (tbase, tlen, g))
635 636
		/* We set the multi-byte form of a character in G
		   (that should be an ASCII character) at WORKBUF.  */
637
		c = GLYPH_CHAR (g);
638
	      else
639
		/* We have a string in Vglyph_table.  */
640
		string = tbase[GLYPH_CHAR (g)];
Richard M. Stallman's avatar
Richard M. Stallman committed
641
	    }
642

643
	  if (NILP (string))
644
	    {
Kenichi Handa's avatar
Kenichi Handa committed
645
	      nbytes = buf - encode_terminal_src;
646
	      if (encode_terminal_src_size - nbytes < MAX_MULTIBYTE_LENGTH)
Kenichi Handa's avatar
Kenichi Handa committed
647
		{
648 649 650
		  encode_terminal_src =
		    xpalloc (encode_terminal_src, &encode_terminal_src_size,
			     MAX_MULTIBYTE_LENGTH, -1, 1);
Kenichi Handa's avatar
Kenichi Handa committed
651 652
		  buf = encode_terminal_src + nbytes;
		}
653 654
	      if (CHAR_BYTE8_P (c)
		  || char_charset (c, charset_list, NULL))
655
		{
656 657 658
		  /* Store the multibyte form of C at BUF.  */
		  buf += CHAR_STRING (c, buf);
		  nchars++;
659 660 661
		}
	      else
		{
662 663
		  /* C is not encodable.  */
		  *buf++ = '?';
664
		  nchars++;
665 666 667 668 669 670
		  while (src + 1 < src_end && CHAR_GLYPH_PADDING_P (src[1]))
		    {
		      *buf++ = '?';
		      nchars++;
		      src++;
		    }
671
		}
672 673 674
	    }
	  else
	    {
675 676 677
	      if (! STRING_MULTIBYTE (string))
		string = string_to_multibyte (string);
	      nbytes = buf - encode_terminal_src;
678
	      if (encode_terminal_src_size - nbytes < SBYTES (string))
679
		{
680 681 682 683 684
		  encode_terminal_src =
		    xpalloc (encode_terminal_src, &encode_terminal_src_size,
			     (SBYTES (string)
			      - (encode_terminal_src_size - nbytes)),
			     -1, 1);
685
		  buf = encode_terminal_src + nbytes;
686
		}
687
	      memcpy (buf, SDATA (string), SBYTES (string));
688 689
	      buf += SBYTES (string);
	      nchars += SCHARS (string);
690
	    }
Karl Heuer's avatar
Karl Heuer committed
691
	}
692 693 694 695 696 697 698
      src++;
    }

  if (nchars == 0)
    {
      coding->produced = 0;
      return NULL;
Karl Heuer's avatar
Karl Heuer committed
699
    }
700

701 702 703
  nbytes = buf - encode_terminal_src;
  coding->source = encode_terminal_src;
  if (encode_terminal_dst_size == 0)
704
    {
705 706
      encode_terminal_dst = xrealloc (encode_terminal_dst,
				      encode_terminal_src_size);
707
      encode_terminal_dst_size = encode_terminal_src_size;
708
    }
709 710 711
  coding->destination = encode_terminal_dst;
  coding->dst_bytes = encode_terminal_dst_size;
  encode_coding_object (coding, Qnil, 0, 0, nchars, nbytes, Qnil);
712
  /* coding->destination may have been reallocated.  */
713 714
  encode_terminal_dst = coding->destination;
  encode_terminal_dst_size = coding->dst_bytes;
715

716
  return (encode_terminal_dst);
Karl Heuer's avatar
Karl Heuer committed
717 718
}

Jim Blandy's avatar
Jim Blandy committed
719

Miles Bader's avatar
Miles Bader committed
720

721 722
/* An implementation of write_glyphs for termcap frames. */

723
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
724
tty_write_glyphs (struct frame *f, struct glyph *string, int len)
Jim Blandy's avatar
Jim Blandy committed
725
{
726 727
  unsigned char *conversion_buffer;
  struct coding_system *coding;
728
  int n, stringlen;
Jim Blandy's avatar
Jim Blandy committed
729

730
  struct tty_display_info *tty = FRAME_TTY (f);
Jim Blandy's avatar
Jim Blandy committed
731