]> code.delx.au - gnu-emacs/blobdiff - src/ccl.c
(x_create_tip_frame): Initialize frame's colors like
[gnu-emacs] / src / ccl.c
index 157992de0a7325279eecd2a2535705aab0c32284..4f0dfbfbdbc0c92d504e3b323bc03f9d360e8a4d 100644 (file)
--- a/src/ccl.c
+++ b/src/ccl.c
@@ -19,16 +19,14 @@ 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.  */
 
-#include <stdio.h>
-
 #ifdef emacs
-
 #include <config.h>
-
-#ifdef STDC_HEADERS
-#include <stdlib.h>
 #endif
 
+#include <stdio.h>
+
+#ifdef emacs
+
 #include "lisp.h"
 #include "charset.h"
 #include "ccl.h"
@@ -59,7 +57,11 @@ Lisp_Object Qcode_conversion_map_id;
    is an index for Vccl_protram_table. */
 Lisp_Object Qccl_program_idx;
 
-/* Vector of CCL program names vs corresponding program data.  */
+/* Table of registered CCL programs.  Each element is a vector of
+   NAME, CCL_PROG, and RESOLVEDP where NAME (symbol) is the name of
+   the program, CCL_PROG (vector) is the compiled code of the program,
+   RESOLVEDP (t or nil) is the flag to tell if symbols in CCL_PROG is
+   already resolved to index numbers or not.  */
 Lisp_Object Vccl_program_table;
 
 /* CCL (Code Conversion Language) is a simple language which has
@@ -291,10 +293,15 @@ Lisp_Object Vccl_program_table;
                                        */
 
 #define CCL_Call               0x13 /* Call the CCL program whose ID is
-                                       (CC..C).
-                                       1:CCCCCCCCCCCCCCCCCCCC000XXXXX
+                                       CC..C or cc..c.
+                                       1:CCCCCCCCCCCCCCCCCCCCFFFXXXXX
+                                       [2:00000000cccccccccccccccccccc]
                                        ------------------------------
-                                       call (CC..C)
+                                       if (FFF)
+                                         call (cc..c)
+                                         IC++;
+                                       else
+                                         call (CC..C)
                                        */
 
 #define CCL_WriteConstString   0x14 /* Write a constant or a string:
@@ -627,16 +634,15 @@ static tr_stack *mapping_stack_pointer;
 #define CCL_GE         0x14    /* X = (X >= Y) */
 #define CCL_NE         0x15    /* X = (X != Y) */
 
