term.c 113 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
static void term_clear_mouse_face (void);
188 189
static void term_mouse_highlight (struct frame *f, int x, int y);

190 191
/* The device for which we have enabled gpm support (or NULL).  */
struct tty_display_info *gpm_tty = NULL;
192 193 194 195 196 197 198 199 200

/* These variables describe the range of text currently shown in its
   mouse-face, together with the window they apply to.  As long as
   the mouse stays within this range, we need not redraw anything on
   its account.  Rows and columns are glyph matrix positions in
   MOUSE_FACE_WINDOW.  */
static int mouse_face_beg_row, mouse_face_beg_col;
static int mouse_face_end_row, mouse_face_end_col;
static int mouse_face_past_end;
201
static Lisp_Object mouse_face_window;
202 203 204 205
static int mouse_face_face_id;

static int pos_x, pos_y;
static int last_mouse_x, last_mouse_y;
206
#endif /* HAVE_GPM */
207

208
/* Ring the bell on a tty. */
209

210
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
211
tty_ring_bell (struct frame *f)
212 213
{
  struct tty_display_info *tty = FRAME_TTY (f);
214

215 216 217 218 219 220
  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
221 222 223
    }
}

224 225
/* Set up termcap modes for Emacs. */

Andreas Schwab's avatar
Andreas Schwab committed
226
void
227
tty_set_terminal_modes (struct terminal *terminal)
Jim Blandy's avatar
Jim Blandy committed
228
{
229
  struct tty_display_info *tty = terminal->display_info.tty;
230

231
  if (tty->output)
Jim Blandy's avatar
Jim Blandy committed
232
    {
233 234
      if (tty->TS_termcap_modes)
        OUTPUT (tty, tty->TS_termcap_modes);
235
      else
236 237 238 239
        {
          /* Output enough newlines to scroll all the old screen contents
             off the screen, so it won't be overwritten and lost.  */
          int i;
240
          current_tty = tty;
241
          for (i = 0; i < FRAME_LINES (XFRAME (selected_frame)); i++)
242
            cmputc ('\n');
243 244
        }

245
      OUTPUT_IF (tty, visible_cursor ? tty->TS_cursor_visible : tty->TS_cursor_normal);
246 247
      OUTPUT_IF (tty, tty->TS_keypad_mode);
      losecursor (tty);
248
      fflush (tty->output);
Jim Blandy's avatar
Jim Blandy committed
249 250 251
    }
}

252 253
/* Reset termcap modes before exiting Emacs. */

Andreas Schwab's avatar
Andreas Schwab committed
254
void
255
tty_reset_terminal_modes (struct terminal *terminal)
Jim Blandy's avatar
Jim Blandy committed
256
{
257
  struct tty_display_info *tty = terminal->display_info.tty;
258 259

  if (tty->output)
Jim Blandy's avatar
Jim Blandy committed
260
    {
261 262
      tty_turn_off_highlight (tty);
      tty_turn_off_insert (tty);
263 264 265 266
      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);
267
      /* Output raw CR so kernel can track the cursor hpos.  */
268
      current_tty = tty;
269
      cmputc ('\r');
270
      fflush (tty->output);
Jim Blandy's avatar
Jim Blandy committed
271 272 273
    }
}

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

276
static void
277
tty_update_end (struct frame *f)
Jim Blandy's avatar
Jim Blandy committed
278
{
279
  struct tty_display_info *tty = FRAME_TTY (f);
280

281 282
  if (!XWINDOW (selected_window)->cursor_off_p)
    tty_show_cursor (tty);
283 284
  tty_turn_off_insert (tty);
  tty_background_highlight (tty);
Jim Blandy's avatar
Jim Blandy committed
285 286
}

287 288
/* The implementation of set_terminal_window for termcap frames. */

289
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
290
tty_set_terminal_window (struct frame *f, int size)
Jim Blandy's avatar
Jim Blandy committed
291
{
292 293 294 295
  struct tty_display_info *tty = FRAME_TTY (f);

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

299 300
static void
tty_set_scroll_region (struct frame *f, int start, int stop)
Jim Blandy's avatar
Jim Blandy committed
301 302
{
  char *buf;
303
  struct tty_display_info *tty = FRAME_TTY (f);
304

305 306 307 308
  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,
309 310 311
		  FRAME_LINES (f), start,
		  FRAME_LINES (f) - stop,
		  FRAME_LINES (f));
Jim Blandy's avatar
Jim Blandy committed
312
  else
313
    buf = tparam (tty->TS_set_window, 0, 0, start, 0, stop, FRAME_COLS (f));
314

315
  OUTPUT (tty, buf);
316
  xfree (buf);
317
  losecursor (tty);
Jim Blandy's avatar
Jim Blandy committed
318
}
319

