diff src/mule-ccl.c @ 70:131b0175ea99 r20-0b30

Import from CVS: tag r20-0b30
author cvs
date Mon, 13 Aug 2007 09:02:59 +0200
parents
children 538048ae2ab8
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mule-ccl.c	Mon Aug 13 09:02:59 2007 +0200
@@ -0,0 +1,641 @@
+/* CCL -- Code Conversion Language Interpreter
+   Copyright (C) 1992, 1995 Free Software Foundation, Inc.
+   Copyright (C) 1995 Sun Microsystems, Inc.
+
+This file is part of XEmacs.
+
+XEmacs is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+XEmacs 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
+along with XEmacs; see the file COPYING.  If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+/* Synched up with: Mule 2.3.  Not in FSF. */
+
+#include <config.h>
+#include "lisp.h"
+
+#include "buffer.h"
+#include "mule-coding.h"
+
+/* CCL operators */
+#define CCL_SetCS		0x00
+#define CCL_SetCL		0x01
+#define CCL_SetR		0x02
+#define CCL_SetA		0x03
+#define CCL_Jump		0x04
+#define CCL_JumpCond		0x05
+#define CCL_WriteJump		0x06
+#define CCL_WriteReadJump	0x07
+#define CCL_WriteCJump		0x08
+#define CCL_WriteCReadJump	0x09
+#define CCL_WriteSJump		0x0A
+#define CCL_WriteSReadJump	0x0B
+#define CCL_WriteAReadJump	0x0C
+#define CCL_Branch		0x0D
+#define CCL_Read1		0x0E
+#define CCL_Read2		0x0F
+#define CCL_ReadBranch		0x10
+#define CCL_Write1		0x11
+#define CCL_Write2		0x12
+#define CCL_WriteC		0x13
+#define CCL_WriteS		0x14
+#define CCL_WriteA		0x15
+#define CCL_End			0x16
+#define CCL_SetSelfCS		0x17
+#define CCL_SetSelfCL		0x18
+#define CCL_SetSelfR		0x19
+#define CCL_SetExprCL		0x1A
+#define CCL_SetExprR		0x1B
+#define CCL_JumpCondC		0x1C
+#define CCL_JumpCondR		0x1D
+#define CCL_ReadJumpCondC	0x1E
+#define CCL_ReadJumpCondR	0x1F
+
+#define CCL_PLUS	0x00
+#define CCL_MINUS	0x01
+#define CCL_MUL		0x02
+#define CCL_DIV		0x03
+#define CCL_MOD		0x04
+#define CCL_AND		0x05
+#define CCL_OR		0x06
+#define CCL_XOR		0x07
+#define CCL_LSH		0x08
+#define CCL_RSH		0x09
+#define CCL_LSH8	0x0A
+#define CCL_RSH8	0x0B
+#define CCL_DIVMOD	0x0C
+#define CCL_LS		0x10
+#define CCL_GT		0x11
+#define CCL_EQ		0x12
+#define CCL_LE		0x13
+#define CCL_GE		0x14
+#define CCL_NE		0x15
+
+/* Header of CCL compiled code */
+#define CCL_HEADER_EOF		0
+#define CCL_HEADER_MAIN		1
+
+#define CCL_STAT_SUCCESS	0
+#define CCL_STAT_SUSPEND	1
+#define CCL_STAT_INVALID_CMD	2
+
+#define CCL_SUCCESS			\
+  ccl->status = CCL_STAT_SUCCESS;	\
+  goto ccl_finish
+#define CCL_SUSPEND			\
+  ccl->ic = --ic;			\
+  ccl->status = CCL_STAT_SUSPEND;	\
+  goto ccl_finish
+#define CCL_INVALID_CMD			\
+  ccl->status = CCL_STAT_INVALID_CMD;	\
+  goto ccl_error_handler
+
+#define CCL_WRITE_CHAR(ch) do					\
+{								\
+  if (!src)							\
+    {								\
+      CCL_INVALID_CMD;						\
+    }								\
+  else								\
+    {								\
+      /* !!#### is this correct for both directions????? */	\
+      Bufbyte __buf__[MAX_EMCHAR_LEN];				\
+      int __len__;						\
+      __len__ = set_charptr_emchar (__buf__, ch);		\
+      Dynarr_add_many (dst, __buf__, __len__);			\
+    }								\
+} while (0)
+
+#define CCL_WRITE_STRING(len) do			\
+{							\
+  if (!src)						\
+    {							\
+      CCL_INVALID_CMD;					\
+    }							\
+  else							\
+    {							\
+      for (j = 0; j < len; j++)				\
+	Dynarr_add (dst, XINT (prog[ic + 1 + j]));	\
+    }							\
+} while (0)
+
+#define CCL_READ_CHAR(r) do		\
+{					\
+  if (!src)				\
+    {					\
+      CCL_INVALID_CMD;			\
+    }					\
+  else if (s < s_end)			\
+    r = *s++;				\
+  else if (end_flag)			\
+    {					\
+      ic = XINT (prog[CCL_HEADER_EOF]);	\
+      continue;				\
+    }					\
+  else					\
+    {					\
+      CCL_SUSPEND;			\
+    }					\
+} while (0)
+
+
+/* Run a CCL program.  The initial state and program are contained in
+   CCL.  SRC, if non-zero, specifies a source string (of size N)
+   to read bytes from, and DST, of non-zero, specifies a destination
+   Dynarr to write bytes to.  If END_FLAG is set, it means that
+   the end section of the CCL program should be run rather than
+   the normal section.
+
+   For CCL programs that do not involve code conversion (e.g.
+   converting a single character into a font index), all parameters
+   but the first will usually be 0. */
+
+int
+ccl_driver (struct ccl_program *ccl, CONST unsigned char *src,
+	    unsigned_char_dynarr *dst, int n, int end_flag)
+{
+  int code, op, rrr, cc, i, j;
+  CONST unsigned char *s, *s_end;
+  int   ic = ccl->ic;
+  int *reg = ccl->reg;
+  Lisp_Object *prog = ccl->prog;
+
+  if (!ic)
+    ic = CCL_HEADER_MAIN;
+
+  if (src)
+    {
+      s = src;
+      s_end = s + n;
+    }
+
+  while (1)
+    {
+      code = XINT (prog[ic++]);
+      op = code & 0x1F;
+      rrr = (code >> 5) & 0x7;
+      cc = code >> 8;
+
+      switch (op)
+	{
+	case CCL_SetCS:
+	  reg[rrr] = cc; continue;
+	case CCL_SetCL:
+	  reg[rrr] = XINT (prog[ic++]); continue;
+	case CCL_SetR:
+	  reg[rrr] = reg[cc]; continue;
+	case CCL_SetA:
+	  cc = reg[cc];
+	  i = XINT (prog[ic++]);
+	  if (cc >= 0 && cc < i)
+	    reg[rrr] = XINT (prog[ic + cc]);
+	  ic += i;
+	  continue;
+	case CCL_Jump:
+	  ic = cc; continue;
+	case CCL_JumpCond:
+	  if (!reg[rrr])
+	    ic = cc;
+	  continue;
+	case CCL_WriteJump:
+	  CCL_WRITE_CHAR (reg[rrr]);
+	  ic = cc;
+	  continue;
+	case CCL_WriteReadJump:
+	  if (ccl->status != CCL_STAT_SUSPEND)
+	    {
+	      CCL_WRITE_CHAR (reg[rrr]);
+	    }
+	  else
+	    ccl->status = CCL_STAT_SUCCESS;
+	  CCL_READ_CHAR (reg[rrr]);
+	  ic = cc;
+	  continue;
+	case CCL_WriteCJump:
+	  CCL_WRITE_CHAR (XINT (prog[ic]));
+	  ic = cc;
+	  continue;
+	case CCL_WriteCReadJump:
+	  if (ccl->status != CCL_STAT_SUSPEND)
+	    {
+	      CCL_WRITE_CHAR (XINT (prog[ic]));
+	    }
+	  else
+	    ccl->status = CCL_STAT_SUCCESS;
+	  CCL_READ_CHAR (reg[rrr]);
+	  ic = cc;
+	  continue;
+	case CCL_WriteSJump:
+	  i = XINT (prog[ic]);
+	  CCL_WRITE_STRING (i);
+	  ic = cc;
+	  continue;
+	case CCL_WriteSReadJump:
+	  if (ccl->status != CCL_STAT_SUSPEND)
+	    {
+	      i = XINT (prog[ic]);
+	      CCL_WRITE_STRING (i);
+	    }
+	  else
+	    ccl->status = CCL_STAT_SUCCESS;
+	  CCL_READ_CHAR (reg[rrr]);
+	  ic = cc;
+	  continue;
+	case CCL_WriteAReadJump:
+	  if (ccl->status != CCL_STAT_SUSPEND)
+	    {
+	      i = XINT (prog[ic]);
+	      if (reg[rrr] >= 0 && reg[rrr] < i)
+		CCL_WRITE_CHAR (XINT (prog[ic + 1 + reg[rrr]]));
+	    }
+	  else
+	    ccl->status = CCL_STAT_SUCCESS;
+	  CCL_READ_CHAR (reg[rrr]);
+	  ic = cc;
+	  continue;
+	case CCL_ReadBranch:
+	  CCL_READ_CHAR (reg[rrr]);
+	case CCL_Branch:
+	  ic = XINT (prog[ic + (((unsigned int) reg[rrr] < cc)
+				? reg[rrr] : cc)]);
+	  continue;
+	case CCL_Read1:
+	  CCL_READ_CHAR (reg[rrr]);
+	  continue;
+	case CCL_Read2:
+	  CCL_READ_CHAR (reg[rrr]);
+	  CCL_READ_CHAR (reg[cc]);
+	  continue;
+	case CCL_Write1:
+	  CCL_WRITE_CHAR (reg[rrr]);
+	  continue;
+	case CCL_Write2:
+	  CCL_WRITE_CHAR (reg[rrr]);
+	  CCL_WRITE_CHAR (reg[cc]);
+	  continue;
+	case CCL_WriteC:
+	  i = XINT (prog[ic++]);
+	  CCL_WRITE_CHAR (i);
+	  continue;
+	case CCL_WriteS:
+	  cc = XINT (prog[ic]);
+	  CCL_WRITE_STRING (cc);
+	  ic += cc + 1;
+	  continue;
+	case CCL_WriteA:
+	  i = XINT (prog[ic++]);
+	  cc = reg[rrr];
+	  if (cc >= 0 && cc < i)
+	    CCL_WRITE_CHAR (XINT (prog[ic + cc]));
+	  ic += i;
+	  continue;
+	case CCL_End:
+	  CCL_SUCCESS;
+	case CCL_SetSelfCS:
+	  i = cc;
+	  op = XINT (prog[ic++]);
+	  goto ccl_set_self;
+	case CCL_SetSelfCL:
+	  i = XINT (prog[ic++]);
+	  op = XINT (prog[ic++]);
+	  goto ccl_set_self;
+	case CCL_SetSelfR:
+	  i = reg[cc];
+	  op = XINT (prog[ic++]);
+	  ccl_set_self:
+	  switch (op)
+	    {
+	    case CCL_PLUS:   reg[rrr] += i;  break;
+	    case CCL_MINUS:  reg[rrr] -= i;  break;
+	    case CCL_MUL:    reg[rrr] *= i;  break;
+	    case CCL_DIV:    reg[rrr] /= i;  break;
+	    case CCL_MOD:    reg[rrr] %= i;  break;
+	    case CCL_AND:    reg[rrr] &= i;  break;
+	    case CCL_OR:     reg[rrr] |= i;  break;
+	    case CCL_XOR:    reg[rrr] ^= i;  break;
+	    case CCL_LSH:    reg[rrr] <<= i; break;
+	    case CCL_RSH:    reg[rrr] >>= i; break;
+	    case CCL_LSH8:   reg[rrr] <<= 8; reg[rrr] |= i; break;
+	    case CCL_RSH8:   reg[7] = reg[rrr] & 0xFF; reg[rrr] >>= 8; break;
+	    case CCL_DIVMOD: reg[7] = reg[rrr] % i;    reg[rrr] /= i;  break;
+	    case CCL_LS:     reg[rrr] = reg[rrr] < i;  break;
+	    case CCL_GT:     reg[rrr] = reg[rrr] > i;  break;
+	    case CCL_EQ:     reg[rrr] = reg[rrr] == i; break;
+	    case CCL_LE:     reg[rrr] = reg[rrr] <= i; break;
+	    case CCL_GE:     reg[rrr] = reg[rrr] >= i; break;
+	    case CCL_NE:     reg[rrr] = reg[rrr] != i; break;
+	    default: CCL_INVALID_CMD;
+	    }
+	    continue;
+	case CCL_SetExprCL:
+	  i = reg[cc];
+	  j = XINT (prog[ic++]);
+	  op = XINT (prog[ic++]);
+	  cc = 0;
+	  goto ccl_set_expr;
+	case CCL_SetExprR:
+	  i = reg[cc];
+	  j = reg[XINT (prog[ic++])];
+	  op = XINT (prog[ic++]);
+	  cc = 0;
+	  goto ccl_set_expr;
+	case CCL_ReadJumpCondC:
+	  CCL_READ_CHAR (reg[rrr]);
+	case CCL_JumpCondC:
+	  i = reg[rrr];
+	  j = XINT (prog[ic++]);
+	  rrr = 7;
+	  op = XINT (prog[ic++]);
+	  goto ccl_set_expr;
+	case CCL_ReadJumpCondR:
+	  CCL_READ_CHAR (reg[rrr]);
+	case CCL_JumpCondR:
+	  i = reg[rrr];
+	  j = reg[XINT (prog[ic++])];
+	  rrr = 7;
+	  op = XINT (prog[ic++]);
+	  ccl_set_expr:
+	  switch (op)
+	    {
+	    case CCL_PLUS:   reg[rrr] = i + j;  break;
+	    case CCL_MINUS:  reg[rrr] = i - j;  break;
+	    case CCL_MUL:    reg[rrr] = i * j;  break;
+	    case CCL_DIV:    reg[rrr] = i / j;  break;
+	    case CCL_MOD:    reg[rrr] = i % j;  break;
+	    case CCL_AND:    reg[rrr] = i & j;  break;
+	    case CCL_OR:     reg[rrr] = i | j;  break;
+	    case CCL_XOR:    reg[rrr] = i ^ j;; break;
+	    case CCL_LSH:    reg[rrr] = i << j; break;
+	    case CCL_RSH:    reg[rrr] = i >> j; break;
+	    case CCL_LSH8:   reg[rrr] = (i << 8) | j; break;
+	    case CCL_RSH8:   reg[rrr] = i >> 8; reg[7] = i & 0xFF; break;
+	    case CCL_DIVMOD: reg[rrr] = i / j;  reg[7] = i % j;    break;
+	    case CCL_LS:     reg[rrr] = i < j;  break;
+	    case CCL_GT:     reg[rrr] = i > j;  break;
+	    case CCL_EQ:     reg[rrr] = i == j; break;
+	    case CCL_LE:     reg[rrr] = i <= j; break;
+	    case CCL_GE:     reg[rrr] = i >= j; break;
+	    case CCL_NE:     reg[rrr] = i != j; break;
+	    default: CCL_INVALID_CMD;
+	    }
+	    if (cc && !reg[rrr])
+	      ic = cc;
+	    continue;
+	default:
+	  CCL_INVALID_CMD;
+	}
+    }
+
+  ccl_error_handler:
+  if (dst)
+    {
+      char buf[200];
+      switch (ccl->status)
+	{
+	case CCL_STAT_INVALID_CMD:
+	  sprintf (buf, "CCL: Invalid command (%x).\n", op);
+	  break;
+	default:
+	  sprintf (buf, "CCL: Unknown error type (%d).\n", ccl->status);
+	}
+      Dynarr_add_many (dst, (unsigned char *) buf, strlen (buf));
+    }
+
+  ccl_finish:
+  ccl->ic = ic;
+  if (dst)
+    return Dynarr_length (dst);
+  else
+    return 0;
+}
+
+/* Set up CCL to execute CCL program VAL, with initial register values
+   coming from REGS (NUMREGS of them are specified) and initial
+   instruction counter coming from INITIAL_IC (a value of 0 means
+   start at the beginning of the program, wherever that is).
+   */
+
+void
+set_ccl_program (struct ccl_program *ccl, Lisp_Object val, int *regs,
+		 int numregs, int initial_ic)
+{
+  int i;
+
+  ccl->saved_vector = val;
+  ccl->prog = XVECTOR (val)->contents;
+  ccl->size = XVECTOR (val)->size;
+  if (initial_ic == 0)
+    ccl->ic = CCL_HEADER_MAIN;
+  else
+    ccl->ic = initial_ic;
+  for (i = 0; i < numregs; i++)
+    ccl->reg[i] = regs[i];
+  for (; i < 8; i++)
+    ccl->reg[i] = 0;
+  ccl->end_flag = 0;
+  ccl->status = 0;
+}
+
+#ifdef emacs
+
+static void
+set_ccl_program_from_lisp_values (struct ccl_program *ccl,
+				  Lisp_Object prog,
+				  Lisp_Object status)
+{
+  int i;
+  int intregs[8];
+  int ic;
+
+  CHECK_VECTOR (prog);
+  CHECK_VECTOR (status);
+
+  if (vector_length (XVECTOR (status)) != 9)
+    signal_simple_error ("Must specify values for the eight registers and IC",
+			 status);
+  for (i = 0; i < 8; i++)
+    {
+      Lisp_Object regval = XVECTOR (status)->contents[i];
+      if (NILP (regval))
+	intregs[i] = 0;
+      else
+	{
+	  CHECK_INT (regval);
+	  intregs[i] = XINT (regval);
+	}
+    }
+
+  {
+    Lisp_Object lic = XVECTOR (status)->contents[8];
+    if (NILP (lic))
+      ic = 0;
+    else
+      {
+	CHECK_NATNUM (lic);
+	ic = XINT (lic);
+      }
+  }
+
+  set_ccl_program (ccl, prog, intregs, 8, ic);
+}
+
+static void
+set_lisp_status_from_ccl_program (Lisp_Object status,
+				  struct ccl_program *ccl)
+{
+  int i;
+
+  for (i = 0; i < 8; i++)
+    XVECTOR (status)->contents[i] = make_int (ccl->reg[i]);
+  XVECTOR (status)->contents[8] = make_int (ccl->ic);
+}
+				  
+
+DEFUN ("execute-ccl-program", Fexecute_ccl_program, 2, 2, 0, /*
+Execute CCL-PROGRAM with registers initialized by STATUS.
+CCL-PROGRAM is a vector of compiled CCL code created by `ccl-compile'.
+STATUS must be a vector of nine values, specifying the initial value
+ for the R0, R1 .. R7 registers and for the instruction counter IC.
+A nil value for a register initializer causes the register to be set
+to 0.  A nil value for the IC initializer causes execution to start
+ at the beginning of the program.
+When the program is done, STATUS is modified (by side-effect) to contain
+ the ending values for the corresponding registers and IC.
+*/
+       (ccl_program, status))
+{
+  struct ccl_program ccl;
+
+  set_ccl_program_from_lisp_values (&ccl, ccl_program, status);
+  ccl_driver (&ccl, 0, 0, 0, 0);
+  set_lisp_status_from_ccl_program (status, &ccl);
+  return Qnil;
+}
+
+DEFUN ("execute-ccl-program-string", Fexecute_ccl_program_string, 3, 3, 0, /*
+Execute CCL-PROGRAM with initial STATUS on STRING.
+CCL-PROGRAM is a vector of compiled CCL code created by `ccl-compile'.
+STATUS must be a vector of nine values, specifying the initial value
+ for the R0, R1 .. R7 registers and for the instruction counter IC.
+A nil value for a register initializer causes the register to be set
+to 0.  A nil value for the IC initializer causes execution to start
+ at the beginning of the program.
+When the program is done, STATUS is modified (by side-effect) to contain
+ the ending values for the corresponding registers and IC.
+Returns the resulting string.
+*/
+       (ccl_program, status, str))
+{
+  struct ccl_program ccl;
+  Lisp_Object val;
+  int len;
+  unsigned_char_dynarr *outbuf;
+
+  set_ccl_program_from_lisp_values (&ccl, ccl_program, status);
+  CHECK_STRING (str);
+
+  outbuf = Dynarr_new (unsigned char);
+  len = ccl_driver (&ccl, XSTRING_DATA (str), outbuf, XSTRING_LENGTH (str), 0);
+  ccl_driver (&ccl, (unsigned char *) "", outbuf, 0, 1);
+  set_lisp_status_from_ccl_program (status, &ccl);
+
+  val = make_string (Dynarr_atp (outbuf, 0), len);
+  Dynarr_free (outbuf);
+  return val;
+}
+
+DEFUN ("ccl-reset-elapsed-time", Fccl_reset_elapsed_time, 0, 0, 0, /*
+Reset the internal value which holds the time elapsed by CCL interpreter.
+*/
+       ())
+{
+  error ("Not yet implemented; use `current-process-time'");
+  return Qnil;
+}
+
+DEFUN ("ccl-elapsed-time", Fccl_elapsed_time, 0, 0, 0, /*
+Return the time elapsed by CCL interpreter as cons of user and system time.
+This measures processor time, not real time.  Both values are floating point
+numbers measured in seconds.  If only one overall value can be determined,
+the return value will be a cons of that value and 0.
+*/
+       ())
+{
+  error ("Not yet implemented; use `current-process-time'");
+  return Qnil;
+}
+
+void
+syms_of_mule_ccl (void)
+{
+  DEFSUBR (Fexecute_ccl_program);
+  DEFSUBR (Fexecute_ccl_program_string);
+  DEFSUBR (Fccl_reset_elapsed_time);
+  DEFSUBR (Fccl_elapsed_time);
+}
+
+#else  /* not emacs */
+#ifdef standalone
+
+#include <alloca.h>
+
+#define INBUF_SIZE 1024
+#define MAX_CCL_CODE_SIZE 4096
+
+void
+main (int argc, char **argv)
+{
+  FILE *progf;
+  char inbuf[INBUF_SIZE];
+  unsigned_char_dynarr *outbuf;
+  struct ccl_program ccl;
+  int i;
+  Lisp_Object ccl_prog = make_vector (MAX_CCL_CODE_SIZE);
+
+  if (argc < 2)
+    {
+      fprintf (stderr,
+	       "Usage: %s ccl_program_file_name <infile >outfile\n",
+	       argv[0]);
+      exit (1);
+    }
+
+  if ((progf = fopen (argv[1], "r")) == NULL)
+    {
+      fprintf (stderr, "%s: Can't read file %s", argv[0], argv[1]);
+      exit (1);
+    }
+
+  XVECTOR (ccl_prog)->size = 0;
+  while (fscanf (progf, "%x", &i) == 1)
+    XVECTOR (ccl_prog)->contents[XVECTOR (ccl_prog)->size++] = make_int (i);
+  set_ccl_program (&ccl, ccl_prog, 0, 0, 0);
+
+  outbuf = Dynarr_new (unsigned char);
+
+  while ((i = fread (inbuf, 1, INBUF_SIZE, stdin)) == INBUF_SIZE)
+    {
+      i = ccl_driver (&ccl, inbuf, outbuf, INBUF_SIZE, 0);
+      fwrite (Dynarr_atp (outbuf, 0), 1, i, stdout);
+    }
+  if (i)
+    {
+      i = ccl_driver (&ccl, inbuf, outbuf, i, 1);
+      fwrite (Dynarr_atp (outbuf, 0), 1, i, stdout);
+    }
+
+  fclose (progf);
+  exit (0);
+}
+#endif  /* standalone */
+#endif  /* not emacs */