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