term.c 107 KB
Newer Older
1
/* Terminal control module for terminals described by TERMCAP
2
   Copyright (C) 1985-1987, 1993-1995, 1998, 2000-2011
Glenn Morris's avatar
Glenn Morris committed
3
                 Free Software 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>
Jim Blandy's avatar
Jim Blandy committed
23 24
#include <stdio.h>
#include <ctype.h>
25
#include <errno.h>
26
#include <sys/file.h>
27
#include <unistd.h>
28
#include <signal.h>
Dan Nicolaescu's avatar
Dan Nicolaescu committed
29
#include <stdarg.h>
30
#include <setjmp.h>
31

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

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

62 63 64
#ifndef O_RDWR
#define O_RDWR 2
#endif
Kenichi Handa's avatar
Kenichi Handa committed
65

66 67 68
#ifndef O_NOCTTY
#define O_NOCTTY 0
#endif
Kenichi Handa's avatar
Kenichi Handa committed
69

70 71 72 73 74 75
/* The name of the default console device.  */
#ifdef WINDOWSNT
#define DEV_TTY  "CONOUT$"
#else
#define DEV_TTY  "/dev/tty"
#endif
Gerd Moellmann's avatar
Gerd Moellmann committed
76

77 78 79 80 81 82 83 84 85 86
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);
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 *);
87 88 89 90
static void maybe_fatal (int must_succeed, struct terminal *terminal,
			 const char *str1, const char *str2, ...) NO_RETURN;
static void vfatal (const char *str, va_list ap) NO_RETURN;

Gerd Moellmann's avatar
Gerd Moellmann committed
91

92 93 94 95 96 97
#define OUTPUT(tty, a)                                          \
  emacs_tputs ((tty), a,                                        \
               (int) (FRAME_LINES (XFRAME (selected_frame))     \
                      - curY (tty)),                            \
               cmputc)

98 99
#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
100

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

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

109
/* Display space properties */
Jim Blandy's avatar
Jim Blandy committed
110

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

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

Jim Blandy's avatar
Jim Blandy committed
130 131
/* internal state */

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

134
int max_frame_cols;
Gerd Moellmann's avatar
Gerd Moellmann committed
135

136
/* The largest frame height in any call to calculate_costs.  */
Gerd Moellmann's avatar
Gerd Moellmann committed
137

138
int max_frame_lines;
139

140 141 142
/* Non-zero if we have dropped our controlling tty and therefore
   should not open a frame on stdout. */
static int no_controlling_tty;
Jim Blandy's avatar
Jim Blandy committed
143 144


145

146
#ifdef HAVE_GPM
147 148
#include <sys/fcntl.h>

149 150
/* The device for which we have enabled gpm support (or NULL).  */
struct tty_display_info *gpm_tty = NULL;
151

152
/* Last recorded mouse coordinates.  */
153
static int last_mouse_x, last_mouse_y;
154
#endif /* HAVE_GPM */
155

156
/* Ring the bell on a tty. */
157

158
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
159
tty_ring_bell (struct frame *f)
160 161
{
  struct tty_display_info *tty = FRAME_TTY (f);
162

163 164 165 166 167 168
  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
169 170 171
    }
}

172 173
/* Set up termcap modes for Emacs. */

Andreas Schwab's avatar
Andreas Schwab committed
174
void
175
tty_set_terminal_modes (struct terminal *terminal)
Jim Blandy's avatar
Jim Blandy committed
176
{
177
  struct tty_display_info *tty = terminal->display_info.tty;
178

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

193
      OUTPUT_IF (tty, visible_cursor ? tty->TS_cursor_visible : tty->TS_cursor_normal);
194 195
      OUTPUT_IF (tty, tty->TS_keypad_mode);
      losecursor (tty);
196
      fflush (tty->output);
Jim Blandy's avatar
Jim Blandy committed
197 198 199
    }
}

200 201
/* Reset termcap modes before exiting Emacs. */