-#define CCL_ENCODE_SJIS 0x16   /* X = HIGHER_BYTE (SJIS (Y, Z))
-                                  r[7] = LOWER_BYTE (SJIS (Y, Z) */
-#define CCL_DECODE_SJIS 0x17   /* X = HIGHER_BYTE (DE-SJIS (Y, Z))
+#define CCL_DECODE_SJIS 0x16   /* X = HIGHER_BYTE (DE-SJIS (Y, Z))
                                   r[7] = LOWER_BYTE (DE-SJIS (Y, Z)) */
+#define CCL_ENCODE_SJIS 0x17   /* X = HIGHER_BYTE (SJIS (Y, Z))
+                                  r[7] = LOWER_BYTE (SJIS (Y, Z) */
 
 /* Terminate CCL program successfully.  */
 #define CCL_SUCCESS                    \
   do {                                 \
     ccl->status = CCL_STAT_SUCCESS;    \
-    ccl->ic = CCL_HEADER_MAIN;         \
     goto ccl_finish;                   \
   } while (0)
 
@@ -660,21 +666,31 @@ static tr_stack *mapping_stack_pointer;
 
 /* Encode one character CH to multibyte form and write to the current
    output buffer.  If CH is less than 256, CH is written as is.  */
-#define CCL_WRITE_CHAR(ch)                             \
-  do {                                                 \
-    if (!dst)                                          \
-      CCL_INVALID_CMD;                                 \
-    else                                               \
-      {                                                        \
-       unsigned char work[4], *str;                    \
-       int len = CHAR_STRING (ch, work, str);          \
-       if (dst + len <= (dst_bytes ? dst_end : src))   \
-         {                                             \
-           while (len--) *dst++ = *str++;              \
-         }                                             \
-       else                                            \
-         CCL_SUSPEND (CCL_STAT_SUSPEND_BY_DST);        \
-      }                                                        \
+#define CCL_WRITE_CHAR(ch)                                     \
+  do {                                                         \
+    int bytes = SINGLE_BYTE_CHAR_P (ch) ? 1: CHAR_BYTES (ch);  \
+    if (ch == '\n' && ccl->eol_type == CODING_EOL_CRLF)                \
+      bytes++;                                                 \
+    if (!dst)                                                  \
+      CCL_INVALID_CMD;                                         \
+    else if (dst + bytes <= (dst_bytes ? dst_end : src))       \
+      {                                                                \
+       if (ch == '\n')                                         \
+         {                                                     \
+           if (ccl->eol_type == CODING_EOL_CRLF)               \
+             *dst++ = '\r', *dst++ = '\n';                     \
+           else if (ccl->eol_type == CODING_EOL_CR)            \
+             *dst++ = '\r';                                    \
+           else                                                \
+             *dst++ = '\n';                                    \
+         }                                                     \
+       else if (bytes == 1)                                    \
+         *dst++ = (ch);                                        \
+       else                                                    \
+         dst += CHAR_STRING (ch, dst);                         \
+      }                                                                \
+    else                                                       \
+      CCL_SUSPEND (CCL_STAT_SUSPEND_BY_DST);                   \
   } while (0)
 
 /* Write a string at ccl_prog[IC] of length LEN to the current output
@@ -708,6 +724,31 @@ static tr_stack *mapping_stack_pointer;
   } while (0)
 
 
+/* Set C to the character code made from CHARSET and CODE.  This is
+   like MAKE_CHAR but check the validity of CHARSET and CODE.  If they
+   are not valid, set C to (CODE & 0xFF) because that is usually the
+   case that CCL_ReadMultibyteChar2 read an invalid code and it set
+   CODE to that invalid byte.  */
+
+#define CCL_MAKE_CHAR(charset, code, c)                                \
+  do {                                                         \
+    if (charset == CHARSET_ASCII)                              \
+      c = code & 0xFF;                                         \
+    else if (CHARSET_DEFINED_P (charset)                       \
+            && (code & 0x7F) >= 32                             \
+            && (code < 256 || ((code >> 7) & 0x7F) >= 32))     \
+      {                                                                \
+       int c1 = code & 0x7F, c2 = 0;                           \
+                                                               \
+       if (code >= 256)                                        \
+         c2 = c1, c1 = (code >> 7) & 0x7F;                     \
+       c = MAKE_CHAR (charset, c1, c2);                        \
+      }                                                                \
+    else                                                       \
+      c = code & 0xFF;                                         \
+  } while (0)
+
+
 /* Execute CCL code on SRC_BYTES length text at SOURCE.  The resulting
    text goes to a place pointed by DESTINATION, the length of which
    should not exceed DST_BYTES.  The bytes actually processed is
@@ -728,6 +769,9 @@ struct ccl_prog_stack
     int ic;                    /* Instruction Counter.  */
   };
 
+/* For the moment, we only support depth 256 of stack.  */ 
+static struct ccl_prog_stack ccl_prog_stack_struct[256];
+
 int
 ccl_driver (ccl, source, destination, src_bytes, dst_bytes, consumed)
      struct ccl_program *ccl;
@@ -743,9 +787,9 @@ ccl_driver (ccl, source, destination, src_bytes, dst_bytes, consumed)
   unsigned char *dst = destination, *dst_end = dst + dst_bytes;
   int jump_address;
   int i, j, op;
-  int stack_idx = 0;
-  /* For the moment, we only support depth 256 of stack.  */ 
-  struct ccl_prog_stack ccl_prog_stack_struct[256];
+  int stack_idx = ccl->stack_idx;
+  /* Instruction counter of the current CCL code. */
+  int this_ic;
 
   if (ic >= ccl->eof_ic)
     ic = CCL_HEADER_MAIN;
@@ -778,6 +822,7 @@ ccl_driver (ccl, source, destination, src_bytes, dst_bytes, consumed)
          break;
        }
 
+      this_ic = ic;
       code = XINT (ccl_prog[ic]); ic++;
       field1 = code >> 8;
       field2 = (code & 0xFF) >> 5;
@@ -899,7 +944,7 @@ ccl_driver (ccl, source, destination, src_bytes, dst_bytes, consumed)
          i = reg[RRR];
          j = XINT (ccl_prog[ic]);
          op = field1 >> 6;
-         ic++;
+         jump_address = ic + 1;
          goto ccl_set_expr;
 
        case CCL_WriteRegister: /* CCCCCCCCCCCCCCCCCCCrrrXXXXX */
@@ -919,18 +964,30 @@ ccl_driver (ccl, source, destination, src_bytes, dst_bytes, consumed)
          i = reg[RRR];
          j = reg[Rrr];
          op = field1 >> 6;
+         jump_address = ic;
          goto ccl_set_expr;
 
-       case CCL_Call:          /* CCCCCCCCCCCCCCCCCCCC000XXXXX */
+       case CCL_Call:          /* 1:CCCCCCCCCCCCCCCCCCCCFFFXXXXX */
          {
            Lisp_Object slot;
+           int prog_id;
+
+           /* If FFF is nonzero, the CCL program ID is in the
+               following code.  */
+           if (rrr)
+             {
+               prog_id = XINT (ccl_prog[ic]);
+               ic++;
+             }
+           else
+             prog_id = field1;
 
            if (stack_idx >= 256
-               || field1 < 0
-               || field1 >= XVECTOR (Vccl_program_table)->size
-               || (slot = XVECTOR (Vccl_program_table)->contents[field1],
-                   !CONSP (slot))
-               || !VECTORP (XCONS (slot)->cdr))
+               || prog_id < 0
+               || prog_id >= XVECTOR (Vccl_program_table)->size
+               || (slot = XVECTOR (Vccl_program_table)->contents[prog_id],
+                   !VECTORP (slot))
+               || !VECTORP (XVECTOR (slot)->contents[1]))
              {
                if (stack_idx > 0)
                  {
@@ -943,7 +1000,7 @@ ccl_driver (ccl, source, destination, src_bytes, dst_bytes, consumed)
            ccl_prog_stack_struct[stack_idx].ccl_prog = ccl_prog;
            ccl_prog_stack_struct[stack_idx].ic = ic;
            stack_idx++;
-           ccl_prog = XVECTOR (XCONS (slot)->cdr)->contents;
+           ccl_prog = XVECTOR (XVECTOR (slot)->contents[1])->contents;
            ic = CCL_HEADER_MAIN;
          }
          break;
@@ -969,12 +1026,18 @@ ccl_driver (ccl, source, destination, src_bytes, dst_bytes, consumed)
          break;
 
        case CCL_End:           /* 0000000000000000000000XXXXX */
-         if (stack_idx-- > 0)
+         if (stack_idx > 0)
            {
+             stack_idx--;
              ccl_prog = ccl_prog_stack_struct[stack_idx].ccl_prog;
              ic = ccl_prog_stack_struct[stack_idx].ic;
              break;
            }
+         if (src)
+           src = src_end;
+         /* ccl->ic should points to this command code again to
+             suppress further processing.  */
+         ic--;
          CCL_SUCCESS;
 
        case CCL_ExprSelfConst: /* 00000OPERATION000000rrrXXXXX */
@@ -1070,8 +1133,8 @@ ccl_driver (ccl, source, destination, src_bytes, dst_bytes, consumed)
            case CCL_LE: reg[rrr] = i <= j; break;
            case CCL_GE: reg[rrr] = i >= j; break;
            case CCL_NE: reg[rrr] = i != j; break;
-           case CCL_ENCODE_SJIS: ENCODE_SJIS (i, j, reg[rrr], reg[7]); break;
            case CCL_DECODE_SJIS: DECODE_SJIS (i, j, reg[rrr], reg[7]); break;
+           case CCL_ENCODE_SJIS: ENCODE_SJIS (i, j, reg[rrr], reg[7]); break;
            default: CCL_INVALID_CMD;
            }
          code &= 0x1F;
@@ -1079,6 +1142,7 @@ ccl_driver (ccl, source, destination, src_bytes, dst_bytes, consumed)
            {
              i = reg[rrr];
              CCL_WRITE_CHAR (i);
+             ic = jump_address;
            }
          else if (!reg[rrr])
            ic = jump_address;
@@ -1090,6 +1154,7 @@ ccl_driver (ccl, source, destination, src_bytes, dst_bytes, consumed)
            case CCL_ReadMultibyteChar2:
              if (!src)
                CCL_INVALID_CMD;
+
              do {
                if (src >= src_end)
                  {
@@ -1098,43 +1163,6 @@ ccl_driver (ccl, source, destination, src_bytes, dst_bytes, consumed)
                  }
              
                i = *src++;
-               if (i == LEADING_CODE_COMPOSITION)
-                 {
-                   if (src >= src_end)
-                     goto ccl_read_multibyte_character_suspend;
-                   if (*src == 0xFF)
-                     {
-                       ccl->private_state = COMPOSING_WITH_RULE_HEAD;
-                       src++;
-                     }
-                   else
-                     ccl->private_state = COMPOSING_NO_RULE_HEAD;
-                 }
-               if (ccl->private_state != 0)
-                 {
-                   /* composite character */
-                   if (*src < 0xA0)
-                     ccl->private_state = 0;
-                   else
-                     {
-                       if (i == 0xA0)
-                         {
-                           if (src >= src_end)
-                             goto ccl_read_multibyte_character_suspend;
-                           i = *src++ & 0x7F;
-                         }
-                       else
-                         i -= 0x20;
-
-                       if (COMPOSING_WITH_RULE_RULE == ccl->private_state)
-                         {
-                           ccl->private_state = COMPOSING_WITH_RULE_HEAD;
-                           continue;
-                         }
-                       else if (COMPOSING_WITH_RULE_HEAD == ccl->private_state)
-                         ccl->private_state = COMPOSING_WITH_RULE_RULE;
-                     }
-                 }
                if (i < 0x80)
                  {
                    /* ASCII */
@@ -1175,13 +1203,26 @@ ccl_driver (ccl, source, destination, src_bytes, dst_bytes, consumed)
                    reg[rrr] = ((i << 7) | (*src & 0x7F));
                    src++;
                  }
+               else if (i == LEADING_CODE_8_BIT_CONTROL)
+                 {
+                   if (src >= src_end)
+                     goto ccl_read_multibyte_character_suspend;
+                   reg[RRR] = CHARSET_8_BIT_CONTROL;
+                   reg[rrr] = (*src++ - 0x20);
+                 }
+               else if (i >= 0xA0)
+                 {
+                   reg[RRR] = CHARSET_8_BIT_GRAPHIC;
+                   reg[rrr] = i;
+                 }
                else
                  {
-                   /* INVALID CODE
-                      Returned charset is -1.  */
-                   reg[RRR] = -1;
+                   /* INVALID CODE.  Return a single byte character.  */
+                   reg[RRR] = CHARSET_ASCII;
+                   reg[rrr] = i;
                  }
-             } while (0);
+               break;
+             } while (1);
              break;
 
            ccl_read_multibyte_character_suspend:
@@ -1198,10 +1239,10 @@ ccl_driver (ccl, source, destination, src_bytes, dst_bytes, consumed)
 
            case CCL_WriteMultibyteChar2:
              i = reg[RRR]; /* charset */
-             if (i == CHARSET_ASCII)
-               i = reg[rrr] & 0x7F;
-             else if (i == CHARSET_COMPOSITION)
-               i = MAKE_COMPOSITE_CHAR (reg[rrr]);
+             if (i == CHARSET_ASCII
+                 || i == CHARSET_8_BIT_CONTROL
+                 || i == CHARSET_8_BIT_GRAPHIC)
+               i = reg[rrr] & 0xFF;
              else if (CHARSET_DIMENSION (i) == 1)
                i = ((i - 0x70) << 7) | (reg[rrr] & 0x7F);
              else if (i < MIN_CHARSET_PRIVATE_DIMENSION2)
@@ -1214,21 +1255,7 @@ ccl_driver (ccl, source, destination, src_bytes, dst_bytes, consumed)
              break;
 
            case CCL_TranslateCharacter:
-             i = reg[RRR]; /* charset */
-             if (i == CHARSET_ASCII)
-               i = reg[rrr] & 0x7F;
-             else if (i == CHARSET_COMPOSITION)
-               {
-                 reg[RRR] = -1;
-                 break;
-               }
-             else if (CHARSET_DIMENSION (i) == 1)
-               i = ((i - 0x70) << 7) | (reg[rrr] & 0x7F);
-             else if (i < MIN_CHARSET_PRIVATE_DIMENSION2)
-               i = ((i - 0x8F) << 14) | (reg[rrr] & 0x3FFF);
-             else
-               i = ((i - 0xE0) << 14) | (reg[rrr] & 0x3FFF);
-
+             CCL_MAKE_CHAR (reg[RRR], reg[rrr], i);
              op = translate_char (GET_TRANSLATION_TABLE (reg[Rrr]),
                                   i, -1, 0, 0);
              SPLIT_CHAR (op, reg[RRR], i, j);
