term.c 114 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>
Gerd Moellmann's avatar
Gerd Moellmann committed
26
#include <string.h>
27
#include <errno.h>
28
#include <sys/file.h>
Miles Bader's avatar
Miles Bader committed
29

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

34 35 36
#if HAVE_TERMIOS_H
#include <termios.h>		/* For TIOCNOTTY. */
#endif
37 38

#include <signal.h>
Dan Nicolaescu's avatar
Dan Nicolaescu committed
39
#include <stdarg.h>
40
#include <setjmp.h>
41

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

66 67 68
/* 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.  */
69 70 71 72
extern void tputs (const char *, int, int (*)(int));
extern int tgetent (char *, const char *);
extern int tgetflag (char *id);
extern int tgetnum (char *id);
73

74
#include "cm.h"
Andreas Schwab's avatar
Andreas Schwab committed
75 76 77
#ifdef HAVE_X_WINDOWS
#include "xterm.h"
#endif
Karl Heuer's avatar
Karl Heuer committed
78

79 80 81
#ifndef O_RDWR
#define O_RDWR 2
#endif
Kenichi Handa's avatar
Kenichi Handa committed
82

83 84 85
#ifndef O_NOCTTY
#define O_NOCTTY 0
#endif
Kenichi Handa's avatar
Kenichi Handa committed
86

87 88 89 90 91 92
/* 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
93

94 95 96 97 98 99 100 101 102 103
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 *);
104 105 106 107
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
108

109 110 111 112 113 114
#define OUTPUT(tty, a)                                          \
  emacs_tputs ((tty), a,                                        \
               (int) (FRAME_LINES (XFRAME (selected_frame))     \
                      - curY (tty)),                            \
               cmputc)

115 116
#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
117

118
#define OUTPUT_IF(tty, a)                                               \
119 120 121 122 123 124 125
  do {                                                                  \
    if (a)                                                              \
      emacs_tputs ((tty), a,                                            \
                   (int) (FRAME_LINES (XFRAME (selected_frame))         \
                          - curY (tty) ),                               \
                   cmputc);                                             \
  } while (0)
126

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

129 130 131 132
/* If true, use "vs", otherwise use "ve" to make the cursor visible.  */

static int visible_cursor;

133
/* Display space properties */
Jim Blandy's avatar
Jim Blandy committed
134

135
/* Functions to call after suspending a tty. */
136
Lisp_Object Vsuspend_tty_functions;
Jim Blandy's avatar
Jim Blandy committed
137

138
/* Functions to call after resuming a tty. */
139
Lisp_Object Vresume_tty_functions;
Jim Blandy's avatar
Jim Blandy committed
140

141
/* Chain of all tty device parameters. */
142
struct tty_display_info *tty_list;
Jim Blandy's avatar
Jim Blandy committed
143

144 145 146 147
/* 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
148
int no_redraw_on_reenter;
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165

/* 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
166 167
/* internal state */

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

170
int max_frame_cols;
Gerd Moellmann's avatar
Gerd Moellmann committed
171

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

174
int max_frame_lines;
175

176 177 178
/* 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
179

180
/* Provided for lisp packages.  */
Gerd Moellmann's avatar
Gerd Moellmann committed
181

182 183
static int system_uses_terminfo;

184
char *tparam (char *, char *, int, int, ...);
185

186
extern char *tgetstr (char *, char **);
Jim Blandy's avatar
Jim Blandy committed
187

188

189
#ifdef HAVE_GPM
190 191
#include <sys/fcntl.h>

192
static void term_clear_mouse_face (void);
193 194
static void term_mouse_highlight (struct frame *f, int x, int y);

195 196
/* The device for which we have enabled gpm support (or NULL).  */
struct tty_display_info *gpm_tty = NULL;
197 198 199 200 201 202 203 204 205

/* 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;
206
static Lisp_Object mouse_face_window;
207 208 209 210
static int mouse_face_face_id;

static int pos_x, pos_y;
static int last_mouse_x, last_mouse_y;
211
#endif /* HAVE_GPM */
212

213
/* Ring the bell on a tty. */
214

215
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
216
tty_ring_bell (struct frame *f)
217 218
{
  struct tty_display_info *tty = FRAME_TTY (f);
219

220 221 222 223 224 225
  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
226 227 228
    }
}

229 230
/* Set up termcap modes for Emacs. */

Andreas Schwab's avatar
Andreas Schwab committed
231
void
232
tty_set_terminal_modes (struct terminal *terminal)
Jim Blandy's avatar
Jim Blandy committed
233
{
234
  struct tty_display_info *tty = terminal->display_info.tty;
235

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

250
      OUTPUT_IF (tty, tty->TS_termcap_modes);
251
      OUTPUT_IF (tty, visible_cursor ? tty->TS_cursor_visible : tty->TS_cursor_normal);
252 253
      OUTPUT_IF (tty, tty->TS_keypad_mode);
      losecursor (tty);
254
      fflush (tty->output);
Jim Blandy's avatar
Jim Blandy committed
255 256 257
    }
}