Andreas Schwab's avatar
Andreas Schwab committed
202
void
203
tty_reset_terminal_modes (struct terminal *terminal)
Jim Blandy's avatar
Jim Blandy committed
204
{
205
  struct tty_display_info *tty = terminal->display_info.tty;
206 207

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

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

224
static void
225
tty_update_end (struct frame *f)
Jim Blandy's avatar
Jim Blandy committed
226
{
227
  struct tty_display_info *tty = FRAME_TTY (f);
228

229 230
  if (!XWINDOW (selected_window)->cursor_off_p)
    tty_show_cursor (tty);
231 232
  tty_turn_off_insert (tty);
  tty_background_highlight (tty);
Jim Blandy's avatar
Jim Blandy committed
233 234
}

235 236
/* The implementation of set_terminal_window for termcap frames. */

237
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
238
tty_set_terminal_window (struct frame *f, int size)
Jim Blandy's avatar
Jim Blandy committed
239
{
240 241 242 243
  struct tty_display_info *tty = FRAME_TTY (f);

  tty->specified_window = size ? size : FRAME_LINES (f);
  if (FRAME_SCROLL_REGION_OK (f))
244
    tty_set_scroll_region (f, 0, tty->specified_window);
Jim Blandy's avatar
Jim Blandy committed
245 246
}

247 248
static void
tty_set_scroll_region (struct frame *f, int start, int stop)
Jim Blandy's avatar
Jim Blandy committed
249 250
{
  char *buf;
251
  struct tty_display_info *tty = FRAME_TTY (f);
252

253
  if (tty->TS_set_scroll_region)
Paul Eggert's avatar
Paul Eggert committed
254
    buf = tparam (tty->TS_set_scroll_region, 0, 0, start, stop - 1, 0, 0);
255 256
  else if (tty->TS_set_scroll_region_1)
    buf = tparam (tty->TS_set_scroll_region_1, 0, 0,
257 258 259
		  FRAME_LINES (f), start,
		  FRAME_LINES (f) - stop,
		  FRAME_LINES (f));
Jim Blandy's avatar
Jim Blandy committed
260
  else
261
    buf = tparam (tty->TS_set_window, 0, 0, start, 0, stop, FRAME_COLS (f));
262

263
  OUTPUT (tty, buf);
264
  xfree (buf);
265
  losecursor (tty);
Jim Blandy's avatar
Jim Blandy committed
266
}
267

Jim Blandy's avatar
Jim Blandy committed
268

269
static void
270
tty_turn_on_insert (struct tty_display_info *tty)
Jim Blandy's avatar
Jim Blandy committed
271
{
272 273 274
  if (!tty->insert_mode)
    OUTPUT (tty, tty->TS_insert_mode);
  tty->insert_mode = 1;
Jim Blandy's avatar
Jim Blandy committed
275 276
}

Andreas Schwab's avatar
Andreas Schwab committed
277
void
278
tty_turn_off_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_end_insert_mode);
  tty->insert_mode = 0;
Jim Blandy's avatar
Jim Blandy committed
283 284
}

285
/* Handle highlighting.  */
Jim Blandy's avatar
Jim Blandy committed
286

Andreas Schwab's avatar
Andreas Schwab committed
287
void
288
tty_turn_off_highlight (struct tty_display_info *tty)
Jim Blandy's avatar
Jim Blandy committed
289
{
290 291 292
  if (tty->standout_mode)
    OUTPUT_IF (tty, tty->TS_end_standout_mode);
  tty->standout_mode = 0;
Jim Blandy's avatar
Jim Blandy committed
293 294
}

295
static void
296
tty_turn_on_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_standout_mode);
  tty->standout_mode = 1;
Jim Blandy's avatar
Jim Blandy committed
301 302
}

303
static void
304
tty_toggle_highlight (struct tty_display_info *tty)
305
{
306
  if (tty->standout_mode)
307
    tty_turn_off_highlight (tty);
308
  else
309
    tty_turn_on_highlight (tty);
310 311
}

Gerd Moellmann's avatar
Gerd Moellmann committed
312 313 314 315

/* Make cursor invisible.  */

static void
316
tty_hide_cursor (struct tty_display_info *tty)
Gerd Moellmann's avatar
Gerd Moellmann committed
317
{
318
  if (tty->cursor_hidden == 0)
319
    {
320 321
      tty->cursor_hidden = 1;
      OUTPUT_IF (tty, tty->TS_cursor_invisible);
322
    }
Gerd Moellmann's avatar
Gerd Moellmann committed
323 324 325 326 327 328
}


/* Ensure that cursor is visible.  */

static void
329
tty_show_cursor (struct tty_display_info *tty)
Gerd Moellmann's avatar
Gerd Moellmann committed
330
{
331
  if (tty->cursor_hidden)
332
    {
333 334
      tty->cursor_hidden = 0;
      OUTPUT_IF (tty, tty->TS_cursor_normal);
335
      if (visible_cursor)
336
        OUTPUT_IF (tty, tty->TS_cursor_visible);
337
    }
Gerd Moellmann's avatar
Gerd Moellmann committed
338 339 340
}


