term.c 108 KB
Newer Older
1
/* Terminal control module for terminals described by TERMCAP
2
   Copyright (C) 1985, 1986, 1987, 1993, 1994, 1995, 1998, 2000, 2001,
Glenn Morris's avatar
Glenn Morris committed
3
                 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
Glenn Morris's avatar
Glenn Morris committed
4
                 Free Software Foundation, Inc.
Jim Blandy's avatar
Jim Blandy committed
5 6 7

This file is part of GNU Emacs.

8
GNU Emacs is free software: you can redistribute it and/or modify
Jim Blandy's avatar
Jim Blandy committed
9
it under the terms of the GNU General Public License as published by
10 11
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Jim Blandy's avatar
Jim Blandy committed
12 13 14 15 16 17 18

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
19
along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
Jim Blandy's avatar
Jim Blandy committed
20

21
/* New redisplay, TTY faces by Gerd Moellmann <gerd@gnu.org>.  */
Jim Blandy's avatar
Jim Blandy committed
22

23
#include <config.h>
Jim Blandy's avatar
Jim Blandy committed
24 25
#include <stdio.h>
#include <ctype.h>
26
#include <errno.h>
27
#include <sys/file.h>
Miles Bader's avatar
Miles Bader committed
28

29
#ifdef HAVE_UNISTD_H
30
#include <unistd.h>
31
#endif
32

33
#include <signal.h>
Dan Nicolaescu's avatar
Dan Nicolaescu committed
34
#include <stdarg.h>
35
#include <setjmp.h>
36

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

61 62 63
/* 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.  */
64 65 66 67
extern void tputs (const char *, int, int (*)(int));
extern int tgetent (char *, const char *);
extern int tgetflag (char *id);
extern int tgetnum (char *id);
68

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

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

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

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

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

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

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

113
#define OUTPUT_IF(tty, a)                                               \
114 115 116 117 118 119 120
  do {                                                                  \
    if (a)                                                              \
      emacs_tputs ((tty), a,                                            \
                   (int) (FRAME_LINES (XFRAME (selected_frame))         \
                          - curY (tty) ),                               \
                   cmputc);                                             \
  } while (0)
121

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

124 125 126 127
/* If true, use "vs", otherwise use "ve" to make the cursor visible.  */

static int visible_cursor;

128
/* Display space properties */
Jim Blandy's avatar
Jim Blandy committed
129

130
/* Functions to call after suspending a tty. */
131
Lisp_Object Vsuspend_tty_functions;
Jim Blandy's avatar
Jim Blandy committed
132

133
/* Functions to call after resuming a tty. */
134
Lisp_Object Vresume_tty_functions;
Jim Blandy's avatar
Jim Blandy committed
135

136
/* Chain of all tty device parameters. */
137
struct tty_display_info *tty_list;
Jim Blandy's avatar
Jim Blandy committed
138

139 140 141 142
/* Nonzero means no need to redraw the entire frame on resuming a
   suspended Emacs.  This is useful on terminals with multiple
   pages, where one page is used for Emacs and another for all
   else. */
Jim Blandy's avatar
Jim Blandy committed
143
int no_redraw_on_reenter;
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160

/* 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
161 162
/* internal state */

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

165
int max_frame_cols;
Gerd Moellmann's avatar
Gerd Moellmann committed
166

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

169
int max_frame_lines;
170

171 172 173
/* 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
174

175
/* Provided for lisp packages.  */
Gerd Moellmann's avatar
Gerd Moellmann committed
176

177 178
static int system_uses_terminfo;

179
char *tparam (char *, char *, int, int, ...);
180

181
extern char *tgetstr (char *, char **);
Jim Blandy's avatar
Jim Blandy committed
182

183

184
#ifdef HAVE_GPM
185 186
#include <sys/fcntl.h>

187 188
/* The device for which we have enabled gpm support (or NULL).  */
struct tty_display_info *gpm_tty = NULL;
189

190
/* Last recorded mouse coordinates.  */
191
static int last_mouse_x, last_mouse_y;
192
#endif /* HAVE_GPM */
193

194
/* Ring the bell on a tty. */
195

196
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
197
tty_ring_bell (struct frame *f)
198 199
{
  struct tty_display_info *tty = FRAME_TTY (f);
200

201 202 203 204 205 206
  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
207 208 209
    }
}