Jim Blandy's avatar
Jim Blandy committed
320

321
static void
322
tty_turn_on_insert (struct tty_display_info *tty)
Jim Blandy's avatar
Jim Blandy committed
323
{
324 325 326
  if (!tty->insert_mode)
    OUTPUT (tty, tty->TS_insert_mode);
  tty->insert_mode = 1;
Jim Blandy's avatar
Jim Blandy committed
327 328
}

Andreas Schwab's avatar
Andreas Schwab committed
329
void
330
tty_turn_off_insert (struct tty_display_info *tty)
Jim Blandy's avatar
Jim Blandy committed
331
{
332 333 334
  if (tty->insert_mode)
    OUTPUT (tty, tty->TS_end_insert_mode);
  tty->insert_mode = 0;
Jim Blandy's avatar
Jim Blandy committed
335 336
}

337
/* Handle highlighting.  */
Jim Blandy's avatar
Jim Blandy committed
338

Andreas Schwab's avatar
Andreas Schwab committed
339
void
340
tty_turn_off_highlight (struct tty_display_info *tty)
Jim Blandy's avatar
Jim Blandy committed
341
{
342 343 344
  if (tty->standout_mode)
    OUTPUT_IF (tty, tty->TS_end_standout_mode);
  tty->standout_mode = 0;
Jim Blandy's avatar
Jim Blandy committed
345 346
}

347
static void
348
tty_turn_on_highlight (struct tty_display_info *tty)
Jim Blandy's avatar
Jim Blandy committed
349
{
350 351 352
  if (!tty->standout_mode)
    OUTPUT_IF (tty, tty->TS_standout_mode);
  tty->standout_mode = 1;
Jim Blandy's avatar
Jim Blandy committed
353 354
}

355
static void
356
tty_toggle_highlight (struct tty_display_info *tty)
357
{
358
  if (tty->standout_mode)
359
    tty_turn_off_highlight (tty);
360
  else
361
    tty_turn_on_highlight (tty);
362 363
}

Gerd Moellmann's avatar
Gerd Moellmann committed
364 365 366 367

/* Make cursor invisible.  */

static void
368
tty_hide_cursor (struct tty_display_info *tty)
Gerd Moellmann's avatar
Gerd Moellmann committed
369
{
370
  if (tty->cursor_hidden == 0)
371
    {
372 373
      tty->cursor_hidden = 1;
      OUTPUT_IF (tty, tty->TS_cursor_invisible);
374
    }
Gerd Moellmann's avatar
Gerd Moellmann committed
375 376 377 378 379 380
}


/* Ensure that cursor is visible.  */

static void
381
tty_show_cursor (struct tty_display_info *tty)
Gerd Moellmann's avatar
Gerd Moellmann committed
382
{
383
  if (tty->cursor_hidden)
384
    {
385 386
      tty->cursor_hidden = 0;
      OUTPUT_IF (tty, tty->TS_cursor_normal);
387
      if (visible_cursor)
388
        OUTPUT_IF (tty, tty->TS_cursor_visible);
389
    }
Gerd Moellmann's avatar
Gerd Moellmann committed
390 391 392
}


Jim Blandy's avatar
Jim Blandy committed
393 394 395 396
/* 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.  */

397 398
static void
tty_background_highlight (struct tty_display_info *tty)
Jim Blandy's avatar
Jim Blandy committed
399 400
{
  if (inverse_video)
401
    tty_turn_on_highlight (tty);
Jim Blandy's avatar
Jim Blandy committed
402
  else
403
    tty_turn_off_highlight (tty);
Jim Blandy's avatar
Jim Blandy committed
404 405 406 407
}

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

Andreas Schwab's avatar
Andreas Schwab committed
408
static void
409
tty_highlight_if_desired (struct tty_display_info *tty)
Jim Blandy's avatar
Jim Blandy committed
410
{
411
  if (inverse_video)
412
    tty_turn_on_highlight (tty);
413
  else
414
    tty_turn_off_highlight (tty);
Jim Blandy's avatar
Jim Blandy committed
415 416 417
}


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