Jim Blandy's avatar
Jim Blandy committed
341 342 343 344
/* 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.  */

345 346
static void
tty_background_highlight (struct tty_display_info *tty)
Jim Blandy's avatar
Jim Blandy committed
347 348
{
  if (inverse_video)
349
    tty_turn_on_highlight (tty);
Jim Blandy's avatar
Jim Blandy committed
350
  else
351
    tty_turn_off_highlight (tty);
Jim Blandy's avatar
Jim Blandy committed
352 353 354 355
}

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

Andreas Schwab's avatar
Andreas Schwab committed
356
static void
357
tty_highlight_if_desired (struct tty_display_info *tty)
Jim Blandy's avatar
Jim Blandy committed
358
{
359
  if (inverse_video)
360
    tty_turn_on_highlight (tty);
361
  else
362
    tty_turn_off_highlight (tty);
Jim Blandy's avatar
Jim Blandy committed
363 364 365
}


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

369
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
370
tty_cursor_to (struct frame *f, int vpos, int hpos)
Jim Blandy's avatar
Jim Blandy committed
371
{
372
  struct tty_display_info *tty = FRAME_TTY (f);
Jim Blandy's avatar
Jim Blandy committed
373

374 375
  /* Detect the case where we are called from reset_sys_modes
     and the costs have never been calculated.  Do nothing.  */
376
  if (! tty->costs_set)
377 378
    return;

379 380
  if (curY (tty) == vpos
      && curX (tty) == hpos)
Jim Blandy's avatar
Jim Blandy committed
381
    return;
382
  if (!tty->TF_standout_motion)
383
    tty_background_highlight (tty);
384
  if (!tty->TF_insmode_motion)
385
    tty_turn_off_insert (tty);
386
  cmgoto (tty, vpos, hpos);
Jim Blandy's avatar
Jim Blandy committed
387 388 389 390
}

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

391
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
392
tty_raw_cursor_to (struct frame *f, int row, int col)
Jim Blandy's avatar
Jim Blandy committed
393
{
394 395
  struct tty_display_info *tty = FRAME_TTY (f);

396 397
  if (curY (tty) == row
      && curX (tty) == col)
Jim Blandy's avatar
Jim Blandy committed
398
    return;
399
  if (!tty->TF_standout_motion)
400
    tty_background_highlight (tty);
401
  if (!tty->TF_insmode_motion)
402
    tty_turn_off_insert (tty);
403
  cmgoto (tty, row, col);
Jim Blandy's avatar
Jim Blandy committed
404 405 406 407
}

/* Erase operations */

408 409
/* Clear from cursor to end of frame on a termcap device. */

410
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
411
tty_clear_to_end (struct frame *f)
Jim Blandy's avatar
Jim Blandy committed
412 413
{
  register int i;
414
  struct tty_display_info *tty = FRAME_TTY (f);
Jim Blandy's avatar
Jim Blandy committed
415

416
  if (tty->TS_clr_to_bottom)
Jim Blandy's avatar
Jim Blandy committed
417
    {
418
      tty_background_highlight (tty);
419
      OUTPUT (tty, tty->TS_clr_to_bottom);
Jim Blandy's avatar
Jim Blandy committed
420 421 422
    }
  else
    {
423
      for (i = curY (tty); i < FRAME_LINES (f); i++)
Jim Blandy's avatar
Jim Blandy committed
424
	{
Karoly Lorentey's avatar
Karoly Lorentey committed
425 426
	  cursor_to (f, i, 0);
	  clear_end_of_line (f, FRAME_COLS (f));
Jim Blandy's avatar
Jim Blandy committed
427 428 429 430
	}
    }
}

431
/* Clear an entire termcap frame. */
Jim Blandy's avatar
Jim Blandy committed
432

433
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
434
tty_clear_frame (struct frame *f)
Jim Blandy's avatar
Jim Blandy committed
435
{
436
  struct tty_display_info *tty = FRAME_TTY (f);
437

438
  if (tty->TS_clr_frame)
Jim Blandy's avatar
Jim Blandy committed
439
    {
440
      tty_background_highlight (tty);
441
      OUTPUT (tty, tty->TS_clr_frame);
442
      cmat (tty, 0, 0);
Jim Blandy's avatar
Jim Blandy committed
443 444 445
    }
  else
    {
Karoly Lorentey's avatar
Karoly Lorentey committed
446 447
      cursor_to (f, 0, 0);
      clear_to_end (f);
Jim Blandy's avatar
Jim Blandy committed
448 449 450
    }
}