210 211
/* Set up termcap modes for Emacs. */

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

217
  if (tty->output)
Jim Blandy's avatar
Jim Blandy committed
218
    {
219 220
      if (tty->TS_termcap_modes)
        OUTPUT (tty, tty->TS_termcap_modes);
221
      else
222 223 224 225
        {
          /* Output enough newlines to scroll all the old screen contents
             off the screen, so it won't be overwritten and lost.  */
          int i;
226
          current_tty = tty;
227
          for (i = 0; i < FRAME_LINES (XFRAME (selected_frame)); i++)
228
            cmputc ('\n');
229 230
        }

231
      OUTPUT_IF (tty, visible_cursor ? tty->TS_cursor_visible : tty->TS_cursor_normal);
232 233
      OUTPUT_IF (tty, tty->TS_keypad_mode);
      losecursor (tty);
234
      fflush (tty->output);
Jim Blandy's avatar
Jim Blandy committed
235 236 237
    }
}

238 239
/* Reset termcap modes before exiting Emacs. */

Andreas Schwab's avatar
Andreas Schwab committed
240
void
241
tty_reset_terminal_modes (struct terminal *terminal)
Jim Blandy's avatar
Jim Blandy committed
242
{
243
  struct tty_display_info *tty = terminal->display_info.tty;
244 245

  if (tty->output)
Jim Blandy's avatar
Jim Blandy committed
246
    {
247 248
      tty_turn_off_highlight (tty);
      tty_turn_off_insert (tty);
249 250 251 252
      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);
253
      /* Output raw CR so kernel can track the cursor hpos.  */
254
      current_tty = tty;
255
      cmputc ('\r');
256
      fflush (tty->output);
Jim Blandy's avatar
Jim Blandy committed
257 258 259
    }
}

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

262
static void
263
tty_update_end (struct frame *f)
Jim Blandy's avatar
Jim Blandy committed
264
{
265
  struct tty_display_info *tty = FRAME_TTY (f);
266

267 268
  if (!XWINDOW (selected_window)->cursor_off_p)
    tty_show_cursor (tty);
269 270
  tty_turn_off_insert (tty);
  tty_background_highlight (tty);
Jim Blandy's avatar
Jim Blandy committed
271 272
}

273 274
/* The implementation of set_terminal_window for termcap frames. */

275
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
276
tty_set_terminal_window (struct frame *f, int size)
Jim Blandy's avatar
Jim Blandy committed
277
{
278 279 280 281
  struct tty_display_info *tty = FRAME_TTY (f);

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

285 286
static void
tty_set_scroll_region (struct frame *f, int start, int stop)
Jim Blandy's avatar
Jim Blandy committed
287 288
{
  char *buf;
289
  struct tty_display_info *tty = FRAME_TTY (f);
290

291 292 293 294
  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,
295 296 297
		  FRAME_LINES (f), start,
		  FRAME_LINES (f) - stop,
		  FRAME_LINES (f));
Jim Blandy's avatar
Jim Blandy committed
298
  else
299
    buf = tparam (tty->TS_set_window, 0, 0, start, 0, stop, FRAME_COLS (f));
300

301
  OUTPUT (tty, buf);
302
  xfree (buf);
303
  losecursor (tty);
Jim Blandy's avatar
Jim Blandy committed
304
}
305

Jim Blandy's avatar
Jim Blandy committed
306

307
static void
308
tty_turn_on_insert (struct tty_display_info *tty)
Jim Blandy's avatar
Jim Blandy committed
309
{
310 311 312
  if (!tty->insert_mode)
    OUTPUT (tty, tty->TS_insert_mode);
  tty->insert_mode = 1;
Jim Blandy's avatar
Jim Blandy committed
313 314
}

Andreas Schwab's avatar
Andreas Schwab committed
315
void
316
tty_turn_off_insert (struct tty_display_info *tty)
Jim Blandy's avatar
Jim Blandy committed
317
{
318 319 320
  if (tty->insert_mode)
    OUTPUT (tty, tty->TS_end_insert_mode);
  tty->insert_mode = 0;
Jim Blandy's avatar
Jim Blandy committed
321 322
}

323
/* Handle highlighting.  */
Jim Blandy's avatar
Jim Blandy committed
324

