Revision: miles@gnu.org--gnu-2005/emacs--unicode--0--patch-95
[bpt/emacs.git] / src / term.c
index 609efcb..0a40993 100644 (file)
@@ -1,6 +1,6 @@
 /* Terminal control module for terminals described by TERMCAP
-   Copyright (C) 1985, 86, 87, 93, 94, 95, 98, 2000, 2001, 2002
-   Free Software Foundation, Inc.
+   Copyright (C) 1985, 1986, 1987, 1993, 1994, 1995, 1998, 2000, 2001,
+                 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -16,8 +16,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU Emacs; see the file COPYING.  If not, write to
-the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
 
 /* New redisplay, TTY faces by Gerd Moellmann <gerd@gnu.org>.  */
 
@@ -451,7 +451,17 @@ set_terminal_modes ()
 {
   if (FRAME_TERMCAP_P (XFRAME (selected_frame)))
     {
-      OUTPUT_IF (TS_termcap_modes);
+      if (TS_termcap_modes)
+       OUTPUT (TS_termcap_modes);
+      else
+       {
+         /* Output enough newlines to scroll all the old screen contents
+            off the screen, so it won't be overwritten and lost.  */
+         int i;
+         for (i = 0; i < FRAME_LINES (XFRAME (selected_frame)); i++)
+           putchar ('\n');
+       }
+
       OUTPUT_IF (TS_cursor_visible);
       OUTPUT_IF (TS_keypad_mode);
       losecursor ();
@@ -793,75 +803,64 @@ clear_end_of_line (first_unused_hpos)
     }
 }
 \f
-/* Buffer to store the result of terminal codes.  It is initialized in
-   term_init and, if necessary, enlarged in encode_terminal_code.  */
-unsigned char *terminal_encode_buffer;
-/* Size of terminal_encode_buffer.  */
-static int terminal_encode_buf_size;
-
-/* Encode SRC_LEN glyphs starting at SRC to terminal output codes and
-   store them in terminal_encode_buffer.
-
-   We store the number of glyphs actually converted in *CONSUMED.  The
-   return value is the number of bytes stored in
-   terminal_encode_buffer.
-
-   This function will stop before encoding all glyphs in these two
-   cases.
-
-   (1) If the first glyph doesn't have a string entry in Vglyph_table,
-       it stops at encountering a glyph that has a string entry in
-       Vglyph_table.n
-
-   (2) If the first has a string entry in Vglyph_table, it stops after
-       encoding that string.
-*/
-
-int
-encode_terminal_code (src, src_len, consumed)
+/* 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 *
+encode_terminal_code (src, src_len, coding)
      struct glyph *src;
      int src_len;
-     int *consumed;
+     struct coding_system *coding;
 {
-  struct glyph *src_start = src, *src_end = src + src_len;
+  struct glyph *src_end = src + src_len;
   register GLYPH g;
-  register int c;
-  Lisp_Object string;
-  unsigned char *workbuf, *buf;
-  int nchars;
+  unsigned char *buf;
+  int nchars, nbytes, required;
   register int tlen = GLYPH_TABLE_LENGTH;
   register Lisp_Object *tbase = GLYPH_TABLE_BASE;
-  struct coding_system *coding;
-  Lisp_Object attrs, charset_list;
+  Lisp_Object charset_list;
 
-#if 1
-  /* GLYPH-TABLE is not supported anymore in xdisp.c.  */
-  tlen = 0;
-#endif
+  /* Allocate sufficient size of buffer to store all characters in
+     multibyte-form.  But, it may be enlarged on demand if
+     Vglyph_table contains a string.  */
+  required = MAX_MULTIBYTE_LENGTH * src_len;
+  if (encode_terminal_src_size < required)
+    {
+      if (encode_terminal_src_size == 0)
+       encode_terminal_src = xmalloc (required);
+      else
+       encode_terminal_src = xrealloc (encode_terminal_src, required);
+      encode_terminal_src_size = required;
+    }
 
