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-2015 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 47
#include "syssignal.h"
#include "systty.h"
48
#include "intervals.h"
Eli Zaretskii's avatar
Eli Zaretskii committed
49 50 51 52
#ifdef MSDOS
#include "msdos.h"
static int been_here = -1;
#endif
Gerd Moellmann's avatar
Gerd Moellmann committed
53

54 55 56 57
#ifdef USE_X_TOOLKIT
#include "../lwlib/lwlib.h"
#endif

58
#include "cm.h"
Andreas Schwab's avatar
Andreas Schwab committed
59 60 61
#ifdef HAVE_X_WINDOWS
#include "xterm.h"
#endif
Karl Heuer's avatar
Karl Heuer committed
62

63
#include "menu.h"
Kenichi Handa's avatar
Kenichi Handa committed
64

65 66 67
/* The name of the default console device.  */
#ifdef WINDOWSNT
#define DEV_TTY  "CONOUT$"
68
#include "w32term.h"
69 70 71
#else
#define DEV_TTY  "/dev/tty"
#endif
Gerd Moellmann's avatar
Gerd Moellmann committed
72

73 74 75
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);
76
static void tty_turn_off_highlight (struct tty_display_info *);
77 78 79 80 81 82 83
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 *);
84 85
static _Noreturn void maybe_fatal (bool, struct terminal *,
				   const char *, const char *, ...)
86 87 88
  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);
89

Gerd Moellmann's avatar
Gerd Moellmann committed
90

91 92
#define OUTPUT(tty, a)                                          \
  emacs_tputs ((tty), a,                                        \
93
               FRAME_TOTAL_LINES (XFRAME (selected_frame)) - curY (tty),	\
94 95
               cmputc)

96 97
#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
98

99
#define OUTPUT_IF(tty, a)                                               \
100 101
  do {                                                                  \
    if (a)                                                              \
102
      OUTPUT (tty, a);							\
103
  } while (0)
104

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

107
/* Display space properties.  */
Jim Blandy's avatar
Jim Blandy committed
108

109
/* Chain of all tty device parameters.  */
110
struct tty_display_info *tty_list;
Jim Blandy's avatar
Jim Blandy committed
111

112 113 114 115 116 117 118 119
/* 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,
120
  NC_ITALIC	 = 1 << 3,
121 122 123
  NC_DIM	 = 1 << 4,
  NC_BOLD	 = 1 << 5,
  NC_INVIS	 = 1 << 6,
124
  NC_PROTECT	 = 1 << 7
125 126
};

Jim Blandy's avatar
Jim Blandy committed
127 128
/* internal state */

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

131
static int max_frame_cols;
Gerd Moellmann's avatar
Gerd Moellmann committed
132

133 134 135
static Lisp_Object Qtty_mode_set_strings;
static Lisp_Object Qtty_mode_reset_strings;

Jim Blandy's avatar
Jim Blandy committed
136

137

138
#ifdef HAVE_GPM
139 140
#include <sys/fcntl.h>

141 142
/* The device for which we have enabled gpm support (or NULL).  */
struct tty_display_info *gpm_tty = NULL;
143

144
/* Last recorded mouse coordinates.  */
145
static int last_mouse_x, last_mouse_y;
146
#endif /* HAVE_GPM */
147

148
/* Ring the bell on a tty. */
149

150
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
151
tty_ring_bell (struct frame *f)
152 153
{
  struct tty_display_info *tty = FRAME_TTY (f);
154

155 156 157 158 159 160
  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
161 162 163
    }
}

164 165
/* Set up termcap modes for Emacs. */

166
static void
167
tty_send_additional_strings (struct terminal *terminal, Lisp_Object sym)
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
{
  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);
        }
    }
}

