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 39
#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif
40 41

#include <signal.h>
Dan Nicolaescu's avatar
Dan Nicolaescu committed
42
#include <stdarg.h>
43
#include <setjmp.h>
44

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

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

77
#include "cm.h"
Andreas Schwab's avatar
Andreas Schwab committed
78 79 80
#ifdef HAVE_X_WINDOWS
#include "xterm.h"
#endif
Karl Heuer's avatar
Karl Heuer committed
81

82 83 84
#ifndef O_RDWR
#define O_RDWR 2
#endif
Kenichi Handa's avatar
Kenichi Handa committed
85

86 87 88
#ifndef O_NOCTTY
#define O_NOCTTY 0
#endif
Kenichi Handa's avatar
Kenichi Handa committed
89

90 91 92 93 94 95
/* 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
96

97 98 99 100 101 102 103 104 105 106
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 *);
107 108 109 110
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
111

112 113 114 115 116 117
#define OUTPUT(tty, a)                                          \
  emacs_tputs ((tty), a,                                        \
               (int) (FRAME_LINES (XFRAME (selected_frame))     \
                      - curY (tty)),                            \
               cmputc)

118 119
#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
120

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

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

132 133 134 135
/* If true, use "vs", otherwise use "ve" to make the cursor visible.  */

static int visible_cursor;

136
/* Display space properties */
Jim Blandy's avatar
Jim Blandy committed
137

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

141
/* Functions to call after resuming a tty. */
142
Lisp_Object Vresume_tty_functions;
Jim Blandy's avatar
Jim Blandy committed
143

144
/* Chain of all tty device parameters. */
145
struct tty_display_info *tty_list;
Jim Blandy's avatar
Jim Blandy committed
146

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

/* 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
169 170
/* internal state */

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

173
int max_frame_cols;
Gerd Moellmann's avatar
Gerd Moellmann committed
174

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

177
int max_frame_lines;
178

179 180 181
/* 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
182

183
/* Provided for lisp packages.  */
Gerd Moellmann's avatar
Gerd Moellmann committed
184

185 186
static int system_uses_terminfo;

187
char *tparam (char *, char *, int, int, ...);
188

189
extern char *tgetstr (char *, char **);
Jim Blandy's avatar
Jim Blandy committed
190

191

192
#ifdef HAVE_GPM
193 194
#include <sys/fcntl.h>

195
static void term_clear_mouse_face (void);
196 197
static void term_mouse_highlight (struct frame *f, int x, int y);

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

/* 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;
209
static Lisp_Object mouse_face_window;
210 211 212 213
static int mouse_face_face_id;

static int pos_x, pos_y;
static int last_mouse_x, last_mouse_y;
214
#endif /* HAVE_GPM */
215

216
/* Ring the bell on a tty. */
217

218
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
219
tty_ring_bell (struct frame *f)
220 221
{
  struct tty_display_info *tty = FRAME_TTY (f);
222

223 224 225 226 227 228
  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
229 230 231
    }
}

232 233
/* Set up termcap modes for Emacs. */

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

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

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

261 262
/* Reset termcap modes before exiting Emacs. */

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

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

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

285
static void
286
tty_update_end (struct frame *f)
Jim Blandy's avatar
Jim Blandy committed
287
{
288
  struct tty_display_info *tty = FRAME_TTY (f);
289

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

296 297
/* The implementation of set_terminal_window for termcap frames. */

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

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

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

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

324
  OUTPUT (tty, buf);
325
  xfree (buf);
326
  losecursor (tty);
Jim Blandy's avatar
Jim Blandy committed
327
}
328

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

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

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

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

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

Gerd Moellmann's avatar
Gerd Moellmann committed
373 374 375 376

/* Make cursor invisible.  */

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


/* Ensure that cursor is visible.  */

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


Jim Blandy's avatar
Jim Blandy committed
402 403 404 405
/* 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.  */

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

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

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

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

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

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

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

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

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

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

469 470
/* Clear from cursor to end of frame on a termcap device. */

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

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

492
/* Clear an entire termcap frame. */
Jim Blandy's avatar
Jim Blandy committed
493

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

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

512
/* An implementation of clear_end_of_line for termcap frames.
Jim Blandy's avatar
Jim Blandy committed
513 514 515

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

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

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

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

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

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

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

589
  charset_list = coding_charset_list (coding);
Karl Heuer's avatar
Karl Heuer committed
590

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

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

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

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

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

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

662
	  string = Qnil;
663
	  SET_GLYPH_FROM_CHAR_GLYPH (g, src[0]);
664

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

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

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

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

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

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

760
  return (encode_terminal_dst);
Karl Heuer's avatar
Karl Heuer committed
761 762
}

Jim Blandy's avatar
Jim Blandy committed
763

Miles Bader's avatar
Miles Bader committed
764

765 766
/* An implementation of write_glyphs for termcap frames. */

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

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

775
  tty_turn_off_insert (tty);
776
  tty_hide_cursor (tty);
Jim Blandy's avatar
Jim Blandy committed
777

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

781 782 783
  if (AutoWrap (tty)
      && curY (tty) + 1 == FRAME_LINES (f)
      && (curX (tty) + len) == FRAME_COLS (f))
Jim Blandy's avatar
Jim Blandy committed
784
    len --;
Karl Heuer's avatar
Karl Heuer committed
785 786
  if (len <= 0)
    return;
Jim Blandy's avatar
Jim Blandy committed
787

788
  cmplus (tty, len);
789

790 791 792
  /* 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.  */
793 794
  coding = (FRAME_TERMINAL_CODING (f)->common_flags & CODING_REQUIRE_ENCODING_MASK
	    ? FRAME_TERMINAL_CODING (f) : &safe_terminal_coding);
795 796
  /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
     the tail.  */
797
  coding->mode &= ~CODING_MODE_LAST_BLOCK;
798

Karl Heuer's avatar
Karl Heuer committed
799
  while (len > 0)
Jim Blandy's avatar
Jim Blandy committed
800
    {
Gerd Moellmann's avatar
Gerd Moellmann committed
801
      /* Identify a run of glyphs with the same face.  */
802
      int face_id = string->face_id;
Gerd Moellmann's avatar
Gerd Moellmann committed
803
      int n;
804

Gerd Moellmann's avatar
Gerd Moellmann committed
805
      for (n = 1; n < len; ++n)
806
	if (string[n].face_id != face_id)
Gerd Moellmann's avatar
Gerd Moellmann committed
807 808 809
	  break;

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

813 814 815 816 817
      if (n == len)
	/* This is the last run.  */
	coding->mode |= CODING_MODE_LAST_BLOCK;
      conversion_buffer = encode_terminal_code (string, n, coding);
      if (coding->produced > 0)