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
/* The name of the default console device.  */
#ifdef WINDOWSNT
61
#include "w32term.h"
62
#endif
Gerd Moellmann's avatar
Gerd Moellmann committed
63

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

Gerd Moellmann's avatar
Gerd Moellmann committed
81

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

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

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

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

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

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

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

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

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

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

Jim Blandy's avatar
Jim Blandy committed
124

125

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

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

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

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

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

143 144 145 146 147 148
  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
149 150 151
    }
}

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

154
static void
155
tty_send_additional_strings (struct terminal *terminal, Lisp_Object sym)
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
{
  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);
        }
    }
}

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

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

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

203 204
/* Reset termcap modes before exiting Emacs. */

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

  if (tty->output)
Jim Blandy's avatar
Jim Blandy committed
211
    {
212
      tty_send_additional_strings (terminal, Qtty_mode_reset_strings);
213 214
      tty_turn_off_highlight (tty);
      tty_turn_off_insert (tty);
215 216 217 218
      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);
219
      /* Output raw CR so kernel can track the cursor hpos.  */
220
      current_tty = tty;
221
      cmputc ('\r');
222
      fflush (tty->output);
Jim Blandy's avatar
Jim Blandy committed
223 224 225
    }
}

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

228
static void
229
tty_update_end (struct frame *f)
Jim Blandy's avatar
Jim Blandy committed
230
{
231
  struct tty_display_info *tty = FRAME_TTY (f);
232

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

240 241
/* The implementation of set_terminal_window for termcap frames. */

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

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

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

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

268
  OUTPUT (tty, buf);
269
  xfree (buf);
270
  losecursor (tty);
Jim Blandy's avatar
Jim Blandy committed
271
}
272

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

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

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

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

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

Gerd Moellmann's avatar
Gerd Moellmann committed
317 318 319 320

/* Make cursor invisible.  */

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


/* Ensure that cursor is visible.  */

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


Jim Blandy's avatar
Jim Blandy committed
354 355 356 357
/* 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.  */

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

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

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

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

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

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

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

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

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

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

421 422
/* Clear from cursor to end of frame on a termcap device. */

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

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

444
/* Clear an entire termcap frame. */
Jim Blandy's avatar
Jim Blandy committed
445

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

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

464
/* An implementation of clear_end_of_line for termcap frames.
Jim Blandy's avatar
Jim Blandy committed
465 466 467

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

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

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

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

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

496
      for (i = curX (tty); i < first_unused_hpos; i++)
Jim Blandy's avatar
Jim Blandy committed
497
	{
498 499 500
	  if (tty->termscript)
	    fputc (' ', tty->termscript);
	  fputc (' ', tty->output);
Jim Blandy's avatar
Jim Blandy committed
501
	}
502
      cmplus (tty, first_unused_hpos - curX (tty));
Jim Blandy's avatar
Jim Blandy committed
503 504 505
    }
}

506 507 508 509
/* 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.  */
510 511
static ptrdiff_t encode_terminal_src_size;
static ptrdiff_t encode_terminal_dst_size;
512 513 514 515 516

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

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

528 529
  /* 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
530 531
     Vglyph_table contains a string or a composite glyph is
     encountered.  */
532
  if (INT_MULTIPLY_WRAPV (src_len, MAX_MULTIBYTE_LENGTH, &required))
533
    memory_full (SIZE_MAX);
534
  if (encode_terminal_src_size < required)
535 536 537 538
    encode_terminal_src = xpalloc (encode_terminal_src,
				   &encode_terminal_src_size,
				   required - encode_terminal_src_size,
				   -1, sizeof *encode_terminal_src);
539

540
  charset_list = coding_charset_list (coding);
Karl Heuer's avatar
Karl Heuer committed
541

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

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

565
	  if (encode_terminal_src_size - nbytes < required)
Kenichi Handa's avatar
Kenichi Handa committed
566
	    {
567 568 569 570
	      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
571 572 573
	      buf = encode_terminal_src + nbytes;
	    }

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

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

590 591
		/* TAB in a composition means display glyphs with
		   padding space on the left or right.  */
592 593 594 595 596 597 598 599 600 601 602 603 604 605
		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 = '?';
606 607 608
		buf += CHAR_STRING (c, buf);
		nchars++;
	      }
Kenichi Handa's avatar
Kenichi Handa committed
609
	}
Karl Heuer's avatar
Karl Heuer committed
610
      /* We must skip glyphs to be padded for a wide character.  */
Kenichi Handa's avatar
Kenichi Handa committed
611
      else if (! CHAR_GLYPH_PADDING_P (*src))
Karl Heuer's avatar
Karl Heuer committed
612
	{
613
	  GLYPH g;
614
	  int c UNINIT;
615 616
	  Lisp_Object string;

617
	  string = Qnil;
618
	  SET_GLYPH_FROM_CHAR_GLYPH (g, src[0]);
619

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

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

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

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

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

713
  return (encode_terminal_dst);
Karl Heuer's avatar
Karl Heuer committed
714 715
}

Jim Blandy's avatar
Jim Blandy committed
716

Miles Bader's avatar
Miles Bader committed
717

718 719
/* An implementation of write_glyphs for termcap frames. */

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

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

729
  tty_turn_off_insert (tty);
</