188
static void
189
tty_set_terminal_modes (struct terminal *terminal)
Jim Blandy's avatar
Jim Blandy committed
190
{
191
  struct tty_display_info *tty = terminal->display_info.tty;
192

193
  if (tty->output)
Jim Blandy's avatar
Jim Blandy committed
194
    {
195 196
      if (tty->TS_termcap_modes)
        OUTPUT (tty, tty->TS_termcap_modes);
197
      else
198 199 200 201
        {
          /* Output enough newlines to scroll all the old screen contents
             off the screen, so it won't be overwritten and lost.  */
          int i;
202
          current_tty = tty;
203
          for (i = 0; i < FRAME_TOTAL_LINES (XFRAME (selected_frame)); i++)
204
            cmputc ('\n');
205 206
        }

207
      OUTPUT_IF (tty, visible_cursor ? tty->TS_cursor_visible : tty->TS_cursor_normal);
208 209
      OUTPUT_IF (tty, tty->TS_keypad_mode);
      losecursor (tty);
210
      tty_send_additional_strings (terminal, Qtty_mode_set_strings);
211
      fflush (tty->output);
Jim Blandy's avatar
Jim Blandy committed
212 213 214
    }
}

215 216
/* Reset termcap modes before exiting Emacs. */

217
static void
218
tty_reset_terminal_modes (struct terminal *terminal)
Jim Blandy's avatar
Jim Blandy committed
219
{
220
  struct tty_display_info *tty = terminal->display_info.tty;
221 222

  if (tty->output)
Jim Blandy's avatar
Jim Blandy committed
223
    {
224
      tty_send_additional_strings (terminal, Qtty_mode_reset_strings);
225 226
      tty_turn_off_highlight (tty);
      tty_turn_off_insert (tty);
227 228 229 230
      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);
231
      /* Output raw CR so kernel can track the cursor hpos.  */
232
      current_tty = tty;
233
      cmputc ('\r');
234
      fflush (tty->output);
Jim Blandy's avatar
Jim Blandy committed
235 236 237
    }
}

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

240
static void
241
tty_update_end (struct frame *f)
Jim Blandy's avatar
Jim Blandy committed
242
{
243
  struct tty_display_info *tty = FRAME_TTY (f);
244

245 246
  if (!XWINDOW (selected_window)->cursor_off_p)
    tty_show_cursor (tty);
247 248
  tty_turn_off_insert (tty);
  tty_background_highlight (tty);
249
  fflush (tty->output);
Jim Blandy's avatar
Jim Blandy committed
250 251
}

252 253
/* The implementation of set_terminal_window for termcap frames. */

254
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
255
tty_set_terminal_window (struct frame *f, int size)
Jim Blandy's avatar
Jim Blandy committed
256
{
257 258
  struct tty_display_info *tty = FRAME_TTY (f);

259
  tty->specified_window = size ? size : FRAME_TOTAL_LINES (f);
260
  if (FRAME_SCROLL_REGION_OK (f))
261
    tty_set_scroll_region (f, 0, tty->specified_window);
Jim Blandy's avatar
Jim Blandy committed
262 263
}

264 265
static void
tty_set_scroll_region (struct frame *f, int start, int stop)
Jim Blandy's avatar
Jim Blandy committed
266 267
{
  char *buf;
268
  struct tty_display_info *tty = FRAME_TTY (f);
269

270
  if (tty->TS_set_scroll_region)
Paul Eggert's avatar
Paul Eggert committed
271
    buf = tparam (tty->TS_set_scroll_region, 0, 0, start, stop - 1, 0, 0);
272 273
  else if (tty->TS_set_scroll_region_1)
    buf = tparam (tty->TS_set_scroll_region_1, 0, 0,
274 275 276
		  FRAME_TOTAL_LINES (f), start,
		  FRAME_TOTAL_LINES (f) - stop,
		  FRAME_TOTAL_LINES (f));
Jim Blandy's avatar
Jim Blandy committed
277
  else
278
    buf = tparam (tty->TS_set_window, 0, 0, start, 0, stop, FRAME_COLS (f));
279

280
  OUTPUT (tty, buf);
281
  xfree (buf);
282
  losecursor (tty);
Jim Blandy's avatar
Jim Blandy committed
283
}
284

Jim Blandy's avatar
Jim Blandy committed
285

