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