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