258 259
/* Reset termcap modes before exiting Emacs. */

Andreas Schwab's avatar
Andreas Schwab committed
260
void
261
tty_reset_terminal_modes (struct terminal *terminal)
Jim Blandy's avatar
Jim Blandy committed
262
{
263
  struct tty_display_info *tty = terminal->display_info.tty;
264 265

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

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

282
static void
283
tty_update_end (struct frame *f)
Jim Blandy's avatar
Jim Blandy committed
284
{
285
  struct tty_display_info *tty = FRAME_TTY (f);
286

287 288
  if (!XWINDOW (selected_window)->cursor_off_p)
    tty_show_cursor (tty);
289 290
  tty_turn_off_insert (tty);
  tty_background_highlight (tty);
Jim Blandy's avatar
Jim Blandy committed
291 292
}

293 294
/* The implementation of set_terminal_window for termcap frames. */

295
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
296
tty_set_terminal_window (struct frame *f, int size)
Jim Blandy's avatar
Jim Blandy committed
297
{
298 299 300 301
  struct tty_display_info *tty = FRAME_TTY (f);

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

305 306
static void
tty_set_scroll_region (struct frame *f, int start, int stop)
Jim Blandy's avatar
Jim Blandy committed
307 308
{
  char *buf;
309
  struct tty_display_info *tty = FRAME_TTY (f);
310

311 312 313 314
  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,
315 316 317
		  FRAME_LINES (f), start,
		  FRAME_LINES (f) - stop,
		  FRAME_LINES (f));
Jim Blandy's avatar
Jim Blandy committed
318
  else
319
    buf = tparam (tty->TS_set_window, 0, 0, start, 0, stop, FRAME_COLS (f));
320

321
  OUTPUT (tty, buf);
322
  xfree (buf);
323
  losecursor (tty);
Jim Blandy's avatar
Jim Blandy committed
324
}
325

Jim Blandy's avatar
Jim Blandy committed
326

327
static void
328
tty_turn_on_insert (struct tty_display_info *tty)
Jim Blandy's avatar
Jim Blandy committed
329
{
330 331 332
  if (!tty->insert_mode)
    OUTPUT (tty, tty->TS_insert_mode);
  tty->insert_mode = 1;
Jim Blandy's avatar
Jim Blandy committed
333 334
}

Andreas Schwab's avatar
Andreas Schwab committed
335
void
336
tty_turn_off_insert (struct tty_display_info *tty)
Jim Blandy's avatar
Jim Blandy committed
337
{
338 339 340
  if (tty->insert_mode)
    OUTPUT (tty, tty->TS_end_insert_mode);
  tty->insert_mode = 0;
Jim Blandy's avatar
Jim Blandy committed
341 342
}

343
/* Handle highlighting.  */
Jim Blandy's avatar
Jim Blandy committed
344

Andreas Schwab's avatar
Andreas Schwab committed
345
void
346
tty_turn_off_highlight (struct tty_display_info *tty)
Jim Blandy's avatar
Jim Blandy committed
347
{
348 349 350
  if (tty->standout_mode)
    OUTPUT_IF (tty, tty->TS_end_standout_mode);
  tty->standout_mode = 0;
Jim Blandy's avatar
Jim Blandy committed
351 352
}

353
static void
354
tty_turn_on_highlight (struct tty_display_info *tty)
Jim Blandy's avatar
Jim Blandy committed
355
{
356 357 358
  if (!tty->standout_mode)
    OUTPUT_IF (tty, tty->TS_standout_mode);
  tty->standout_mode = 1;
Jim Blandy's avatar
Jim Blandy committed
359 360
}

361
static void
362
tty_toggle_highlight (struct tty_display_info *tty)
363
{
364
  if (tty->standout_mode)
365
    tty_turn_off_highlight (tty);
366
  else
367
    tty_turn_on_highlight (tty);
368 369
}

Gerd Moellmann's avatar
Gerd Moellmann committed
370 371 372 373

/* Make cursor invisible.  */

static void
374
tty_hide_cursor (struct tty_display_info *tty)
Gerd Moellmann's avatar
Gerd Moellmann committed
375
{
376
  if (tty->cursor_hidden == 0)
377
    {
378 379
      tty->cursor_hidden = 1;
      OUTPUT_IF (tty, tty->TS_cursor_invisible);
380
    }
Gerd Moellmann's avatar
Gerd Moellmann committed
381 382 383 384 385 386
}


/* Ensure that cursor is visible.  */

static void
387
tty_show_cursor (struct tty_display_info *tty)
Gerd Moellmann's avatar
Gerd Moellmann committed
388
{
389
  if (tty->cursor_hidden)
390
    {
391 392
      tty->cursor_hidden = 0;
      OUTPUT_IF (tty, tty->TS_cursor_normal);
393
      if (visible_cursor)
394
        OUTPUT_IF (tty, tty->TS_cursor_visible);
395
    }
Gerd Moellmann's avatar
Gerd Moellmann committed
396 397 398
}


Jim Blandy's avatar
Jim Blandy committed
399 400 401 402
/* 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.  */

403 404
static void
tty_background_highlight (struct tty_display_info *tty)
Jim Blandy's avatar
Jim Blandy committed
405 406
{
  if (inverse_video)
407
    tty_turn_on_highlight (tty);
Jim Blandy's avatar
Jim Blandy committed
408
  else
409
    tty_turn_off_highlight (tty);
Jim Blandy's avatar
Jim Blandy committed
410 411 412 413
}

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

Andreas Schwab's avatar
Andreas Schwab committed
414
static void
415
tty_highlight_if_desired (struct tty_display_info *tty)
Jim Blandy's avatar
Jim Blandy committed
416
{
417
  if (inverse_video)
418
    tty_turn_on_highlight (tty);
419
  else
420
    tty_turn_off_highlight (tty);
Jim Blandy's avatar
Jim Blandy committed
421 422 423
}


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

427
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
428
tty_cursor_to (struct frame *f, int vpos, int hpos)
Jim Blandy's avatar
Jim Blandy committed
429
{
430
  struct tty_display_info *tty = FRAME_TTY (f);
Jim Blandy's avatar
Jim Blandy committed
431

432 433
  /* Detect the case where we are called from reset_sys_modes
     and the costs have never been calculated.  Do nothing.  */
434
  if (! tty->costs_set)
435 436
    return;

437 438
  if (curY (tty) == vpos
      && curX (tty) == hpos)
Jim Blandy's avatar
Jim Blandy committed
439
    return;
440
  if (!tty->TF_standout_motion)
441
    tty_background_highlight (tty);
442
  if (!tty->TF_insmode_motion)
443
    tty_turn_off_insert (tty);
444
  cmgoto (tty, vpos, hpos);
Jim Blandy's avatar
Jim Blandy committed
445 446 447 448
}

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

449
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
450
tty_raw_cursor_to (struct frame *f, int row, int col)
Jim Blandy's avatar
Jim Blandy committed
451
{
452 453
  struct tty_display_info *tty = FRAME_TTY (f);

454 455
  if (curY (tty) == row
      && curX (tty) == col)
Jim Blandy's avatar
Jim Blandy committed
456
    return;
457
  if (!tty->TF_standout_motion)
458
    tty_background_highlight (tty);
459
  if (!tty->TF_insmode_motion)
460
    tty_turn_off_insert (tty);
461
  cmgoto (tty, row, col);
Jim Blandy's avatar
Jim Blandy committed
462 463 464 465
}

/* Erase operations */

466 467
/* Clear from cursor to end of frame on a termcap device. */

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

474
  if (tty->TS_clr_to_bottom)
Jim Blandy's avatar
Jim Blandy committed
475
    {
476
      tty_background_highlight (tty);
477
      OUTPUT (tty, tty->TS_clr_to_bottom);
Jim Blandy's avatar
Jim Blandy committed
478 479 480
    }
  else
    {
481
      for (i = curY (tty); i < FRAME_LINES (f); i++)
Jim Blandy's avatar
Jim Blandy committed
482
	{
Karoly Lorentey's avatar
Karoly Lorentey committed
483 484
	  cursor_to (f, i, 0);
	  clear_end_of_line (f, FRAME_COLS (f));
Jim Blandy's avatar
Jim Blandy committed
485 486 487 488
	}
    }
}

