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