451
/* An implementation of clear_end_of_line for termcap frames.
Jim Blandy's avatar
Jim Blandy committed
452 453 454

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

455
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
456
tty_clear_end_of_line (struct frame *f, int first_unused_hpos)
Jim Blandy's avatar
Jim Blandy committed
457 458
{
  register int i;
459
  struct tty_display_info *tty = FRAME_TTY (f);
Jim Blandy's avatar
Jim Blandy committed
460

461 462
  /* Detect the case where we are called from reset_sys_modes
     and the costs have never been calculated.  Do nothing.  */
463
  if (! tty->costs_set)
464 465
    return;

466
  if (curX (tty) >= first_unused_hpos)
Jim Blandy's avatar
Jim Blandy committed
467
    return;
468
  tty_background_highlight (tty);
469
  if (tty->TS_clr_line)
Jim Blandy's avatar
Jim Blandy committed
470
    {
471
      OUTPUT1 (tty, tty->TS_clr_line);
Jim Blandy's avatar
Jim Blandy committed
472 473 474
    }
  else
    {			/* have to do it the hard way */
475
      tty_turn_off_insert (tty);
Jim Blandy's avatar
Jim Blandy committed
476

Gerd Moellmann's avatar
Gerd Moellmann committed
477
      /* Do not write in last row last col with Auto-wrap on. */
478
      if (AutoWrap (tty)
Karoly Lorentey's avatar
Karoly Lorentey committed
479 480
          && curY (tty) == FrameRows (tty) - 1
	  && first_unused_hpos == FrameCols (tty))
Jim Blandy's avatar
Jim Blandy committed
481 482
	first_unused_hpos--;

483
      for (i = curX (tty); i < first_unused_hpos; i++)
Jim Blandy's avatar
Jim Blandy committed
484
	{
485 486 487
	  if (tty->termscript)
	    fputc (' ', tty->termscript);
	  fputc (' ', tty->output);
Jim Blandy's avatar
Jim Blandy committed
488
	}
489
      cmplus (tty, first_unused_hpos - curX (tty));
Jim Blandy's avatar
Jim Blandy committed
490 491 492
    }
}

493 494 495 496 497 498 499 500 501 502 503
/* 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.  */
static int encode_terminal_src_size;
static int encode_terminal_dst_size;

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

