term.c 128 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-2019 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 <https://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
#include <fcntl.h>
Paul Eggert's avatar
Paul Eggert committed
25
#include <stdlib.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"
47
#include "sysstdio.h"
Eli Zaretskii's avatar
Eli Zaretskii committed
48 49 50 51
#ifdef MSDOS
#include "msdos.h"
static int been_here = -1;
#endif
Gerd Moellmann's avatar
Gerd Moellmann committed
52

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

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

60 61
/* The name of the default console device.  */
#ifdef WINDOWSNT
62
#include "w32term.h"
63
#endif
Gerd Moellmann's avatar
Gerd Moellmann committed
64

65 66 67
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);
68
static void tty_turn_off_highlight (struct tty_display_info *);
69 70 71 72 73 74 75
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 *);
76 77
static _Noreturn void maybe_fatal (bool, struct terminal *,
				   const char *, const char *, ...)
78 79 80
  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);
81

Gerd Moellmann's avatar
Gerd Moellmann committed
82

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

88 89
#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
90

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

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

99
/* Display space properties.  */
Jim Blandy's avatar
Jim Blandy committed
100

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

104 105 106 107 108 109 110 111
/* 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,
112
  NC_ITALIC	 = 1 << 3,
113 114 115
  NC_DIM	 = 1 << 4,
  NC_BOLD	 = 1 << 5,
  NC_INVIS	 = 1 << 6,
116
  NC_PROTECT	 = 1 << 7
117 118
};

Jim Blandy's avatar
Jim Blandy committed
119 120
/* internal state */

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

123
static int max_frame_cols;
Gerd Moellmann's avatar
Gerd Moellmann committed
124

Jim Blandy's avatar
Jim Blandy committed
125

126

127
#ifdef HAVE_GPM
128 129
#include <sys/fcntl.h>

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

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

137
/* Ring the bell on a tty. */
138

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

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

153 154
/* Set up termcap modes for Emacs. */

155
static void
156
tty_send_additional_strings (struct terminal *terminal, Lisp_Object sym)
157
{
Paul Eggert's avatar
Paul Eggert committed
158 159 160 161 162 163
  /* Use only accessors like CDR_SAFE and assq_no_quit to avoid any
     form of quitting or signaling an error, since this function can
     run as part of the "emergency escape" procedure invoked in the
     middle of GC, where quitting means crashing (Bug#17406).  */
  if (! terminal->name)
    return;
164 165
  struct tty_display_info *tty = terminal->display_info.tty;

Paul Eggert's avatar
Paul Eggert committed
166 167
  for (Lisp_Object extra_codes
	 = CDR_SAFE (assq_no_quit (sym, terminal->param_alist));
168 169 170 171 172 173
       CONSP (extra_codes);
       extra_codes = XCDR (extra_codes))
    {
      Lisp_Object string = XCAR (extra_codes);
      if (STRINGP (string))
        {
174
	  fwrite_unlocked (SDATA (string), 1, SBYTES (string), tty->output);
175
          if (tty->termscript)
176 177
	    fwrite_unlocked (SDATA (string), 1, SBYTES (string),
			     tty->termscript);
178 179 180 181
        }
    }
}

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

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

201
      OUTPUT_IF (tty, visible_cursor ? tty->TS_cursor_visible : tty->TS_cursor_normal);
202 203
      OUTPUT_IF (tty, tty->TS_keypad_mode);
      losecursor (tty);
204
      tty_send_additional_strings (terminal, Qtty_mode_set_strings);
205
      fflush_unlocked (tty->output);
Jim Blandy's avatar
Jim Blandy committed
206 207 208
    }
}

209 210
/* Reset termcap modes before exiting Emacs. */

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

  if (tty->output)
Jim Blandy's avatar
Jim Blandy committed
217
    {
218
      tty_send_additional_strings (terminal, Qtty_mode_reset_strings);
219 220
      tty_turn_off_highlight (tty);
      tty_turn_off_insert (tty);
221 222 223 224
      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);
225
      /* Output raw CR so kernel can track the cursor hpos.  */
226
      current_tty = tty;
227
      cmputc ('\r');
228
      fflush_unlocked (tty->output);