@@ -1241,21 +1268,7 @@ ccl_driver (ccl, source, destination, src_bytes, dst_bytes, consumed)
            case CCL_TranslateCharacterConstTbl:
              op = XINT (ccl_prog[ic]); /* table */
              ic++;
-             i = reg[RRR]; /* charset */
-             if (i == CHARSET_ASCII)
-               i = reg[rrr] & 0x7F;
-             else if (i == CHARSET_COMPOSITION)
-               {
-                 reg[RRR] = -1;
-                 break;
-               }
-             else if (CHARSET_DIMENSION (i) == 1)
-               i = ((i - 0x70) << 7) | (reg[rrr] & 0x7F);
-             else if (i < MIN_CHARSET_PRIVATE_DIMENSION2)
-               i = ((i - 0x8F) << 14) | (reg[rrr] & 0x3FFF);
-             else
-               i = ((i - 0xE0) << 14) | (reg[rrr] & 0x3FFF);
-
+             CCL_MAKE_CHAR (reg[RRR], reg[rrr], i);
              op = translate_char (GET_TRANSLATION_TABLE (op), i, -1, 0, 0);
              SPLIT_CHAR (op, reg[RRR], i, j);
              if (j != -1)
@@ -1295,7 +1308,7 @@ ccl_driver (ccl, source, destination, src_bytes, dst_bytes, consumed)
 
                    /* Check map varidity.  */
                    if (!CONSP (map)) continue;
-                   map = XCONS(map)->cdr;
+                   map = XCDR (map);
                    if (!VECTORP (map)) continue;
                    size = XVECTOR (map)->size;
                    if (size <= 1) continue;
