XEmacs 21.4.18 (Social Property).
[chise/xemacs-chise.git.1] / src / mule-ccl.c
1 /* CCL (Code Conversion Language) interpreter.
2    Copyright (C) 1995, 1997 Electrotechnical Laboratory, JAPAN.
3    Licensed to the Free Software Foundation.
4
5 This file is part of GNU Emacs.
6
7 GNU Emacs is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs; see the file COPYING.  If not, write to
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA.  */
21
22 /* Synched up with : FSF Emacs 21.0.90 except TranslateCharacter */
23
24 #ifdef emacs
25 #include <config.h>
26 #endif
27
28 #include <stdio.h>
29
30 #ifdef emacs
31
32 #include "lisp.h"
33 #include "buffer.h"
34 #include "mule-charset.h"
35 #include "mule-ccl.h"
36 #include "file-coding.h"
37
38 #else  /* not emacs */
39
40 #include "mulelib.h"
41
42 #endif /* not emacs */
43
44 /* This contains all code conversion map available to CCL.  */
45 Lisp_Object Vcode_conversion_map_vector;
46
47 /* Alist of fontname patterns vs corresponding CCL program.  */
48 Lisp_Object Vfont_ccl_encoder_alist;
49
50 /* This symbol is a property which associates with ccl program vector.
51    Ex: (get 'ccl-big5-encoder 'ccl-program) returns ccl program vector.  */
52 Lisp_Object Qccl_program;
53
54 /* These symbols are properties which associate with code conversion
55    map and their ID respectively.  */
56 Lisp_Object Qcode_conversion_map;
57 Lisp_Object Qcode_conversion_map_id;
58
59 /* Symbols of ccl program have this property, a value of the property
60    is an index for Vccl_program_table. */
61 Lisp_Object Qccl_program_idx;
62
63 /* Table of registered CCL programs.  Each element is a vector of
64    NAME, CCL_PROG, and RESOLVEDP where NAME (symbol) is the name of
65    the program, CCL_PROG (vector) is the compiled code of the program,
66    RESOLVEDP (t or nil) is the flag to tell if symbols in CCL_PROG is
67    already resolved to index numbers or not.  */
68 Lisp_Object Vccl_program_table;
69
70 /* CCL (Code Conversion Language) is a simple language which has
71    operations on one input buffer, one output buffer, and 7 registers.
72    The syntax of CCL is described in `ccl.el'.  Emacs Lisp function
73    `ccl-compile' compiles a CCL program and produces a CCL code which
74    is a vector of integers.  The structure of this vector is as
75    follows: The 1st element: buffer-magnification, a factor for the
76    size of output buffer compared with the size of input buffer.  The
77    2nd element: address of CCL code to be executed when encountered
78    with end of input stream.  The 3rd and the remaining elements: CCL
79    codes.  */
80
81 /* Header of CCL compiled code */
82 #define CCL_HEADER_BUF_MAG      0
83 #define CCL_HEADER_EOF          1
84 #define CCL_HEADER_MAIN         2
85
86 /* CCL code is a sequence of 28-bit non-negative integers (i.e. the
87    MSB is always 0), each contains CCL command and/or arguments in the
88    following format:
89
90         |----------------- integer (28-bit) ------------------|
91         |------- 17-bit ------|- 3-bit --|- 3-bit --|- 5-bit -|
92         |--constant argument--|-register-|-register-|-command-|
93            ccccccccccccccccc      RRR        rrr       XXXXX
94   or
95         |------- relative address -------|-register-|-command-|
96                cccccccccccccccccccc          rrr       XXXXX
97   or
98         |------------- constant or other args ----------------|
99                      cccccccccccccccccccccccccccc
100
101    where, `cc...c' is a non-negative integer indicating constant value
102    (the left most `c' is always 0) or an absolute jump address, `RRR'
103    and `rrr' are CCL register number, `XXXXX' is one of the following
104    CCL commands.  */
105
106 /* CCL commands
107
108    Each comment fields shows one or more lines for command syntax and
109    the following lines for semantics of the command.  In semantics, IC
110    stands for Instruction Counter.  */
111
112 #define CCL_SetRegister         0x00 /* Set register a register value:
113                                         1:00000000000000000RRRrrrXXXXX
114                                         ------------------------------
115                                         reg[rrr] = reg[RRR];
116                                         */
117
118 #define CCL_SetShortConst       0x01 /* Set register a short constant value:
119                                         1:CCCCCCCCCCCCCCCCCCCCrrrXXXXX
120                                         ------------------------------
121                                         reg[rrr] = CCCCCCCCCCCCCCCCCCC;
122                                         */
123
124 #define CCL_SetConst            0x02 /* Set register a constant value:
125                                         1:00000000000000000000rrrXXXXX
126                                         2:CONSTANT
127                                         ------------------------------
128                                         reg[rrr] = CONSTANT;
129                                         IC++;
130                                         */
131
132 #define CCL_SetArray            0x03 /* Set register an element of array:
133                                         1:CCCCCCCCCCCCCCCCCRRRrrrXXXXX
134                                         2:ELEMENT[0]
135                                         3:ELEMENT[1]
136                                         ...
137                                         ------------------------------
138                                         if (0 <= reg[RRR] < CC..C)
139                                           reg[rrr] = ELEMENT[reg[RRR]];
140                                         IC += CC..C;
141                                         */
142
143 #define CCL_Jump                0x04 /* Jump:
144                                         1:A--D--D--R--E--S--S-000XXXXX
145                                         ------------------------------
146                                         IC += ADDRESS;
147                                         */
148
149 /* Note: If CC..C is greater than 0, the second code is omitted.  */
150
151 #define CCL_JumpCond            0x05 /* Jump conditional:
152                                         1:A--D--D--R--E--S--S-rrrXXXXX
153                                         ------------------------------
154                                         if (!reg[rrr])
155                                           IC += ADDRESS;
156                                         */
157
158
159 #define CCL_WriteRegisterJump   0x06 /* Write register and jump:
160                                         1:A--D--D--R--E--S--S-rrrXXXXX
161                                         ------------------------------
162                                         write (reg[rrr]);
163                                         IC += ADDRESS;
164                                         */
165
166 #define CCL_WriteRegisterReadJump 0x07 /* Write register, read, and jump:
167                                         1:A--D--D--R--E--S--S-rrrXXXXX
168                                         2:A--D--D--R--E--S--S-rrrYYYYY
169                                         -----------------------------
170                                         write (reg[rrr]);
171                                         IC++;
172                                         read (reg[rrr]);
173                                         IC += ADDRESS;
174                                         */
175 /* Note: If read is suspended, the resumed execution starts from the
176    second code (YYYYY == CCL_ReadJump).  */
177
178 #define CCL_WriteConstJump      0x08 /* Write constant and jump:
179                                         1:A--D--D--R--E--S--S-000XXXXX
180                                         2:CONST
181                                         ------------------------------
182                                         write (CONST);
183                                         IC += ADDRESS;
184                                         */
185
186 #define CCL_WriteConstReadJump  0x09 /* Write constant, read, and jump:
187                                         1:A--D--D--R--E--S--S-rrrXXXXX
188                                         2:CONST
189                                         3:A--D--D--R--E--S--S-rrrYYYYY
190                                         -----------------------------
191                                         write (CONST);
192                                         IC += 2;
193                                         read (reg[rrr]);
194                                         IC += ADDRESS;
195                                         */
196 /* Note: If read is suspended, the resumed execution starts from the
197    second code (YYYYY == CCL_ReadJump).  */
198
199 #define CCL_WriteStringJump     0x0A /* Write string and jump:
200                                         1:A--D--D--R--E--S--S-000XXXXX
201                                         2:LENGTH
202                                         3:0000STRIN[0]STRIN[1]STRIN[2]
203                                         ...
204                                         ------------------------------
205                                         write_string (STRING, LENGTH);
206                                         IC += ADDRESS;
207                                         */
208
209 #define CCL_WriteArrayReadJump  0x0B /* Write an array element, read, and jump:
210                                         1:A--D--D--R--E--S--S-rrrXXXXX
211                                         2:LENGTH
212                                         3:ELEMENET[0]
213                                         4:ELEMENET[1]
214                                         ...
215                                         N:A--D--D--R--E--S--S-rrrYYYYY
216                                         ------------------------------
217                                         if (0 <= reg[rrr] < LENGTH)
218                                           write (ELEMENT[reg[rrr]]);
219                                         IC += LENGTH + 2; (... pointing at N+1)
220                                         read (reg[rrr]);
221                                         IC += ADDRESS;
222                                         */
223 /* Note: If read is suspended, the resumed execution starts from the
224    Nth code (YYYYY == CCL_ReadJump).  */
225
226 #define CCL_ReadJump            0x0C /* Read and jump:
227                                         1:A--D--D--R--E--S--S-rrrYYYYY
228                                         -----------------------------
229                                         read (reg[rrr]);
230                                         IC += ADDRESS;
231                                         */
232
233 #define CCL_Branch              0x0D /* Jump by branch table:
234                                         1:CCCCCCCCCCCCCCCCCCCCrrrXXXXX
235                                         2:A--D--D--R--E-S-S[0]000XXXXX
236                                         3:A--D--D--R--E-S-S[1]000XXXXX
237                                         ...
238                                         ------------------------------
239                                         if (0 <= reg[rrr] < CC..C)
240                                           IC += ADDRESS[reg[rrr]];
241                                         else
242                                           IC += ADDRESS[CC..C];
243                                         */
244
245 #define CCL_ReadRegister        0x0E /* Read bytes into registers:
246                                         1:CCCCCCCCCCCCCCCCCCCCrrrXXXXX
247                                         2:CCCCCCCCCCCCCCCCCCCCrrrXXXXX
248                                         ...
249                                         ------------------------------
250                                         while (CCC--)
251                                           read (reg[rrr]);
252                                         */
253
254 #define CCL_WriteExprConst      0x0F  /* write result of expression:
255                                         1:00000OPERATION000RRR000XXXXX
256                                         2:CONSTANT
257                                         ------------------------------
258                                         write (reg[RRR] OPERATION CONSTANT);
259                                         IC++;
260                                         */
261
262 /* Note: If the Nth read is suspended, the resumed execution starts
263    from the Nth code.  */
264
265 #define CCL_ReadBranch          0x10 /* Read one byte into a register,
266                                         and jump by branch table:
267                                         1:CCCCCCCCCCCCCCCCCCCCrrrXXXXX
268                                         2:A--D--D--R--E-S-S[0]000XXXXX
269                                         3:A--D--D--R--E-S-S[1]000XXXXX
270                                         ...
271                                         ------------------------------
272                                         read (read[rrr]);
273                                         if (0 <= reg[rrr] < CC..C)
274                                           IC += ADDRESS[reg[rrr]];
275                                         else
276                                           IC += ADDRESS[CC..C];
277                                         */
278
279 #define CCL_WriteRegister       0x11 /* Write registers:
280                                         1:CCCCCCCCCCCCCCCCCCCrrrXXXXX
281                                         2:CCCCCCCCCCCCCCCCCCCrrrXXXXX
282                                         ...
283                                         ------------------------------
284                                         while (CCC--)
285                                           write (reg[rrr]);
286                                         ...
287                                         */
288
289 /* Note: If the Nth write is suspended, the resumed execution
290    starts from the Nth code.  */
291
292 #define CCL_WriteExprRegister   0x12 /* Write result of expression
293                                         1:00000OPERATIONRrrRRR000XXXXX
294                                         ------------------------------
295                                         write (reg[RRR] OPERATION reg[Rrr]);
296                                         */
297
298 #define CCL_Call                0x13 /* Call the CCL program whose ID is
299                                         CC..C or cc..c.
300                                         1:CCCCCCCCCCCCCCCCCCCCFFFXXXXX
301                                         [2:00000000cccccccccccccccccccc]
302                                         ------------------------------
303                                         if (FFF)
304                                           call (cc..c)
305                                           IC++;
306                                         else
307                                           call (CC..C)
308                                         */
309
310 #define CCL_WriteConstString    0x14 /* Write a constant or a string:
311                                         1:CCCCCCCCCCCCCCCCCCCCrrrXXXXX
312                                         [2:0000STRIN[0]STRIN[1]STRIN[2]]
313                                         [...]
314                                         -----------------------------
315                                         if (!rrr)
316                                           write (CC..C)
317                                         else
318                                           write_string (STRING, CC..C);
319                                           IC += (CC..C + 2) / 3;
320                                         */
321
322 #define CCL_WriteArray          0x15 /* Write an element of array:
323                                         1:CCCCCCCCCCCCCCCCCCCCrrrXXXXX
324                                         2:ELEMENT[0]
325                                         3:ELEMENT[1]
326                                         ...
327                                         ------------------------------
328                                         if (0 <= reg[rrr] < CC..C)
329                                           write (ELEMENT[reg[rrr]]);
330                                         IC += CC..C;
331                                         */
332
333 #define CCL_End                 0x16 /* Terminate:
334                                         1:00000000000000000000000XXXXX
335                                         ------------------------------
336                                         terminate ();
337                                         */
338
339 /* The following two codes execute an assignment arithmetic/logical
340    operation.  The form of the operation is like REG OP= OPERAND.  */
341
342 #define CCL_ExprSelfConst       0x17 /* REG OP= constant:
343                                         1:00000OPERATION000000rrrXXXXX
344                                         2:CONSTANT
345                                         ------------------------------
346                                         reg[rrr] OPERATION= CONSTANT;
347                                         */
348
349 #define CCL_ExprSelfReg         0x18 /* REG1 OP= REG2:
350                                         1:00000OPERATION000RRRrrrXXXXX
351                                         ------------------------------
352                                         reg[rrr] OPERATION= reg[RRR];
353                                         */
354
355 /* The following codes execute an arithmetic/logical operation.  The
356    form of the operation is like REG_X = REG_Y OP OPERAND2.  */
357
358 #define CCL_SetExprConst        0x19 /* REG_X = REG_Y OP constant:
359                                         1:00000OPERATION000RRRrrrXXXXX
360                                         2:CONSTANT
361                                         ------------------------------
362                                         reg[rrr] = reg[RRR] OPERATION CONSTANT;
363                                         IC++;
364                                         */
365
366 #define CCL_SetExprReg          0x1A /* REG1 = REG2 OP REG3:
367                                         1:00000OPERATIONRrrRRRrrrXXXXX
368                                         ------------------------------
369                                         reg[rrr] = reg[RRR] OPERATION reg[Rrr];
370                                         */
371
372 #define CCL_JumpCondExprConst   0x1B /* Jump conditional according to
373                                         an operation on constant:
374                                         1:A--D--D--R--E--S--S-rrrXXXXX
375                                         2:OPERATION
376                                         3:CONSTANT
377                                         -----------------------------
378                                         reg[7] = reg[rrr] OPERATION CONSTANT;
379                                         if (!(reg[7]))
380                                           IC += ADDRESS;
381                                         else
382                                           IC += 2
383                                         */
384
385 #define CCL_JumpCondExprReg     0x1C /* Jump conditional according to
386                                         an operation on register:
387                                         1:A--D--D--R--E--S--S-rrrXXXXX
388                                         2:OPERATION
389                                         3:RRR
390                                         -----------------------------
391                                         reg[7] = reg[rrr] OPERATION reg[RRR];
392                                         if (!reg[7])
393                                           IC += ADDRESS;
394                                         else
395                                           IC += 2;
396                                         */
397
398 #define CCL_ReadJumpCondExprConst 0x1D /* Read and jump conditional according
399                                           to an operation on constant:
400                                         1:A--D--D--R--E--S--S-rrrXXXXX
401                                         2:OPERATION
402                                         3:CONSTANT
403                                         -----------------------------
404                                         read (reg[rrr]);
405                                         reg[7] = reg[rrr] OPERATION CONSTANT;
406                                         if (!reg[7])
407                                           IC += ADDRESS;
408                                         else
409                                           IC += 2;
410                                         */
411
412 #define CCL_ReadJumpCondExprReg 0x1E /* Read and jump conditional according
413                                         to an operation on register:
414                                         1:A--D--D--R--E--S--S-rrrXXXXX
415                                         2:OPERATION
416                                         3:RRR
417                                         -----------------------------
418                                         read (reg[rrr]);
419                                         reg[7] = reg[rrr] OPERATION reg[RRR];
420                                         if (!reg[7])
421                                           IC += ADDRESS;
422                                         else
423                                           IC += 2;
424                                         */
425
426 #define CCL_Extension           0x1F /* Extended CCL code
427                                         1:ExtendedCOMMNDRrrRRRrrrXXXXX
428                                         2:ARGUMENT
429                                         3:...
430                                         ------------------------------
431                                         extended_command (rrr,RRR,Rrr,ARGS)
432                                       */
433
434 /*
435    Here after, Extended CCL Instructions.
436    Bit length of extended command is 14.
437    Therefore, the instruction code range is 0..16384(0x3fff).
438  */
439
440 /* Read a multibyte characeter.
441    A code point is stored into reg[rrr].  A charset ID is stored into
442    reg[RRR].  */
443
444 #define CCL_ReadMultibyteChar2  0x00 /* Read Multibyte Character
445                                         1:ExtendedCOMMNDRrrRRRrrrXXXXX  */
446
447 /* Write a multibyte character.
448    Write a character whose code point is reg[rrr] and the charset ID
449    is reg[RRR].  */
450
451 #define CCL_WriteMultibyteChar2 0x01 /* Write Multibyte Character
452                                         1:ExtendedCOMMNDRrrRRRrrrXXXXX  */
453
454 /* Translate a character whose code point is reg[rrr] and the charset
455    ID is reg[RRR] by a translation table whose ID is reg[Rrr].
456
457    A translated character is set in reg[rrr] (code point) and reg[RRR]
458    (charset ID).  */
459
460 #define CCL_TranslateCharacter  0x02 /* Translate a multibyte character
461                                         1:ExtendedCOMMNDRrrRRRrrrXXXXX  */
462
463 /* Translate a character whose code point is reg[rrr] and the charset
464    ID is reg[RRR] by a translation table whose ID is ARGUMENT.
465
466    A translated character is set in reg[rrr] (code point) and reg[RRR]
467    (charset ID).  */
468
469 #define CCL_TranslateCharacterConstTbl 0x03 /* Translate a multibyte character
470                                                1:ExtendedCOMMNDRrrRRRrrrXXXXX
471                                                2:ARGUMENT(Translation Table ID)
472                                             */
473
474 /* Iterate looking up MAPs for reg[rrr] starting from the Nth (N =
475    reg[RRR]) MAP until some value is found.
476
477    Each MAP is a Lisp vector whose element is number, nil, t, or
478    lambda.
479    If the element is nil, ignore the map and proceed to the next map.
480    If the element is t or lambda, finish without changing reg[rrr].
481    If the element is a number, set reg[rrr] to the number and finish.
482
483    Detail of the map structure is described in the comment for
484    CCL_MapMultiple below.  */
485
486 #define CCL_IterateMultipleMap  0x10 /* Iterate multiple maps
487                                         1:ExtendedCOMMNDXXXRRRrrrXXXXX
488                                         2:NUMBER of MAPs
489                                         3:MAP-ID1
490                                         4:MAP-ID2
491                                         ...
492                                      */
493
494 /* Map the code in reg[rrr] by MAPs starting from the Nth (N =
495    reg[RRR]) map.
496
497    MAPs are supplied in the succeeding CCL codes as follows:
498
499    When CCL program gives this nested structure of map to this command:
500         ((MAP-ID11
501           MAP-ID12
502           (MAP-ID121 MAP-ID122 MAP-ID123)
503           MAP-ID13)
504          (MAP-ID21
505           (MAP-ID211 (MAP-ID2111) MAP-ID212)
506           MAP-ID22)),
507    the compiled CCL code has this sequence:
508         CCL_MapMultiple (CCL code of this command)
509         16 (total number of MAPs and SEPARATORs)
510         -7 (1st SEPARATOR)
511         MAP-ID11
512         MAP-ID12
513         -3 (2nd SEPARATOR)
514         MAP-ID121
515         MAP-ID122
516         MAP-ID123
517         MAP-ID13
518         -7 (3rd SEPARATOR)
519         MAP-ID21
520         -4 (4th SEPARATOR)
521         MAP-ID211
522         -1 (5th SEPARATOR)
523         MAP_ID2111
524         MAP-ID212
525         MAP-ID22
526
527    A value of each SEPARATOR follows this rule:
528         MAP-SET := SEPARATOR [(MAP-ID | MAP-SET)]+
529         SEPARATOR := -(number of MAP-IDs and SEPARATORs in the MAP-SET)
530
531    (*)....Nest level of MAP-SET must not be over than MAX_MAP_SET_LEVEL.
532
533    When some map fails to map (i.e. it doesn't have a value for
534    reg[rrr]), the mapping is treated as identity.
535
536    The mapping is iterated for all maps in each map set (set of maps
537    separated by SEPARATOR) except in the case that lambda is
538    encountered.  More precisely, the mapping proceeds as below:
539
540    At first, VAL0 is set to reg[rrr], and it is translated by the
541    first map to VAL1.  Then, VAL1 is translated by the next map to
542    VAL2.  This mapping is iterated until the last map is used.  The
543    result of the mapping is the last value of VAL?.  When the mapping
544    process reached to the end of the map set, it moves to the next
545    map set.  If the next does not exit, the mapping process terminates,
546    and regard the last value as a result.
547
548    But, when VALm is mapped to VALn and VALn is not a number, the
549    mapping proceeds as follows:
550
551    If VALn is nil, the lastest map is ignored and the mapping of VALm
552    proceeds to the next map.
553
554    In VALn is t, VALm is reverted to reg[rrr] and the mapping of VALm
555    proceeds to the next map.
556
557    If VALn is lambda, move to the next map set like reaching to the
558    end of the current map set.
559
560    If VALn is a symbol, call the CCL program refered by it.
561    Then, use reg[rrr] as a mapped value except for -1, -2 and -3.
562    Such special values are regarded as nil, t, and lambda respectively.
563
564    Each map is a Lisp vector of the following format (a) or (b):
565         (a)......[STARTPOINT VAL1 VAL2 ...]
566         (b)......[t VAL STARTPOINT ENDPOINT],
567    where
568         STARTPOINT is an offset to be used for indexing a map,
569         ENDPOINT is a maximum index number of a map,
570         VAL and VALn is a number, nil, t, or lambda.
571
572    Valid index range of a map of type (a) is:
573         STARTPOINT <= index < STARTPOINT + map_size - 1
574    Valid index range of a map of type (b) is:
575         STARTPOINT <= index < ENDPOINT  */
576
577 #define CCL_MapMultiple 0x11    /* Mapping by multiple code conversion maps
578                                          1:ExtendedCOMMNDXXXRRRrrrXXXXX
579                                          2:N-2
580                                          3:SEPARATOR_1 (< 0)
581                                          4:MAP-ID_1
582                                          5:MAP-ID_2
583                                          ...
584                                          M:SEPARATOR_x (< 0)
585                                          M+1:MAP-ID_y
586                                          ...
587                                          N:SEPARATOR_z (< 0)
588                                       */
589
590 #define MAX_MAP_SET_LEVEL 30
591
592 typedef struct
593 {
594   int rest_length;
595   int orig_val;
596 } tr_stack;
597
598 static tr_stack mapping_stack[MAX_MAP_SET_LEVEL];
599 static tr_stack *mapping_stack_pointer;
600
601 /* If this variable is non-zero, it indicates the stack_idx
602    of immediately called by CCL_MapMultiple. */
603 static int stack_idx_of_map_multiple;
604
605 #define PUSH_MAPPING_STACK(restlen, orig)               \
606   do {                                                  \
607     mapping_stack_pointer->rest_length = (restlen);     \
608     mapping_stack_pointer->orig_val = (orig);           \
609     mapping_stack_pointer++;                            \
610   } while (0)
611
612 #define POP_MAPPING_STACK(restlen, orig)                \
613   do {                                                  \
614     mapping_stack_pointer--;                            \
615     (restlen) = mapping_stack_pointer->rest_length;     \
616     (orig) = mapping_stack_pointer->orig_val;           \
617   } while (0)
618
619 #define CCL_CALL_FOR_MAP_INSTRUCTION(symbol, ret_ic)            \
620   do {                                                          \
621     struct ccl_program called_ccl;                              \
622     if (stack_idx >= 256                                        \
623         || (setup_ccl_program (&called_ccl, (symbol)) != 0))    \
624       {                                                         \
625         if (stack_idx > 0)                                      \
626           {                                                     \
627             ccl_prog = ccl_prog_stack_struct[0].ccl_prog;       \
628             ic = ccl_prog_stack_struct[0].ic;                   \
629           }                                                     \
630         CCL_INVALID_CMD;                                        \
631       }                                                         \
632     ccl_prog_stack_struct[stack_idx].ccl_prog = ccl_prog;       \
633     ccl_prog_stack_struct[stack_idx].ic = (ret_ic);             \
634     stack_idx++;                                                \
635     ccl_prog = called_ccl.prog;                                 \
636     ic = CCL_HEADER_MAIN;                                       \
637     /* The "if (1)" prevents warning                            \
638        "end-of loop code not reached" */                        \
639     if (1) goto ccl_repeat;                                     \
640   } while (0)
641
642 #define CCL_MapSingle           0x12 /* Map by single code conversion map
643                                         1:ExtendedCOMMNDXXXRRRrrrXXXXX
644                                         2:MAP-ID
645                                         ------------------------------
646                                         Map reg[rrr] by MAP-ID.
647                                         If some valid mapping is found,
648                                           set reg[rrr] to the result,
649                                         else
650                                           set reg[RRR] to -1.
651                                      */
652
653 /* CCL arithmetic/logical operators. */
654 #define CCL_PLUS        0x00    /* X = Y + Z */
655 #define CCL_MINUS       0x01    /* X = Y - Z */
656 #define CCL_MUL         0x02    /* X = Y * Z */
657 #define CCL_DIV         0x03    /* X = Y / Z */
658 #define CCL_MOD         0x04    /* X = Y % Z */
659 #define CCL_AND         0x05    /* X = Y & Z */
660 #define CCL_OR          0x06    /* X = Y | Z */
661 #define CCL_XOR         0x07    /* X = Y ^ Z */
662 #define CCL_LSH         0x08    /* X = Y << Z */
663 #define CCL_RSH         0x09    /* X = Y >> Z */
664 #define CCL_LSH8        0x0A    /* X = (Y << 8) | Z */
665 #define CCL_RSH8        0x0B    /* X = Y >> 8, r[7] = Y & 0xFF  */
666 #define CCL_DIVMOD      0x0C    /* X = Y / Z, r[7] = Y % Z */
667 #define CCL_LS          0x10    /* X = (X < Y) */
668 #define CCL_GT          0x11    /* X = (X > Y) */
669 #define CCL_EQ          0x12    /* X = (X == Y) */
670 #define CCL_LE          0x13    /* X = (X <= Y) */
671 #define CCL_GE          0x14    /* X = (X >= Y) */
672 #define CCL_NE          0x15    /* X = (X != Y) */
673
674 #define CCL_DECODE_SJIS 0x16    /* X = HIGHER_BYTE (DE-SJIS (Y, Z))
675                                    r[7] = LOWER_BYTE (DE-SJIS (Y, Z)) */
676 #define CCL_ENCODE_SJIS 0x17    /* X = HIGHER_BYTE (SJIS (Y, Z))
677                                    r[7] = LOWER_BYTE (SJIS (Y, Z) */
678
679 /* Terminate CCL program successfully.  */
680 #define CCL_SUCCESS                     \
681   do {                                  \
682     ccl->status = CCL_STAT_SUCCESS;     \
683   /* The "if (1)" inhibits the warning  \
684      "end-of loop code not reached" */  \
685   if (1) goto ccl_finish;               \
686   } while (0)
687
688 /* Suspend CCL program because of reading from empty input buffer or
689    writing to full output buffer.  When this program is resumed, the
690    same I/O command is executed.  */
691 #define CCL_SUSPEND(stat)       \
692   do {                          \
693     ic--;                       \
694   ccl->status = (stat);                 \
695   /* The "if (1)" inhibits the warning  \
696      "end-of loop code not reached" */  \
697   if (1) goto ccl_finish;               \
698   } while (0)
699
700 /* Terminate CCL program because of invalid command.  Should not occur
701    in the normal case.  */
702 #define CCL_INVALID_CMD                 \
703   do {                                  \
704     ccl->status = CCL_STAT_INVALID_CMD; \
705   /* The "if (1)" inhibits the warning  \
706      "end-of loop code not reached" */  \
707   if (1) goto ccl_error_handler;        \
708   } while (0)
709
710 /* Encode one character CH to multibyte form and write to the current
711    output buffer.  At encoding time, if CH is less than 256, CH is
712    written as is.  At decoding time, if CH cannot be regarded as an
713    ASCII character, write it in multibyte form.  */
714 #define CCL_WRITE_CHAR(ch)                                      \
715   do {                                                          \
716     if (!destination)                                           \
717       CCL_INVALID_CMD;                                          \
718     if (conversion_mode == CCL_MODE_ENCODING)                   \
719       {                                                         \
720         if ((ch) == '\n')                                       \
721           {                                                     \
722             if (ccl->eol_type == CCL_CODING_EOL_CRLF)           \
723               {                                                 \
724                 Dynarr_add (destination, '\r');                 \
725                 Dynarr_add (destination, '\n');                 \
726               }                                                 \
727             else if (ccl->eol_type == CCL_CODING_EOL_CR)        \
728               Dynarr_add (destination, '\r');                   \
729             else                                                \
730               Dynarr_add (destination, '\n');                   \
731           }                                                     \
732         else if ((ch) < 0x100)                                  \
733           {                                                     \
734             Dynarr_add (destination, ch);                       \
735           }                                                     \
736         else                                                    \
737           {                                                     \
738             Bufbyte work[MAX_EMCHAR_LEN];                       \
739             int len;                                            \
740             len = non_ascii_set_charptr_emchar (work, ch);      \
741             Dynarr_add_many (destination, work, len);           \
742           }                                                     \
743       }                                                         \
744     else                                                        \
745       {                                                         \
746         if (!CHAR_MULTIBYTE_P(ch))                              \
747           {                                                     \
748             Dynarr_add (destination, ch);                       \
749           }                                                     \
750         else                                                    \
751           {                                                     \
752             Bufbyte work[MAX_EMCHAR_LEN];                       \
753             int len;                                            \
754             len = non_ascii_set_charptr_emchar (work, ch);      \
755             Dynarr_add_many (destination, work, len);           \
756           }                                                     \
757       }                                                         \
758   } while (0)
759
760 /* Write a string at ccl_prog[IC] of length LEN to the current output
761    buffer.  But this macro treat this string as a binary.  Therefore,
762    cannot handle a multibyte string except for Control-1 characters. */
763 #define CCL_WRITE_STRING(len)                                   \
764   do {                                                          \
765     Bufbyte work[MAX_EMCHAR_LEN];                               \
766     int ch, bytes;                                              \
767     if (!destination)                                           \
768       CCL_INVALID_CMD;                                          \
769     else if (conversion_mode == CCL_MODE_ENCODING)              \
770       {                                                         \
771         for (i = 0; i < (len); i++)                             \
772           {                                                     \
773             ch = ((XINT (ccl_prog[ic + (i / 3)]))               \
774                   >> ((2 - (i % 3)) * 8)) & 0xFF;               \
775             if (ch == '\n')                                     \
776               {                                                 \
777                 if (ccl->eol_type == CCL_CODING_EOL_CRLF)       \
778                   {                                             \
779                     Dynarr_add (destination, '\r');             \
780                     Dynarr_add (destination, '\n');             \
781                   }                                             \
782                 else if (ccl->eol_type == CCL_CODING_EOL_CR)    \
783                   Dynarr_add (destination, '\r');               \
784                 else                                            \
785                   Dynarr_add (destination, '\n');               \
786               }                                                 \
787             if (ch < 0x100)                                     \
788               {                                                 \
789                 Dynarr_add (destination, ch);                   \
790               }                                                 \
791             else                                                \
792               {                                                 \
793                 bytes = non_ascii_set_charptr_emchar (work, ch); \
794                 Dynarr_add_many (destination, work, len);       \
795               }                                                 \
796           }                                                     \
797       }                                                         \
798     else                                                        \
799       {                                                         \
800         for (i = 0; i < (len); i++)                             \
801           {                                                     \
802             ch = ((XINT (ccl_prog[ic + (i / 3)]))               \
803                   >> ((2 - (i % 3)) * 8)) & 0xFF;               \
804             if (!CHAR_MULTIBYTE_P(ch))                          \
805               {                                                 \
806                 Dynarr_add (destination, ch);                   \
807               }                                                 \
808             else                                                \
809               {                                                 \
810                 bytes = non_ascii_set_charptr_emchar (work, ch); \
811                 Dynarr_add_many (destination, work, len);       \
812               }                                                 \
813           }                                                     \
814       }                                                         \
815   } while (0)
816
817 /* Read one byte from the current input buffer into Rth register.  */
818 #define CCL_READ_CHAR(r)                                \
819   do {                                                  \
820     if (!src)                                           \
821       CCL_INVALID_CMD;                                  \
822     if (src < src_end)                                  \
823       (r) = *src++;                                     \
824     else                                                \
825       {                                                 \
826         if (ccl->last_block)                            \
827           {                                             \
828             ic = ccl->eof_ic;                           \
829             goto ccl_repeat;                            \
830           }                                             \
831         else                                            \
832           CCL_SUSPEND (CCL_STAT_SUSPEND_BY_SRC);        \
833       }                                                 \
834   } while (0)
835
836
837 /* Set C to the character code made from CHARSET and CODE.  This is
838    like MAKE_CHAR but check the validity of CHARSET and CODE.  If they
839    are not valid, set C to (CODE & 0xFF) because that is usually the
840    case that CCL_ReadMultibyteChar2 read an invalid code and it set
841    CODE to that invalid byte.  */
842
843 /* On XEmacs, TranslateCharacter is not supported.  Thus, this
844    macro is not used.  */
845 #if 0
846 #define CCL_MAKE_CHAR(charset, code, c)                         \
847   do {                                                          \
848     if ((charset) == CHARSET_ASCII)                             \
849       (c) = (code) & 0xFF;                                              \
850     else if (CHARSET_DEFINED_P (charset)                        \
851              && ((code) & 0x7F) >= 32                           \
852              && ((code) < 256 || ((code >> 7) & 0x7F) >= 32))   \
853       {                                                         \
854         int c1 = (code) & 0x7F, c2 = 0;                         \
855                                                                 \
856         if ((code) >= 256)                                      \
857           c2 = c1, c1 = ((code) >> 7) & 0x7F;                   \
858         (c) = MAKE_CHAR (charset, c1, c2);                      \
859       }                                                         \
860     else                                                        \
861       (c) = (code) & 0xFF;                                              \
862   } while (0)
863 #endif
864
865
866 /* Execute CCL code on SRC_BYTES length text at SOURCE.  The resulting
867    text goes to a place pointed by DESTINATION, the length of which
868    should not exceed DST_BYTES.  The bytes actually processed is
869    returned as *CONSUMED.  The return value is the length of the
870    resulting text.  As a side effect, the contents of CCL registers
871    are updated.  If SOURCE or DESTINATION is NULL, only operations on
872    registers are permitted.  */
873
874 #ifdef CCL_DEBUG
875 #define CCL_DEBUG_BACKTRACE_LEN 256
876 int ccl_backtrace_table[CCL_BACKTRACE_TABLE];
877 int ccl_backtrace_idx;
878 #endif
879
880 struct ccl_prog_stack
881   {
882     Lisp_Object *ccl_prog;      /* Pointer to an array of CCL code.  */
883     int ic;                     /* Instruction Counter.  */
884   };
885
886 /* For the moment, we only support depth 256 of stack.  */
887 static struct ccl_prog_stack ccl_prog_stack_struct[256];
888
889 int
890 ccl_driver (struct ccl_program *ccl,
891             const unsigned char *source,
892             unsigned_char_dynarr *destination,
893             int src_bytes,
894             int *consumed,
895             int conversion_mode)
896 {
897   register int *reg = ccl->reg;
898   register int ic = ccl->ic;
899   register int code = -1;
900   register int field1, field2;
901   register Lisp_Object *ccl_prog = ccl->prog;
902   const unsigned char *src = source, *src_end = src + src_bytes;
903   int jump_address;
904   int i, j, op;
905   int stack_idx = ccl->stack_idx;
906   /* Instruction counter of the current CCL code. */
907   int this_ic = 0;
908
909   if (ic >= ccl->eof_ic)
910     ic = CCL_HEADER_MAIN;
911
912   if (ccl->buf_magnification ==0) /* We can't produce any bytes.  */
913     destination = NULL;
914
915   /* Set mapping stack pointer. */
916   mapping_stack_pointer = mapping_stack;
917
918 #ifdef CCL_DEBUG
919   ccl_backtrace_idx = 0;
920 #endif
921
922   for (;;)
923     {
924     ccl_repeat:
925 #ifdef CCL_DEBUG
926       ccl_backtrace_table[ccl_backtrace_idx++] = ic;
927       if (ccl_backtrace_idx >= CCL_DEBUG_BACKTRACE_LEN)
928         ccl_backtrace_idx = 0;
929       ccl_backtrace_table[ccl_backtrace_idx] = 0;
930 #endif
931
932       if (!NILP (Vquit_flag) && NILP (Vinhibit_quit))
933         {
934           /* We can't just signal Qquit, instead break the loop as if
935              the whole data is processed.  Don't reset Vquit_flag, it
936              must be handled later at a safer place.  */
937           if (consumed)
938             src = source + src_bytes;
939           ccl->status = CCL_STAT_QUIT;
940           break;
941         }
942
943       this_ic = ic;
944       code = XINT (ccl_prog[ic]); ic++;
945       field1 = code >> 8;
946       field2 = (code & 0xFF) >> 5;
947
948 #define rrr field2
949 #define RRR (field1 & 7)
950 #define Rrr ((field1 >> 3) & 7)
951 #define ADDR field1
952 #define EXCMD (field1 >> 6)
953
954       switch (code & 0x1F)
955         {
956         case CCL_SetRegister:   /* 00000000000000000RRRrrrXXXXX */
957           reg[rrr] = reg[RRR];
958           break;
959
960         case CCL_SetShortConst: /* CCCCCCCCCCCCCCCCCCCCrrrXXXXX */
961           reg[rrr] = field1;
962           break;
963
964         case CCL_SetConst:      /* 00000000000000000000rrrXXXXX */
965           reg[rrr] = XINT (ccl_prog[ic]);
966           ic++;
967           break;
968
969         case CCL_SetArray:      /* CCCCCCCCCCCCCCCCCCCCRRRrrrXXXXX */
970           i = reg[RRR];
971           j = field1 >> 3;
972           if ((unsigned int) i < j)
973             reg[rrr] = XINT (ccl_prog[ic + i]);
974           ic += j;
975           break;
976
977         case CCL_Jump:          /* A--D--D--R--E--S--S-000XXXXX */
978           ic += ADDR;
979           break;
980
981         case CCL_JumpCond:      /* A--D--D--R--E--S--S-rrrXXXXX */
982           if (!reg[rrr])
983             ic += ADDR;
984           break;
985
986         case CCL_WriteRegisterJump: /* A--D--D--R--E--S--S-rrrXXXXX */
987           i = reg[rrr];
988           CCL_WRITE_CHAR (i);
989           ic += ADDR;
990           break;
991
992         case CCL_WriteRegisterReadJump: /* A--D--D--R--E--S--S-rrrXXXXX */
993           i = reg[rrr];
994           CCL_WRITE_CHAR (i);
995           ic++;
996           CCL_READ_CHAR (reg[rrr]);
997           ic += ADDR - 1;
998           break;
999
1000         case CCL_WriteConstJump: /* A--D--D--R--E--S--S-000XXXXX */
1001           i = XINT (ccl_prog[ic]);
1002           CCL_WRITE_CHAR (i);
1003           ic += ADDR;
1004           break;
1005
1006         case CCL_WriteConstReadJump: /* A--D--D--R--E--S--S-rrrXXXXX */
1007           i = XINT (ccl_prog[ic]);
1008           CCL_WRITE_CHAR (i);
1009           ic++;
1010           CCL_READ_CHAR (reg[rrr]);
1011           ic += ADDR - 1;
1012           break;
1013
1014         case CCL_WriteStringJump: /* A--D--D--R--E--S--S-000XXXXX */
1015           j = XINT (ccl_prog[ic]);
1016           ic++;
1017           CCL_WRITE_STRING (j);
1018           ic += ADDR - 1;
1019           break;
1020
1021         case CCL_WriteArrayReadJump: /* A--D--D--R--E--S--S-rrrXXXXX */
1022           i = reg[rrr];
1023           j = XINT (ccl_prog[ic]);
1024           if ((unsigned int) i < j)
1025             {
1026               i = XINT (ccl_prog[ic + 1 + i]);
1027               CCL_WRITE_CHAR (i);
1028             }
1029           ic += j + 2;
1030           CCL_READ_CHAR (reg[rrr]);
1031           ic += ADDR - (j + 2);
1032           break;
1033
1034         case CCL_ReadJump:      /* A--D--D--R--E--S--S-rrrYYYYY */
1035           CCL_READ_CHAR (reg[rrr]);
1036           ic += ADDR;
1037           break;
1038
1039         case CCL_ReadBranch:    /* CCCCCCCCCCCCCCCCCCCCrrrXXXXX */
1040           CCL_READ_CHAR (reg[rrr]);
1041           /* fall through ... */
1042         case CCL_Branch:        /* CCCCCCCCCCCCCCCCCCCCrrrXXXXX */
1043           if ((unsigned int) reg[rrr] < field1)
1044             ic += XINT (ccl_prog[ic + reg[rrr]]);
1045           else
1046             ic += XINT (ccl_prog[ic + field1]);
1047           break;
1048
1049         case CCL_ReadRegister:  /* CCCCCCCCCCCCCCCCCCCCrrXXXXX */
1050           while (1)
1051             {
1052               CCL_READ_CHAR (reg[rrr]);
1053               if (!field1) break;
1054               code = XINT (ccl_prog[ic]); ic++;
1055               field1 = code >> 8;
1056               field2 = (code & 0xFF) >> 5;
1057             }
1058           break;
1059
1060         case CCL_WriteExprConst:  /* 1:00000OPERATION000RRR000XXXXX */
1061           rrr = 7;
1062           i = reg[RRR];
1063           j = XINT (ccl_prog[ic]);
1064           op = field1 >> 6;
1065           jump_address = ic + 1;
1066           goto ccl_set_expr;
1067
1068         case CCL_WriteRegister: /* CCCCCCCCCCCCCCCCCCCrrrXXXXX */
1069           while (1)
1070             {
1071               i = reg[rrr];
1072               CCL_WRITE_CHAR (i);
1073               if (!field1) break;
1074               code = XINT (ccl_prog[ic]); ic++;
1075               field1 = code >> 8;
1076               field2 = (code & 0xFF) >> 5;
1077             }
1078           break;
1079
1080         case CCL_WriteExprRegister: /* 1:00000OPERATIONRrrRRR000XXXXX */
1081           rrr = 7;
1082           i = reg[RRR];
1083           j = reg[Rrr];
1084           op = field1 >> 6;
1085           jump_address = ic;
1086           goto ccl_set_expr;
1087
1088         case CCL_Call:          /* 1:CCCCCCCCCCCCCCCCCCCCFFFXXXXX */
1089           {
1090             Lisp_Object slot;
1091             int prog_id;
1092
1093             /* If FFF is nonzero, the CCL program ID is in the
1094                following code.  */
1095             if (rrr)
1096               {
1097                 prog_id = XINT (ccl_prog[ic]);
1098                 ic++;
1099               }
1100             else
1101               prog_id = field1;
1102
1103             if (stack_idx >= 256
1104                 || prog_id < 0
1105                 || prog_id >= XVECTOR (Vccl_program_table)->size
1106                 || (slot = XVECTOR (Vccl_program_table)->contents[prog_id],
1107                     !VECTORP (slot))
1108                 || !VECTORP (XVECTOR (slot)->contents[1]))
1109               {
1110                 if (stack_idx > 0)
1111                   {
1112                     ccl_prog = ccl_prog_stack_struct[0].ccl_prog;
1113                     ic = ccl_prog_stack_struct[0].ic;
1114                   }
1115                 CCL_INVALID_CMD;
1116               }
1117
1118             ccl_prog_stack_struct[stack_idx].ccl_prog = ccl_prog;
1119             ccl_prog_stack_struct[stack_idx].ic = ic;
1120             stack_idx++;
1121             ccl_prog = XVECTOR (XVECTOR (slot)->contents[1])->contents;
1122             ic = CCL_HEADER_MAIN;
1123           }
1124           break;
1125
1126         case CCL_WriteConstString: /* CCCCCCCCCCCCCCCCCCCCrrrXXXXX */
1127           if (!rrr)
1128             CCL_WRITE_CHAR (field1);
1129           else
1130             {
1131               CCL_WRITE_STRING (field1);
1132               ic += (field1 + 2) / 3;
1133             }
1134           break;
1135
1136         case CCL_WriteArray:    /* CCCCCCCCCCCCCCCCCCCCrrrXXXXX */
1137           i = reg[rrr];
1138           if ((unsigned int) i < field1)
1139             {
1140               j = XINT (ccl_prog[ic + i]);
1141               CCL_WRITE_CHAR (j);
1142             }
1143           ic += field1;
1144           break;
1145
1146         case CCL_End:           /* 0000000000000000000000XXXXX */
1147           if (stack_idx > 0)
1148             {
1149               stack_idx--;
1150               ccl_prog = ccl_prog_stack_struct[stack_idx].ccl_prog;
1151               ic = ccl_prog_stack_struct[stack_idx].ic;
1152               break;
1153             }
1154           if (src)
1155             src = src_end;
1156           /* ccl->ic should points to this command code again to
1157              suppress further processing.  */
1158           ic--;
1159           CCL_SUCCESS;
1160
1161         case CCL_ExprSelfConst: /* 00000OPERATION000000rrrXXXXX */
1162           i = XINT (ccl_prog[ic]);
1163           ic++;
1164           op = field1 >> 6;
1165           goto ccl_expr_self;
1166
1167         case CCL_ExprSelfReg:   /* 00000OPERATION000RRRrrrXXXXX */
1168           i = reg[RRR];
1169           op = field1 >> 6;
1170
1171         ccl_expr_self:
1172           switch (op)
1173             {
1174             case CCL_PLUS: reg[rrr] += i; break;
1175             case CCL_MINUS: reg[rrr] -= i; break;
1176             case CCL_MUL: reg[rrr] *= i; break;
1177             case CCL_DIV: reg[rrr] /= i; break;
1178             case CCL_MOD: reg[rrr] %= i; break;
1179             case CCL_AND: reg[rrr] &= i; break;
1180             case CCL_OR: reg[rrr] |= i; break;
1181             case CCL_XOR: reg[rrr] ^= i; break;
1182             case CCL_LSH: reg[rrr] <<= i; break;
1183             case CCL_RSH: reg[rrr] >>= i; break;
1184             case CCL_LSH8: reg[rrr] <<= 8; reg[rrr] |= i; break;
1185             case CCL_RSH8: reg[7] = reg[rrr] & 0xFF; reg[rrr] >>= 8; break;
1186             case CCL_DIVMOD: reg[7] = reg[rrr] % i; reg[rrr] /= i; break;
1187             case CCL_LS: reg[rrr] = reg[rrr] < i; break;
1188             case CCL_GT: reg[rrr] = reg[rrr] > i; break;
1189             case CCL_EQ: reg[rrr] = reg[rrr] == i; break;
1190             case CCL_LE: reg[rrr] = reg[rrr] <= i; break;
1191             case CCL_GE: reg[rrr] = reg[rrr] >= i; break;
1192             case CCL_NE: reg[rrr] = reg[rrr] != i; break;
1193             default: CCL_INVALID_CMD;
1194             }
1195           break;
1196
1197         case CCL_SetExprConst:  /* 00000OPERATION000RRRrrrXXXXX */
1198           i = reg[RRR];
1199           j = XINT (ccl_prog[ic]);
1200           op = field1 >> 6;
1201           jump_address = ++ic;
1202           goto ccl_set_expr;
1203
1204         case CCL_SetExprReg:    /* 00000OPERATIONRrrRRRrrrXXXXX */
1205           i = reg[RRR];
1206           j = reg[Rrr];
1207           op = field1 >> 6;
1208           jump_address = ic;
1209           goto ccl_set_expr;
1210
1211         case CCL_ReadJumpCondExprConst: /* A--D--D--R--E--S--S-rrrXXXXX */
1212           CCL_READ_CHAR (reg[rrr]);
1213         case CCL_JumpCondExprConst: /* A--D--D--R--E--S--S-rrrXXXXX */
1214           i = reg[rrr];
1215           op = XINT (ccl_prog[ic]);
1216           jump_address = ic++ + ADDR;
1217           j = XINT (ccl_prog[ic]);
1218           ic++;
1219           rrr = 7;
1220           goto ccl_set_expr;
1221
1222         case CCL_ReadJumpCondExprReg: /* A--D--D--R--E--S--S-rrrXXXXX */
1223           CCL_READ_CHAR (reg[rrr]);
1224         case CCL_JumpCondExprReg:
1225           i = reg[rrr];
1226           op = XINT (ccl_prog[ic]);
1227           jump_address = ic++ + ADDR;
1228           j = reg[XINT (ccl_prog[ic])];
1229           ic++;
1230           rrr = 7;
1231
1232         ccl_set_expr:
1233           switch (op)
1234             {
1235             case CCL_PLUS: reg[rrr] = i + j; break;
1236             case CCL_MINUS: reg[rrr] = i - j; break;
1237             case CCL_MUL: reg[rrr] = i * j; break;
1238             case CCL_DIV: reg[rrr] = i / j; break;
1239             case CCL_MOD: reg[rrr] = i % j; break;
1240             case CCL_AND: reg[rrr] = i & j; break;
1241             case CCL_OR: reg[rrr] = i | j; break;
1242             case CCL_XOR: reg[rrr] = i ^ j;; break;
1243             case CCL_LSH: reg[rrr] = i << j; break;
1244             case CCL_RSH: reg[rrr] = i >> j; break;
1245             case CCL_LSH8: reg[rrr] = (i << 8) | j; break;
1246             case CCL_RSH8: reg[rrr] = i >> 8; reg[7] = i & 0xFF; break;
1247             case CCL_DIVMOD: reg[rrr] = i / j; reg[7] = i % j; break;
1248             case CCL_LS: reg[rrr] = i < j; break;
1249             case CCL_GT: reg[rrr] = i > j; break;
1250             case CCL_EQ: reg[rrr] = i == j; break;
1251             case CCL_LE: reg[rrr] = i <= j; break;
1252             case CCL_GE: reg[rrr] = i >= j; break;
1253             case CCL_NE: reg[rrr] = i != j; break;
1254             case CCL_DECODE_SJIS:
1255               /* DECODE_SJIS set MSB for internal format
1256                  as opposed to Emacs.  */
1257               DECODE_SJIS (i, j, reg[rrr], reg[7]);
1258               reg[rrr] &= 0x7F;
1259               reg[7] &= 0x7F;
1260               break;
1261             case CCL_ENCODE_SJIS:
1262               /* ENCODE_SJIS assumes MSB of SJIS-char is set
1263                  as opposed to Emacs.  */
1264               ENCODE_SJIS (i | 0x80, j | 0x80, reg[rrr], reg[7]);
1265               break;
1266             default: CCL_INVALID_CMD;
1267             }
1268           code &= 0x1F;
1269           if (code == CCL_WriteExprConst || code == CCL_WriteExprRegister)
1270             {
1271               i = reg[rrr];
1272               CCL_WRITE_CHAR (i);
1273               ic = jump_address;
1274             }
1275           else if (!reg[rrr])
1276             ic = jump_address;
1277           break;
1278
1279         case CCL_Extension:
1280           switch (EXCMD)
1281             {
1282             case CCL_ReadMultibyteChar2:
1283               if (!src)
1284                 CCL_INVALID_CMD;
1285
1286                 if (src >= src_end)
1287                   {
1288                     src++;
1289                     goto ccl_read_multibyte_character_suspend;
1290                   }
1291
1292                 i = *src++;
1293                 if (i < 0x80)
1294                   {
1295                     /* ASCII */
1296                     reg[rrr] = i;
1297                     reg[RRR] = LEADING_BYTE_ASCII;
1298                   }
1299                 else if (i <= MAX_LEADING_BYTE_OFFICIAL_1)
1300                   {
1301                     if (src >= src_end)
1302                       goto ccl_read_multibyte_character_suspend;
1303                     reg[RRR] = i;
1304                     reg[rrr] = (*src++ & 0x7F);
1305                   }
1306                 else if (LEADING_BYTE_CONTROL_1 == i)
1307                   {
1308                     if (src >= src_end)
1309                       goto ccl_read_multibyte_character_suspend;
1310                     reg[RRR] = i;
1311                     reg[rrr] = (*src++ - 0xA0);
1312                   }
1313                 else if (i <= MAX_LEADING_BYTE_OFFICIAL_2)
1314                   {
1315                     if ((src + 1) >= src_end)
1316                       goto ccl_read_multibyte_character_suspend;
1317                     reg[RRR] = i;
1318                     i = (*src++ & 0x7F);
1319                     reg[rrr] = ((i << 7) | (*src & 0x7F));
1320                     src++;
1321                   }
1322                 else if (i == PRE_LEADING_BYTE_PRIVATE_1)
1323                   {
1324                     if ((src + 1) >= src_end)
1325                       goto ccl_read_multibyte_character_suspend;
1326                     reg[RRR] = *src++;
1327                     reg[rrr] = (*src++ & 0x7F);
1328                   }
1329                 else if (i == PRE_LEADING_BYTE_PRIVATE_2)
1330                   {
1331                     if ((src + 2) >= src_end)
1332                       goto ccl_read_multibyte_character_suspend;
1333                     reg[RRR] = *src++;
1334                     i = (*src++ & 0x7F);
1335                     reg[rrr] = ((i << 7) | (*src & 0x7F));
1336                     src++;
1337                   }
1338                 else
1339                   {
1340                     /* INVALID CODE.  Return a single byte character.  */
1341                     reg[RRR] = LEADING_BYTE_ASCII;
1342                     reg[rrr] = i;
1343                   }
1344               break;
1345
1346             ccl_read_multibyte_character_suspend:
1347               src--;
1348               if (ccl->last_block)
1349                 {
1350                   ic = ccl->eof_ic;
1351                   goto ccl_repeat;
1352                 }
1353               else
1354                 CCL_SUSPEND (CCL_STAT_SUSPEND_BY_SRC);
1355
1356               break;
1357
1358             case CCL_WriteMultibyteChar2:
1359               i = reg[RRR]; /* charset */
1360               if (i == LEADING_BYTE_ASCII || i == LEADING_BYTE_CONTROL_1)
1361                 i = reg[rrr] & 0xFF;
1362               else if (XCHARSET_DIMENSION (CHARSET_BY_LEADING_BYTE (i)) == 1)
1363                 i = (((i - FIELD2_TO_OFFICIAL_LEADING_BYTE) << 7)
1364                      | (reg[rrr] & 0x7F));
1365               else if (i < MAX_LEADING_BYTE_OFFICIAL_2)
1366                 i = ((i - FIELD1_TO_OFFICIAL_LEADING_BYTE) << 14) | reg[rrr];
1367               else
1368                 i = ((i - FIELD1_TO_PRIVATE_LEADING_BYTE) << 14) | reg[rrr];
1369
1370               CCL_WRITE_CHAR (i);
1371
1372               break;
1373
1374             case CCL_TranslateCharacter:
1375 #if 0
1376               /* XEmacs does not have translate_char, and its
1377                  equivalent nor.  We do nothing on this operation. */
1378               CCL_MAKE_CHAR (reg[RRR], reg[rrr], i);
1379               op = translate_char (GET_TRANSLATION_TABLE (reg[Rrr]),
1380                                    i, -1, 0, 0);
1381               SPLIT_CHAR (op, reg[RRR], i, j);
1382               if (j != -1)
1383                 i = (i << 7) | j;
1384
1385               reg[rrr] = i;
1386 #endif
1387               break;
1388
1389             case CCL_TranslateCharacterConstTbl:
1390 #if 0
1391               /* XEmacs does not have translate_char, and its
1392                  equivalent nor.  We do nothing on this operation. */
1393               op = XINT (ccl_prog[ic]); /* table */
1394               ic++;
1395               CCL_MAKE_CHAR (reg[RRR], reg[rrr], i);
1396               op = translate_char (GET_TRANSLATION_TABLE (op), i, -1, 0, 0);
1397               SPLIT_CHAR (op, reg[RRR], i, j);
1398               if (j != -1)
1399                 i = (i << 7) | j;
1400
1401               reg[rrr] = i;
1402 #endif
1403               break;
1404
1405             case CCL_IterateMultipleMap:
1406               {
1407                 Lisp_Object map, content, attrib, value;
1408                 int point, size, fin_ic;
1409
1410                 j = XINT (ccl_prog[ic++]); /* number of maps. */
1411                 fin_ic = ic + j;
1412                 op = reg[rrr];
1413                 if ((j > reg[RRR]) && (j >= 0))
1414                   {
1415                     ic += reg[RRR];
1416                     i = reg[RRR];
1417                   }
1418                 else
1419                   {
1420                     reg[RRR] = -1;
1421                     ic = fin_ic;
1422                     break;
1423                   }
1424
1425                 for (;i < j;i++)
1426                   {
1427
1428                     size = XVECTOR (Vcode_conversion_map_vector)->size;
1429                     point = XINT (ccl_prog[ic++]);
1430                     if (point >= size) continue;
1431                     map =
1432                       XVECTOR (Vcode_conversion_map_vector)->contents[point];
1433
1434                     /* Check map validity.  */
1435                     if (!CONSP (map)) continue;
1436                     map = XCDR (map);
1437                     if (!VECTORP (map)) continue;
1438                     size = XVECTOR (map)->size;
1439                     if (size <= 1) continue;
1440
1441                     content = XVECTOR (map)->contents[0];
1442
1443                     /* check map type,
1444                        [STARTPOINT VAL1 VAL2 ...] or
1445                        [t ELEMENT STARTPOINT ENDPOINT]  */
1446                     if (INTP (content))
1447                       {
1448                         point = XUINT (content);
1449                         point = op - point + 1;
1450                         if (!((point >= 1) && (point < size))) continue;
1451                         content = XVECTOR (map)->contents[point];
1452                       }
1453                     else if (EQ (content, Qt))
1454                       {
1455                         if (size != 4) continue;
1456                         if ((op >= XUINT (XVECTOR (map)->contents[2]))
1457                             && (op < XUINT (XVECTOR (map)->contents[3])))
1458                           content = XVECTOR (map)->contents[1];
1459                         else
1460                           continue;
1461                       }
1462                     else
1463                       continue;
1464
1465                     if (NILP (content))
1466                       continue;
1467                     else if (INTP (content))
1468                       {
1469                         reg[RRR] = i;
1470                         reg[rrr] = XINT(content);
1471                         break;
1472                       }
1473                     else if (EQ (content, Qt) || EQ (content, Qlambda))
1474                       {
1475                         reg[RRR] = i;
1476                         break;
1477                       }
1478                     else if (CONSP (content))
1479                       {
1480                         attrib = XCAR (content);
1481                         value = XCDR (content);
1482                         if (!INTP (attrib) || !INTP (value))
1483                           continue;
1484                         reg[RRR] = i;
1485                         reg[rrr] = XUINT (value);
1486                         break;
1487                       }
1488                     else if (SYMBOLP (content))
1489                       CCL_CALL_FOR_MAP_INSTRUCTION (content, fin_ic);
1490                     else
1491                       CCL_INVALID_CMD;
1492                   }
1493                 if (i == j)
1494                   reg[RRR] = -1;
1495                 ic = fin_ic;
1496               }
1497               break;
1498
1499             case CCL_MapMultiple:
1500               {
1501                 Lisp_Object map, content, attrib, value;
1502                 int point, size, map_vector_size;
1503                 int map_set_rest_length, fin_ic;
1504                 int current_ic = this_ic;
1505
1506                 /* inhibit recursive call on MapMultiple. */
1507                 if (stack_idx_of_map_multiple > 0)
1508                   {
1509                     if (stack_idx_of_map_multiple <= stack_idx)
1510                       {
1511                         stack_idx_of_map_multiple = 0;
1512                         mapping_stack_pointer = mapping_stack;
1513                         CCL_INVALID_CMD;
1514                       }
1515                   }
1516                 else
1517                   mapping_stack_pointer = mapping_stack;
1518                 stack_idx_of_map_multiple = 0;
1519
1520                 map_set_rest_length =
1521                   XINT (ccl_prog[ic++]); /* number of maps and separators. */
1522                 fin_ic = ic + map_set_rest_length;
1523                 op = reg[rrr];
1524
1525                 if ((map_set_rest_length > reg[RRR]) && (reg[RRR] >= 0))
1526                   {
1527                     ic += reg[RRR];
1528                     i = reg[RRR];
1529                     map_set_rest_length -= i;
1530                   }
1531                 else
1532                   {
1533                     ic = fin_ic;
1534                     reg[RRR] = -1;
1535                     mapping_stack_pointer = mapping_stack;
1536                     break;
1537                   }
1538
1539                 if (mapping_stack_pointer <= (mapping_stack + 1))
1540                   {
1541                     /* Set up initial state. */
1542                     mapping_stack_pointer = mapping_stack;
1543                     PUSH_MAPPING_STACK (0, op);
1544                     reg[RRR] = -1;
1545                   }
1546                 else
1547                   {
1548                     /* Recover after calling other ccl program. */
1549                     int orig_op;
1550
1551                     POP_MAPPING_STACK (map_set_rest_length, orig_op);
1552                     POP_MAPPING_STACK (map_set_rest_length, reg[rrr]);
1553                     switch (op)
1554                       {
1555                       case -1:
1556                         /* Regard it as Qnil. */
1557                         op = orig_op;
1558                         i++;
1559                         ic++;
1560                         map_set_rest_length--;
1561                         break;
1562                       case -2:
1563                         /* Regard it as Qt. */
1564                         op = reg[rrr];
1565                         i++;
1566                         ic++;
1567                         map_set_rest_length--;
1568                         break;
1569                       case -3:
1570                         /* Regard it as Qlambda. */
1571                         op = orig_op;
1572                         i += map_set_rest_length;
1573                         ic += map_set_rest_length;
1574                         map_set_rest_length = 0;
1575                         break;
1576                       default:
1577                         /* Regard it as normal mapping. */
1578                         i += map_set_rest_length;
1579                         ic += map_set_rest_length;
1580                         POP_MAPPING_STACK (map_set_rest_length, reg[rrr]);
1581                         break;
1582                       }
1583                   }
1584                 map_vector_size = XVECTOR (Vcode_conversion_map_vector)->size;
1585
1586                 do {
1587                   for (;map_set_rest_length > 0;i++, ic++, map_set_rest_length--)
1588                     {
1589                       point = XINT(ccl_prog[ic]);
1590                       if (point < 0)
1591                         {
1592                           /* +1 is for including separator. */
1593                           point = -point + 1;
1594                           if (mapping_stack_pointer
1595                               >= mapping_stack + countof (mapping_stack))
1596                             CCL_INVALID_CMD;
1597                           PUSH_MAPPING_STACK (map_set_rest_length - point,
1598                                               reg[rrr]);
1599                           map_set_rest_length = point;
1600                           reg[rrr] = op;
1601                           continue;
1602                         }
1603
1604                       if (point >= map_vector_size) continue;
1605                       map = (XVECTOR (Vcode_conversion_map_vector)
1606                              ->contents[point]);
1607
1608                       /* Check map validity.  */
1609                       if (!CONSP (map)) continue;
1610                       map = XCDR (map);
1611                       if (!VECTORP (map)) continue;
1612                       size = XVECTOR (map)->size;
1613                       if (size <= 1) continue;
1614
1615                       content = XVECTOR (map)->contents[0];
1616
1617                       /* check map type,
1618                          [STARTPOINT VAL1 VAL2 ...] or
1619                          [t ELEMENT STARTPOINT ENDPOINT]  */
1620                       if (INTP (content))
1621                         {
1622                           point = XUINT (content);
1623                           point = op - point + 1;
1624                           if (!((point >= 1) && (point < size))) continue;
1625                           content = XVECTOR (map)->contents[point];
1626                         }
1627                       else if (EQ (content, Qt))
1628                         {
1629                           if (size != 4) continue;
1630                           if ((op >= XUINT (XVECTOR (map)->contents[2])) &&
1631                               (op < XUINT (XVECTOR (map)->contents[3])))
1632                             content = XVECTOR (map)->contents[1];
1633                           else
1634                             continue;
1635                         }
1636                       else
1637                         continue;
1638
1639                       if (NILP (content))
1640                         continue;
1641
1642                       reg[RRR] = i;
1643                       if (INTP (content))
1644                         {
1645                           op = XINT (content);
1646                           i += map_set_rest_length - 1;
1647                           ic += map_set_rest_length - 1;
1648                           POP_MAPPING_STACK (map_set_rest_length, reg[rrr]);
1649                           map_set_rest_length++;
1650                         }
1651                       else if (CONSP (content))
1652                         {
1653                           attrib = XCAR (content);
1654                           value = XCDR (content);
1655                           if (!INTP (attrib) || !INTP (value))
1656                             continue;
1657                           op = XUINT (value);
1658                           i += map_set_rest_length - 1;
1659                           ic += map_set_rest_length - 1;
1660                           POP_MAPPING_STACK (map_set_rest_length, reg[rrr]);
1661                           map_set_rest_length++;
1662                         }
1663                       else if (EQ (content, Qt))
1664                         {
1665                           op = reg[rrr];
1666                         }
1667                       else if (EQ (content, Qlambda))
1668                         {
1669                           i += map_set_rest_length;
1670                           ic += map_set_rest_length;
1671                           break;
1672                         }
1673                       else if (SYMBOLP (content))
1674                         {
1675                           if (mapping_stack_pointer
1676                               >= mapping_stack + countof (mapping_stack))
1677                             CCL_INVALID_CMD;
1678                           PUSH_MAPPING_STACK (map_set_rest_length, reg[rrr]);
1679                           PUSH_MAPPING_STACK (map_set_rest_length, op);
1680                           stack_idx_of_map_multiple = stack_idx + 1;
1681                           CCL_CALL_FOR_MAP_INSTRUCTION (content, current_ic);
1682                         }
1683                       else
1684                         CCL_INVALID_CMD;
1685                     }
1686                   if (mapping_stack_pointer <= (mapping_stack + 1))
1687                     break;
1688                   POP_MAPPING_STACK (map_set_rest_length, reg[rrr]);
1689                   i += map_set_rest_length;
1690                   ic += map_set_rest_length;
1691                   POP_MAPPING_STACK (map_set_rest_length, reg[rrr]);
1692                 } while (1);
1693
1694                 ic = fin_ic;
1695               }
1696               reg[rrr] = op;
1697               break;
1698
1699             case CCL_MapSingle:
1700               {
1701                 Lisp_Object map, attrib, value, content;
1702                 int size, point;
1703                 j = XINT (ccl_prog[ic++]); /* map_id */
1704                 op = reg[rrr];
1705                 if (j >= XVECTOR (Vcode_conversion_map_vector)->size)
1706                   {
1707                     reg[RRR] = -1;
1708                     break;
1709                   }
1710                 map = XVECTOR (Vcode_conversion_map_vector)->contents[j];
1711                 if (!CONSP (map))
1712                   {
1713                     reg[RRR] = -1;
1714                     break;
1715                   }
1716                 map = XCDR (map);
1717                 if (!VECTORP (map))
1718                   {
1719                     reg[RRR] = -1;
1720                     break;
1721                   }
1722                 size = XVECTOR (map)->size;
1723                 point = XUINT (XVECTOR (map)->contents[0]);
1724                 point = op - point + 1;
1725                 reg[RRR] = 0;
1726                 if ((size <= 1) ||
1727                     (!((point >= 1) && (point < size))))
1728                   reg[RRR] = -1;
1729                 else
1730                   {
1731                     reg[RRR] = 0;
1732                     content = XVECTOR (map)->contents[point];
1733                     if (NILP (content))
1734                       reg[RRR] = -1;
1735                     else if (INTP (content))
1736                       reg[rrr] = XINT (content);
1737                     else if (EQ (content, Qt));
1738                     else if (CONSP (content))
1739                       {
1740                         attrib = XCAR (content);
1741                         value = XCDR (content);
1742                         if (!INTP (attrib) || !INTP (value))
1743                           continue;
1744                         reg[rrr] = XUINT(value);
1745                         break;
1746                       }
1747                     else if (SYMBOLP (content))
1748                       CCL_CALL_FOR_MAP_INSTRUCTION (content, ic);
1749                     else
1750                       reg[RRR] = -1;
1751                   }
1752               }
1753               break;
1754
1755             default:
1756               CCL_INVALID_CMD;
1757             }
1758           break;
1759
1760         default:
1761           CCL_INVALID_CMD;
1762         }
1763     }
1764
1765  ccl_error_handler:
1766   if (destination)
1767     {
1768       /* We can insert an error message only if DESTINATION is
1769          specified and we still have a room to store the message
1770          there.  */
1771       char msg[256];
1772
1773       switch (ccl->status)
1774         {
1775         case CCL_STAT_INVALID_CMD:
1776           sprintf(msg, "\nCCL: Invalid command %x (ccl_code = %x) at %d.",
1777                   code & 0x1F, code, this_ic);
1778 #ifdef CCL_DEBUG
1779           {
1780             int i = ccl_backtrace_idx - 1;
1781             int j;
1782
1783             Dynarr_add_many (destination, (unsigned char *) msg, strlen (msg));
1784
1785             for (j = 0; j < CCL_DEBUG_BACKTRACE_LEN; j++, i--)
1786               {
1787                 if (i < 0) i = CCL_DEBUG_BACKTRACE_LEN - 1;
1788                 if (ccl_backtrace_table[i] == 0)
1789                   break;
1790                 sprintf(msg, " %d", ccl_backtrace_table[i]);
1791                 Dynarr_add_many (destination, (unsigned char *) msg, strlen (msg));
1792               }
1793             goto ccl_finish;
1794           }
1795 #endif
1796           break;
1797
1798         case CCL_STAT_QUIT:
1799           sprintf(msg, "\nCCL: Exited.");
1800           break;
1801
1802         default:
1803           sprintf(msg, "\nCCL: Unknown error type (%d).", ccl->status);
1804         }
1805
1806       Dynarr_add_many (destination, (unsigned char *) msg, strlen (msg));
1807     }
1808
1809  ccl_finish:
1810   ccl->ic = ic;
1811   ccl->stack_idx = stack_idx;
1812   ccl->prog = ccl_prog;
1813   if (consumed) *consumed = src - source;
1814   if (!destination)
1815     return 0;
1816   return Dynarr_length (destination);
1817 }
1818
1819 /* Resolve symbols in the specified CCL code (Lisp vector).  This
1820    function converts symbols of code conversion maps and character
1821    translation tables embedded in the CCL code into their ID numbers.
1822
1823    The return value is a vector (CCL itself or a new vector in which
1824    all symbols are resolved), Qt if resolving of some symbol failed,
1825    or nil if CCL contains invalid data.  */
1826
1827 static Lisp_Object
1828 resolve_symbol_ccl_program (Lisp_Object ccl)
1829 {
1830   int i, veclen, unresolved = 0;
1831   Lisp_Object result, contents, val;
1832
1833   result = ccl;
1834   veclen = XVECTOR (result)->size;
1835
1836   for (i = 0; i < veclen; i++)
1837     {
1838       contents = XVECTOR (result)->contents[i];
1839       if (INTP (contents))
1840         continue;
1841       else if (CONSP (contents)
1842                && SYMBOLP (XCAR (contents))
1843                && SYMBOLP (XCDR (contents)))
1844         {
1845           /* This is the new style for embedding symbols.  The form is
1846              (SYMBOL . PROPERTY).  (get SYMBOL PROPERTY) should give
1847              an index number.  */
1848
1849           if (EQ (result, ccl))
1850             result =  Fcopy_sequence (ccl);
1851
1852           val = Fget (XCAR (contents), XCDR (contents), Qnil);
1853           if (NATNUMP (val))
1854             XVECTOR (result)->contents[i] = val;
1855           else
1856             unresolved = 1;
1857           continue;
1858         }
1859       else if (SYMBOLP (contents))
1860         {
1861           /* This is the old style for embedding symbols.  This style
1862              may lead to a bug if, for instance, a translation table
1863              and a code conversion map have the same name.  */
1864           if (EQ (result, ccl))
1865             result = Fcopy_sequence (ccl);
1866
1867           val = Fget (contents, Qcode_conversion_map_id, Qnil);
1868           if (NATNUMP (val))
1869             XVECTOR (result)->contents[i] = val;
1870           else
1871             {
1872               val = Fget (contents, Qccl_program_idx, Qnil);
1873               if (NATNUMP (val))
1874                 XVECTOR (result)->contents[i] = val;
1875               else
1876                 unresolved = 1;
1877             }
1878           continue;
1879         }
1880       return Qnil;
1881     }
1882
1883   return (unresolved ? Qt : result);
1884 }
1885
1886 /* Return the compiled code (vector) of CCL program CCL_PROG.
1887    CCL_PROG is a name (symbol) of the program or already compiled
1888    code.  If necessary, resolve symbols in the compiled code to index
1889    numbers.  If we failed to get the compiled code or to resolve
1890    symbols, return Qnil.  */
1891
1892 static Lisp_Object
1893 ccl_get_compiled_code (Lisp_Object ccl_prog)
1894 {
1895   Lisp_Object val, slot;
1896
1897   if (VECTORP (ccl_prog))
1898     {
1899       val = resolve_symbol_ccl_program (ccl_prog);
1900       return (VECTORP (val) ? val : Qnil);
1901     }
1902   if (!SYMBOLP (ccl_prog))
1903     return Qnil;
1904
1905   val = Fget (ccl_prog, Qccl_program_idx, Qnil);
1906   if (! NATNUMP (val)
1907       || XINT (val) >= XVECTOR_LENGTH (Vccl_program_table))
1908     return Qnil;
1909   slot = XVECTOR_DATA (Vccl_program_table)[XINT (val)];
1910   if (! VECTORP (slot)
1911       || XVECTOR (slot)->size != 3
1912       || ! VECTORP (XVECTOR_DATA (slot)[1]))
1913     return Qnil;
1914   if (NILP (XVECTOR_DATA (slot)[2]))
1915     {
1916       val = resolve_symbol_ccl_program (XVECTOR_DATA (slot)[1]);
1917       if (! VECTORP (val))
1918         return Qnil;
1919       XVECTOR_DATA (slot)[1] = val;
1920       XVECTOR_DATA (slot)[2] = Qt;
1921     }
1922   return XVECTOR_DATA (slot)[1];
1923 }
1924
1925 /* Setup fields of the structure pointed by CCL appropriately for the
1926    execution of CCL program CCL_PROG.  CCL_PROG is the name (symbol)
1927    of the CCL program or the already compiled code (vector).
1928    Return 0 if we succeed this setup, else return -1.
1929
1930    If CCL_PROG is nil, we just reset the structure pointed by CCL.  */
1931 int
1932 setup_ccl_program (struct ccl_program *ccl, Lisp_Object ccl_prog)
1933 {
1934   int i;
1935
1936   if (! NILP (ccl_prog))
1937     {
1938       ccl_prog = ccl_get_compiled_code (ccl_prog);
1939       if (! VECTORP (ccl_prog))
1940         return -1;
1941       ccl->size = XVECTOR_LENGTH (ccl_prog);
1942       ccl->prog = XVECTOR_DATA (ccl_prog);
1943       ccl->eof_ic = XINT (XVECTOR_DATA (ccl_prog)[CCL_HEADER_EOF]);
1944       ccl->buf_magnification = XINT (XVECTOR_DATA (ccl_prog)[CCL_HEADER_BUF_MAG]);
1945     }
1946   ccl->ic = CCL_HEADER_MAIN;
1947   for (i = 0; i < 8; i++)
1948     ccl->reg[i] = 0;
1949   ccl->last_block = 0;
1950   ccl->private_state = 0;
1951   ccl->status = 0;
1952   ccl->stack_idx = 0;
1953   ccl->eol_type = CCL_CODING_EOL_LF;
1954   return 0;
1955 }
1956
1957 #ifdef emacs
1958
1959 DEFUN ("ccl-program-p", Fccl_program_p, 1, 1, 0, /*
1960 Return t if OBJECT is a CCL program name or a compiled CCL program code.
1961 See the documentation of  `define-ccl-program' for the detail of CCL program.
1962 */
1963        (object))
1964 {
1965   Lisp_Object val;
1966
1967   if (VECTORP (object))
1968     {
1969       val = resolve_symbol_ccl_program (object);
1970       return (VECTORP (val) ? Qt : Qnil);
1971     }
1972   if (!SYMBOLP (object))
1973     return Qnil;
1974
1975   val = Fget (object, Qccl_program_idx, Qnil);
1976   return ((! NATNUMP (val)
1977            || XINT (val) >= XVECTOR_LENGTH (Vccl_program_table))
1978           ? Qnil : Qt);
1979 }
1980
1981 DEFUN ("ccl-execute", Fccl_execute, 2, 2, 0, /*
1982 Execute CCL-PROGRAM with registers initialized by REGISTERS.
1983
1984 CCL-PROGRAM is a CCL program name (symbol)
1985 or a compiled code generated by `ccl-compile' (for backward compatibility,
1986 in this case, the overhead of the execution is bigger than the former case).
1987 No I/O commands should appear in CCL-PROGRAM.
1988
1989 REGISTERS is a vector of [R0 R1 ... R7] where RN is an initial value
1990  of Nth register.
1991
1992 As side effect, each element of REGISTERS holds the value of
1993  corresponding register after the execution.
1994
1995 See the documentation of `define-ccl-program' for the detail of CCL program.
1996 */
1997        (ccl_prog, reg))
1998 {
1999   struct ccl_program ccl;
2000   int i;
2001
2002   if (setup_ccl_program (&ccl, ccl_prog) < 0)
2003     error ("Invalid CCL program");
2004
2005   CHECK_VECTOR (reg);
2006   if (XVECTOR_LENGTH (reg) != 8)
2007     error ("Length of vector REGISTERS is not 8");
2008
2009   for (i = 0; i < 8; i++)
2010     ccl.reg[i] = (INTP (XVECTOR_DATA (reg)[i])
2011                   ? XINT (XVECTOR_DATA (reg)[i])
2012                   : 0);
2013
2014   ccl_driver (&ccl, (const unsigned char *)0,
2015               (unsigned_char_dynarr *)0, 0, (int *)0,
2016               CCL_MODE_ENCODING);
2017   QUIT;
2018   if (ccl.status != CCL_STAT_SUCCESS)
2019     error ("Error in CCL program at %dth code", ccl.ic);
2020
2021   for (i = 0; i < 8; i++)
2022     XSETINT (XVECTOR (reg)->contents[i], ccl.reg[i]);
2023   return Qnil;
2024 }
2025
2026 DEFUN ("ccl-execute-on-string", Fccl_execute_on_string,
2027        3, 4, 0, /*
2028 Execute CCL-PROGRAM with initial STATUS on STRING.
2029
2030 CCL-PROGRAM is a symbol registered by register-ccl-program,
2031 or a compiled code generated by `ccl-compile' (for backward compatibility,
2032 in this case, the execution is slower).
2033
2034 Read buffer is set to STRING, and write buffer is allocated automatically.
2035
2036 STATUS is a vector of [R0 R1 ... R7 IC], where
2037  R0..R7 are initial values of corresponding registers,
2038  IC is the instruction counter specifying from where to start the program.
2039 If R0..R7 are nil, they are initialized to 0.
2040 If IC is nil, it is initialized to head of the CCL program.
2041
2042 If optional 4th arg CONTINUE is non-nil, keep IC on read operation
2043 when read buffer is exhausted, else, IC is always set to the end of
2044 CCL-PROGRAM on exit.
2045
2046 It returns the contents of write buffer as a string,
2047  and as side effect, STATUS is updated.
2048
2049 See the documentation of `define-ccl-program' for the detail of CCL program.
2050 */
2051        (ccl_prog, status, string, continue_))
2052 {
2053   Lisp_Object val;
2054   struct ccl_program ccl;
2055   int i, produced;
2056   unsigned_char_dynarr *outbuf;
2057   struct gcpro gcpro1, gcpro2;
2058
2059   if (setup_ccl_program (&ccl, ccl_prog) < 0)
2060     error ("Invalid CCL program");
2061
2062   CHECK_VECTOR (status);
2063   if (XVECTOR (status)->size != 9)
2064     error ("Length of vector STATUS is not 9");
2065   CHECK_STRING (string);
2066
2067   GCPRO2 (status, string);
2068
2069   for (i = 0; i < 8; i++)
2070     {
2071       if (NILP (XVECTOR_DATA (status)[i]))
2072         XSETINT (XVECTOR_DATA (status)[i], 0);
2073       if (INTP (XVECTOR_DATA (status)[i]))
2074         ccl.reg[i] = XINT (XVECTOR_DATA (status)[i]);
2075     }
2076   if (INTP (XVECTOR (status)->contents[i]))
2077     {
2078       i = XINT (XVECTOR_DATA (status)[8]);
2079       if (ccl.ic < i && i < ccl.size)
2080         ccl.ic = i;
2081     }
2082   outbuf = Dynarr_new (unsigned_char);
2083   ccl.last_block = NILP (continue_);
2084   produced = ccl_driver (&ccl, XSTRING_DATA (string), outbuf,
2085                          XSTRING_LENGTH (string),
2086                          (int *) 0,
2087                          CCL_MODE_DECODING);
2088   for (i = 0; i < 8; i++)
2089     XSETINT (XVECTOR_DATA (status)[i], ccl.reg[i]);
2090   XSETINT (XVECTOR_DATA (status)[8], ccl.ic);
2091   UNGCPRO;
2092
2093   val = make_string (Dynarr_atp (outbuf, 0), produced);
2094   Dynarr_free (outbuf);
2095   QUIT;
2096   if (ccl.status == CCL_STAT_SUSPEND_BY_DST)
2097     error ("Output buffer for the CCL programs overflow");
2098   if (ccl.status != CCL_STAT_SUCCESS
2099       && ccl.status != CCL_STAT_SUSPEND_BY_SRC)
2100     error ("Error in CCL program at %dth code", ccl.ic);
2101
2102   return val;
2103 }
2104
2105 DEFUN ("register-ccl-program", Fregister_ccl_program,
2106        2, 2, 0, /*
2107 Register CCL program CCL-PROG as NAME in `ccl-program-table'.
2108 CCL-PROG should be a compiled CCL program (vector), or nil.
2109 If it is nil, just reserve NAME as a CCL program name.
2110 Return index number of the registered CCL program.
2111 */
2112        (name, ccl_prog))
2113 {
2114   int len = XVECTOR_LENGTH (Vccl_program_table);
2115   int idx;
2116   Lisp_Object resolved;
2117
2118   CHECK_SYMBOL (name);
2119   resolved = Qnil;
2120   if (!NILP (ccl_prog))
2121     {
2122       CHECK_VECTOR (ccl_prog);
2123       resolved = resolve_symbol_ccl_program (ccl_prog);
2124       if (! NILP (resolved))
2125         {
2126           ccl_prog = resolved;
2127           resolved = Qt;
2128         }
2129     }
2130
2131   for (idx = 0; idx < len; idx++)
2132     {
2133       Lisp_Object slot;
2134
2135       slot = XVECTOR_DATA (Vccl_program_table)[idx];
2136       if (!VECTORP (slot))
2137         /* This is the first unused slot.  Register NAME here.  */
2138         break;
2139
2140       if (EQ (name, XVECTOR_DATA (slot)[0]))
2141         {
2142           /* Update this slot.  */
2143           XVECTOR_DATA (slot)[1] = ccl_prog;
2144           XVECTOR_DATA (slot)[2] = resolved;
2145           return make_int (idx);
2146         }
2147     }
2148
2149   if (idx == len)
2150     {
2151       /* Extend the table.  */
2152       Lisp_Object new_table;
2153       int j;
2154
2155       new_table = Fmake_vector (make_int (len * 2), Qnil);
2156       for (j = 0; j < len; j++)
2157         XVECTOR_DATA (new_table)[j]
2158           = XVECTOR_DATA (Vccl_program_table)[j];
2159       Vccl_program_table = new_table;
2160     }
2161
2162   {
2163     Lisp_Object elt;
2164
2165     elt = Fmake_vector (make_int (3), Qnil);
2166     XVECTOR_DATA (elt)[0] = name;
2167     XVECTOR_DATA (elt)[1] = ccl_prog;
2168     XVECTOR_DATA (elt)[2] = resolved;
2169     XVECTOR_DATA (Vccl_program_table)[idx] = elt;
2170   }
2171
2172   Fput (name, Qccl_program_idx, make_int (idx));
2173   return make_int (idx);
2174 }
2175
2176 /* Register code conversion map.
2177    A code conversion map consists of numbers, Qt, Qnil, and Qlambda.
2178    The first element is start code point.
2179    The rest elements are mapped numbers.
2180    Symbol t means to map to an original number before mapping.
2181    Symbol nil means that the corresponding element is empty.
2182    Symbol lambda means to terminate mapping here.
2183 */
2184
2185 DEFUN ("register-code-conversion-map", Fregister_code_conversion_map,
2186        2, 2, 0, /*
2187 Register SYMBOL as code conversion map MAP.
2188 Return index number of the registered map.
2189 */
2190        (symbol, map))
2191 {
2192   int len = XVECTOR_LENGTH (Vcode_conversion_map_vector);
2193   int i;
2194   Lisp_Object idx;
2195
2196   CHECK_SYMBOL (symbol);
2197   CHECK_VECTOR (map);
2198
2199   for (i = 0; i < len; i++)
2200     {
2201       Lisp_Object slot = XVECTOR_DATA (Vcode_conversion_map_vector)[i];
2202
2203       if (!CONSP (slot))
2204         break;
2205
2206       if (EQ (symbol, XCAR (slot)))
2207         {
2208           idx = make_int (i);
2209           XCDR (slot) = map;
2210           Fput (symbol, Qcode_conversion_map, map);
2211           Fput (symbol, Qcode_conversion_map_id, idx);
2212           return idx;
2213         }
2214     }
2215
2216   if (i == len)
2217     {
2218       Lisp_Object new_vector = Fmake_vector (make_int (len * 2), Qnil);
2219       int j;
2220
2221       for (j = 0; j < len; j++)
2222         XVECTOR_DATA (new_vector)[j]
2223           = XVECTOR_DATA (Vcode_conversion_map_vector)[j];
2224       Vcode_conversion_map_vector = new_vector;
2225     }
2226
2227   idx = make_int (i);
2228   Fput (symbol, Qcode_conversion_map, map);
2229   Fput (symbol, Qcode_conversion_map_id, idx);
2230   XVECTOR_DATA (Vcode_conversion_map_vector)[i] = Fcons (symbol, map);
2231   return idx;
2232 }
2233
2234
2235 void
2236 syms_of_mule_ccl (void)
2237 {
2238   DEFSUBR (Fccl_program_p);
2239   DEFSUBR (Fccl_execute);
2240   DEFSUBR (Fccl_execute_on_string);
2241   DEFSUBR (Fregister_ccl_program);
2242   DEFSUBR (Fregister_code_conversion_map);
2243 }
2244
2245 void
2246 vars_of_mule_ccl (void)
2247 {
2248   staticpro (&Vccl_program_table);
2249   Vccl_program_table = Fmake_vector (make_int (32), Qnil);
2250
2251   defsymbol (&Qccl_program, "ccl-program");
2252   defsymbol (&Qccl_program_idx, "ccl-program-idx");
2253   defsymbol (&Qcode_conversion_map, "code-conversion-map");
2254   defsymbol (&Qcode_conversion_map_id, "code-conversion-map-id");
2255
2256   DEFVAR_LISP ("code-conversion-map-vector", &Vcode_conversion_map_vector /*
2257 Vector of code conversion maps.
2258 */ );
2259   Vcode_conversion_map_vector = Fmake_vector (make_int (16), Qnil);
2260
2261   DEFVAR_LISP ("font-ccl-encoder-alist", &Vfont_ccl_encoder_alist /*
2262 Alist of fontname patterns vs corresponding CCL program.
2263 Each element looks like (REGEXP . CCL-CODE),
2264  where CCL-CODE is a compiled CCL program.
2265 When a font whose name matches REGEXP is used for displaying a character,
2266  CCL-CODE is executed to calculate the code point in the font
2267  from the charset number and position code(s) of the character which are set
2268  in CCL registers R0, R1, and R2 before the execution.
2269 The code point in the font is set in CCL registers R1 and R2
2270  when the execution terminated.
2271 If the font is single-byte font, the register R2 is not used.
2272 */ );
2273   Vfont_ccl_encoder_alist = Qnil;
2274 }
2275
2276 #endif  /* emacs */