-  /* 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.  */
-  coding = (terminal_coding.common_flags & CODING_REQUIRE_ENCODING_MASK
-           ? &terminal_coding
-           : &safe_terminal_coding);
-  coding->destination = terminal_encode_buffer;
-  coding->dst_bytes = terminal_encode_buf_size;
-  coding->mode |= CODING_MODE_LAST_BLOCK;
-  attrs = CODING_ID_ATTRS (coding->id);
-  charset_list = CODING_ATTR_CHARSET_LIST (attrs);
+  charset_list = coding_charset_list (coding);
 
-  workbuf = buf = alloca (MAX_MULTIBYTE_LENGTH * src_len);
-  for (nchars = 0; src < src_end; src++)
+  buf = encode_terminal_src;
+  nchars = 0;
+  while (src < src_end)
     {
       /* We must skip glyphs to be padded for a wide character.  */
       if (! CHAR_GLYPH_PADDING_P (*src))
        {
-         g = GLYPH_FROM_CHAR_GLYPH (src[0]);
+         int c;
+         Lisp_Object string;
+
          string = Qnil;
+         g = GLYPH_FROM_CHAR_GLYPH (src[0]);
 
          if (g < 0 || g >= tlen)
-           c = src->u.ch;
+           {
+             /* This glyph doesn't has an entry in Vglyph_table.  */
+             c = src->u.ch;
+           }
          else
            {
              /* This glyph has an entry in Vglyph_table,
@@ -879,47 +878,68 @@ encode_terminal_code (src, src_len, consumed)
 
          if (NILP (string))
            {
-             if (char_charset (c, charset_list, NULL))
+             if (char_charset (c, charset_list, NULL))
                {
-                 /* C is not encodable.  */
-                 int i;
-
-                 for (i = CHAR_WIDTH (c) - 1; i >= 0; i--, nchars++)
-                   *buf++ = '?';
+                 /* Store the multibyte form of C at BUF.  */
+                 buf += CHAR_STRING (c, buf);
+                 nchars++;
                }
              else
                {
-                 /* Store the multibyte form of C at BUF.  */
-                 buf += CHAR_STRING (c, buf);
+                 /* C is not encodable.  */
+                 *buf++ = '?';
                  nchars++;
+                 while (src + 1 < src_end && CHAR_GLYPH_PADDING_P (src[1]))
+                   {
+                     *buf++ = '?';
+                     nchars++;
+                     src++;
+                   }
                }
            }
          else
            {
-             if (nchars == 0)
+             unsigned char *p = SDATA (string), *pend = p + SBYTES (string);
+
+             if (! STRING_MULTIBYTE (string))
+               string = string_to_multibyte (string);
+             nbytes = buf - encode_terminal_src;
+             if (encode_terminal_src_size < nbytes + SBYTES (string))
                {
-                 encode_coding_object (coding, string, 0, 0, SCHARS (string),
-                                       SBYTES (string), Qnil);
-                 src++;
+                 encode_terminal_src_size = nbytes + SBYTES (string);
+                 encode_terminal_src = xrealloc (encode_terminal_src,
+                                                 encode_terminal_src_size);
+                 buf = encode_terminal_src + nbytes;
                }
-             break;
+             bcopy (SDATA (string), buf, SBYTES (string));
+             buf += SBYTES (string);
+             nchars += SCHARS (string);
            }
        }
+      src++;
     }
 
-  if (nchars > 0)
+  if (nchars == 0)
     {
-      coding->source = workbuf;
-      encode_coding_object (coding, Qnil, 0, 0, nchars,
-                           buf - workbuf, Qnil);
+      coding->produced = 0;
+      return NULL;
     }
+
+  nbytes = buf - encode_terminal_src;
+  coding->source = encode_terminal_src;
+  if (encode_terminal_dst_size == 0)
+    {
+      encode_terminal_dst_size = encode_terminal_src_size;
+      encode_terminal_dst = xmalloc (encode_terminal_dst_size);
+    }
+  coding->destination = encode_terminal_dst;
+  coding->dst_bytes = encode_terminal_dst_size;
+  encode_coding_object (coding, Qnil, 0, 0, nchars, nbytes, Qnil);
   /* coding->destination may have been reallocated.  */