286
static void
287
tty_turn_on_insert (struct tty_display_info *tty)
Jim Blandy's avatar
Jim Blandy committed
288
{
289 290 291
  if (!tty->insert_mode)
    OUTPUT (tty, tty->TS_insert_mode);
  tty->insert_mode = 1;
Jim Blandy's avatar
Jim Blandy committed
292 293
}

Andreas Schwab's avatar
Andreas Schwab committed
294
void
295
tty_turn_off_insert (struct tty_display_info *tty)
Jim Blandy's avatar
Jim Blandy committed
296
{
297 298 299
  if (tty->insert_mode)
    OUTPUT (tty, tty->TS_end_insert_mode);
  tty->insert_mode = 0;
Jim Blandy's avatar
Jim Blandy committed
300 301
}

302
/* Handle highlighting.  */
Jim Blandy's avatar
Jim Blandy committed
303

304
static void
305
tty_turn_off_highlight (struct tty_display_info *tty)
Jim Blandy's avatar
Jim Blandy committed
306
{
307 308 309
  if (tty->standout_mode)
    OUTPUT_IF (tty, tty->TS_end_standout_mode);
  tty->standout_mode = 0;
Jim Blandy's avatar
Jim Blandy committed
310 311
}

312
static void
313
tty_turn_on_highlight (struct tty_display_info *tty)
Jim Blandy's avatar
Jim Blandy committed
314
{
315 316 317
  if (!tty->standout_mode)
    OUTPUT_IF (tty, tty->TS_standout_mode);
  tty->standout_mode = 1;
Jim Blandy's avatar
Jim Blandy committed
318 319
}

320
static void
321
tty_toggle_highlight (struct tty_display_info *tty)
322
{
323
  if (tty->standout_mode)
324
    tty_turn_off_highlight (tty);
325
  else
326
    tty_turn_on_highlight (tty);
327 328
}

Gerd Moellmann's avatar
Gerd Moellmann committed
329 330 331 332

/* Make cursor invisible.  */

static void
333
tty_hide_cursor (struct tty_display_info *tty)
Gerd Moellmann's avatar
Gerd Moellmann committed
334
{
335
  if (tty->cursor_hidden == 0)
336
    {
337
      tty->cursor_hidden = 1;
338 339 340
#ifdef WINDOWSNT
      w32con_hide_cursor ();
#else
341
      OUTPUT_IF (tty, tty->TS_cursor_invisible);
342
#endif
343
    }
Gerd Moellmann's avatar
Gerd Moellmann committed
344 345 346 347 348 349
}


/* Ensure that cursor is visible.  */

static void
350
tty_show_cursor (struct tty_display_info *tty)
Gerd Moellmann's avatar
Gerd Moellmann committed
351
{
352
  if (tty->cursor_hidden)
353
    {
354
      tty->cursor_hidden = 0;
355 356 357
#ifdef WINDOWSNT
      w32con_show_cursor ();
#else
358
      OUTPUT_IF (tty, tty->TS_cursor_normal);
359
      if (visible_cursor)
360
        OUTPUT_IF (tty, tty->TS_cursor_visible);
361
#endif
362
    }
Gerd Moellmann's avatar
Gerd Moellmann committed
363 364 365
}


Jim Blandy's avatar
Jim Blandy committed
366 367 368 369
/* 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.  */

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

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

Andreas Schwab's avatar
Andreas Schwab committed
381
static void
382
tty_highlight_if_desired (struct tty_display_info *tty)
Jim Blandy's avatar
Jim Blandy committed
383
{
384
  if (inverse_video)
385
    tty_turn_on_highlight (tty);
386
  else
387
    tty_turn_off_highlight (tty);
Jim Blandy's avatar
Jim Blandy committed
388 389 390
}


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