421
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
422
tty_cursor_to (struct frame *f, int vpos, int hpos)
Jim Blandy's avatar
Jim Blandy committed
423
{
424
  struct tty_display_info *tty = FRAME_TTY (f);
Jim Blandy's avatar
Jim Blandy committed
425

426 427
  /* Detect the case where we are called from reset_sys_modes
     and the costs have never been calculated.  Do nothing.  */
428
  if (! tty->costs_set)
429 430
    return;

431 432
  if (curY (tty) == vpos
      && curX (tty) == hpos)
Jim Blandy's avatar
Jim Blandy committed
433
    return;
434
  if (!tty->TF_standout_motion)
435
    tty_background_highlight (tty);
436
  if (!tty->TF_insmode_motion)
437
    tty_turn_off_insert (tty);
438
  cmgoto (tty, vpos, hpos);
Jim Blandy's avatar
Jim Blandy committed
439 440 441 442
}

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

443
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
444
tty_raw_cursor_to (struct frame *f, int row, int col)
Jim Blandy's avatar
Jim Blandy committed
445
{
446 447
  struct tty_display_info *tty = FRAME_TTY (f);

448 449
  if (curY (tty) == row
      && curX (tty) == col)
Jim Blandy's avatar
Jim Blandy committed
450
    return;
451
  if (!tty->TF_standout_motion)
452
    tty_background_highlight (tty);
453
  if (!tty->TF_insmode_motion)
454
    tty_turn_off_insert (tty);
455
  cmgoto (tty, row, col);
Jim Blandy's avatar
Jim Blandy committed
456 457 458 459
}

/* Erase operations */

460 461
/* Clear from cursor to end of frame on a termcap device. */

462
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
463
tty_clear_to_end (struct frame *f)
Jim Blandy's avatar
Jim Blandy committed
464 465
{
  register int i;
466
  struct tty_display_info *tty = FRAME_TTY (f);
Jim Blandy's avatar
Jim Blandy committed
467

468
  if (tty->TS_clr_to_bottom)
Jim Blandy's avatar
Jim Blandy committed
469
    {
470
      tty_background_highlight (tty);
471
      OUTPUT (tty, tty->TS_clr_to_bottom);
Jim Blandy's avatar
Jim Blandy committed
472 473 474
    }
  else
    {
475
      for (i = curY (tty); i < FRAME_LINES (f); i++)
Jim Blandy's avatar
Jim Blandy committed
476
	{
Karoly Lorentey's avatar
Karoly Lorentey committed
477 478
	  cursor_to (f, i, 0);
	  clear_end_of_line (f, FRAME_COLS (f));
Jim Blandy's avatar
Jim Blandy committed
479 480 481 482
	}
    }
}

483
/* Clear an entire termcap frame. */
Jim Blandy's avatar
Jim Blandy committed
484

485
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
486
tty_clear_frame (struct frame *f)
Jim Blandy's avatar
Jim Blandy committed
487
{
488
  struct tty_display_info *tty = FRAME_TTY (f);
489

490
  if (tty->TS_clr_frame)
Jim Blandy's avatar
Jim Blandy committed
491
    {
492
      tty_background_highlight (tty);
493
      OUTPUT (tty, tty->TS_clr_frame);
494
      cmat (tty, 0, 0);
Jim Blandy's avatar
Jim Blandy committed
495 496 497
    }
  else
    {
Karoly Lorentey's avatar
Karoly Lorentey committed
498 499
      cursor_to (f, 0, 0);
      clear_to_end (f);
Jim Blandy's avatar
Jim Blandy committed
500 501 502
    }
}

503
/* An implementation of clear_end_of_line for termcap frames.
Jim Blandy's avatar
Jim Blandy committed
504 505 506

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

507
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
508
tty_clear_end_of_line (struct frame *f, int first_unused_hpos)
Jim Blandy's avatar
Jim Blandy committed
509 510
{
  register int i;
511
  struct tty_display_info *tty = FRAME_TTY (f);
Jim Blandy's avatar
Jim Blandy committed
512

513 514
  /* Detect the case where we are called from reset_sys_modes
     and the costs have never been calculated.  Do nothing.  */
515
  if (! tty->costs_set)
516 517
    return;

518
  if (curX (tty) >= first_unused_hpos)
Jim Blandy's avatar
Jim Blandy committed
519
    return;
520
  tty_background_highlight (tty);
521
  if (tty->TS_clr_line)