-  terminal_encode_buffer = coding->destination;
-  if (terminal_encode_buf_size < coding->dst_bytes)
-    terminal_encode_buf_size = coding->dst_bytes;
+  encode_terminal_dst = coding->destination;
+  encode_terminal_dst_size = coding->dst_bytes;
 
-  *consumed = src - src_start;
-  return (coding->produced);
+  return (encode_terminal_dst);
 }
 
 
@@ -931,6 +951,8 @@ write_glyphs (string, len)
   int produced, consumed;
   struct frame *sf = XFRAME (selected_frame);
   struct frame *f = updating_frame ? updating_frame : sf;
+  unsigned char *conversion_buffer;
+  struct coding_system *coding;
 
   if (write_glyphs_hook
       && ! FRAME_TERMCAP_P (f))
@@ -954,9 +976,14 @@ write_glyphs (string, len)
 
   cmplus (len);
 
+  /* 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.  */
+  coding = (terminal_coding.common_flags & CODING_REQUIRE_ENCODING_MASK
+           ? &terminal_coding : &safe_terminal_coding);
   /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
      the tail.  */
-  terminal_coding.mode &= ~CODING_MODE_LAST_BLOCK;
+  coding->mode &= ~CODING_MODE_LAST_BLOCK;
 
   while (len > 0)
     {
@@ -972,21 +999,20 @@ write_glyphs (string, len)
       highlight_if_desired ();
       turn_on_face (f, face_id);
 
-      while (n > 0)
+      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)
        {
-         produced = encode_terminal_code (string, n, &consumed);
-         if (produced > 0)
-           {
-             fwrite (terminal_encode_buffer, 1, produced, stdout);
-             if (ferror (stdout))
-               clearerr (stdout);
-             if (termscript)
-               fwrite (terminal_encode_buffer, 1, produced, termscript);
-           }
-         len -= consumed;
-         n -= consumed;
-         string += consumed;
+         fwrite (conversion_buffer, 1, coding->produced, stdout);
+         if (ferror (stdout))
+           clearerr (stdout);
+         if (termscript)
+           fwrite (conversion_buffer, 1, coding->produced, termscript);
        }
+      len -= n;
+      string += n;
 
       /* Turn appearance modes off.  */
       turn_off_face (f, face_id);
@@ -1006,6 +1032,9 @@ insert_glyphs (start, len)
   char *buf;
   struct glyph *glyph = NULL;
   struct frame *f, *sf;
+  unsigned char *conversion_buffer;
+  unsigned char space[1];
+  struct coding_system *coding;
 
   if (len <= 0)
     return;
@@ -1031,17 +1060,26 @@ insert_glyphs (start, len)
 
   turn_on_insert ();
   cmplus (len);
-  /* The bit CODING_MODE_LAST_BLOCK should be set to 1 only at the tail.  */
-  terminal_coding.mode &= ~CODING_MODE_LAST_BLOCK;
+
+  if (! start)
+    space[0] = SPACEGLYPH;
+
+  /* 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.  */
+  coding = (terminal_coding.common_flags & CODING_REQUIRE_ENCODING_MASK
+           ? &terminal_coding : &safe_terminal_coding);
+  /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
+     the tail.  */
+  coding->mode &= ~CODING_MODE_LAST_BLOCK;
+
   while (len-- > 0)
     {
-      int produced, consumed;
-
       OUTPUT1_IF (TS_ins_char);
       if (!start)
        {
-         terminal_encode_buffer[0] = SPACEGLYPH;
-         produced = 1;
+         conversion_buffer = space;
+         coding->produced = 1;
        }
       else
        {
@@ -1056,16 +1094,21 @@ insert_glyphs (start, len)
              OUTPUT1_IF (TS_ins_char);
              start++, len--;
            }
-         produced = encode_terminal_code (glyph, 1, &consumed);
+
+         if (len <= 0)
+           /* This is the last glyph.  */
+           coding->mode |= CODING_MODE_LAST_BLOCK;
+
+         conversion_buffer = encode_terminal_code (glyph, 1, coding);
        }
 