394
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
395
tty_cursor_to (struct frame *f, int vpos, int hpos)
Jim Blandy's avatar
Jim Blandy committed
396
{
397
  struct tty_display_info *tty = FRAME_TTY (f);
Jim Blandy's avatar
Jim Blandy committed
398

399 400
  /* Detect the case where we are called from reset_sys_modes
     and the costs have never been calculated.  Do nothing.  */
401
  if (! tty->costs_set)
402 403
    return;

404 405
  if (curY (tty) == vpos
      && curX (tty) == hpos)
Jim Blandy's avatar
Jim Blandy committed
406
    return;
407
  if (!tty->TF_standout_motion)
408
    tty_background_highlight (tty);
409
  if (!tty->TF_insmode_motion)
410
    tty_turn_off_insert (tty);
411
  cmgoto (tty, vpos, hpos);
Jim Blandy's avatar
Jim Blandy committed
412 413 414 415
}

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

416
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
417
tty_raw_cursor_to (struct frame *f, int row, int col)
Jim Blandy's avatar
Jim Blandy committed
418
{
419 420
  struct tty_display_info *tty = FRAME_TTY (f);

421 422
  if (curY (tty) == row
      && curX (tty) == col)
Jim Blandy's avatar
Jim Blandy committed
423
    return;
424
  if (!tty->TF_standout_motion)
425
    tty_background_highlight (tty);
426
  if (!tty->TF_insmode_motion)
427
    tty_turn_off_insert (tty);
428
  cmgoto (tty, row, col);
Jim Blandy's avatar
Jim Blandy committed
429 430 431 432
}

/* Erase operations */

433 434
/* Clear from cursor to end of frame on a termcap device. */

435
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
436
tty_clear_to_end (struct frame *f)
Jim Blandy's avatar
Jim Blandy committed
437 438
{
  register int i;
439
  struct tty_display_info *tty = FRAME_TTY (f);
Jim Blandy's avatar
Jim Blandy committed
440

441
  if (tty->TS_clr_to_bottom)
Jim Blandy's avatar
Jim Blandy committed
442
    {
443
      tty_background_highlight (tty);
444
      OUTPUT (tty, tty->TS_clr_to_bottom);
Jim Blandy's avatar
Jim Blandy committed
445 446 447
    }
  else
    {
448
      for (i = curY (tty); i < FRAME_TOTAL_LINES (f); i++)
Jim Blandy's avatar
Jim Blandy committed
449
	{
Karoly Lorentey's avatar
Karoly Lorentey committed
450 451
	  cursor_to (f, i, 0);
	  clear_end_of_line (f, FRAME_COLS (f));
Jim Blandy's avatar
Jim Blandy committed
452 453 454 455
	}
    }
}

456
/* Clear an entire termcap frame. */
Jim Blandy's avatar
Jim Blandy committed
457

458
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
459
tty_clear_frame (struct frame *f)
Jim Blandy's avatar
Jim Blandy committed
460
{
461
  struct tty_display_info *tty = FRAME_TTY (f);
462

463
  if (tty->TS_clr_frame)
Jim Blandy's avatar
Jim Blandy committed
464
    {
465
      tty_background_highlight (tty);
466
      OUTPUT (tty, tty->TS_clr_frame);
467
      cmat (tty, 0, 0);
Jim Blandy's avatar
Jim Blandy committed
468 469 470
    }
  else
    {
Karoly Lorentey's avatar
Karoly Lorentey committed
471 472
      cursor_to (f, 0, 0);
      clear_to_end (f);
Jim Blandy's avatar
Jim Blandy committed
473 474 475
    }
}

476
/* An implementation of clear_end_of_line for termcap frames.
Jim Blandy's avatar
Jim Blandy committed
477 478 479

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

480
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
481
tty_clear_end_of_line (struct frame *f, int first_unused_hpos)
Jim Blandy's avatar
Jim Blandy committed
482 483
{
  register int i;
484
  struct tty_display_info *tty = FRAME_TTY (f);
Jim Blandy's avatar
Jim Blandy committed
485

486 487
  /* Detect the case where we are called from reset_sys_modes
     and the costs have never been calculated.  Do nothing.  */
488
  if (! tty->costs_set)
489 490
    return;

491
  if (curX (tty) >= first_unused_hpos)
Jim Blandy's avatar
Jim Blandy committed
492
    return;