Jim Blandy's avatar
Jim Blandy committed
522
    {
523
      OUTPUT1 (tty, tty->TS_clr_line);
Jim Blandy's avatar
Jim Blandy committed
524 525 526
    }
  else
    {			/* have to do it the hard way */
527
      tty_turn_off_insert (tty);
Jim Blandy's avatar
Jim Blandy committed
528

Gerd Moellmann's avatar
Gerd Moellmann committed
529
      /* Do not write in last row last col with Auto-wrap on. */
530
      if (AutoWrap (tty)
Karoly Lorentey's avatar
Karoly Lorentey committed
531 532
          && curY (tty) == FrameRows (tty) - 1
	  && first_unused_hpos == FrameCols (tty))
Jim Blandy's avatar
Jim Blandy committed
533 534
	first_unused_hpos--;

535
      for (i = curX (tty); i < first_unused_hpos; i++)
Jim Blandy's avatar
Jim Blandy committed
536
	{
537 538 539
	  if (tty->termscript)
	    fputc (' ', tty->termscript);
	  fputc (' ', tty->output);
Jim Blandy's avatar
Jim Blandy committed
540
	}
541
      cmplus (tty, first_unused_hpos - curX (tty));
Jim Blandy's avatar
Jim Blandy committed
542 543 544
    }
}

545 546 547 548 549 550 551 552 553 554 555 556
/* 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 *
557
encode_terminal_code (struct glyph *src, int src_len, struct coding_system *coding)
Karl Heuer's avatar
Karl Heuer committed
558
{
559
  struct glyph *src_end = src + src_len;
560 561
  unsigned char *buf;
  int nchars, nbytes, required;
Karl Heuer's avatar
Karl Heuer committed
562 563
  register int tlen = GLYPH_TABLE_LENGTH;
  register Lisp_Object *tbase = GLYPH_TABLE_BASE;
564
  Lisp_Object charset_list;
565

566 567
  /* 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
568 569
     Vglyph_table contains a string or a composite glyph is
     encountered.  */
570 571 572
  required = MAX_MULTIBYTE_LENGTH * src_len;
  if (encode_terminal_src_size < required)
    {
573
      if (encode_terminal_src)
574
	encode_terminal_src = xrealloc (encode_terminal_src, required);
575 576
      else
	encode_terminal_src = xmalloc (required);
577 578
      encode_terminal_src_size = required;
    }
579

580
  charset_list = coding_charset_list (coding);
Karl Heuer's avatar
Karl Heuer committed
581

582 583 584
  buf = encode_terminal_src;
  nchars = 0;
  while (src < src_end)