Jim Blandy's avatar
Jim Blandy committed
229 230 231
    }
}

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

234
static void
235
tty_update_end (struct frame *f)
Jim Blandy's avatar
Jim Blandy committed
236
{
237
  struct tty_display_info *tty = FRAME_TTY (f);
238

239 240
  if (!XWINDOW (selected_window)->cursor_off_p)
    tty_show_cursor (tty);
241 242
  tty_turn_off_insert (tty);
  tty_background_highlight (tty);
243
  fflush_unlocked (tty->output);
Jim Blandy's avatar
Jim Blandy committed
244 245
}

246 247
/* The implementation of set_terminal_window for termcap frames. */

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

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

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

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

274
  OUTPUT (tty, buf);
275
  xfree (buf);
276
  losecursor (tty);
Jim Blandy's avatar
Jim Blandy committed
277
}
278

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

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

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

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

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

Gerd Moellmann's avatar
Gerd Moellmann committed
323 324 325 326

/* Make cursor invisible.  */

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


/* Ensure that cursor is visible.  */

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


Jim Blandy's avatar
Jim Blandy committed
360 361 362 363
/* 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.  */

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

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

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

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

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

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

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

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

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

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

427 428
/* Clear from cursor to end of frame on a termcap device. */

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

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

450
/* Clear an entire termcap frame. */
Jim Blandy's avatar
Jim Blandy committed
451

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

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

470
/* An implementation of clear_end_of_line for termcap frames.
Jim Blandy's avatar
Jim Blandy committed
471 472 473

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

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

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

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

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

502
      for (i = curX (tty); i < first_unused_hpos; i++)
Jim Blandy's avatar
Jim Blandy committed
503
	{
504
	  if (tty->termscript)
505 506
	    fputc_unlocked (' ', tty->termscript);
	  fputc_unlocked (' ', tty->output);
Jim Blandy's avatar
Jim Blandy committed
507
	}
508
      cmplus (tty, first_unused_hpos - curX (tty));
Jim Blandy's avatar
Jim Blandy committed
509 510 511
    }
}

512 513 514 515
/* 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.  */
516 517
static ptrdiff_t encode_terminal_src_size;
static ptrdiff_t encode_terminal_dst_size;
518 519 520 521 522

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

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

534 535
  /* 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
536 537
     Vglyph_table contains a string or a composite glyph is
     encountered.  */
538
  if (INT_MULTIPLY_WRAPV (src_len, MAX_MULTIBYTE_LENGTH, &required))
539
    memory_full (SIZE_MAX);
540
  if (encode_terminal_src_size < required)
541 542 543 544
    encode_terminal_src = xpalloc (encode_terminal_src,
				   &encode_terminal_src_size,
				   required - encode_terminal_src_size,
				   -1, sizeof *encode_terminal_src);
545

546
  charset_list = coding_charset_list (coding);
Karl Heuer's avatar
Karl Heuer committed
547

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

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

571
	  if (encode_terminal_src_size - nbytes < required)
Kenichi Handa's avatar
Kenichi Handa committed
572
	    {
573 574 575 576
	      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
577 578 579
	      buf = encode_terminal_src + nbytes;
	    }

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

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

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

623
	  string = Qnil;
624
	  SET_GLYPH_FROM_CHAR_GLYPH (g, src[0]);
625

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

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

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

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

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

719
  return (encode_terminal_dst);
Karl Heuer's avatar
Karl Heuer committed
720 721
}

Jim Blandy's avatar
Jim Blandy committed
722

Miles Bader's avatar
Miles Bader committed
723

724 725
/* An implementation of write_glyphs for termcap frames. */

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

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

735
  tty_turn_off_insert (tty);
736
  tty_hide_cursor (tty);
Jim Blandy's avatar
Jim Blandy committed
737

Gerd Moellmann's avatar
Gerd Moellmann committed
738
  /* Don't dare write in last column of bottom line, if Auto-Wrap,
Jim Blandy's avatar
Jim Blandy committed
739
     since that would scroll the whole frame on some terminals.  */
Jim Blandy's avatar
Jim Blandy committed
740

Karoly Lorentey's avatar