Andreas Schwab's avatar
Andreas Schwab committed
325
void
326
tty_turn_off_highlight (struct tty_display_info *tty)
Jim Blandy's avatar
Jim Blandy committed
327
{
328 329 330
  if (tty->standout_mode)
    OUTPUT_IF (tty, tty->TS_end_standout_mode);
  tty->standout_mode = 0;
Jim Blandy's avatar
Jim Blandy committed
331 332
}

333
static void
334
tty_turn_on_highlight (struct tty_display_info *tty)
Jim Blandy's avatar
Jim Blandy committed
335
{
336 337 338
  if (!tty->standout_mode)
    OUTPUT_IF (tty, tty->TS_standout_mode);
  tty->standout_mode = 1;
Jim Blandy's avatar
Jim Blandy committed
339 340
}

341
static void
342
tty_toggle_highlight (struct tty_display_info *tty)
343
{
344
  if (tty->standout_mode)
345
    tty_turn_off_highlight (tty);
346
  else
347
    tty_turn_on_highlight (tty);
348 349
}

Gerd Moellmann's avatar
Gerd Moellmann committed
350 351 352 353

/* Make cursor invisible.  */

static void
354
tty_hide_cursor (struct tty_display_info *tty)
Gerd Moellmann's avatar
Gerd Moellmann committed
355
{
356
  if (tty->cursor_hidden == 0)
357
    {
358 359
      tty->cursor_hidden = 1;
      OUTPUT_IF (tty, tty->TS_cursor_invisible);
360
    }
Gerd Moellmann's avatar
Gerd Moellmann committed
361 362 363 364 365 366
}


/* Ensure that cursor is visible.  */

static void
367
tty_show_cursor (struct tty_display_info *tty)
Gerd Moellmann's avatar
Gerd Moellmann committed
368
{
369
  if (tty->cursor_hidden)
370
    {
371 372
      tty->cursor_hidden = 0;
      OUTPUT_IF (tty, tty->TS_cursor_normal);
373
      if (visible_cursor)
374
        OUTPUT_IF (tty, tty->TS_cursor_visible);
375
    }
Gerd Moellmann's avatar
Gerd Moellmann committed
376 377 378
}


Jim Blandy's avatar
Jim Blandy committed
379 380 381 382
/* 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.  */

383 384
static void
tty_background_highlight (struct tty_display_info *tty)
Jim Blandy's avatar
Jim Blandy committed
385 386
{
  if (inverse_video)
387
    tty_turn_on_highlight (tty);
Jim Blandy's avatar
Jim Blandy committed
388
  else
389
    tty_turn_off_highlight (tty);
Jim Blandy's avatar
Jim Blandy committed
390 391 392 393
}

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

Andreas Schwab's avatar
Andreas Schwab committed
394
static void
395
tty_highlight_if_desired (struct tty_display_info *tty)
Jim Blandy's avatar
Jim Blandy committed
396
{
397
  if (inverse_video)
398
    tty_turn_on_highlight (tty);
399
  else
400
    tty_turn_off_highlight (tty);
Jim Blandy's avatar
Jim Blandy committed
401 402 403
}


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

407
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
408
tty_cursor_to (struct frame *f, int vpos, int hpos)
Jim Blandy's avatar
Jim Blandy committed
409
{
410
  struct tty_display_info *tty = FRAME_TTY (f);
Jim Blandy's avatar
Jim Blandy committed
411

412 413
  /* Detect the case where we are called from reset_sys_modes
     and the costs have never been calculated.  Do nothing.  */
414
  if (! tty->costs_set)
415 416
    return;

417 418
  if (curY (tty) == vpos
      && curX (tty) == hpos)
Jim Blandy's avatar
Jim Blandy committed
419
    return;
420
  if (!tty->TF_standout_motion)
421
    tty_background_highlight (tty);
422
  if (!tty->TF_insmode_motion)
423
    tty_turn_off_insert (tty);
424
  cmgoto (tty, vpos, hpos);
Jim Blandy's avatar
Jim Blandy committed
425 426 427 428
}

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