504
static unsigned char *
505
encode_terminal_code (struct glyph *src, int src_len, struct coding_system *coding)
Karl Heuer's avatar
Karl Heuer committed
506
{
507
  struct glyph *src_end = src + src_len;
508 509
  unsigned char *buf;
  int nchars, nbytes, required;
Karl Heuer's avatar
Karl Heuer committed
510 511
  register int tlen = GLYPH_TABLE_LENGTH;
  register Lisp_Object *tbase = GLYPH_TABLE_BASE;
512
  Lisp_Object charset_list;
513

514 515
  /* 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
516 517
     Vglyph_table contains a string or a composite glyph is
     encountered.  */
518 519 520
  required = MAX_MULTIBYTE_LENGTH * src_len;
  if (encode_terminal_src_size < required)
    {
521
      if (encode_terminal_src)
522
	encode_terminal_src = xrealloc (encode_terminal_src, required);
523 524
      else
	encode_terminal_src = xmalloc (required);
525 526
      encode_terminal_src_size = required;
    }
527

528
  charset_list = coding_charset_list (coding);
Karl Heuer's avatar
Karl Heuer committed
529

530 531 532
  buf = encode_terminal_src;
  nchars = 0;
  while (src < src_end)
Karl Heuer's avatar
Karl Heuer committed
533
    {
Kenichi Handa's avatar
Kenichi Handa committed
534 535
      if (src->type == COMPOSITE_GLYPH)
	{
536 537
	  struct composition *cmp IF_LINT (= NULL);
	  Lisp_Object gstring IF_LINT (= Qnil);
Kenichi Handa's avatar
Kenichi Handa committed
538 539 540
	  int i;

	  nbytes = buf - encode_terminal_src;
541 542 543
	  if (src->u.cmp.automatic)
	    {
	      gstring = composition_gstring_from_id (src->u.cmp.id);
544
	      required = src->slice.cmp.to + 1 - src->slice.cmp.from;
545 546 547 548 549 550
	    }
	  else
	    {
	      cmp = composition_table[src->u.cmp.id];
	      required = MAX_MULTIBYTE_LENGTH * cmp->glyph_len;
	    }
Kenichi Handa's avatar
Kenichi Handa committed
551 552 553 554 555 556 557 558 559

	  if (encode_terminal_src_size < nbytes + required)
	    {
	      encode_terminal_src_size = nbytes + required;
	      encode_terminal_src = xrealloc (encode_terminal_src,
					      encode_terminal_src_size);
	      buf = encode_terminal_src + nbytes;
	    }

560
	  if (src->u.cmp.automatic)
561
	    for (i = src->slice.cmp.from; i <= src->slice.cmp.to; i++)
562 563 564 565 566
	      {
		Lisp_Object g = LGSTRING_GLYPH (gstring, i);
		int c = LGLYPH_CHAR (g);

		if (! char_charset (c, charset_list, NULL))
567
		  c = '?';
568 569 570 571 572 573 574 575
		buf += CHAR_STRING (c, buf);
		nchars++;
	      }
	  else
	    for (i = 0; i < cmp->glyph_len; i++)
	      {
		int c = COMPOSITION_GLYPH (cmp, i);

576 577 578 579 580 581 582 583 584 585 586 587 588 589
		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 = '?';
590 591 592
		buf += CHAR_STRING (c, buf);
		nchars++;
	      }
Kenichi Handa's avatar
Kenichi Handa committed
593
	}
Karl Heuer's avatar
Karl Heuer committed
594
      /* We must skip glyphs to be padded for a wide character.  */
Kenichi Handa's avatar
Kenichi Handa committed
595
      else if (! CHAR_GLYPH_PADDING_P (*src))
Karl Heuer's avatar
Karl Heuer committed
596
	{
597
	  GLYPH g;
598
	  int c IF_LINT (= 0);
599 600
	  Lisp_Object string;

601
	  string = Qnil;
602
	  SET_GLYPH_FROM_CHAR_GLYPH (g, src[0]);
603

604
	  if (GLYPH_INVALID_P (g) || GLYPH_SIMPLE_P (tbase, tlen, g))
605
	    {
606
	      /* This glyph doesn't have an entry in Vglyph_table.  */
607 608
	      c = src->u.ch;
	    }
609
	  else
Karl Heuer's avatar
Karl Heuer committed
610
	    {
611
	      /* This glyph has an entry in Vglyph_table,
Karl Heuer's avatar
Karl Heuer committed
612 613
		 so process any alias before testing for simpleness.  */
	      GLYPH_FOLLOW_ALIASES (tbase, tlen, g);
614 615

	      if (GLYPH_SIMPLE_P (tbase, tlen, g))
616 617
		/* We set the multi-byte form of a character in G
		   (that should be an ASCII character) at WORKBUF.  */
618
		c = GLYPH_CHAR (g);
619
	      else
620
		/* We have a string in Vglyph_table.  */
621
		string = tbase[GLYPH_CHAR (g)];
Richard M. Stallman's avatar
Richard M. Stallman committed
622
	    }
623

624
	  if (NILP (string))
625
	    {
Kenichi Handa's avatar
Kenichi Handa committed
626 627 628 629 630 631 632 633
	      nbytes = buf - encode_terminal_src;
	      if (encode_terminal_src_size < nbytes + MAX_MULTIBYTE_LENGTH)
		{
		  encode_terminal_src_size = nbytes + MAX_MULTIBYTE_LENGTH;
		  encode_terminal_src = xrealloc (encode_terminal_src,
						  encode_terminal_src_size);
		  buf = encode_terminal_src + nbytes;
		}
634 635
	      if (CHAR_BYTE8_P (c)
		  || char_charset (c, charset_list, NULL))
636
		{
637 638 639
		  /* Store the multibyte form of C at BUF.  */
		  buf += CHAR_STRING (c, buf);
		  nchars++;
640 641 642
		}
	      else
		{
643 644
		  /* C is not encodable.  */
		  *buf++ = '?';
645
		  nchars++;
646 647 648 649 650 651
		  while (src + 1 < src_end && CHAR_GLYPH_PADDING_P (src[1]))
		    {
		      *buf++ = '?';
		      nchars++;
		      src++;
		    }
652
		}
653 654 655
	    }
	  else
	    {
656 657 658
	      if (! STRING_MULTIBYTE (string))
		string = string_to_multibyte (string);
	      nbytes = buf - encode_terminal_src;
659
	      if (encode_terminal_src_size < nbytes + SBYTES (string))
660
		{
661 662 663 664
		  encode_terminal_src_size = nbytes + SBYTES (string);
		  encode_terminal_src = xrealloc (encode_terminal_src,
						  encode_terminal_src_size);
		  buf = encode_terminal_src + nbytes;
665
		}
666
	      memcpy (buf, SDATA (string), SBYTES (string));
667 668
	      buf += SBYTES (string);
	      nchars += SCHARS (string);
669
	    }
Karl Heuer's avatar
Karl Heuer committed
670
	}
671 672 673 674 675 676 677
      src++;
    }

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

680 681 682
  nbytes = buf - encode_terminal_src;
  coding->source = encode_terminal_src;
  if (encode_terminal_dst_size == 0)
683
    {
684
      encode_terminal_dst_size = encode_terminal_src_size;
685 686 687 688 689
      if (encode_terminal_dst)
	encode_terminal_dst = xrealloc (encode_terminal_dst,
					encode_terminal_dst_size);
      else
	encode_terminal_dst = xmalloc (encode_terminal_dst_size);
690
    }
691 692 693
  coding->destination = encode_terminal_dst;
  coding->dst_bytes = encode_terminal_dst_size;
  encode_coding_object (coding, Qnil, 0, 0, nchars, nbytes, Qnil);
694
  /* coding->destination may have been reallocated.  */
695 696
  encode_terminal_dst = coding->destination;
  encode_terminal_dst_size = coding->dst_bytes;
697

698
  return (encode_terminal_dst);
Karl Heuer's avatar
Karl Heuer committed
699 700
}