489
/* Clear an entire termcap frame. */
Jim Blandy's avatar
Jim Blandy committed
490

491
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
492
tty_clear_frame (struct frame *f)
Jim Blandy's avatar
Jim Blandy committed
493
{
494
  struct tty_display_info *tty = FRAME_TTY (f);
495

496
  if (tty->TS_clr_frame)
Jim Blandy's avatar
Jim Blandy committed
497
    {
498
      tty_background_highlight (tty);
499
      OUTPUT (tty, tty->TS_clr_frame);
500
      cmat (tty, 0, 0);
Jim Blandy's avatar
Jim Blandy committed
501 502 503
    }
  else
    {
Karoly Lorentey's avatar
Karoly Lorentey committed
504 505
      cursor_to (f, 0, 0);
      clear_to_end (f);
Jim Blandy's avatar
Jim Blandy committed
506 507 508
    }
}

509
/* An implementation of clear_end_of_line for termcap frames.
Jim Blandy's avatar
Jim Blandy committed
510 511 512

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

513
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
514
tty_clear_end_of_line (struct frame *f, int first_unused_hpos)
Jim Blandy's avatar
Jim Blandy committed
515 516
{
  register int i;
517
  struct tty_display_info *tty = FRAME_TTY (f);
Jim Blandy's avatar
Jim Blandy committed
518

519 520
  /* Detect the case where we are called from reset_sys_modes
     and the costs have never been calculated.  Do nothing.  */