429
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
430
tty_raw_cursor_to (struct frame *f, int row, int col)
Jim Blandy's avatar
Jim Blandy committed
431
{
432 433
  struct tty_display_info *tty = FRAME_TTY (f);

434 435
  if (curY (tty) == row
      && curX (tty) == col)
Jim Blandy's avatar
Jim Blandy committed
436
    return;
437
  if (!tty->TF_standout_motion)
438
    tty_background_highlight (tty);
439
  if (!tty->TF_insmode_motion)
440
    tty_turn_off_insert (tty);
441
  cmgoto (tty, row, col);
Jim Blandy's avatar
Jim Blandy committed
442 443 444 445
}

/* Erase operations */

446 447
/* Clear from cursor to end of frame on a termcap device. */

448
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
449
tty_clear_to_end (struct frame *f)
Jim Blandy's avatar
Jim Blandy committed
450 451
{
  register int i;
452
  struct tty_display_info *tty = FRAME_TTY (f);
Jim Blandy's avatar
Jim Blandy committed
453

454
  if (tty->TS_clr_to_bottom)
Jim Blandy's avatar
Jim Blandy committed
455
    {
456
      tty_background_highlight (tty);
457
      OUTPUT (tty, tty->TS_clr_to_bottom);
Jim Blandy's avatar
Jim Blandy committed
458 459 460
    }
  else
    {
461
      for (i = curY (tty); i < FRAME_LINES (f); i++)
Jim Blandy's avatar
Jim Blandy committed
462
	{
Karoly Lorentey's avatar
Karoly Lorentey committed
463 464
	  cursor_to (f, i, 0);
	  clear_end_of_line (f, FRAME_COLS (f));
Jim Blandy's avatar
Jim Blandy committed
465 466 467 468
	}
    }
}

469
/* Clear an entire termcap frame. */
Jim Blandy's avatar
Jim Blandy committed
470

471
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
472
tty_clear_frame (struct frame *f)
Jim Blandy's avatar
Jim Blandy committed
473
{
474
  struct tty_display_info *tty = FRAME_TTY (f);
475

476
  if (tty->TS_clr_frame)
Jim Blandy's avatar
Jim Blandy committed
477
    {
478
      tty_background_highlight (tty);
479
      OUTPUT (tty, tty->TS_clr_frame);
480
      cmat (tty, 0, 0);
Jim Blandy's avatar
Jim Blandy committed
481 482 483
    }
  else
    {
Karoly Lorentey's avatar
Karoly Lorentey committed
484 485
      cursor_to (f, 0, 0);
      clear_to_end (f);
Jim Blandy's avatar
Jim Blandy committed
486 487 488
    }
}

489
/* An implementation of clear_end_of_line for termcap frames.
Jim Blandy's avatar
Jim Blandy committed
490 491 492

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

493
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
494
tty_clear_end_of_line (struct frame *f, int first_unused_hpos)
Jim Blandy's avatar
Jim Blandy committed
495 496
{
  register int i;
497
  struct tty_display_info *tty = FRAME_TTY (f);
Jim Blandy's avatar
Jim Blandy committed
498

499 500
  /* Detect the case where we are called from reset_sys_modes
     and the costs have never been calculated.  Do nothing.  */
501
  if (! tty->costs_set)
502 503
    return;

504
  if (curX (tty) >= first_unused_hpos)
Jim Blandy's avatar
Jim Blandy committed
505
    return;
506
  tty_background_highlight (tty);
507
  if (tty->TS_clr_line)
Jim Blandy's avatar
Jim Blandy committed
508
    {
509
      OUTPUT1 (tty, tty->TS_clr_line);
Jim Blandy's avatar
Jim Blandy committed
510 511 512
    }
  else
    {			/* have to do it the hard way */
513
      tty_turn_off_insert (tty);
Jim Blandy's avatar
Jim Blandy committed
514

Gerd Moellmann's avatar
Gerd Moellmann committed
515
      /* Do not write in last row last col with Auto-wrap on. */
516
      if (AutoWrap (tty)
Karoly Lorentey's avatar
Karoly Lorentey committed
517 518
          && curY (tty) == FrameRows (tty) - 1
	  && first_unused_hpos == FrameCols (tty))
Jim Blandy's avatar
Jim Blandy committed
519 520
	first_unused_hpos--;

521
      for (i = curX (tty); i < first_unused_hpos; i++)
Jim Blandy's avatar
Jim Blandy committed
522
	{
523 524 525
	  if (tty->termscript)
	    fputc (' ', tty->termscript);
	  fputc (' ', tty->output);
Jim Blandy's avatar
Jim Blandy committed
526
	}
527
      cmplus (tty, first_unused_hpos - curX (tty));
Jim Blandy's avatar
Jim Blandy committed
528 529 530
    }
}

