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

56 57 58
/* For now, don't try to include termcap.h.  On some systems,
   configure finds a non-standard termcap.h that the main build
   won't find.  */
59 60 61 62
extern void tputs (const char *, int, int (*)(int));
extern int tgetent (char *, const char *);
extern int tgetflag (char *id);
extern int tgetnum (char *id);
63

64 65 66 67
char *tparam (char *, char *, int, int, ...);

extern char *tgetstr (char *, char **);

68
#include "cm.h"
Andreas Schwab's avatar
Andreas Schwab committed
69 70 71
#ifdef HAVE_X_WINDOWS
#include "xterm.h"
#endif
Karl Heuer's avatar
Karl Heuer committed
72

73 74 75
#ifndef O_RDWR
#define O_RDWR 2
#endif
Kenichi Handa's avatar
Kenichi Handa committed
76

77 78 79
#ifndef O_NOCTTY
#define O_NOCTTY 0
#endif
Kenichi Handa's avatar
Kenichi Handa committed
80

81 82 83 84 85 86
/* 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
87

88 89 90 91 92 93 94 95 96 97
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 *);
98 99 100 101
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
102

103 104 105 106 107 108
#define OUTPUT(tty, a)                                          \
  emacs_tputs ((tty), a,                                        \
               (int) (FRAME_LINES (XFRAME (selected_frame))     \
                      - curY (tty)),                            \
               cmputc)

109 110
#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
111

112
#define OUTPUT_IF(tty, a)                                               \
113 114
  do {                                                                  \
    if (a)                                                              \
115
      OUTPUT (tty, a);							\
116
  } while (0)
117

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

120
/* Display space properties */
Jim Blandy's avatar
Jim Blandy committed
121

122
/* Chain of all tty device parameters. */
123
struct tty_display_info *tty_list;
Jim Blandy's avatar
Jim Blandy committed
124

125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
/* 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
141 142
/* internal state */

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

145
int max_frame_cols;
Gerd Moellmann's avatar
Gerd Moellmann committed
146

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

149
int max_frame_lines;
150

151 152 153
/* 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
154 155


156

157
#ifdef HAVE_GPM
158 159
#include <sys/fcntl.h>

160 161
/* The device for which we have enabled gpm support (or NULL).  */
struct tty_display_info *gpm_tty = NULL;
162

163
/* Last recorded mouse coordinates.  */
164
static int last_mouse_x, last_mouse_y;
165
#endif /* HAVE_GPM */
166

167
/* Ring the bell on a tty. */
168

169
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
170
tty_ring_bell (struct frame *f)
171 172
{
  struct tty_display_info *tty = FRAME_TTY (f);
173

174 175 176 177 178 179
  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
180 181 182
    }
}

183 184
/* Set up termcap modes for Emacs. */

Andreas Schwab's avatar
Andreas Schwab committed
185
void
186
tty_set_terminal_modes (struct terminal *terminal)
Jim Blandy's avatar
Jim Blandy committed
187
{
188
  struct tty_display_info *tty = terminal->display_info.tty;
189

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

204
      OUTPUT_IF (tty, visible_cursor ? tty->TS_cursor_visible : tty->TS_cursor_normal);
205 206
      OUTPUT_IF (tty, tty->TS_keypad_mode);
      losecursor (tty);
207
      fflush (tty->output);
Jim Blandy's avatar
Jim Blandy committed
208 209 210
    }
}

211 212
/* Reset termcap modes before exiting Emacs. */

Andreas Schwab's avatar
Andreas Schwab committed
213
void
214
tty_reset_terminal_modes (struct terminal *terminal)
Jim Blandy's avatar
Jim Blandy committed
215
{
216
  struct tty_display_info *tty = terminal->display_info.tty;
217 218

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

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

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

240 241
  if (!XWINDOW (selected_window)->cursor_off_p)
    tty_show_cursor (tty);
242 243
  tty_turn_off_insert (tty);
  tty_background_highlight (tty);
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 253 254
  struct tty_display_info *tty = FRAME_TTY (f);

  tty->specified_window = size ? size : FRAME_LINES (f);
  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 265 266 267
  if (tty->TS_set_scroll_region)
    buf = tparam (tty->TS_set_scroll_region, 0, 0, start, stop - 1);
  else if (tty->TS_set_scroll_region_1)
    buf = tparam (tty->TS_set_scroll_region_1, 0, 0,
268 269 270
		  FRAME_LINES (f), start,
		  FRAME_LINES (f) - stop,
		  FRAME_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

Andreas Schwab's avatar
Andreas Schwab committed
298
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 332
      tty->cursor_hidden = 1;
      OUTPUT_IF (tty, tty->TS_cursor_invisible);
333
    }
Gerd Moellmann's avatar
Gerd Moellmann committed
334 335 336 337 338 339
}


/* Ensure that cursor is visible.  */

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


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

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

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

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

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

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

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

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

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

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

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

419 420
/* Clear from cursor to end of frame on a termcap device. */

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

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

442
/* Clear an entire termcap frame. */
Jim Blandy's avatar
Jim Blandy committed
443

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

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

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

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

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

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

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

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

494
      for (i = curX (tty); i < first_unused_hpos; i++)