-      if (produced > 0)
+      if (coding->produced > 0)
        {
-         fwrite (terminal_encode_buffer, 1, produced, stdout);
+         fwrite (conversion_buffer, 1, coding->produced, stdout);
          if (ferror (stdout))
            clearerr (stdout);
          if (termscript)
-           fwrite (terminal_encode_buffer, 1, produced, termscript);
+           fwrite (conversion_buffer, 1, coding->produced, termscript);
        }
 
       OUTPUT1_IF (TS_pad_inserted_char);
@@ -1443,7 +1486,26 @@ static struct fkey_table keys[] =
   {"k6", "f6"},
   {"k7", "f7"},
   {"k8", "f8"},
-  {"k9", "f9"}
+  {"k9", "f9"},
+
+  {"&0", "S-cancel"},    /*shifted cancel key*/
+  {"&9", "S-begin"},     /*shifted begin key*/
+  {"*0", "S-find"},      /*shifted find key*/
+  {"*1", "S-execute"},   /*shifted execute? actually shifted command key*/
+  {"*4", "S-delete"},    /*shifted delete-character key*/
+  {"*7", "S-end"},       /*shifted end key*/
+  {"*8", "S-clearline"}, /*shifted clear-to end-of-line key*/
+  {"#1", "S-help"},      /*shifted help key*/
+  {"#2", "S-home"},      /*shifted home key*/
+  {"#3", "S-insert"},    /*shifted insert-character key*/
+  {"#4", "S-left"},      /*shifted left-arrow key*/
+  {"%d", "S-menu"},      /*shifted menu? actually shifted options key*/
+  {"%c", "S-next"},      /*shifted next key*/
+  {"%e", "S-prior"},     /*shifted previous key*/
+  {"%f", "S-print"},     /*shifted print key*/
+  {"%g", "S-redo"},      /*shifted redo key*/
+  {"%i", "S-right"},     /*shifted right-arrow key*/
+  {"!3", "S-undo"}       /*shifted undo key*/
   };
 
 static char **term_get_fkeys_arg;
@@ -1774,7 +1836,7 @@ produce_stretch_glyph (it)
           && calc_pixel_width_or_height (&tem, it, prop, 0, 1, &align_to))
     {
       if (it->glyph_row == NULL || !it->glyph_row->mode_line_p)
-       align_to = (align_to < 0 
+       align_to = (align_to < 0
                    ? 0
                    : align_to - window_box_left_offset (it->w, TEXT_AREA));
       else if (align_to < 0)
@@ -1823,6 +1885,7 @@ produce_special_glyphs (it, what)
      enum display_element_type what;
 {
   struct it temp_it;
+  GLYPH glyph;
 
   temp_it = *it;
   temp_it.dp = NULL;
@@ -1838,15 +1901,11 @@ produce_special_glyphs (it, what)
          && INTEGERP (DISP_CONTINUE_GLYPH (it->dp))
          && GLYPH_CHAR_VALID_P (XINT (DISP_CONTINUE_GLYPH (it->dp))))
        {
-         temp_it.c = FAST_GLYPH_CHAR (XINT (DISP_CONTINUE_GLYPH (it->dp)));
-         temp_it.len = CHAR_BYTES (temp_it.c);
+         glyph = XINT (DISP_CONTINUE_GLYPH (it->dp));
+         glyph = spec_glyph_lookup_face (XWINDOW (it->window), glyph);
        }
       else
-       temp_it.c = '\\';
-
-      produce_glyphs (&temp_it);
-      it->pixel_width = temp_it.pixel_width;
-      it->nglyphs = temp_it.pixel_width;
+       glyph = '\\';
     }
   else if (what == IT_TRUNCATION)
     {
@@ -1855,18 +1914,22 @@ produce_special_glyphs (it, what)
          && INTEGERP (DISP_TRUNC_GLYPH (it->dp))
          && GLYPH_CHAR_VALID_P (XINT (DISP_TRUNC_GLYPH (it->dp))))
        {
-         temp_it.c = FAST_GLYPH_CHAR (XINT (DISP_TRUNC_GLYPH (it->dp)));
-         temp_it.len = CHAR_BYTES (temp_it.c);
+         glyph = XINT (DISP_TRUNC_GLYPH (it->dp));
+         glyph = spec_glyph_lookup_face (XWINDOW (it->window), glyph);
        }
       else
-       temp_it.c = '$';
-
-      produce_glyphs (&temp_it);
-      it->pixel_width = temp_it.pixel_width;
-      it->nglyphs = temp_it.pixel_width;
+       glyph = '$';
     }
   else
     abort ();