@@ -1339,8 +1352,8 @@ ccl_driver (ccl, source, destination, src_bytes, dst_bytes, consumed)
                      }
                    else if (CONSP (content))
                      {
-                       attrib = XCONS (content)->car;
-                       value = XCONS (content)->cdr;
+                       attrib = XCAR (content);
+                       value = XCDR (content);
                        if (!NUMBERP (attrib) || !NUMBERP (value))
                          continue;
                        reg[RRR] = i;
@@ -1404,7 +1417,7 @@ ccl_driver (ccl, source, destination, src_bytes, dst_bytes, consumed)
 
                    /* Check map varidity.  */
                    if (!CONSP (map)) continue;
-                   map = XCONS (map)->cdr;
+                   map = XCDR (map);
                    if (!VECTORP (map)) continue;
                    size = XVECTOR (map)->size;
                    if (size <= 1) continue;
@@ -1444,8 +1457,8 @@ ccl_driver (ccl, source, destination, src_bytes, dst_bytes, consumed)
                      }
                    else if (CONSP (content))
                      {
-                       attrib = XCONS (content)->car;
-                       value = XCONS (content)->cdr;
+                       attrib = XCAR (content);
+                       value = XCDR (content);
                        if (!NUMBERP (attrib) || !NUMBERP (value))
                          continue;
                        reg[RRR] = i;
@@ -1462,6 +1475,7 @@ ccl_driver (ccl, source, destination, src_bytes, dst_bytes, consumed)
                      }
                    else if (EQ (content, Qlambda))
                      {
+                       reg[RRR] = i;
                        break;
                      }
                    else
@@ -1489,7 +1503,7 @@ ccl_driver (ccl, source, destination, src_bytes, dst_bytes, consumed)
                    reg[RRR] = -1;
                    break;
                  }
