(iso-languages): For Portuguese ~c and
[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
dfcf069d 730int
4ed46869
KH
731ccl_driver (ccl, source, destination, src_bytes, dst_bytes, consumed)
732 struct ccl_program *ccl;
733 unsigned char *source, *destination;
734 int src_bytes, dst_bytes;
735 int *consumed;
736{
737 register int *reg = ccl->reg;
738 register int ic = ccl->ic;
739 register int code, field1, field2;
e995085f 740 register Lisp_Object *ccl_prog = ccl->prog;
4ed46869
KH
741 unsigned char *src = source, *src_end = src + src_bytes;
742 unsigned char *dst = destination, *dst_end = dst + dst_bytes;
743 int jump_address;
744 int i, j, op;
745 int stack_idx = 0;
746 /* For the moment, we only support depth 256 of stack. */
747 struct ccl_prog_stack ccl_prog_stack_struct[256];
519bf146
KH
748 /* Instruction counter of the current CCL code. */
749 int this_ic;
4ed46869
KH
750
751 if (ic >= ccl->eof_ic)
752 ic = CCL_HEADER_MAIN;
753
12abd7d1
KH
754 if (ccl->buf_magnification ==0) /* We can't produce any bytes. */
755 dst = NULL;
756
4ed46869
KH
757#ifdef CCL_DEBUG
758 ccl_backtrace_idx = 0;
759#endif
760
761 for (;;)
762 {
4ccd0d4a 763 ccl_repeat:
4ed46869
KH
764#ifdef CCL_DEBUG
765 ccl_backtrace_table[ccl_backtrace_idx++] = ic;
766 if (ccl_backtrace_idx >= CCL_DEBUG_BACKTRACE_LEN)
767 ccl_backtrace_idx = 0;
768 ccl_backtrace_table[ccl_backtrace_idx] = 0;
769#endif
770
771 if (!NILP (Vquit_flag) && NILP (Vinhibit_quit))
772 {
773 /* We can't just signal Qquit, instead break the loop as if
774 the whole data is processed. Don't reset Vquit_flag, it
775 must be handled later at a safer place. */
776 if (consumed)
777 src = source + src_bytes;
778 ccl->status = CCL_STAT_QUIT;
779 break;
780 }
781
519bf146 782 this_ic = ic;
4ed46869
KH
783 code = XINT (ccl_prog[ic]); ic++;
784 field1 = code >> 8;
785 field2 = (code & 0xFF) >> 5;
786
787#define rrr field2
788#define RRR (field1 & 7)
789#define Rrr ((field1 >> 3) & 7)
790#define ADDR field1
e34b1164 791#define EXCMD (field1 >> 6)
4ed46869
KH
792
793 switch (code & 0x1F)
794 {
795 case CCL_SetRegister: /* 00000000000000000RRRrrrXXXXX */
796 reg[rrr] = reg[RRR];
797 break;
798
799 case CCL_SetShortConst: /* CCCCCCCCCCCCCCCCCCCCrrrXXXXX */
800 reg[rrr] = field1;
801 break;
802
803 case CCL_SetConst: /* 00000000000000000000rrrXXXXX */
804 reg[rrr] = XINT (ccl_prog[ic]);
805 ic++;
806 break;
807
808 case CCL_SetArray: /* CCCCCCCCCCCCCCCCCCCCRRRrrrXXXXX */
809 i = reg[RRR];
810 j = field1 >> 3;
811 if ((unsigned int) i < j)
812 reg[rrr] = XINT (ccl_prog[ic + i]);
813 ic += j;
814 break;
815
816 case CCL_Jump: /* A--D--D--R--E--S--S-000XXXXX */
817 ic += ADDR;
818 break;
819
820 case CCL_JumpCond: /* A--D--D--R--E--S--S-rrrXXXXX */
821 if (!reg[rrr])
822 ic += ADDR;
823 break;
824
825 case CCL_WriteRegisterJump: /* A--D--D--R--E--S--S-rrrXXXXX */
826 i = reg[rrr];
827 CCL_WRITE_CHAR (i);
828 ic += ADDR;
829 break;
830
831 case CCL_WriteRegisterReadJump: /* A--D--D--R--E--S--S-rrrXXXXX */
832 i = reg[rrr];
833 CCL_WRITE_CHAR (i);
834 ic++;
835 CCL_READ_CHAR (reg[rrr]);
836 ic += ADDR - 1;
837 break;
838
839 case CCL_WriteConstJump: /* A--D--D--R--E--S--S-000XXXXX */
840 i = XINT (ccl_prog[ic]);
841 CCL_WRITE_CHAR (i);
842 ic += ADDR;
843 break;
844
845 case CCL_WriteConstReadJump: /* A--D--D--R--E--S--S-rrrXXXXX */
846 i = XINT (ccl_prog[ic]);
847 CCL_WRITE_CHAR (i);
848 ic++;
849 CCL_READ_CHAR (reg[rrr]);
850 ic += ADDR - 1;
851 break;
852
853 case CCL_WriteStringJump: /* A--D--D--R--E--S--S-000XXXXX */
854 j = XINT (ccl_prog[ic]);
855 ic++;
856 CCL_WRITE_STRING (j);
857 ic += ADDR - 1;
858 break;
859
860 case CCL_WriteArrayReadJump: /* A--D--D--R--E--S--S-rrrXXXXX */
861 i = reg[rrr];
2e34157c 862 j = XINT (ccl_prog[ic]);
4ed46869
KH
863 if ((unsigned int) i < j)
864 {
887bfbd7 865 i = XINT (ccl_prog[ic + 1 + i]);
4ed46869
KH
866 CCL_WRITE_CHAR (i);
867 }
887bfbd7 868 ic += j + 2;
4ed46869
KH
869 CCL_READ_CHAR (reg[rrr]);
870 ic += ADDR - (j + 2);
871 break;
872
873 case CCL_ReadJump: /* A--D--D--R--E--S--S-rrrYYYYY */
874 CCL_READ_CHAR (reg[rrr]);
875 ic += ADDR;
876 break;
877
878 case CCL_ReadBranch: /* CCCCCCCCCCCCCCCCCCCCrrrXXXXX */
879 CCL_READ_CHAR (reg[rrr]);
880 /* fall through ... */
881 case CCL_Branch: /* CCCCCCCCCCCCCCCCCCCCrrrXXXXX */
882 if ((unsigned int) reg[rrr] < field1)
883 ic += XINT (ccl_prog[ic + reg[rrr]]);
884 else
885 ic += XINT (ccl_prog[ic + field1]);
886 break;
887
888 case CCL_ReadRegister: /* CCCCCCCCCCCCCCCCCCCCrrXXXXX */
889 while (1)
890 {
891 CCL_READ_CHAR (reg[rrr]);
892 if (!field1) break;
893 code = XINT (ccl_prog[ic]); ic++;
894 field1 = code >> 8;
895 field2 = (code & 0xFF) >> 5;
896 }
897 break;
898
899 case CCL_WriteExprConst: /* 1:00000OPERATION000RRR000XXXXX */
900 rrr = 7;
901 i = reg[RRR];
902 j = XINT (ccl_prog[ic]);
903 op = field1 >> 6;
904 ic++;
905 goto ccl_set_expr;
906
907 case CCL_WriteRegister: /* CCCCCCCCCCCCCCCCCCCrrrXXXXX */
908 while (1)
909 {
910 i = reg[rrr];
911 CCL_WRITE_CHAR (i);
912 if (!field1) break;
913 code = XINT (ccl_prog[ic]); ic++;
914 field1 = code >> 8;
915 field2 = (code & 0xFF) >> 5;
916 }
917 break;
918
919 case CCL_WriteExprRegister: /* 1:00000OPERATIONRrrRRR000XXXXX */
920 rrr = 7;
921 i = reg[RRR];
922 j = reg[Rrr];
923 op = field1 >> 6;
924 goto ccl_set_expr;
925
926 case CCL_Call: /* CCCCCCCCCCCCCCCCCCCC000XXXXX */
927 {
928 Lisp_Object slot;
929
930 if (stack_idx >= 256
931 || field1 < 0
932 || field1 >= XVECTOR (Vccl_program_table)->size
933 || (slot = XVECTOR (Vccl_program_table)->contents[field1],
934 !CONSP (slot))
935 || !VECTORP (XCONS (slot)->cdr))
936 {
937 if (stack_idx > 0)
938 {
939 ccl_prog = ccl_prog_stack_struct[0].ccl_prog;
940 ic = ccl_prog_stack_struct[0].ic;
941 }
942 CCL_INVALID_CMD;
943 }
944
945 ccl_prog_stack_struct[stack_idx].ccl_prog = ccl_prog;
946 ccl_prog_stack_struct[stack_idx].ic = ic;
947 stack_idx++;
948 ccl_prog = XVECTOR (XCONS (slot)->cdr)->contents;
949 ic = CCL_HEADER_MAIN;
950 }
951 break;
952
953 case CCL_WriteConstString: /* CCCCCCCCCCCCCCCCCCCCrrrXXXXX */
954 if (!rrr)
955 CCL_WRITE_CHAR (field1);
956 else
957 {
958 CCL_WRITE_STRING (field1);
959 ic += (field1 + 2) / 3;
960 }
961 break;
962
963 case CCL_WriteArray: /* CCCCCCCCCCCCCCCCCCCCrrrXXXXX */
964 i = reg[rrr];
965 if ((unsigned int) i < field1)
966 {
967 j = XINT (ccl_prog[ic + i]);
968 CCL_WRITE_CHAR (j);
969 }
970 ic += field1;
971 break;
972
973 case CCL_End: /* 0000000000000000000000XXXXX */
974 if (stack_idx-- > 0)
975 {
976 ccl_prog = ccl_prog_stack_struct[stack_idx].ccl_prog;
977 ic = ccl_prog_stack_struct[stack_idx].ic;
978 break;
979 }
ad3d1b1d
KH
980 if (src)
981 src = src_end;
982 /* ccl->ic should points to this command code again to
983 suppress further processing. */
984 ic--;
4ed46869
KH
985 CCL_SUCCESS;
986
987 case CCL_ExprSelfConst: /* 00000OPERATION000000rrrXXXXX */
988 i = XINT (ccl_prog[ic]);
989 ic++;
990 op = field1 >> 6;
991 goto ccl_expr_self;
992
993 case CCL_ExprSelfReg: /* 00000OPERATION000RRRrrrXXXXX */
994 i = reg[RRR];
995 op = field1 >> 6;
996
997 ccl_expr_self:
998 switch (op)
999 {
1000 case CCL_PLUS: reg[rrr] += i; break;
1001 case CCL_MINUS: reg[rrr] -= i; break;
1002 case CCL_MUL: reg[rrr] *= i; break;
1003 case CCL_DIV: reg[rrr] /= i; break;
1004 case CCL_MOD: reg[rrr] %= i; break;
1005 case CCL_AND: reg[rrr] &= i; break;
1006 case CCL_OR: reg[rrr] |= i; break;
1007 case CCL_XOR: reg[rrr] ^= i; break;
1008 case CCL_LSH: reg[rrr] <<= i; break;
1009 case CCL_RSH: reg[rrr] >>= i; break;
1010 case CCL_LSH8: reg[rrr] <<= 8; reg[rrr] |= i; break;
1011 case CCL_RSH8: reg[7] = reg[rrr] & 0xFF; reg[rrr] >>= 8; break;
1012 case CCL_DIVMOD: reg[7] = reg[rrr] % i; reg[rrr] /= i; break;
1013 case CCL_LS: reg[rrr] = reg[rrr] < i; break;
1014 case CCL_GT: reg[rrr] = reg[rrr] > i; break;
1015 case CCL_EQ: reg[rrr] = reg[rrr] == i; break;
1016 case CCL_LE: reg[rrr] = reg[rrr] <= i; break;
1017 case CCL_GE: reg[rrr] = reg[rrr] >= i; break;
1018 case CCL_NE: reg[rrr] = reg[rrr] != i; break;
1019 default: CCL_INVALID_CMD;
1020 }
1021 break;
1022
1023 case CCL_SetExprConst: /* 00000OPERATION000RRRrrrXXXXX */
1024 i = reg[RRR];
1025 j = XINT (ccl_prog[ic]);
1026 op = field1 >> 6;
1027 jump_address = ++ic;
1028 goto ccl_set_expr;
1029
1030 case CCL_SetExprReg: /* 00000OPERATIONRrrRRRrrrXXXXX */
1031 i = reg[RRR];
1032 j = reg[Rrr];
1033 op = field1 >> 6;
1034 jump_address = ic;
1035 goto ccl_set_expr;
1036
1037 case CCL_ReadJumpCondExprConst: /* A--D--D--R--E--S--S-rrrXXXXX */
1038 CCL_READ_CHAR (reg[rrr]);
1039 case CCL_JumpCondExprConst: /* A--D--D--R--E--S--S-rrrXXXXX */
1040 i = reg[rrr];
1041 op = XINT (ccl_prog[ic]);
1042 jump_address = ic++ + ADDR;
1043 j = XINT (ccl_prog[ic]);
1044 ic++;
1045 rrr = 7;
1046 goto ccl_set_expr;
1047
1048 case CCL_ReadJumpCondExprReg: /* A--D--D--R--E--S--S-rrrXXXXX */
1049 CCL_READ_CHAR (reg[rrr]);
1050 case CCL_JumpCondExprReg:
1051 i = reg[rrr];
1052 op = XINT (ccl_prog[ic]);
1053 jump_address = ic++ + ADDR;
1054 j = reg[XINT (ccl_prog[ic])];
1055 ic++;
1056 rrr = 7;
1057
1058 ccl_set_expr:
1059 switch (op)
1060 {
1061 case CCL_PLUS: reg[rrr] = i + j; break;
1062 case CCL_MINUS: reg[rrr] = i - j; break;
1063 case CCL_MUL: reg[rrr] = i * j; break;
1064 case CCL_DIV: reg[rrr] = i / j; break;
1065 case CCL_MOD: reg[rrr] = i % j; break;
1066 case CCL_AND: reg[rrr] = i & j; break;
1067 case CCL_OR: reg[rrr] = i | j; break;
1068 case CCL_XOR: reg[rrr] = i ^ j;; break;
1069 case CCL_LSH: reg[rrr] = i << j; break;
1070 case CCL_RSH: reg[rrr] = i >> j; break;
1071 case CCL_LSH8: reg[rrr] = (i << 8) | j; break;
1072 case CCL_RSH8: reg[rrr] = i >> 8; reg[7] = i & 0xFF; break;
1073 case CCL_DIVMOD: reg[rrr] = i / j; reg[7] = i % j; break;
1074 case CCL_LS: reg[rrr] = i < j; break;
1075 case CCL_GT: reg[rrr] = i > j; break;
1076 case CCL_EQ: reg[rrr] = i == j; break;
1077 case CCL_LE: reg[rrr] = i <= j; break;
1078 case CCL_GE: reg[rrr] = i >= j; break;
1079 case CCL_NE: reg[rrr] = i != j; break;
4ed46869 1080 case CCL_DECODE_SJIS: DECODE_SJIS (i, j, reg[rrr], reg[7]); break;
51520e8a 1081 case CCL_ENCODE_SJIS: ENCODE_SJIS (i, j, reg[rrr], reg[7]); break;
4ed46869
KH
1082 default: CCL_INVALID_CMD;
1083 }
1084 code &= 0x1F;
1085 if (code == CCL_WriteExprConst || code == CCL_WriteExprRegister)
1086 {
1087 i = reg[rrr];
1088 CCL_WRITE_CHAR (i);
1089 }
1090 else if (!reg[rrr])
1091 ic = jump_address;
1092 break;
1093
e34b1164
KH
1094 case CCL_Extention:
1095 switch (EXCMD)
1096 {
6ae21908 1097 case CCL_ReadMultibyteChar2:
e34b1164
KH
1098 if (!src)
1099 CCL_INVALID_CMD;
1100 do {
1101 if (src >= src_end)
6ae21908
KH
1102 {
1103 src++;
1104 goto ccl_read_multibyte_character_suspend;
1105 }
e34b1164
KH
1106
1107 i = *src++;
1108 if (i == LEADING_CODE_COMPOSITION)
1109 {
1110 if (src >= src_end)
1111 goto ccl_read_multibyte_character_suspend;
1112 if (*src == 0xFF)
1113 {
1114 ccl->private_state = COMPOSING_WITH_RULE_HEAD;
1115 src++;
1116 }
1117 else
1118 ccl->private_state = COMPOSING_NO_RULE_HEAD;
1119 }
1120 if (ccl->private_state != 0)
1121 {
1122 /* composite character */
1123 if (*src < 0xA0)
1124 ccl->private_state = 0;
1125 else
1126 {
1127 if (i == 0xA0)
1128 {
1129 if (src >= src_end)
1130 goto ccl_read_multibyte_character_suspend;
1131 i = *src++ & 0x7F;
1132 }
1133 else
1134 i -= 0x20;
1135
1136 if (COMPOSING_WITH_RULE_RULE == ccl->private_state)
1137 {
1138 ccl->private_state = COMPOSING_WITH_RULE_HEAD;
1139 continue;
1140 }
1141 else if (COMPOSING_WITH_RULE_HEAD == ccl->private_state)
1142 ccl->private_state = COMPOSING_WITH_RULE_RULE;
1143 }
1144 }
1145 if (i < 0x80)
1146 {
1147 /* ASCII */
1148 reg[rrr] = i;
1149 reg[RRR] = CHARSET_ASCII;
1150 }
1151 else if (i <= MAX_CHARSET_OFFICIAL_DIMENSION1)
1152 {
1153 if (src >= src_end)
1154 goto ccl_read_multibyte_character_suspend;
1155 reg[RRR] = i;
1156 reg[rrr] = (*src++ & 0x7F);
1157 }
1158 else if (i <= MAX_CHARSET_OFFICIAL_DIMENSION2)
1159 {
1160 if ((src + 1) >= src_end)
1161 goto ccl_read_multibyte_character_suspend;
1162 reg[RRR] = i;
1163 i = (*src++ & 0x7F);
1164 reg[rrr] = ((i << 7) | (*src & 0x7F));
1165 src++;
1166 }
6ae21908
KH
1167 else if ((i == LEADING_CODE_PRIVATE_11)
1168 || (i == LEADING_CODE_PRIVATE_12))
e34b1164
KH
1169 {
1170 if ((src + 1) >= src_end)
1171 goto ccl_read_multibyte_character_suspend;
1172 reg[RRR] = *src++;
1173 reg[rrr] = (*src++ & 0x7F);
1174 }
6ae21908
KH
1175 else if ((i == LEADING_CODE_PRIVATE_21)
1176 || (i == LEADING_CODE_PRIVATE_22))
e34b1164
KH
1177 {
1178 if ((src + 2) >= src_end)
1179 goto ccl_read_multibyte_character_suspend;
1180 reg[RRR] = *src++;
1181 i = (*src++ & 0x7F);
1182 reg[rrr] = ((i << 7) | (*src & 0x7F));
1183 src++;
1184 }
1185 else
1186 {
ad3d1b1d
KH
1187 /* INVALID CODE. Return a single byte character. */
1188 reg[RRR] = CHARSET_ASCII;
1189 reg[rrr] = i;
e34b1164
KH
1190 }
1191 } while (0);
1192 break;
1193
1194 ccl_read_multibyte_character_suspend:
1195 src--;
1196 if (ccl->last_block)
1197 {
1198 ic = ccl->eof_ic;
0db078dc 1199 goto ccl_repeat;
e34b1164
KH
1200 }
1201 else
1202 CCL_SUSPEND (CCL_STAT_SUSPEND_BY_SRC);
1203
1204 break;
1205
6ae21908 1206 case CCL_WriteMultibyteChar2:
e34b1164
KH
1207 i = reg[RRR]; /* charset */
1208 if (i == CHARSET_ASCII)
1209 i = reg[rrr] & 0x7F;
1210 else if (i == CHARSET_COMPOSITION)
1211 i = MAKE_COMPOSITE_CHAR (reg[rrr]);
1212 else if (CHARSET_DIMENSION (i) == 1)
1213 i = ((i - 0x70) << 7) | (reg[rrr] & 0x7F);
1214 else if (i < MIN_CHARSET_PRIVATE_DIMENSION2)
1215 i = ((i - 0x8F) << 14) | reg[rrr];
1216 else
1217 i = ((i - 0xE0) << 14) | reg[rrr];
1218
1219 CCL_WRITE_CHAR (i);
1220
1221 break;
1222
8146262a 1223 case CCL_TranslateCharacter:
e34b1164
KH
1224 i = reg[RRR]; /* charset */
1225 if (i == CHARSET_ASCII)
9b0ca869 1226 i = reg[rrr];
e34b1164
KH
1227 else if (i == CHARSET_COMPOSITION)
1228 {
1229 reg[RRR] = -1;
1230 break;
1231 }
1232 else if (CHARSET_DIMENSION (i) == 1)
1233 i = ((i - 0x70) << 7) | (reg[rrr] & 0x7F);
1234 else if (i < MIN_CHARSET_PRIVATE_DIMENSION2)
1235 i = ((i - 0x8F) << 14) | (reg[rrr] & 0x3FFF);
1236 else
1237 i = ((i - 0xE0) << 14) | (reg[rrr] & 0x3FFF);
1238
8146262a
KH
1239 op = translate_char (GET_TRANSLATION_TABLE (reg[Rrr]),
1240 i, -1, 0, 0);
e34b1164
KH
1241 SPLIT_CHAR (op, reg[RRR], i, j);
1242 if (j != -1)
1243 i = (i << 7) | j;
1244
1245 reg[rrr] = i;
1246 break;
1247
8146262a 1248 case CCL_TranslateCharacterConstTbl:
e34b1164
KH
1249 op = XINT (ccl_prog[ic]); /* table */
1250 ic++;
1251 i = reg[RRR]; /* charset */
1252 if (i == CHARSET_ASCII)
9b0ca869 1253 i = reg[rrr];
e34b1164
KH
1254 else if (i == CHARSET_COMPOSITION)
1255 {
1256 reg[RRR] = -1;
1257 break;
1258 }
1259 else if (CHARSET_DIMENSION (i) == 1)
1260 i = ((i - 0x70) << 7) | (reg[rrr] & 0x7F);
1261 else if (i < MIN_CHARSET_PRIVATE_DIMENSION2)
1262 i = ((i - 0x8F) << 14) | (reg[rrr] & 0x3FFF);
1263 else
1264 i = ((i - 0xE0) << 14) | (reg[rrr] & 0x3FFF);
1265
8146262a 1266 op = translate_char (GET_TRANSLATION_TABLE (op), i, -1, 0, 0);
e34b1164
KH
1267 SPLIT_CHAR (op, reg[RRR], i, j);
1268 if (j != -1)
1269 i = (i << 7) | j;
1270
1271 reg[rrr] = i;
1272 break;
1273
1274 case CCL_IterateMultipleMap:
1275 {
8146262a 1276 Lisp_Object map, content, attrib, value;
e34b1164
KH
1277 int point, size, fin_ic;
1278
8146262a 1279 j = XINT (ccl_prog[ic++]); /* number of maps. */
e34b1164
KH
1280 fin_ic = ic + j;
1281 op = reg[rrr];
1282 if ((j > reg[RRR]) && (j >= 0))
1283 {
1284 ic += reg[RRR];
1285 i = reg[RRR];
1286 }
1287 else
1288 {
1289 reg[RRR] = -1;
1290 ic = fin_ic;
1291 break;
1292 }
1293
1294 for (;i < j;i++)
1295 {
1296
8146262a 1297 size = XVECTOR (Vcode_conversion_map_vector)->size;
d387866a 1298 point = XINT (ccl_prog[ic++]);
e34b1164 1299 if (point >= size) continue;
8146262a
KH
1300 map =
1301 XVECTOR (Vcode_conversion_map_vector)->contents[point];
1302
1303 /* Check map varidity. */
1304 if (!CONSP (map)) continue;
1305 map = XCONS(map)->cdr;
1306 if (!VECTORP (map)) continue;
1307 size = XVECTOR (map)->size;
e34b1164 1308 if (size <= 1) continue;
6ae21908 1309
8146262a 1310 content = XVECTOR (map)->contents[0];
6ae21908 1311
8146262a 1312 /* check map type,
6ae21908
KH
1313 [STARTPOINT VAL1 VAL2 ...] or
1314 [t ELELMENT STARTPOINT ENDPOINT] */
1315 if (NUMBERP (content))
1316 {
1317 point = XUINT (content);
1318 point = op - point + 1;
1319 if (!((point >= 1) && (point < size))) continue;
8146262a 1320 content = XVECTOR (map)->contents[point];
6ae21908
KH
1321 }
1322 else if (EQ (content, Qt))
1323 {
1324 if (size != 4) continue;
8146262a
KH
1325 if ((op >= XUINT (XVECTOR (map)->contents[2]))
1326 && (op < XUINT (XVECTOR (map)->contents[3])))
1327 content = XVECTOR (map)->contents[1];
6ae21908
KH
1328 else
1329 continue;
1330 }
1331 else
1332 continue;
e34b1164
KH
1333
1334 if (NILP (content))
1335 continue;
1336 else if (NUMBERP (content))
1337 {
1338 reg[RRR] = i;
6ae21908 1339 reg[rrr] = XINT(content);
e34b1164
KH
1340 break;
1341 }
1342 else if (EQ (content, Qt) || EQ (content, Qlambda))
1343 {
1344 reg[RRR] = i;
1345 break;
1346 }
1347 else if (CONSP (content))
1348 {
1349 attrib = XCONS (content)->car;
1350 value = XCONS (content)->cdr;
1351 if (!NUMBERP (attrib) || !NUMBERP (value))
1352 continue;
1353 reg[RRR] = i;
6ae21908 1354 reg[rrr] = XUINT (value);
e34b1164
KH
1355 break;
1356 }
1357 }
1358 if (i == j)
1359 reg[RRR] = -1;
1360 ic = fin_ic;
1361 }
1362 break;
1363
8146262a 1364 case CCL_MapMultiple:
e34b1164 1365 {
8146262a
KH
1366 Lisp_Object map, content, attrib, value;
1367 int point, size, map_vector_size;
1368 int map_set_rest_length, fin_ic;
1369
1370 map_set_rest_length =
1371 XINT (ccl_prog[ic++]); /* number of maps and separators. */
1372 fin_ic = ic + map_set_rest_length;
1373 if ((map_set_rest_length > reg[RRR]) && (reg[RRR] >= 0))
e34b1164
KH
1374 {
1375 ic += reg[RRR];
1376 i = reg[RRR];
8146262a 1377 map_set_rest_length -= i;
e34b1164
KH
1378 }
1379 else
1380 {
1381 ic = fin_ic;
1382 reg[RRR] = -1;
1383 break;
1384 }
8146262a 1385 mapping_stack_pointer = mapping_stack;
e34b1164 1386 op = reg[rrr];
8146262a 1387 PUSH_MAPPING_STACK (0, op);
e34b1164 1388 reg[RRR] = -1;
8146262a
KH
1389 map_vector_size = XVECTOR (Vcode_conversion_map_vector)->size;
1390 for (;map_set_rest_length > 0;i++, map_set_rest_length--)
e34b1164 1391 {
6ae21908
KH
1392 point = XINT(ccl_prog[ic++]);
1393 if (point < 0)
e34b1164 1394 {
6ae21908 1395 point = -point;
8146262a
KH
1396 if (mapping_stack_pointer
1397 >= &mapping_stack[MAX_MAP_SET_LEVEL])
6ae21908
KH
1398 {
1399 CCL_INVALID_CMD;
1400 }
8146262a
KH
1401 PUSH_MAPPING_STACK (map_set_rest_length - point,
1402 reg[rrr]);
1403 map_set_rest_length = point + 1;
6ae21908 1404 reg[rrr] = op;
e34b1164
KH
1405 continue;
1406 }
6ae21908 1407
8146262a
KH
1408 if (point >= map_vector_size) continue;
1409 map = (XVECTOR (Vcode_conversion_map_vector)
1410 ->contents[point]);
6ae21908 1411
8146262a
KH
1412 /* Check map varidity. */
1413 if (!CONSP (map)) continue;
1414 map = XCONS (map)->cdr;
1415 if (!VECTORP (map)) continue;
1416 size = XVECTOR (map)->size;
e34b1164 1417 if (size <= 1) continue;
6ae21908 1418
8146262a 1419 content = XVECTOR (map)->contents[0];
6ae21908 1420
8146262a 1421 /* check map type,
6ae21908
KH
1422 [STARTPOINT VAL1 VAL2 ...] or
1423 [t ELEMENT STARTPOINT ENDPOINT] */
1424 if (NUMBERP (content))
1425 {
1426 point = XUINT (content);
1427 point = op - point + 1;
1428 if (!((point >= 1) && (point < size))) continue;
8146262a 1429 content = XVECTOR (map)->contents[point];
6ae21908
KH
1430 }
1431 else if (EQ (content, Qt))
1432 {
1433 if (size != 4) continue;
8146262a
KH
1434 if ((op >= XUINT (XVECTOR (map)->contents[2])) &&
1435 (op < XUINT (XVECTOR (map)->contents[3])))
1436 content = XVECTOR (map)->contents[1];
6ae21908
KH
1437 else
1438 continue;
1439 }
1440 else
1441 continue;
e34b1164
KH
1442
1443 if (NILP (content))
1444 continue;
1445 else if (NUMBERP (content))
1446 {
6ae21908 1447 op = XINT (content);
e34b1164 1448 reg[RRR] = i;
8146262a
KH
1449 i += map_set_rest_length;
1450 POP_MAPPING_STACK (map_set_rest_length, reg[rrr]);
e34b1164
KH
1451 }
1452 else if (CONSP (content))
1453 {
1454 attrib = XCONS (content)->car;
1455 value = XCONS (content)->cdr;
1456 if (!NUMBERP (attrib) || !NUMBERP (value))
1457 continue;
1458 reg[RRR] = i;
1459 op = XUINT (value);
8146262a
KH
1460 i += map_set_rest_length;
1461 POP_MAPPING_STACK (map_set_rest_length, reg[rrr]);
e34b1164
KH
1462 }
1463 else if (EQ (content, Qt))
1464 {
1465 reg[RRR] = i;
1466 op = reg[rrr];
8146262a
KH
1467 i += map_set_rest_length;
1468 POP_MAPPING_STACK (map_set_rest_length, reg[rrr]);
e34b1164
KH
1469 }
1470 else if (EQ (content, Qlambda))
6ae21908
KH
1471 {
1472 break;
1473 }
1474 else
1475 CCL_INVALID_CMD;
e34b1164
KH
1476 }
1477 ic = fin_ic;
1478 }
1479 reg[rrr] = op;
1480 break;
1481
8146262a 1482 case CCL_MapSingle:
e34b1164 1483 {
8146262a 1484 Lisp_Object map, attrib, value, content;
e34b1164 1485 int size, point;
8146262a 1486 j = XINT (ccl_prog[ic++]); /* map_id */
e34b1164 1487 op = reg[rrr];
8146262a 1488 if (j >= XVECTOR (Vcode_conversion_map_vector)->size)
e34b1164
KH
1489 {
1490 reg[RRR] = -1;
1491 break;
1492 }
8146262a
KH
1493 map = XVECTOR (Vcode_conversion_map_vector)->contents[j];
1494 if (!CONSP (map))
e34b1164
KH
1495 {
1496 reg[RRR] = -1;
1497 break;
1498 }
8146262a
KH
1499 map = XCONS(map)->cdr;
1500 if (!VECTORP (map))
e34b1164
KH
1501 {
1502 reg[RRR] = -1;
1503 break;
1504 }
8146262a
KH
1505 size = XVECTOR (map)->size;
1506 point = XUINT (XVECTOR (map)->contents[0]);
e34b1164
KH
1507 point = op - point + 1;
1508 reg[RRR] = 0;
1509 if ((size <= 1) ||
1510 (!((point >= 1) && (point < size))))
1511 reg[RRR] = -1;
1512 else
1513 {
8146262a 1514 content = XVECTOR (map)->contents[point];
e34b1164
KH
1515 if (NILP (content))
1516 reg[RRR] = -1;
1517 else if (NUMBERP (content))
6ae21908 1518 reg[rrr] = XINT (content);
e34b1164
KH
1519 else if (EQ (content, Qt))
1520 reg[RRR] = i;
1521 else if (CONSP (content))
1522 {
1523 attrib = XCONS (content)->car;
1524 value = XCONS (content)->cdr;
1525 if (!NUMBERP (attrib) || !NUMBERP (value))
1526 continue;
1527 reg[rrr] = XUINT(value);
1528 break;
1529 }
1530 else
1531 reg[RRR] = -1;
1532 }
1533 }
1534 break;
1535
1536 default:
1537 CCL_INVALID_CMD;
1538 }
1539 break;
1540
4ed46869
KH
1541 default:
1542 CCL_INVALID_CMD;
1543 }
1544 }
1545
1546 ccl_error_handler:
1547 if (destination)
1548 {
1549 /* We can insert an error message only if DESTINATION is
1550 specified and we still have a room to store the message
1551 there. */
1552 char msg[256];
1553 int msglen;
1554
12abd7d1
KH
1555 if (!dst)
1556 dst = destination;
1557
4ed46869
KH
1558 switch (ccl->status)
1559 {
1560 case CCL_STAT_INVALID_CMD:
1561 sprintf(msg, "\nCCL: Invalid command %x (ccl_code = %x) at %d.",
519bf146 1562 code & 0x1F, code, this_ic);
4ed46869
KH
1563#ifdef CCL_DEBUG
1564 {
1565 int i = ccl_backtrace_idx - 1;
1566 int j;
1567
1568 msglen = strlen (msg);
12abd7d1 1569 if (dst + msglen <= (dst_bytes ? dst_end : src))
4ed46869
KH
1570 {
1571 bcopy (msg, dst, msglen);
1572 dst += msglen;
1573 }
1574
1575 for (j = 0; j < CCL_DEBUG_BACKTRACE_LEN; j++, i--)
1576 {
1577 if (i < 0) i = CCL_DEBUG_BACKTRACE_LEN - 1;
1578 if (ccl_backtrace_table[i] == 0)
1579 break;
1580 sprintf(msg, " %d", ccl_backtrace_table[i]);
1581 msglen = strlen (msg);
12abd7d1 1582 if (dst + msglen > (dst_bytes ? dst_end : src))
4ed46869
KH
1583 break;
1584 bcopy (msg, dst, msglen);
1585 dst += msglen;
1586 }
12abd7d1 1587 goto ccl_finish;
4ed46869 1588 }
4ed46869 1589#endif
12abd7d1 1590 break;
4ed46869
KH
1591
1592 case CCL_STAT_QUIT:
1593 sprintf(msg, "\nCCL: Quited.");
1594 break;
1595
1596 default:
1597 sprintf(msg, "\nCCL: Unknown error type (%d).", ccl->status);
1598 }
1599
1600 msglen = strlen (msg);
12abd7d1 1601 if (dst + msglen <= (dst_bytes ? dst_end : src))
4ed46869
KH
1602 {
1603 bcopy (msg, dst, msglen);
1604 dst += msglen;
1605 }
1606 }
1607
1608 ccl_finish:
1609 ccl->ic = ic;
1610 if (consumed) *consumed = src - source;
12abd7d1 1611 return (dst ? dst - destination : 0);
4ed46869
KH
1612}
1613
1614/* Setup fields of the structure pointed by CCL appropriately for the
ad3d1b1d
KH
1615 execution of compiled CCL code in VEC (vector of integer).
1616 If VEC is nil, we skip setting ups based on VEC. */
07478155 1617void
4ed46869
KH
1618setup_ccl_program (ccl, vec)
1619 struct ccl_program *ccl;
1620 Lisp_Object vec;
1621{
1622 int i;
1623
ad3d1b1d
KH
1624 if (VECTORP (vec))
1625 {
1626 struct Lisp_Vector *vp = XVECTOR (vec);
1627
1628 ccl->size = vp->size;
1629 ccl->prog = vp->contents;
1630 ccl->eof_ic = XINT (vp->contents[CCL_HEADER_EOF]);
1631 ccl->buf_magnification = XINT (vp->contents[CCL_HEADER_BUF_MAG]);
1632 }
4ed46869 1633 ccl->ic = CCL_HEADER_MAIN;
4ed46869
KH
1634 for (i = 0; i < 8; i++)
1635 ccl->reg[i] = 0;
1636 ccl->last_block = 0;
e34b1164 1637 ccl->private_state = 0;
4ed46869
KH
1638 ccl->status = 0;
1639}
1640
6ae21908 1641/* Resolve symbols in the specified CCL code (Lisp vector). This
8146262a
KH
1642 function converts symbols of code conversion maps and character
1643 translation tables embeded in the CCL code into their ID numbers. */
6ae21908
KH
1644
1645Lisp_Object
1646resolve_symbol_ccl_program (ccl)
1647 Lisp_Object ccl;
1648{
1649 int i, veclen;
1650 Lisp_Object result, contents, prop;
1651
1652 result = ccl;
1653 veclen = XVECTOR (result)->size;
1654
1655 /* Set CCL program's table ID */
1656 for (i = 0; i < veclen; i++)
1657 {
1658 contents = XVECTOR (result)->contents[i];
1659 if (SYMBOLP (contents))
1660 {
1661 if (EQ(result, ccl))
1662 result = Fcopy_sequence (ccl);
1663
f967223b 1664 prop = Fget (contents, Qtranslation_table_id);
6ae21908
KH
1665 if (NUMBERP (prop))
1666 {
1667 XVECTOR (result)->contents[i] = prop;
1668 continue;
1669 }
8146262a 1670 prop = Fget (contents, Qcode_conversion_map_id);
6ae21908
KH
1671 if (NUMBERP (prop))
1672 {
1673 XVECTOR (result)->contents[i] = prop;
1674 continue;
1675 }
1676 prop = Fget (contents, Qccl_program_idx);
1677 if (NUMBERP (prop))
1678 {
1679 XVECTOR (result)->contents[i] = prop;
1680 continue;
1681 }
1682 }
1683 }
1684
1685 return result;
1686}
1687
1688
4ed46869
KH
1689#ifdef emacs
1690
1691DEFUN ("ccl-execute", Fccl_execute, Sccl_execute, 2, 2, 0,
1692 "Execute CCL-PROGRAM with registers initialized by REGISTERS.\n\
6ae21908
KH
1693\n\
1694CCL-PROGRAM is a symbol registered by register-ccl-program,\n\
1695or a compiled code generated by `ccl-compile' (for backward compatibility,\n\
1696in this case, the execution is slower).\n\
1697No I/O commands should appear in CCL-PROGRAM.\n\
1698\n\
4ed46869
KH
1699REGISTERS is a vector of [R0 R1 ... R7] where RN is an initial value\n\
1700 of Nth register.\n\
6ae21908
KH
1701\n\
1702As side effect, each element of REGISTERS holds the value of\n\
4ed46869
KH
1703 corresponding register after the execution.")
1704 (ccl_prog, reg)
1705 Lisp_Object ccl_prog, reg;
1706{
1707 struct ccl_program ccl;
1708 int i;
6ae21908 1709 Lisp_Object ccl_id;
4ed46869 1710
6ae21908
KH
1711 if ((SYMBOLP (ccl_prog)) &&
1712 (!NILP (ccl_id = Fget (ccl_prog, Qccl_program_idx))))
1713 {
1714 ccl_prog = XVECTOR (Vccl_program_table)->contents[XUINT (ccl_id)];
1715 CHECK_LIST (ccl_prog, 0);
1716 ccl_prog = XCONS (ccl_prog)->cdr;
1717 CHECK_VECTOR (ccl_prog, 1);
1718 }
1719 else
1720 {
1721 CHECK_VECTOR (ccl_prog, 1);
1722 ccl_prog = resolve_symbol_ccl_program (ccl_prog);
1723 }
1724
1725 CHECK_VECTOR (reg, 2);
4ed46869
KH
1726 if (XVECTOR (reg)->size != 8)
1727 error ("Invalid length of vector REGISTERS");
1728
1729 setup_ccl_program (&ccl, ccl_prog);
1730 for (i = 0; i < 8; i++)
1731 ccl.reg[i] = (INTEGERP (XVECTOR (reg)->contents[i])
1732 ? XINT (XVECTOR (reg)->contents[i])
1733 : 0);
1734
1735 ccl_driver (&ccl, (char *)0, (char *)0, 0, 0, (int *)0);
1736 QUIT;
1737 if (ccl.status != CCL_STAT_SUCCESS)
1738 error ("Error in CCL program at %dth code", ccl.ic);
1739
1740 for (i = 0; i < 8; i++)
1741 XSETINT (XVECTOR (reg)->contents[i], ccl.reg[i]);
1742 return Qnil;
1743}
1744
1745DEFUN ("ccl-execute-on-string", Fccl_execute_on_string, Sccl_execute_on_string,
39a68837 1746 3, 5, 0,
4ed46869 1747 "Execute CCL-PROGRAM with initial STATUS on STRING.\n\
6ae21908
KH
1748\n\
1749CCL-PROGRAM is a symbol registered by register-ccl-program,\n\
1750or a compiled code generated by `ccl-compile' (for backward compatibility,\n\
1751in this case, the execution is slower).\n\
1752\n\
4ed46869 1753Read buffer is set to STRING, and write buffer is allocated automatically.\n\
6ae21908 1754\n\
4ed46869
KH
1755STATUS is a vector of [R0 R1 ... R7 IC], where\n\
1756 R0..R7 are initial values of corresponding registers,\n\
1757 IC is the instruction counter specifying from where to start the program.\n\
1758If R0..R7 are nil, they are initialized to 0.\n\
1759If IC is nil, it is initialized to head of the CCL program.\n\
39a68837 1760\n\
6ae21908 1761If optional 4th arg CONTINUE is non-nil, keep IC on read operation\n\
cb5373dd 1762when read buffer is exausted, else, IC is always set to the end of\n\
db6089c5 1763CCL-PROGRAM on exit.\n\
39a68837
KH
1764\n\
1765It returns the contents of write buffer as a string,\n\
6ae21908 1766 and as side effect, STATUS is updated.\n\
39a68837
KH
1767If the optional 5th arg UNIBYTE-P is non-nil, the returned string\n\
1768is a unibyte string. By default it is a multibyte string.")
1769 (ccl_prog, status, str, contin, unibyte_p)
1770 Lisp_Object ccl_prog, status, str, contin, unibyte_p;
4ed46869
KH
1771{
1772 Lisp_Object val;
1773 struct ccl_program ccl;
1774 int i, produced;
1775 int outbufsize;
1776 char *outbuf;
1777 struct gcpro gcpro1, gcpro2, gcpro3;
6ae21908
KH
1778 Lisp_Object ccl_id;
1779
1780 if ((SYMBOLP (ccl_prog)) &&
1781 (!NILP (ccl_id = Fget (ccl_prog, Qccl_program_idx))))
1782 {
1783 ccl_prog = XVECTOR (Vccl_program_table)->contents[XUINT (ccl_id)];
1784 CHECK_LIST (ccl_prog, 0);
1785 ccl_prog = XCONS (ccl_prog)->cdr;
1786 CHECK_VECTOR (ccl_prog, 1);
1787 }
1788 else
1789 {
1790 CHECK_VECTOR (ccl_prog, 1);
1791 ccl_prog = resolve_symbol_ccl_program (ccl_prog);
1792 }
4ed46869 1793
4ed46869
KH
1794 CHECK_VECTOR (status, 1);
1795 if (XVECTOR (status)->size != 9)
1796 error ("Invalid length of vector STATUS");
1797 CHECK_STRING (str, 2);
1798 GCPRO3 (ccl_prog, status, str);
1799
1800 setup_ccl_program (&ccl, ccl_prog);
1801 for (i = 0; i < 8; i++)
1802 {
1803 if (NILP (XVECTOR (status)->contents[i]))
1804 XSETINT (XVECTOR (status)->contents[i], 0);
1805 if (INTEGERP (XVECTOR (status)->contents[i]))
1806 ccl.reg[i] = XINT (XVECTOR (status)->contents[i]);
1807 }
1808 if (INTEGERP (XVECTOR (status)->contents[i]))
1809 {
1810 i = XFASTINT (XVECTOR (status)->contents[8]);
1811 if (ccl.ic < i && i < ccl.size)
1812 ccl.ic = i;
1813 }
fc932ac6 1814 outbufsize = STRING_BYTES (XSTRING (str)) * ccl.buf_magnification + 256;
4ed46869
KH
1815 outbuf = (char *) xmalloc (outbufsize);
1816 if (!outbuf)
1817 error ("Not enough memory");
cb5373dd 1818 ccl.last_block = NILP (contin);
4ed46869 1819 produced = ccl_driver (&ccl, XSTRING (str)->data, outbuf,
fc932ac6 1820 STRING_BYTES (XSTRING (str)), outbufsize, (int *)0);
4ed46869
KH
1821 for (i = 0; i < 8; i++)
1822 XSET (XVECTOR (status)->contents[i], Lisp_Int, ccl.reg[i]);
1823 XSETINT (XVECTOR (status)->contents[8], ccl.ic);
1824 UNGCPRO;
1825
39a68837
KH
1826 if (NILP (unibyte_p))
1827 val = make_string (outbuf, produced);
1828 else
1829 val = make_unibyte_string (outbuf, produced);
4ed46869
KH
1830 free (outbuf);
1831 QUIT;
1832 if (ccl.status != CCL_STAT_SUCCESS
e34b1164
KH
1833 && ccl.status != CCL_STAT_SUSPEND_BY_SRC
1834 && ccl.status != CCL_STAT_SUSPEND_BY_DST)
4ed46869
KH
1835 error ("Error in CCL program at %dth code", ccl.ic);
1836
1837 return val;
1838}
1839
1840DEFUN ("register-ccl-program", Fregister_ccl_program, Sregister_ccl_program,
1841 2, 2, 0,
7bce92a6
KH
1842 "Register CCL program PROGRAM of NAME in `ccl-program-table'.\n\
1843PROGRAM should be a compiled code of CCL program, or nil.\n\
4ed46869
KH
1844Return index number of the registered CCL program.")
1845 (name, ccl_prog)
1846 Lisp_Object name, ccl_prog;
1847{
1848 int len = XVECTOR (Vccl_program_table)->size;
e34b1164 1849 int i;
4ed46869
KH
1850
1851 CHECK_SYMBOL (name, 0);
1852 if (!NILP (ccl_prog))
6ae21908
KH
1853 {
1854 CHECK_VECTOR (ccl_prog, 1);
1855 ccl_prog = resolve_symbol_ccl_program (ccl_prog);
1856 }
4ed46869
KH
1857
1858 for (i = 0; i < len; i++)
1859 {
1860 Lisp_Object slot = XVECTOR (Vccl_program_table)->contents[i];
1861
1862 if (!CONSP (slot))
1863 break;
1864
1865 if (EQ (name, XCONS (slot)->car))
1866 {
1867 XCONS (slot)->cdr = ccl_prog;
1868 return make_number (i);
1869 }
1870 }
1871
1872 if (i == len)
1873 {
6703ac4f 1874 Lisp_Object new_table = Fmake_vector (make_number (len * 2), Qnil);
4ed46869
KH
1875 int j;
1876
1877 for (j = 0; j < len; j++)
1878 XVECTOR (new_table)->contents[j]
1879 = XVECTOR (Vccl_program_table)->contents[j];
1880 Vccl_program_table = new_table;
1881 }
1882
1883 XVECTOR (Vccl_program_table)->contents[i] = Fcons (name, ccl_prog);
b23c2440 1884 Fput (name, Qccl_program_idx, make_number (i));
4ed46869
KH
1885 return make_number (i);
1886}
1887
8146262a
KH
1888/* Register code conversion map.
1889 A code conversion map consists of numbers, Qt, Qnil, and Qlambda.
e34b1164 1890 The first element is start code point.
8146262a
KH
1891 The rest elements are mapped numbers.
1892 Symbol t means to map to an original number before mapping.
1893 Symbol nil means that the corresponding element is empty.
1894 Symbol lambda menas to terminate mapping here.
e34b1164
KH
1895*/
1896
8146262a
KH
1897DEFUN ("register-code-conversion-map", Fregister_code_conversion_map,
1898 Sregister_code_conversion_map,
e34b1164 1899 2, 2, 0,
8146262a
KH
1900 "Register SYMBOL as code conversion map MAP.\n\
1901Return index number of the registered map.")
1902 (symbol, map)
1903 Lisp_Object symbol, map;
e34b1164 1904{
8146262a 1905 int len = XVECTOR (Vcode_conversion_map_vector)->size;
e34b1164
KH
1906 int i;
1907 Lisp_Object index;
1908
1909 CHECK_SYMBOL (symbol, 0);
8146262a 1910 CHECK_VECTOR (map, 1);
e34b1164
KH
1911
1912 for (i = 0; i < len; i++)
1913 {
8146262a 1914 Lisp_Object slot = XVECTOR (Vcode_conversion_map_vector)->contents[i];
e34b1164
KH
1915
1916 if (!CONSP (slot))
1917 break;
1918
1919 if (EQ (symbol, XCONS (slot)->car))
1920 {
1921 index = make_number (i);
8146262a
KH
1922 XCONS (slot)->cdr = map;
1923 Fput (symbol, Qcode_conversion_map, map);
1924 Fput (symbol, Qcode_conversion_map_id, index);
e34b1164
KH
1925 return index;
1926 }
1927 }
1928
1929 if (i == len)
1930 {
1931 Lisp_Object new_vector = Fmake_vector (make_number (len * 2), Qnil);
1932 int j;
1933
1934 for (j = 0; j < len; j++)
1935 XVECTOR (new_vector)->contents[j]
8146262a
KH
1936 = XVECTOR (Vcode_conversion_map_vector)->contents[j];
1937 Vcode_conversion_map_vector = new_vector;
e34b1164
KH
1938 }
1939
1940 index = make_number (i);
8146262a
KH
1941 Fput (symbol, Qcode_conversion_map, map);
1942 Fput (symbol, Qcode_conversion_map_id, index);
1943 XVECTOR (Vcode_conversion_map_vector)->contents[i] = Fcons (symbol, map);
e34b1164
KH
1944 return index;
1945}
1946
1947
dfcf069d 1948void
4ed46869
KH
1949syms_of_ccl ()
1950{
1951 staticpro (&Vccl_program_table);
6703ac4f 1952 Vccl_program_table = Fmake_vector (make_number (32), Qnil);
4ed46869 1953
6ae21908
KH
1954 Qccl_program = intern ("ccl-program");
1955 staticpro (&Qccl_program);
1956
1957 Qccl_program_idx = intern ("ccl-program-idx");
1958 staticpro (&Qccl_program_idx);
e34b1164 1959
8146262a
KH
1960 Qcode_conversion_map = intern ("code-conversion-map");
1961 staticpro (&Qcode_conversion_map);
6ae21908 1962
8146262a
KH
1963 Qcode_conversion_map_id = intern ("code-conversion-map-id");
1964 staticpro (&Qcode_conversion_map_id);
6ae21908 1965
8146262a
KH
1966 DEFVAR_LISP ("code-conversion-map-vector", &Vcode_conversion_map_vector,
1967 "Vector of code conversion maps.");
1968 Vcode_conversion_map_vector = Fmake_vector (make_number (16), Qnil);
e34b1164 1969
4ed46869
KH
1970 DEFVAR_LISP ("font-ccl-encoder-alist", &Vfont_ccl_encoder_alist,
1971 "Alist of fontname patterns vs corresponding CCL program.\n\
1972Each element looks like (REGEXP . CCL-CODE),\n\
1973 where CCL-CODE is a compiled CCL program.\n\
1974When a font whose name matches REGEXP is used for displaying a character,\n\
1975 CCL-CODE is executed to calculate the code point in the font\n\
1976 from the charset number and position code(s) of the character which are set\n\
1977 in CCL registers R0, R1, and R2 before the execution.\n\
1978The code point in the font is set in CCL registers R1 and R2\n\
1979 when the execution terminated.\n\
1980If the font is single-byte font, the register R2 is not used.");
1981 Vfont_ccl_encoder_alist = Qnil;
1982
1983 defsubr (&Sccl_execute);
1984 defsubr (&Sccl_execute_on_string);
1985 defsubr (&Sregister_ccl_program);
8146262a 1986 defsubr (&Sregister_code_conversion_map);
4ed46869
KH
1987}
1988
1989#endif /* emacs */