+
+  temp_it.c = FAST_GLYPH_CHAR (glyph);
+  temp_it.face_id = FAST_GLYPH_FACE (glyph);
+  temp_it.len = CHAR_BYTES (temp_it.c);
+
+  produce_glyphs (&temp_it);
+  it->pixel_width = temp_it.pixel_width;
+  it->nglyphs = temp_it.pixel_width;
 }
 
 
@@ -1885,7 +1948,8 @@ produce_special_glyphs (it, what)
       ? (TN_no_color_video & (ATTR)) == 0      \
       : 1)
 
-/* Turn appearances of face FACE_ID on tty frame F on.  */
+/* Turn appearances of face FACE_ID on tty frame F on.
+   FACE_ID is a realized face ID number, in the face cache.  */
 
 static void
 turn_on_face (f, face_id)
@@ -1965,18 +2029,20 @@ turn_on_face (f, face_id)
 
   if (TN_max_colors > 0)
     {
-      char *p;
+      char *ts, *p;
 
-      if (fg >= 0 && TS_set_foreground)
+      ts = standout_mode ? TS_set_background : TS_set_foreground;
+      if (fg >= 0 && ts)
        {
-         p = tparam (TS_set_foreground, NULL, 0, (int) fg);
+         p = tparam (ts, NULL, 0, (int) fg);
          OUTPUT (p);
          xfree (p);
        }
 
-      if (bg >= 0 && TS_set_background)
+      ts = standout_mode ? TS_set_foreground : TS_set_background;
+      if (bg >= 0 && ts)
        {
-         p = tparam (TS_set_background, NULL, 0, (int) bg);
+         p = tparam (ts, NULL, 0, (int) bg);
          OUTPUT (p);
          xfree (p);
        }
@@ -2239,6 +2305,9 @@ term_init (terminal_type)
   int status;
   struct frame *sf = XFRAME (selected_frame);
 
+  encode_terminal_src_size = 0;
+  encode_terminal_dst_size = 0;
+
 #ifdef WINDOWSNT
   initialize_w32_display ();
 
@@ -2632,14 +2701,6 @@ to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.",
 
   FRAME_CAN_HAVE_SCROLL_BARS (sf) = 0;
   FRAME_VERTICAL_SCROLL_BAR_TYPE (sf) = vertical_scroll_bar_none;
-
-  if (! terminal_encode_buffer)
-    {
-      terminal_encode_buffer = xmalloc (1024);
-      if (! terminal_encode_buffer)
-       abort ();
-      terminal_encode_buf_size = 1024;
-    }
 #endif /* WINDOWSNT */
 
   xfree (buffer);
@@ -2657,6 +2718,16 @@ fatal (str, arg1, arg2)
   exit (1);
 }
 
+DEFUN ("tty-no-underline", Ftty_no_underline, Stty_no_underline, 0, 0, 0,
+       doc: /* Declare that this terminal does not handle underlining.
+This is used to override the terminfo data, for certain terminals that
+do not really do underlining, but say that they do.  */)
+  ()
+{
+  TS_enter_underline_mode = 0;
+  return Qnil;
+}
+
 void
 syms_of_term ()
 {
@@ -2676,6 +2747,7 @@ The function should accept no arguments.  */);
 
   defsubr (&Stty_display_color_p);
   defsubr (&Stty_display_color_cells);
+  defsubr (&Stty_no_underline);
 }
 
 /* arch-tag: 498e7449-6f2e-45e2-91dd-b7d4ca488193