Karl Heuer's avatar
Karl Heuer committed
585
    {
Kenichi Handa's avatar
Kenichi Handa committed
586 587
      if (src->type == COMPOSITE_GLYPH)
	{
588 589
	  struct composition *cmp;
	  Lisp_Object gstring;
Kenichi Handa's avatar
Kenichi Handa committed
590 591 592
	  int i;

	  nbytes = buf - encode_terminal_src;
593 594 595
	  if (src->u.cmp.automatic)
	    {
	      gstring = composition_gstring_from_id (src->u.cmp.id);
596
	      required = src->slice.cmp.to + 1 - src->slice.cmp.from;
597 598 599 600 601 602
	    }
	  else
	    {
	      cmp = composition_table[src->u.cmp.id];
	      required = MAX_MULTIBYTE_LENGTH * cmp->glyph_len;
	    }
Kenichi Handa's avatar
Kenichi Handa committed
603 604 605 606 607 608 609 610 611

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

612
	  if (src->u.cmp.automatic)
613
	    for (i = src->slice.cmp.from; i <= src->slice.cmp.to; i++)
614 615 616 617 618
	      {
		Lisp_Object g = LGSTRING_GLYPH (gstring, i);
		int c = LGLYPH_CHAR (g);

		if (! char_charset (c, charset_list, NULL))
619
		  c = '?';
620 621 622 623 624 625 626 627
		buf += CHAR_STRING (c, buf);
		nchars++;
	      }
	  else
	    for (i = 0; i < cmp->glyph_len; i++)
	      {
		int c = COMPOSITION_GLYPH (cmp, i);

628 629 630 631 632 633 634 635 636 637 638 639 640 641
		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 = '?';
642 643 644
		buf += CHAR_STRING (c, buf);
		nchars++;
	      }
Kenichi Handa's avatar
Kenichi Handa committed
645
	}
Karl Heuer's avatar
Karl Heuer committed
646
      /* We must skip glyphs to be padded for a wide character.  */
Kenichi Handa's avatar
Kenichi Handa committed
647
      else if (! CHAR_GLYPH_PADDING_P (*src))
Karl Heuer's avatar
Karl Heuer committed
648
	{
649
	  GLYPH g;
650 651 652
	  int c;
	  Lisp_Object string;

653
	  string = Qnil;
654
	  SET_GLYPH_FROM_CHAR_GLYPH (g, src[0]);
655

656
	  if (GLYPH_INVALID_P (g) || GLYPH_SIMPLE_P (tbase, tlen, g))
657
	    {
658
	      /* This glyph doesn't have an entry in Vglyph_table.  */
659 660
	      c = src->u.ch;
	    }
661
	  else
Karl Heuer's avatar
Karl Heuer committed
662
	    {
663
	      /* This glyph has an entry in Vglyph_table,
Karl Heuer's avatar
Karl Heuer committed
664 665
		 so process any alias before testing for simpleness.  */
	      GLYPH_FOLLOW_ALIASES (tbase, tlen, g);
666 667

	      if (GLYPH_SIMPLE_P (tbase, tlen, g))
668 669
		/* We set the multi-byte form of a character in G
		   (that should be an ASCII character) at WORKBUF.  */
670
		c = GLYPH_CHAR (g);
671
	      else
672
		/* We have a string in Vglyph_table.  */
673
		string = tbase[GLYPH_CHAR (g)];
Richard M. Stallman's avatar
Richard M. Stallman committed
674
	    }
675

676
	  if (NILP (string))
677
	    {
Kenichi Handa's avatar
Kenichi Handa committed
678 679 680 681 682 683 684 685
	      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;
		}
686 687
	      if (CHAR_BYTE8_P (c)
		  || char_charset (c, charset_list, NULL))
688
		{
689 690 691
		  /* Store the multibyte form of C at BUF.  */
		  buf += CHAR_STRING (c, buf);
		  nchars++;
692 693 694
		}
	      else
		{
695 696
		  /* C is not encodable.  */
		  *buf++ = '?';
697
		  nchars++;
698 699 700 701 702 703
		  while (src + 1 < src_end && CHAR_GLYPH_PADDING_P (src[1]))
		    {
		      *buf++ = '?';
		      nchars++;
		      src++;
		    }
704
		}
705 706 707
	    }
	  else
	    {
708
	      unsigned char *p = SDATA (string);
709 710 711 712

	      if (! STRING_MULTIBYTE (string))
		string = string_to_multibyte (string);
	      nbytes = buf - encode_terminal_src;
713
	      if (encode_terminal_src_size < nbytes + SBYTES (string))
714
		{
715 716 717 718
		  encode_terminal_src_size = nbytes + SBYTES (string);
		  encode_terminal_src = xrealloc (encode_terminal_src,
						  encode_terminal_src_size);
		  buf = encode_terminal_src + nbytes;
719
		}
720
	      memcpy (buf, SDATA (string), SBYTES (string));
721 722
	      buf += SBYTES (string);
	      nchars += SCHARS (string);
723
	    }
Karl Heuer's avatar
Karl Heuer committed
724
	}
725 726 727 728 729 730 731
      src++;
    }

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

734 735 736
  nbytes = buf - encode_terminal_src;
  coding->source = encode_terminal_src;
  if (encode_terminal_dst_size == 0)
737
    {
738
      encode_terminal_dst_size = encode_terminal_src_size;
739 740 741 742 743
      if (encode_terminal_dst)
	encode_terminal_dst = xrealloc (encode_terminal_dst,
					encode_terminal_dst_size);
      else
	encode_terminal_dst = xmalloc (encode_terminal_dst_size);
744
    }
745 746 747
  coding->destination = encode_terminal_dst;
  coding->dst_bytes = encode_terminal_dst_size;
  encode_coding_object (coding, Qnil, 0, 0, nchars, nbytes, Qnil);
748
  /* coding->destination may have been reallocated.  */
749 750
  encode_terminal_dst = coding->destination;
  encode_terminal_dst_size = coding->dst_bytes;
751

752
  return (encode_terminal_dst);
Karl Heuer's avatar
Karl Heuer committed
753 754
}

Jim Blandy's avatar
Jim Blandy committed
755

Miles Bader's avatar
Miles Bader committed
756

757 758
/* An implementation of write_glyphs for termcap frames. */

759
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
760
tty_write_glyphs (struct frame *f, struct glyph *string, int len)
Jim Blandy's avatar
Jim Blandy committed
761
{
762 763
  unsigned char *conversion_buffer;
  struct coding_system *coding;
Jim Blandy's avatar
Jim Blandy committed
764

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

767
  tty_turn_off_insert (tty);
768
  tty_hide_cursor (tty);