493
  tty_background_highlight (tty);
494
  if (tty->TS_clr_line)
Jim Blandy's avatar
Jim Blandy committed
495
    {
496
      OUTPUT1 (tty, tty->TS_clr_line);
Jim Blandy's avatar
Jim Blandy committed
497 498 499
    }
  else
    {			/* have to do it the hard way */
500
      tty_turn_off_insert (tty);
Jim Blandy's avatar
Jim Blandy committed
501

Gerd Moellmann's avatar
Gerd Moellmann committed
502
      /* Do not write in last row last col with Auto-wrap on. */
503
      if (AutoWrap (tty)
Karoly Lorentey's avatar
Karoly Lorentey committed
504 505
          && curY (tty) == FrameRows (tty) - 1
	  && first_unused_hpos == FrameCols (tty))
Jim Blandy's avatar
Jim Blandy committed
506 507
	first_unused_hpos--;

508
      for (i = curX (tty); i < first_unused_hpos; i++)
Jim Blandy's avatar
Jim Blandy committed
509
	{
510 511 512
	  if (tty->termscript)
	    fputc (' ', tty->termscript);
	  fputc (' ', tty->output);
Jim Blandy's avatar
Jim Blandy committed
513
	}
514
      cmplus (tty, first_unused_hpos - curX (tty));
Jim Blandy's avatar
Jim Blandy committed
515 516 517
    }
}

518 519 520 521
/* 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.  */
522 523
static ptrdiff_t encode_terminal_src_size;
static ptrdiff_t encode_terminal_dst_size;
524 525 526 527 528

/* 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.  */

529
unsigned char *
530 531
encode_terminal_code (struct glyph *src, int src_len,
		      struct coding_system *coding)