521
  if (! tty->costs_set)
522 523
    return;

524
  if (curX (tty) >= first_unused_hpos)
Jim Blandy's avatar
Jim Blandy committed
525
    return;
526
  tty_background_highlight (tty);
527
  if (tty->TS_clr_line)
Jim Blandy's avatar
Jim Blandy committed
528
    {
529
      OUTPUT1 (tty, tty->TS_clr_line);
Jim Blandy's avatar
Jim Blandy committed
530 531 532
    }
  else
    {			/* have to do it the hard way */
533
      tty_turn_off_insert (tty);
Jim Blandy's avatar
Jim Blandy committed
534

Gerd Moellmann's avatar
Gerd Moellmann committed
535
      /* Do not write in last row last col with Auto-wrap on. */
536
      if (AutoWrap (tty)
Karoly Lorentey's avatar
Karoly Lorentey committed
537 538
          && curY (tty) == FrameRows (tty) - 1
	  && first_unused_hpos == FrameCols (tty))
Jim Blandy's avatar
Jim Blandy committed
539 540
	first_unused_hpos--;

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

572 573
  /* 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
574 575
     Vglyph_table contains a string or a composite glyph is
     encountered.  */
576 577 578
  required = MAX_MULTIBYTE_LENGTH * src_len;
  if (encode_terminal_src_size < required)
    {
579
      if (encode_terminal_src)
580
	encode_terminal_src = xrealloc (encode_terminal_src, required);
581 582
      else
	encode_terminal_src = xmalloc (required);
583 584
      encode_terminal_src_size = required;
    }
585

586
  charset_list = coding_charset_list (coding);
Karl Heuer's avatar
Karl Heuer committed
587

588 589 590
  buf = encode_terminal_src;
  nchars = 0;
  while (src < src_end)
Karl Heuer's avatar
Karl Heuer committed
591
    {
Kenichi Handa's avatar
Kenichi Handa committed
592 593
      if (src->type == COMPOSITE_GLYPH)
	{
594 595
	  struct composition *cmp;
	  Lisp_Object gstring;
Kenichi Handa's avatar
Kenichi Handa committed
596 597 598
	  int i;

	  nbytes = buf - encode_terminal_src;
599 600 601
	  if (src->u.cmp.automatic)
	    {
	      gstring = composition_gstring_from_id (src->u.cmp.id);
602
	      required = src->u.cmp.to + 1 - src->u.cmp.from;
603 604 605 606 607 608
	    }
	  else
	    {
	      cmp = composition_table[src->u.cmp.id];
	      required = MAX_MULTIBYTE_LENGTH * cmp->glyph_len;
	    }
Kenichi Handa's avatar
Kenichi Handa committed
609 610 611 612 613 614 615 616 617

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

618
	  if (src->u.cmp.automatic)
619
	    for (i = src->u.cmp.from; i <= src->u.cmp.to; i++)
620 621 622 623 624
	      {
		Lisp_Object g = LGSTRING_GLYPH (gstring, i);
		int c = LGLYPH_CHAR (g);

		if (! char_charset (c, charset_list, NULL))
625
		  c = '?';
626 627 628 629 630 631 632 633
		buf += CHAR_STRING (c, buf);
		nchars++;
	      }
	  else
	    for (i = 0; i < cmp->glyph_len; i++)
	      {
		int c = COMPOSITION_GLYPH (cmp, i);

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

659
	  string = Qnil;
660
	  SET_GLYPH_FROM_CHAR_GLYPH (g, src[0]);
661

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

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

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

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

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

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

757
  return (encode_terminal_dst);
Karl Heuer's avatar
Karl Heuer committed
758 759
}

Jim Blandy's avatar
Jim Blandy committed
760

Miles Bader's avatar
Miles Bader committed
761

762 763
/* An implementation of write_glyphs for termcap frames. */

764
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
765
tty_write_glyphs (struct frame *f, struct glyph *string, int len)
Jim Blandy's avatar
Jim Blandy committed
766
{
767 768
  unsigned char *conversion_buffer;
  struct coding_system *coding;
Jim Blandy's avatar
Jim Blandy committed
769

770
  struct tty_display_info *tty = FRAME_TTY (f);