-               map = XCONS(map)->cdr;
+               map = XCDR (map);
                if (!VECTORP (map))
                  {
                    reg[RRR] = -1;
@@ -1504,17 +1518,17 @@ ccl_driver (ccl, source, destination, src_bytes, dst_bytes, consumed)
                  reg[RRR] = -1;
                else
                  {
+                   reg[RRR] = 0;
                    content = XVECTOR (map)->contents[point];
                    if (NILP (content))
                      reg[RRR] = -1;
                    else if (NUMBERP (content))
                      reg[rrr] = XINT (content);
-                   else if (EQ (content, Qt))
-                     reg[RRR] = i;
+                   else if (EQ (content, Qt));
                    else if (CONSP (content))
                      {
-                       attrib = XCONS (content)->car;
-                       value = XCONS (content)->cdr;
+                       attrib = XCAR (content);
+                       value = XCDR (content);
                        if (!NUMBERP (attrib) || !NUMBERP (value))
                          continue;
                        reg[rrr] = XUINT(value);
@@ -1552,7 +1566,7 @@ ccl_driver (ccl, source, destination, src_bytes, dst_bytes, consumed)
        {
        case CCL_STAT_INVALID_CMD:
          sprintf(msg, "\nCCL: Invalid command %x (ccl_code = %x) at %d.",
-                 code & 0x1F, code, ic);
+                 code & 0x1F, code, this_ic);
 #ifdef CCL_DEBUG
          {
            int i = ccl_backtrace_idx - 1;
@@ -1600,87 +1614,192 @@ ccl_driver (ccl, source, destination, src_bytes, dst_bytes, consumed)
 
  ccl_finish:
   ccl->ic = ic;
+  ccl->stack_idx = stack_idx;
+  ccl->prog = ccl_prog;
   if (consumed) *consumed = src - source;
   return (dst ? dst - destination : 0);
 }
 
-/* Setup fields of the structure pointed by CCL appropriately for the
-   execution of compiled CCL code in VEC (vector of integer).  */
-void
-setup_ccl_program (ccl, vec)
-     struct ccl_program *ccl;
-     Lisp_Object vec;
-{
-  int i;
-
-  ccl->size = XVECTOR (vec)->size;
-  ccl->prog = XVECTOR (vec)->contents;
-  ccl->ic = CCL_HEADER_MAIN;
-  ccl->eof_ic = XINT (XVECTOR (vec)->contents[CCL_HEADER_EOF]);
-  ccl->buf_magnification = XINT (XVECTOR (vec)->contents[CCL_HEADER_BUF_MAG]);
-  for (i = 0; i < 8; i++)
-    ccl->reg[i] = 0;
-  ccl->last_block = 0;
-  ccl->private_state = 0;
-  ccl->status = 0;
-}
-
 /* Resolve symbols in the specified CCL code (Lisp vector).  This
    function converts symbols of code conversion maps and character
-   translation tables embeded in the CCL code into their ID numbers.  */
+   translation tables embeded in the CCL code into their ID numbers.
+
+   The return value is a vector (CCL itself or a new vector in which
+   all symbols are resolved), Qt if resolving of some symbol failed,
+   or nil if CCL contains invalid data.  */
 
-Lisp_Object
+static Lisp_Object
 resolve_symbol_ccl_program (ccl)
      Lisp_Object ccl;
 {
-  int i, veclen;
-  Lisp_Object result, contents, prop;
+  int i, veclen, unresolved = 0;
+  Lisp_Object result, contents, val;
 
   result = ccl;
   veclen = XVECTOR (result)->size;
 
-  /* Set CCL program's table ID */
   for (i = 0; i < veclen; i++)
     {
       contents = XVECTOR (result)->contents[i];
-      if (SYMBOLP (contents))
+      if (INTEGERP (contents))
+       continue;
+      else if (CONSP (contents)
+              && SYMBOLP (XCAR (contents))
+              && SYMBOLP (XCDR (contents)))
        {
-         if (EQ(result, ccl))
+         /* This is the new style for embedding symbols.  The form is
+            (SYMBOL . PROPERTY).  (get SYMBOL PROPERTY) should give
+            an index number.  */
+
+         if (EQ (result, ccl))
+           result =  Fcopy_sequence (ccl);
+
+         val = Fget (XCAR (contents), XCDR (contents));
+         if (NATNUMP (val))
+           XVECTOR (result)->contents[i] = val;
+         else
+           unresolved = 1;
+         continue;
+       }
+      else if (SYMBOLP (contents))
+       {
+         /* This is the old style for embedding symbols.  This style
+             may lead to a bug if, for instance, a translation table
+             and a code conversion map have the same name.  */
+         if (EQ (result, ccl))
            result = Fcopy_sequence (ccl);
 
-         prop = Fget (contents, Qtranslation_table_id);
-         if (NUMBERP (prop))
-           {
-             XVECTOR (result)->contents[i] = prop;
-             continue;
-           }
-         prop = Fget (contents, Qcode_conversion_map_id);
-         if (NUMBERP (prop))
-           {
-             XVECTOR (result)->contents[i] = prop;
-             continue;
-           }
-         prop = Fget (contents, Qccl_program_idx);
-         if (NUMBERP (prop))
+         val = Fget (contents, Qtranslation_table_id);
+         if (NATNUMP (val))
+           XVECTOR (result)->contents[i] = val;
+         else
            {
-             XVECTOR (result)->contents[i] = prop;
-             continue;
+             val = Fget (contents, Qcode_conversion_map_id);
+             if (NATNUMP (val))
+               XVECTOR (result)->contents[i] = val;
+             else
+               {
+                 val = Fget (contents, Qccl_program_idx);
+                 if (NATNUMP (val))
+                   XVECTOR (result)->contents[i] = val;
+                 else
+                   unresolved = 1;
+               }
            }
+         continue;
        }
+      return Qnil;
     }
 
-  return result;
+  return (unresolved ? Qt : result);
 }
 
+/* Return the compiled code (vector) of CCL program CCL_PROG.
+   CCL_PROG is a name (symbol) of the program or already compiled
+   code.  If necessary, resolve symbols in the compiled code to index
+   numbers.  If we failed to get the compiled code or to resolve
+   symbols, return Qnil.  */
+
+static Lisp_Object
+ccl_get_compiled_code (ccl_prog)
+     Lisp_Object ccl_prog;
+{
+  Lisp_Object val, slot;
+
+  if (VECTORP (ccl_prog))
+    {
+      val = resolve_symbol_ccl_program (ccl_prog);
+      return (VECTORP (val) ? val : Qnil);
+    }
+  if (!SYMBOLP (ccl_prog))
+    return Qnil;
+
+  val = Fget (ccl_prog, Qccl_program_idx);
+  if (! NATNUMP (val)
+      || XINT (val) >= XVECTOR (Vccl_program_table)->size)
+    return Qnil;
+  slot = XVECTOR (Vccl_program_table)->contents[XINT (val)];
+  if (! VECTORP (slot)
+      || XVECTOR (slot)->size != 3
+      || ! VECTORP (XVECTOR (slot)->contents[1]))
+    return Qnil;
+  if (NILP (XVECTOR (slot)->contents[2]))
+    {
+      val = resolve_symbol_ccl_program (XVECTOR (slot)->contents[1]);
+      if (! VECTORP (val))
+       return Qnil;
+      XVECTOR (slot)->contents[1] = val;
+      XVECTOR (slot)->contents[2] = Qt;
+    }
+  return XVECTOR (slot)->contents[1];
+}
+
+/* Setup fields of the structure pointed by CCL appropriately for the
+   execution of CCL program CCL_PROG.  CCL_PROG is the name (symbol)
+   of the CCL program or the already compiled code (vector).
+   Return 0 if we succeed this setup, else return -1.
+
+   If CCL_PROG is nil, we just reset the structure pointed by CCL.  */
+int
+setup_ccl_program (ccl, ccl_prog)
+     struct ccl_program *ccl;
+     Lisp_Object ccl_prog;
+{
+  int i;
+
+  if (! NILP (ccl_prog))
+    {
+      struct Lisp_Vector *vp;
+
+      ccl_prog = ccl_get_compiled_code (ccl_prog);
+      if (! VECTORP (ccl_prog))
+       return -1;
+      vp = XVECTOR (ccl_prog);
+      ccl->size = vp->size;
+      ccl->prog = vp->contents;
+      ccl->eof_ic = XINT (vp->contents[CCL_HEADER_EOF]);
+      ccl->buf_magnification = XINT (vp->contents[CCL_HEADER_BUF_MAG]);
+    }
+  ccl->ic = CCL_HEADER_MAIN;
+  for (i = 0; i < 8; i++)
+    ccl->reg[i] = 0;
+  ccl->last_block = 0;
+  ccl->private_state = 0;
+  ccl->status = 0;
+  ccl->stack_idx = 0;
+  ccl->eol_type = CODING_EOL_LF;
+  return 0;
+}
 
 #ifdef emacs
 
+DEFUN ("ccl-program-p", Fccl_program_p, Sccl_program_p, 1, 1, 0,
+  "Return t if OBJECT is a CCL program name or a compiled CCL program code.")
+  (object)
+     Lisp_Object object;
+{
+  Lisp_Object val;
+
+  if (VECTORP (object))
+    {
+      val = resolve_symbol_ccl_program (object);
+      return (VECTORP (val) ? Qt : Qnil);
+    }
+  if (!SYMBOLP (object))
+    return Qnil;
+
+  val = Fget (object, Qccl_program_idx);
+  return ((! NATNUMP (val)
+          || XINT (val) >= XVECTOR (Vccl_program_table)->size)
+         ? Qnil : Qt);
+}
+
 DEFUN ("ccl-execute", Fccl_execute, Sccl_execute, 2, 2, 0,
   "Execute CCL-PROGRAM with registers initialized by REGISTERS.\n\
 \n\
-CCL-PROGRAM is a symbol registered by register-ccl-program,\n\
+CCL-PROGRAM is a CCL program name (symbol)\n\
 or a compiled code generated by `ccl-compile' (for backward compatibility,\n\
-in this case, the execution is slower).\n\
+in this case, the overhead of the execution is bigger than the former case).\n\
 No I/O commands should appear in CCL-PROGRAM.\n\
 \n\
 REGISTERS is a vector of [R0 R1 ... R7] where RN is an initial value\n\
@@ -1693,27 +1812,14 @@ As side effect, each element of REGISTERS holds the value of\n\
 {
   struct ccl_program ccl;
   int i;
-  Lisp_Object ccl_id;
 
-  if ((SYMBOLP (ccl_prog)) &&
-      (!NILP (ccl_id = Fget (ccl_prog, Qccl_program_idx))))
-    {
-      ccl_prog = XVECTOR (Vccl_program_table)->contents[XUINT (ccl_id)];
-      CHECK_LIST (ccl_prog, 0);
-      ccl_prog = XCONS (ccl_prog)->cdr;
-      CHECK_VECTOR (ccl_prog, 1);
-    }
-  else
-    {
-      CHECK_VECTOR (ccl_prog, 1);
-      ccl_prog = resolve_symbol_ccl_program (ccl_prog);
-    }
+  if (setup_ccl_program (&ccl, ccl_prog) < 0)
+    error ("Invalid CCL program");
 
-  CHECK_VECTOR (reg, 2);
+  CHECK_VECTOR (reg, 1);
   if (XVECTOR (reg)->size != 8)
-    error ("Invalid length of vector REGISTERS");
+    error ("Length of vector REGISTERS is not 9");
 
-  setup_ccl_program (&ccl, ccl_prog);
   for (i = 0; i < 8; i++)
     ccl.reg[i] = (INTEGERP (XVECTOR (reg)->contents[i])
                  ? XINT (XVECTOR (reg)->contents[i])
@@ -1761,30 +1867,18 @@ is a unibyte string.  By default it is a multibyte string.")
   int i, produced;
   int outbufsize;
   char *outbuf;
-  struct gcpro gcpro1, gcpro2, gcpro3;
-  Lisp_Object ccl_id;
+  struct gcpro gcpro1, gcpro2;
 
-  if ((SYMBOLP (ccl_prog)) &&
-      (!NILP (ccl_id = Fget (ccl_prog, Qccl_program_idx))))
-    {
-      ccl_prog = XVECTOR (Vccl_program_table)->contents[XUINT (ccl_id)];
-      CHECK_LIST (ccl_prog, 0);
-      ccl_prog = XCONS (ccl_prog)->cdr;
-      CHECK_VECTOR (ccl_prog, 1);
-    }
-  else
-    {
-      CHECK_VECTOR (ccl_prog, 1);
-      ccl_prog = resolve_symbol_ccl_program (ccl_prog);
-    }
+  if (setup_ccl_program (&ccl, ccl_prog) < 0)
+    error ("Invalid CCL program");
 
   CHECK_VECTOR (status, 1);
   if (XVECTOR (status)->size != 9)
-    error ("Invalid length of vector STATUS");
+    error ("Length of vector STATUS is not 9");
   CHECK_STRING (str, 2);
-  GCPRO3 (ccl_prog, status, str);
 
-  setup_ccl_program (&ccl, ccl_prog);
+  GCPRO2 (status, str);
+
   for (i = 0; i < 8; i++)
     {
       if (NILP (XVECTOR (status)->contents[i]))
@@ -1826,50 +1920,73 @@ is a unibyte string.  By default it is a multibyte string.")
 
 DEFUN ("register-ccl-program", Fregister_ccl_program, Sregister_ccl_program,
        2, 2, 0,
-  "Register CCL program PROGRAM of NAME in `ccl-program-table'.\n\
-PROGRAM should be a compiled code of CCL program, or nil.\n\
+  "Register CCL program CCL_PROG as NAME in `ccl-program-table'.\n\
+CCL_PROG should be a compiled CCL program (vector), or nil.\n\
+If it is nil, just reserve NAME as a CCL program name.\n\
 Return index number of the registered CCL program.")
   (name, ccl_prog)
      Lisp_Object name, ccl_prog;
 {
   int len = XVECTOR (Vccl_program_table)->size;
-  int i;
+  int idx;
+  Lisp_Object resolved;
 
   CHECK_SYMBOL (name, 0);
+  resolved = Qnil;
   if (!NILP (ccl_prog))
     {
       CHECK_VECTOR (ccl_prog, 1);
-      ccl_prog = resolve_symbol_ccl_program (ccl_prog);
+      resolved = resolve_symbol_ccl_program (ccl_prog);
+      if (! NILP (resolved))
+       {
+         ccl_prog = resolved;
+         resolved = Qt;
+       }
     }
-  
-  for (i = 0; i < len; i++)
+
+  for (idx = 0; idx < len; idx++)
     {
-      Lisp_Object slot = XVECTOR (Vccl_program_table)->contents[i];
+      Lisp_Object slot;
 
-      if (!CONSP (slot))
+      slot = XVECTOR (Vccl_program_table)->contents[idx];
+      if (!VECTORP (slot))
+       /* This is the first unsed slot.  Register NAME here.  */
        break;
 
-      if (EQ (name, XCONS (slot)->car))
+      if (EQ (name, XVECTOR (slot)->contents[0]))
        {
-         XCONS (slot)->cdr = ccl_prog;
-         return make_number (i);
+         /* Update this slot.  */
+         XVECTOR (slot)->contents[1] = ccl_prog;
+         XVECTOR (slot)->contents[2] = resolved;
+         return make_number (idx);
        }
     }
 
-  if (i == len)
+  if (idx == len)
     {
-      Lisp_Object new_table = Fmake_vector (make_number (len * 2), Qnil);
+      /* Extend the table.  */
+      Lisp_Object new_table;
       int j;
 
+      new_table = Fmake_vector (make_number (len * 2), Qnil);
       for (j = 0; j < len; j++)
        XVECTOR (new_table)->contents[j]
          = XVECTOR (Vccl_program_table)->contents[j];
       Vccl_program_table = new_table;
     }
 
-  XVECTOR (Vccl_program_table)->contents[i] = Fcons (name, ccl_prog);
-  Fput (name, Qccl_program_idx, make_number (i));
-  return make_number (i);
+  {
+    Lisp_Object elt;
+
+    elt = Fmake_vector (make_number (3), Qnil);
+    XVECTOR (elt)->contents[0] = name;
+    XVECTOR (elt)->contents[1] = ccl_prog;
+    XVECTOR (elt)->contents[2] = resolved;
+    XVECTOR (Vccl_program_table)->contents[idx] = elt;
+  }
+
+  Fput (name, Qccl_program_idx, make_number (idx));
+  return make_number (idx);
 }
 
 /* Register code conversion map.
@@ -1903,10 +2020,10 @@ Return index number of the registered map.")
       if (!CONSP (slot))
        break;
 
-      if (EQ (symbol, XCONS (slot)->car))
+      if (EQ (symbol, XCAR (slot)))
        {
          index = make_number (i);
-         XCONS (slot)->cdr = map;
+         XCDR (slot) = map;
          Fput (symbol, Qcode_conversion_map, map);
          Fput (symbol, Qcode_conversion_map_id, index);
          return index;
@@ -1967,6 +2084,7 @@ The code point in the font is set in CCL registers R1 and R2\n\
 If the font is single-byte font, the register R2 is not used.");
   Vfont_ccl_encoder_alist = Qnil;
 
+  defsubr (&Sccl_program_p);
   defsubr (&Sccl_execute);
   defsubr (&Sccl_execute_on_string);
   defsubr (&Sregister_ccl_program);