Jim Blandy's avatar
Jim Blandy committed
701

Miles Bader's avatar
Miles Bader committed
702

703 704
/* An implementation of write_glyphs for termcap frames. */

705
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
706
tty_write_glyphs (struct frame *f, struct glyph *string, int len)
Jim Blandy's avatar
Jim Blandy committed
707
{
708 709
  unsigned char *conversion_buffer;
  struct coding_system *coding;
Jim Blandy's avatar
Jim Blandy committed
710

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

713
  tty_turn_off_insert (tty);
714
  tty_hide_cursor (tty);
Jim Blandy's avatar
Jim Blandy committed
715

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

719 720 721
  if (AutoWrap (tty)
      && curY (tty) + 1 == FRAME_LINES (f)
      && (curX (tty) + len) == FRAME_COLS (f))
Jim Blandy's avatar
Jim Blandy committed
722
    len --;
Karl Heuer's avatar
Karl Heuer committed
723 724
  if (len <= 0)
    return;
Jim Blandy's avatar
Jim Blandy committed
725

726
  cmplus (tty, len);
727

728 729 730
  /* If terminal_coding does any conversion, use it, otherwise use
     safe_terminal_coding.  We can't use CODING_REQUIRE_ENCODING here
     because it always return 1 if the member src_multibyte is 1.  */
731 732
  coding = (FRAME_TERMINAL_CODING (f)->common_flags & CODING_REQUIRE_ENCODING_MASK
	    ? FRAME_TERMINAL_CODING (f) : &safe_terminal_coding);
733 734
  /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
     the tail.  */
735
  coding->mode &= ~CODING_MODE_LAST_BLOCK;
736

Karl Heuer's avatar
Karl Heuer committed
737
  while (len > 0)
Jim Blandy's avatar
Jim Blandy committed
738
    {
Gerd Moellmann's avatar
Gerd Moellmann committed
739
      /* Identify a run of glyphs with the same face.  */
740
      int face_id = string->face_id;
Gerd Moellmann's avatar
Gerd Moellmann committed
741
      int n;
742

Gerd Moellmann's avatar
Gerd Moellmann committed
743
      for (n = 1; n < len; ++n)
744
	if (string[n].face_id != face_id)
Gerd Moellmann's avatar
Gerd Moellmann committed
745 746 747
	  break;

      /* Turn appearance modes of the face of the run on.  */
748
      tty_highlight_if_desired (tty);
Gerd Moellmann's avatar
Gerd Moellmann committed
749 750
      turn_on_face (f, face_id);