531 532 533 534 535 536 537 538 539 540 541 542
/* 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 *
543
encode_terminal_code (struct glyph *src, int src_len, struct coding_system *coding)
Karl Heuer's avatar
Karl Heuer committed
544
{
545
  struct glyph *src_end = src + src_len;
546 547
  unsigned char *buf;
  int nchars, nbytes, required;
Karl Heuer's avatar
Karl Heuer committed
548 549
  register int tlen = GLYPH_TABLE_LENGTH;
  register Lisp_Object *tbase = GLYPH_TABLE_BASE;
550
  Lisp_Object charset_list;
551

552 553
  /* 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
554 555
     Vglyph_table contains a string or a composite glyph is
     encountered.  */
556 557 558
  required = MAX_MULTIBYTE_LENGTH * src_len;
  if (encode_terminal_src_size < required)
    {
559
      if (encode_terminal_src)
560
	encode_terminal_src = xrealloc (encode_terminal_src, required);
561 562
      else
	encode_terminal_src = xmalloc (required);
563 564
      encode_terminal_src_size = required;
    }
565

566
  charset_list = coding_charset_list (coding);
Karl Heuer's avatar
Karl Heuer committed
567

568 569 570
  buf = encode_terminal_src;
  nchars = 0;
  while (src < src_end)
Karl Heuer's avatar
Karl Heuer committed
571
    {
Kenichi Handa's avatar
Kenichi Handa committed
572 573
      if (src->type == COMPOSITE_GLYPH)
	{
574 575
	  struct composition *cmp;
	  Lisp_Object gstring;
Kenichi Handa's avatar
Kenichi Handa committed
576 577 578
	  int i;

	  nbytes = buf - encode_terminal_src;
579 580 581
	  if (src->u.cmp.automatic)
	    {
	      gstring = composition_gstring_from_id (src->u.cmp.id);
582
	      required = src->slice.cmp.to + 1 - src->slice.cmp.from;
583 584 585 586 587 588
	    }
	  else
	    {
	      cmp = composition_table[src->u.cmp.id];
	      required = MAX_MULTIBYTE_LENGTH * cmp->glyph_len;
	    }
Kenichi Handa's avatar
Kenichi Handa committed
589 590 591 592 593 594 595 596 597

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

598
	  if (src->u.cmp.automatic)
599
	    for (i = src->slice.cmp.from; i <= src->slice.cmp.to; i++)
600 601 602 603 604
	      {
		Lisp_Object g = LGSTRING_GLYPH (gstring, i);
		int c = LGLYPH_CHAR (g);

		if (! char_charset (c, charset_list, NULL))
605
		  c = '?';
606 607 608 609 610 611 612 613
		buf += CHAR_STRING (c, buf);
		nchars++;
	      }
	  else
	    for (i = 0; i < cmp->glyph_len; i++)
	      {
		int c = COMPOSITION_GLYPH (cmp, i);

614 615 616 617 618 619 620 621 622 623 624 625 626 627
		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 = '?';
628 629 630
		buf += CHAR_STRING (c, buf);
		nchars++;
	      }
Kenichi Handa's avatar
Kenichi Handa committed
631
	}
Karl Heuer's avatar
Karl Heuer committed
632
      /* We must skip glyphs to be padded for a wide character.  */
Kenichi Handa's avatar
Kenichi Handa committed
633
      else if (! CHAR_GLYPH_PADDING_P (*src))
Karl Heuer's avatar
Karl Heuer committed
634
	{
635
	  GLYPH g;
636 637 638
	  int c;
	  Lisp_Object string;

639
	  string = Qnil;
640
	  SET_GLYPH_FROM_CHAR_GLYPH (g, src[0]);
641

642
	  if (GLYPH_INVALID_P (g) || GLYPH_SIMPLE_P (tbase, tlen, g))
643
	    {
644
	      /* This glyph doesn't have an entry in Vglyph_table.  */
645 646
	      c = src->u.ch;
	    }
647
	  else
Karl Heuer's avatar
Karl Heuer committed
648
	    {
649
	      /* This glyph has an entry in Vglyph_table,
Karl Heuer's avatar
Karl Heuer committed
650 651
		 so process any alias before testing for simpleness.  */
	      GLYPH_FOLLOW_ALIASES (tbase, tlen, g);
652 653

	      if (GLYPH_SIMPLE_P (tbase, tlen, g))
654 655
		/* We set the multi-byte form of a character in G
		   (that should be an ASCII character) at WORKBUF.  */
656
		c = GLYPH_CHAR (g);
657
	      else
658
		/* We have a string in Vglyph_table.  */
659
		string = tbase[GLYPH_CHAR (g)];
Richard M. Stallman's avatar
Richard M. Stallman committed
660
	    }
661

662
	  if (NILP (string))
663
	    {
Kenichi Handa's avatar
Kenichi Handa committed
664 665 666 667 668 669 670 671
	      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;
		}
672 673
	      if (CHAR_BYTE8_P (c)
		  || char_charset (c, charset_list, NULL))
674
		{
675 676 677
		  /* Store the multibyte form of C at BUF.  */
		  buf += CHAR_STRING (c, buf);
		  nchars++;
678 679 680
		}
	      else
		{
681 682
		  /* C is not encodable.  */
		  *buf++ = '?';
683
		  nchars++;
684 685 686 687 688 689
		  while (src + 1 < src_end && CHAR_GLYPH_PADDING_P (src[1]))
		    {
		      *buf++ = '?';
		      nchars++;
		      src++;
		    }
690
		}
691 692 693
	    }
	  else
	    {
694
	      unsigned char *p = SDATA (string);
695 696 697 698

	      if (! STRING_MULTIBYTE (string))
		string = string_to_multibyte (string);
	      nbytes = buf - encode_terminal_src;
699
	      if (encode_terminal_src_size < nbytes + SBYTES (string))
700
		{
701 702 703 704
		  encode_terminal_src_size = nbytes + SBYTES (string);
		  encode_terminal_src = xrealloc (encode_terminal_src,
						  encode_terminal_src_size);
		  buf = encode_terminal_src + nbytes;
705
		}
706
	      memcpy (buf, SDATA (string), SBYTES (string));
707 708
	      buf += SBYTES (string);
	      nchars += SCHARS (string);
709
	    }
Karl Heuer's avatar
Karl Heuer committed
710
	}