Karl Heuer's avatar
Karl Heuer committed
532
{
533
  struct glyph *src_end = src + src_len;
534
  unsigned char *buf;
535 536
  ptrdiff_t nchars, nbytes, required;
  ptrdiff_t tlen = GLYPH_TABLE_LENGTH;
Karl Heuer's avatar
Karl Heuer committed
537
  register Lisp_Object *tbase = GLYPH_TABLE_BASE;
538
  Lisp_Object charset_list;
539

540 541
  /* 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
542 543
     Vglyph_table contains a string or a composite glyph is
     encountered.  */
544 545 546 547
  if (min (PTRDIFF_MAX, SIZE_MAX) / MAX_MULTIBYTE_LENGTH < src_len)
    memory_full (SIZE_MAX);
  required = src_len;
  required *= MAX_MULTIBYTE_LENGTH;
548 549
  if (encode_terminal_src_size < required)
    {
550
      encode_terminal_src = xrealloc (encode_terminal_src, required);
551 552
      encode_terminal_src_size = required;
    }
553

554
  charset_list = coding_charset_list (coding);
Karl Heuer's avatar
Karl Heuer committed
555

556 557 558
  buf = encode_terminal_src;
  nchars = 0;
  while (src < src_end)
Karl Heuer's avatar
Karl Heuer committed
559
    {
Kenichi Handa's avatar
Kenichi Handa committed
560 561
      if (src->type == COMPOSITE_GLYPH)
	{
562 563
	  struct composition *cmp IF_LINT (= NULL);
	  Lisp_Object gstring IF_LINT (= Qnil);
Kenichi Handa's avatar
Kenichi Handa committed
564 565 566
	  int i;

	  nbytes = buf - encode_terminal_src;
567 568 569
	  if (src->u.cmp.automatic)
	    {
	      gstring = composition_gstring_from_id (src->u.cmp.id);
570
	      required = src->slice.cmp.to - src->slice.cmp.from + 1;
571 572 573 574
	    }
	  else
	    {
	      cmp = composition_table[src->u.cmp.id];
575 576
	      required = cmp->glyph_len;
	      required *= MAX_MULTIBYTE_LENGTH;
577
	    }
Kenichi Handa's avatar
Kenichi Handa committed
578

579
	  if (encode_terminal_src_size - nbytes < required)
Kenichi Handa's avatar
Kenichi Handa committed
580
	    {
581 582 583 584
	      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
585 586 587
	      buf = encode_terminal_src + nbytes;
	    }

588
	  if (src->u.cmp.automatic)
589
	    for (i = src->slice.cmp.from; i <= src->slice.cmp.to; i++)
590 591 592 593 594
	      {
		Lisp_Object g = LGSTRING_GLYPH (gstring, i);
		int c = LGLYPH_CHAR (g);

		if (! char_charset (c, charset_list, NULL))
595
		  c = '?';
596 597 598 599 600 601 602 603
		buf += CHAR_STRING (c, buf);
		nchars++;
	      }
	  else
	    for (i = 0; i < cmp->glyph_len; i++)
	      {
		int c = COMPOSITION_GLYPH (cmp, i);

604 605
		/* TAB in a composition means display glyphs with
		   padding space on the left or right.  */
606 607 608 609 610 611 612 613 614 615 616 617 618 619
		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 = '?';
620 621 622
		buf += CHAR_STRING (c, buf);
		nchars++;
	      }
Kenichi Handa's avatar
Kenichi Handa committed
623
	}
Karl Heuer's avatar
Karl Heuer committed
624
      /* We must skip glyphs to be padded for a wide character.  */
Kenichi Handa's avatar
Kenichi Handa committed
625
      else if (! CHAR_GLYPH_PADDING_P (*src))
Karl Heuer's avatar
Karl Heuer committed
626
	{
627
	  GLYPH g;
628
	  int c IF_LINT (= 0);
629 630
	  Lisp_Object string;

631
	  string = Qnil;
632
	  SET_GLYPH_FROM_CHAR_GLYPH (g, src[0]);
633

634
	  if (GLYPH_INVALID_P (g) || GLYPH_SIMPLE_P (tbase, tlen, g))
635
	    {
636
	      /* This glyph doesn't have an entry in Vglyph_table.  */
637 638
	      c = src->u.ch;
	    }
639
	  else
Karl Heuer's avatar
Karl Heuer committed
640
	    {
641
	      /* This glyph has an entry in Vglyph_table,
Karl Heuer's avatar
Karl Heuer committed
642 643
		 so process any alias before testing for simpleness.  */
	      GLYPH_FOLLOW_ALIASES (tbase, tlen, g);
644 645

	      if (GLYPH_SIMPLE_P (tbase, tlen, g))
646 647
		/* We set the multi-byte form of a character in G
		   (that should be an ASCII character) at WORKBUF.  */
648
		c = GLYPH_CHAR (g);
649
	      else
650
		/* We have a string in Vglyph_table.  */
651
		string = tbase[GLYPH_CHAR (g)];
Richard M. Stallman's avatar
Richard M. Stallman committed
652
	    }
653

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

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

712 713 714
  nbytes = buf - encode_terminal_src;
  coding->source = encode_terminal_src;
  if (encode_terminal_dst_size == 0)
715
    {
716 717
      encode_terminal_dst = xrealloc (encode_terminal_dst,
				      encode_terminal_src_size);
718
      encode_terminal_dst_size = encode_terminal_src_size;
719
    }
720 721 722
  coding->destination = encode_terminal_dst;
  coding->dst_bytes = encode_terminal_dst_size;
  encode_coding_object (coding, Qnil, 0, 0, nchars, nbytes, Qnil);
723
  /* coding->destination may have been reallocated.  */
724 725
  encode_terminal_dst = coding->destination;
  encode_terminal_dst_size = coding->dst_bytes;
726

727
  return (encode_terminal_dst);
Karl Heuer's avatar
Karl Heuer committed
728 729
}

Jim Blandy's avatar
Jim Blandy committed
730

Miles Bader's avatar
Miles Bader committed
731

732 733
/* An implementation of write_glyphs for termcap frames. */

734
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
735
tty_write_glyphs (struct frame *f, struct glyph *string, int len)
Jim Blandy's avatar
Jim Blandy committed
736
{
Kenichi Handa's avatar