Jim Blandy's avatar
Jim Blandy committed
495
	{
496 497 498
	  if (tty->termscript)
	    fputc (' ', tty->termscript);
	  fputc (' ', tty->output);
Jim Blandy's avatar
Jim Blandy committed
499
	}
500
      cmplus (tty, first_unused_hpos - curX (tty));
Jim Blandy's avatar
Jim Blandy committed
501 502 503
    }
}

504 505 506 507 508 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.  */
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.  */

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

525 526
  /* 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
527 528
     Vglyph_table contains a string or a composite glyph is
     encountered.  */
529 530 531
  required = MAX_MULTIBYTE_LENGTH * src_len;
  if (encode_terminal_src_size < required)
    {
532
      if (encode_terminal_src)
533
	encode_terminal_src = xrealloc (encode_terminal_src, required);
534 535
      else
	encode_terminal_src = xmalloc (required);
536 537
      encode_terminal_src_size = required;
    }
538

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

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

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

	  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;
	    }

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

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

587 588 589 590 591 592 593 594 595 596 597 598 599 600
		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 = '?';
601 602 603
		buf += CHAR_STRING (c, buf);
		nchars++;
	      }
Kenichi Handa's avatar
Kenichi Handa committed
604
	}
Karl Heuer's avatar
Karl Heuer committed
605
      /* We must skip glyphs to be padded for a wide character.  */
Kenichi Handa's avatar
Kenichi Handa committed
606
      else if (! CHAR_GLYPH_PADDING_P (*src))
Karl Heuer's avatar
Karl Heuer committed
607
	{
608
	  GLYPH g;
609 610 611
	  int c;
	  Lisp_Object string;

612
	  string = Qnil;
613
	  SET_GLYPH_FROM_CHAR_GLYPH (g, src[0]);
614

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

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

635
	  if (NILP (string))
636
	    {
Kenichi Handa's avatar
Kenichi Handa committed
637 638 639 640 641 642 643 644
	      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;
		}
645 646
	      if (CHAR_BYTE8_P (c)
		  || char_charset (c, charset_list, NULL))
647
		{
648 649 650
		  /* Store the multibyte form of C at BUF.  */
		  buf += CHAR_STRING (c, buf);
		  nchars++;
651 652 653
		}
	      else
		{
654 655
		  /* C is not encodable.  */
		  *buf++ = '?';
656
		  nchars++;
657 658 659 660 661 662
		  while (src + 1 < src_end && CHAR_GLYPH_PADDING_P (src[1]))
		    {
		      *buf++ = '?';
		      nchars++;
		      src++;
		    }
663
		}
664 665 666
	    }
	  else
	    {
667
	      unsigned char *p = SDATA (string);
668 669 670 671

	      if (! STRING_MULTIBYTE (string))
		string = string_to_multibyte (string);
	      nbytes = buf - encode_terminal_src;
672
	      if (encode_terminal_src_size < nbytes + SBYTES (string))
673
		{
674 675 676 677
		  encode_terminal_src_size = nbytes + SBYTES (string);
		  encode_terminal_src = xrealloc (encode_terminal_src,
						  encode_terminal_src_size);
		  buf = encode_terminal_src + nbytes;
678
		}
679
	      memcpy (buf, SDATA (string), SBYTES (string));
680 681
	      buf += SBYTES (string);
	      nchars += SCHARS (string);
682
	    }
Karl Heuer's avatar
Karl Heuer committed
683
	}
684 685 686 687 688 689 690
      src++;
    }

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

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

711
  return (encode_terminal_dst);
Karl Heuer's avatar
Karl Heuer committed
712 713
}

Jim Blandy's avatar
Jim Blandy committed
714

Miles Bader's avatar
Miles Bader committed
715

716 717
/* An implementation of write_glyphs for termcap frames. */

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

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

726
  tty_turn_off_insert (tty);
727
  tty_hide_cursor (tty);
Jim Blandy's avatar
Jim Blandy committed
728

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

732 733 734
  if (AutoWrap (tty)
      && curY (tty) + 1 == FRAME_LINES (f)
      && (curX (tty) + len) == FRAME_COLS (f))
Jim Blandy's avatar
Jim Blandy committed
735
    len --;
Karl Heuer's avatar
Karl Heuer committed
736 737
  if (len <= 0)
    return;
Jim Blandy's avatar
Jim Blandy committed
738

739
  cmplus (tty, len);
740

741 742 743
  /* 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.  */
744 745
  coding = (FRAME_TERMINAL_CODING (f)->common_flags & CODING_REQUIRE_ENCODING_MASK
	    ? FRAME_TERMINAL_CODING (f) : &safe_terminal_coding);
746 747
  /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
     the tail.  */
748
  coding->mode &= ~CODING_MODE_LAST_BLOCK;
749

Karl Heuer's avatar
Karl Heuer committed
750
  while (len > 0)
Jim Blandy's avatar
Jim Blandy committed
751
    {
Gerd Moellmann's avatar
Gerd Moellmann committed
752
      /* Identify a run of glyphs with the same face.  */
753
      int face_id = string->face_id;
Gerd Moellmann's avatar
Gerd Moellmann committed
754
      int n;
755

Gerd Moellmann's avatar
Gerd Moellmann committed
756
      for (n = 1; n < len; ++n)
757
	if (string[n].face_id != face_id)