711 712 713 714 715 716 717
      src++;
    }

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

720 721 722
  nbytes = buf - encode_terminal_src;
  coding->source = encode_terminal_src;
  if (encode_terminal_dst_size == 0)
723
    {
724
      encode_terminal_dst_size = encode_terminal_src_size;
725 726 727 728 729
      if (encode_terminal_dst)
	encode_terminal_dst = xrealloc (encode_terminal_dst,
					encode_terminal_dst_size);
      else
	encode_terminal_dst = xmalloc (encode_terminal_dst_size);
730
    }
731 732 733
  coding->destination = encode_terminal_dst;
  coding->dst_bytes = encode_terminal_dst_size;
  encode_coding_object (coding, Qnil, 0, 0, nchars, nbytes, Qnil);
734
  /* coding->destination may have been reallocated.  */
735 736
  encode_terminal_dst = coding->destination;
  encode_terminal_dst_size = coding->dst_bytes;
737

738
  return (encode_terminal_dst);
Karl Heuer's avatar
Karl Heuer committed
739 740
}

Jim Blandy's avatar
Jim Blandy committed
741

Miles Bader's avatar
Miles Bader committed
742

743 744
/* An implementation of write_glyphs for termcap frames. */

745
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
746
tty_write_glyphs (struct frame *f, struct glyph *string, int len)
Jim Blandy's avatar
Jim Blandy committed
747
{
748 749
  unsigned char *conversion_buffer;
  struct coding_system *coding;
Jim Blandy's avatar
Jim Blandy committed
750

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

753
  tty_turn_off_insert (tty);
754
  tty_hide_cursor (tty);
Jim Blandy's avatar
Jim Blandy committed
755

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

759 760 761
  if (AutoWrap (tty)
      && curY (tty) + 1 == FRAME_LINES (f)
      && (curX (tty) + len) == FRAME_COLS (f))