Initial revision
[bpt/emacs.git] / src / ccl.c
CommitLineData
4ed46869
KH
1/* CCL (Code Conversion Language) interpreter.
2 Ver.1.0
3
4 Copyright (C) 1995 Free Software Foundation, Inc.
5 Copyright (C) 1995 Electrotechnical Laboratory, JAPAN.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
20
21#include <stdio.h>
22
23#ifdef emacs
24
25#include <config.h>
26#include "lisp.h"
27#include "charset.h"
28#include "ccl.h"
29#include "coding.h"
30
31#else /* not emacs */
32
33#include "mulelib.h"
34
35#endif /* not emacs */
36
37/* Alist of fontname patterns vs corresponding CCL program. */
38Lisp_Object Vfont_ccl_encoder_alist;
39
40/* Vector of CCL program names vs corresponding program data. */
41Lisp_Object Vccl_program_table;
42
43/* CCL (Code Conversion Language) is a simple language which has
44 operations on one input buffer, one output buffer, and 7 registers.
45 The syntax of CCL is described in `ccl.el'. Emacs Lisp function
46 `ccl-compile' compiles a CCL program and produces a CCL code which
47 is a vector of integers. The structure of this vector is as
48 follows: The 1st element: buffer-magnification, a factor for the
49 size of output buffer compared with the size of input buffer. The
50 2nd element: address of CCL code to be executed when encountered
51 with end of input stream. The 3rd and the remaining elements: CCL
52 codes. */
53
54/* Header of CCL compiled code */
55#define CCL_HEADER_BUF_MAG 0
56#define CCL_HEADER_EOF 1
57#define CCL_HEADER_MAIN 2
58
59/* CCL code is a sequence of 28-bit non-negative integers (i.e. the
60 MSB is always 0), each contains CCL command and/or arguments in the
61 following format:
62
63 |----------------- integer (28-bit) ------------------|
64 |------- 17-bit ------|- 3-bit --|- 3-bit --|- 5-bit -|
65 |--constant argument--|-register-|-register-|-command-|
66 ccccccccccccccccc RRR rrr XXXXX
67 or
68 |------- relative address -------|-register-|-command-|
69 cccccccccccccccccccc rrr XXXXX
70 or
71 |------------- constant or other args ----------------|
72 cccccccccccccccccccccccccccc
73
74 where, `cc...c' is a non-negative integer indicating constant value
75 (the left most `c' is always 0) or an absolute jump address, `RRR'
76 and `rrr' are CCL register number, `XXXXX' is one of the following
77 CCL commands. */
78
79/* CCL commands
80
81 Each comment fields shows one or more lines for command syntax and
82 the following lines for semantics of the command. In semantics, IC
83 stands for Instruction Counter. */
84
85#define CCL_SetRegister 0x00 /* Set register a register value:
86 1:00000000000000000RRRrrrXXXXX
87 ------------------------------
88 reg[rrr] = reg[RRR];
89 */
90
91#define CCL_SetShortConst 0x01 /* Set register a short constant value:
92 1:CCCCCCCCCCCCCCCCCCCCrrrXXXXX
93 ------------------------------
94 reg[rrr] = CCCCCCCCCCCCCCCCCCC;
95 */
96
97#define CCL_SetConst 0x02 /* Set register a constant value:
98 1:00000000000000000000rrrXXXXX
99 2:CONSTANT
100 ------------------------------
101 reg[rrr] = CONSTANT;
102 IC++;
103 */
104
105#define CCL_SetArray 0x03 /* Set register an element of array:
106 1:CCCCCCCCCCCCCCCCCRRRrrrXXXXX
107 2:ELEMENT[0]
108 3:ELEMENT[1]
109 ...
110 ------------------------------
111 if (0 <= reg[RRR] < CC..C)
112 reg[rrr] = ELEMENT[reg[RRR]];
113 IC += CC..C;
114 */
115
116#define CCL_Jump 0x04 /* Jump:
117 1:A--D--D--R--E--S--S-000XXXXX
118 ------------------------------
119 IC += ADDRESS;
120 */
121
122/* Note: If CC..C is greater than 0, the second code is omitted. */
123
124#define CCL_JumpCond 0x05 /* Jump conditional:
125 1:A--D--D--R--E--S--S-rrrXXXXX
126 ------------------------------
127 if (!reg[rrr])
128 IC += ADDRESS;
129 */
130
131
132#define CCL_WriteRegisterJump 0x06 /* Write register and jump:
133 1:A--D--D--R--E--S--S-rrrXXXXX
134 ------------------------------
135 write (reg[rrr]);
136 IC += ADDRESS;
137 */
138
139#define CCL_WriteRegisterReadJump 0x07 /* Write register, read, and jump:
140 1:A--D--D--R--E--S--S-rrrXXXXX
141 2:A--D--D--R--E--S--S-rrrYYYYY
142 -----------------------------
143 write (reg[rrr]);
144 IC++;
145 read (reg[rrr]);
146 IC += ADDRESS;
147 */
148/* Note: If read is suspended, the resumed execution starts from the
149 second code (YYYYY == CCL_ReadJump). */
150
151#define CCL_WriteConstJump 0x08 /* Write constant and jump:
152 1:A--D--D--R--E--S--S-000XXXXX
153 2:CONST
154 ------------------------------
155 write (CONST);
156 IC += ADDRESS;
157 */
158
159#define CCL_WriteConstReadJump 0x09 /* Write constant, read, and jump:
160 1:A--D--D--R--E--S--S-rrrXXXXX
161 2:CONST
162 3:A--D--D--R--E--S--S-rrrYYYYY
163 -----------------------------
164 write (CONST);
165 IC += 2;
166 read (reg[rrr]);
167 IC += ADDRESS;
168 */
169/* Note: If read is suspended, the resumed execution starts from the
170 second code (YYYYY == CCL_ReadJump). */
171
172#define CCL_WriteStringJump 0x0A /* Write string and jump:
173 1:A--D--D--R--E--S--S-000XXXXX
174 2:LENGTH
175 3:0000STRIN[0]STRIN[1]STRIN[2]
176 ...
177 ------------------------------
178 write_string (STRING, LENGTH);
179 IC += ADDRESS;
180 */
181
182#define CCL_WriteArrayReadJump 0x0B /* Write an array element, read, and jump:
183 1:A--D--D--R--E--S--S-rrrXXXXX
184 2:LENGTH
185 3:ELEMENET[0]
186 4:ELEMENET[1]
187 ...
188 N:A--D--D--R--E--S--S-rrrYYYYY
189 ------------------------------
190 if (0 <= reg[rrr] < LENGTH)
191 write (ELEMENT[reg[rrr]]);
192 IC += LENGTH + 2; (... pointing at N+1)
193 read (reg[rrr]);
194 IC += ADDRESS;
195 */
196/* Note: If read is suspended, the resumed execution starts from the
197 Mth code (YYYYY == CCL_ReadJump). */
198
199#define CCL_ReadJump 0x0C /* Read and jump:
200 1:A--D--D--R--E--S--S-rrrYYYYY
201 -----------------------------
202 read (reg[rrr]);
203 IC += ADDRESS;
204 */
205
206#define CCL_Branch 0x0D /* Jump by branch table:
207 1:CCCCCCCCCCCCCCCCCCCCrrrXXXXX
208 2:A--D--D--R--E-S-S[0]000XXXXX
209 3:A--D--D--R--E-S-S[1]000XXXXX
210 ...
211 ------------------------------
212 if (0 <= reg[rrr] < CC..C)
213 IC += ADDRESS[reg[rrr]];
214 else
215 IC += ADDRESS[CC..C];
216 */
217
218#define CCL_ReadRegister 0x0E /* Read bytes into registers:
219 1:CCCCCCCCCCCCCCCCCCCCrrrXXXXX
220 2:CCCCCCCCCCCCCCCCCCCCrrrXXXXX
221 ...
222 ------------------------------
223 while (CCC--)
224 read (reg[rrr]);
225 */
226
227#define CCL_WriteExprConst 0x0F /* write result of expression:
228 1:00000OPERATION000RRR000XXXXX
229 2:CONSTANT
230 ------------------------------
231 write (reg[RRR] OPERATION CONSTANT);
232 IC++;
233 */
234
235/* Note: If the Nth read is suspended, the resumed execution starts
236 from the Nth code. */
237
238#define CCL_ReadBranch 0x10 /* Read one byte into a register,
239 and jump by branch table:
240 1:CCCCCCCCCCCCCCCCCCCCrrrXXXXX
241 2:A--D--D--R--E-S-S[0]000XXXXX
242 3:A--D--D--R--E-S-S[1]000XXXXX
243 ...
244 ------------------------------
245 read (read[rrr]);
246 if (0 <= reg[rrr] < CC..C)
247 IC += ADDRESS[reg[rrr]];
248 else
249 IC += ADDRESS[CC..C];
250 */
251
252#define CCL_WriteRegister 0x11 /* Write registers:
253 1:CCCCCCCCCCCCCCCCCCCrrrXXXXX
254 2:CCCCCCCCCCCCCCCCCCCrrrXXXXX
255 ...
256 ------------------------------
257 while (CCC--)
258 write (reg[rrr]);
259 ...
260 */
261
262/* Note: If the Nth write is suspended, the resumed execution
263 starts from the Nth code. */
264
265#define CCL_WriteExprRegister 0x12 /* Write result of expression
266 1:00000OPERATIONRrrRRR000XXXXX
267 ------------------------------
268 write (reg[RRR] OPERATION reg[Rrr]);
269 */
270
271#define CCL_Call 0x13 /* Write a constant:
272 1:CCCCCCCCCCCCCCCCCCCC000XXXXX
273 ------------------------------
274 call (CC..C)
275 */
276
277#define CCL_WriteConstString 0x14 /* Write a constant or a string:
278 1:CCCCCCCCCCCCCCCCCCCCrrrXXXXX
279 [2:0000STRIN[0]STRIN[1]STRIN[2]]
280 [...]
281 -----------------------------
282 if (!rrr)
283 write (CC..C)
284 else
285 write_string (STRING, CC..C);
286 IC += (CC..C + 2) / 3;
287 */
288
289#define CCL_WriteArray 0x15 /* Write an element of array:
290 1:CCCCCCCCCCCCCCCCCCCCrrrXXXXX
291 2:ELEMENT[0]
292 3:ELEMENT[1]
293 ...
294 ------------------------------
295 if (0 <= reg[rrr] < CC..C)
296 write (ELEMENT[reg[rrr]]);
297 IC += CC..C;
298 */
299
300#define CCL_End 0x16 /* Terminate:
301 1:00000000000000000000000XXXXX
302 ------------------------------
303 terminate ();
304 */
305
306/* The following two codes execute an assignment arithmetic/logical
307 operation. The form of the operation is like REG OP= OPERAND. */
308
309#define CCL_ExprSelfConst 0x17 /* REG OP= constant:
310 1:00000OPERATION000000rrrXXXXX
311 2:CONSTANT
312 ------------------------------
313 reg[rrr] OPERATION= CONSTANT;
314 */
315
316#define CCL_ExprSelfReg 0x18 /* REG1 OP= REG2:
317 1:00000OPERATION000RRRrrrXXXXX
318 ------------------------------
319 reg[rrr] OPERATION= reg[RRR];
320 */
321
322/* The following codes execute an arithmetic/logical operation. The
323 form of the operation is like REG_X = REG_Y OP OPERAND2. */
324
325#define CCL_SetExprConst 0x19 /* REG_X = REG_Y OP constant:
326 1:00000OPERATION000RRRrrrXXXXX
327 2:CONSTANT
328 ------------------------------
329 reg[rrr] = reg[RRR] OPERATION CONSTANT;
330 IC++;
331 */
332
333#define CCL_SetExprReg 0x1A /* REG1 = REG2 OP REG3:
334 1:00000OPERATIONRrrRRRrrrXXXXX
335 ------------------------------
336 reg[rrr] = reg[RRR] OPERATION reg[Rrr];
337 */
338
339#define CCL_JumpCondExprConst 0x1B /* Jump conditional according to
340 an operation on constant:
341 1:A--D--D--R--E--S--S-rrrXXXXX
342 2:OPERATION
343 3:CONSTANT
344 -----------------------------
345 reg[7] = reg[rrr] OPERATION CONSTANT;
346 if (!(reg[7]))
347 IC += ADDRESS;
348 else
349 IC += 2
350 */
351
352#define CCL_JumpCondExprReg 0x1C /* Jump conditional according to
353 an operation on register:
354 1:A--D--D--R--E--S--S-rrrXXXXX
355 2:OPERATION
356 3:RRR
357 -----------------------------
358 reg[7] = reg[rrr] OPERATION reg[RRR];
359 if (!reg[7])
360 IC += ADDRESS;
361 else
362 IC += 2;
363 */
364
365#define CCL_ReadJumpCondExprConst 0x1D /* Read and jump conditional according
366 to an operation on constant:
367 1:A--D--D--R--E--S--S-rrrXXXXX
368 2:OPERATION
369 3:CONSTANT
370 -----------------------------
371 read (reg[rrr]);
372 reg[7] = reg[rrr] OPERATION CONSTANT;
373 if (!reg[7])
374 IC += ADDRESS;
375 else
376 IC += 2;
377 */
378
379#define CCL_ReadJumpCondExprReg 0x1E /* Read and jump conditional according
380 to an operation on register:
381 1:A--D--D--R--E--S--S-rrrXXXXX
382 2:OPERATION
383 3:RRR
384 -----------------------------
385 read (reg[rrr]);
386 reg[7] = reg[rrr] OPERATION reg[RRR];
387 if (!reg[7])
388 IC += ADDRESS;
389 else
390 IC += 2;
391 */
392
393#define CCL_Extention 0x1F /* Extended CCL code
394 1:ExtendedCOMMNDRrrRRRrrrXXXXX
395 2:ARGUEMENT
396 3:...
397 ------------------------------
398 extended_command (rrr,RRR,Rrr,ARGS)
399 */
400
401
402/* CCL arithmetic/logical operators. */
403#define CCL_PLUS 0x00 /* X = Y + Z */
404#define CCL_MINUS 0x01 /* X = Y - Z */
405#define CCL_MUL 0x02 /* X = Y * Z */
406#define CCL_DIV 0x03 /* X = Y / Z */
407#define CCL_MOD 0x04 /* X = Y % Z */
408#define CCL_AND 0x05 /* X = Y & Z */
409#define CCL_OR 0x06 /* X = Y | Z */
410#define CCL_XOR 0x07 /* X = Y ^ Z */
411#define CCL_LSH 0x08 /* X = Y << Z */
412#define CCL_RSH 0x09 /* X = Y >> Z */
413#define CCL_LSH8 0x0A /* X = (Y << 8) | Z */
414#define CCL_RSH8 0x0B /* X = Y >> 8, r[7] = Y & 0xFF */
415#define CCL_DIVMOD 0x0C /* X = Y / Z, r[7] = Y % Z */
416#define CCL_LS 0x10 /* X = (X < Y) */
417#define CCL_GT 0x11 /* X = (X > Y) */
418#define CCL_EQ 0x12 /* X = (X == Y) */
419#define CCL_LE 0x13 /* X = (X <= Y) */
420#define CCL_GE 0x14 /* X = (X >= Y) */
421#define CCL_NE 0x15 /* X = (X != Y) */
422
423#define CCL_ENCODE_SJIS 0x16 /* X = HIGHER_BYTE (SJIS (Y, Z))
424 r[7] = LOWER_BYTE (SJIS (Y, Z) */
425#define CCL_DECODE_SJIS 0x17 /* X = HIGHER_BYTE (DE-SJIS (Y, Z))
426 r[7] = LOWER_BYTE (DE-SJIS (Y, Z)) */
427
428/* Macros for exit status of CCL program. */
429#define CCL_STAT_SUCCESS 0 /* Terminated successfully. */
430#define CCL_STAT_SUSPEND 1 /* Terminated because of empty input
431 buffer or full output buffer. */
432#define CCL_STAT_INVALID_CMD 2 /* Terminated because of invalid
433 command. */
434#define CCL_STAT_QUIT 3 /* Terminated because of quit. */
435
436/* Terminate CCL program successfully. */
437#define CCL_SUCCESS \
438 do { \
439 ccl->status = CCL_STAT_SUCCESS; \
440 ccl->ic = CCL_HEADER_MAIN; \
441 goto ccl_finish; \
442 } while (0)
443
444/* Suspend CCL program because of reading from empty input buffer or
445 writing to full output buffer. When this program is resumed, the
446 same I/O command is executed. */
447#define CCL_SUSPEND \
448 do { \
449 ic--; \
450 ccl->status = CCL_STAT_SUSPEND; \
451 goto ccl_finish; \
452 } while (0)
453
454/* Terminate CCL program because of invalid command. Should not occur
455 in the normal case. */
456#define CCL_INVALID_CMD \
457 do { \
458 ccl->status = CCL_STAT_INVALID_CMD; \
459 goto ccl_error_handler; \
460 } while (0)
461
462/* Encode one character CH to multibyte form and write to the current
463 output buffer. If CH is negative, write one byte -CH. */
464#define CCL_WRITE_CHAR(ch) \
465 do { \
466 if (!dst) \
467 CCL_INVALID_CMD; \
468 else \
469 { \
470 unsigned char work[4], *str; \
471 int len = CHAR_STRING (ch, work, str); \
472 if (dst + len <= dst_end) \
473 { \
474 bcopy (str, dst, len); \
475 dst += len; \
476 } \
477 else \
478 CCL_SUSPEND; \
479 } \
480 } while (0)
481
482/* Write a string at ccl_prog[IC] of length LEN to the current output
483 buffer. */
484#define CCL_WRITE_STRING(len) \
485 do { \
486 if (!dst) \
487 CCL_INVALID_CMD; \
488 else if (dst + len <= dst_end) \
489 for (i = 0; i < len; i++) \
490 *dst++ = ((XFASTINT (ccl_prog[ic + (i / 3)])) \
491 >> ((2 - (i % 3)) * 8)) & 0xFF; \
492 else \
493 CCL_SUSPEND; \
494 } while (0)
495
496/* Read one byte from the current input buffer into Rth register. */
497#define CCL_READ_CHAR(r) \
498 do { \
499 if (!src) \
500 CCL_INVALID_CMD; \
501 else if (src < src_end) \
502 r = *src++; \
503 else if (ccl->last_block) \
504 { \
505 ic = ccl->eof_ic; \
506 goto ccl_finish; \
507 } \
508 else \
509 CCL_SUSPEND; \
510 } while (0)
511
512
513/* Execute CCL code on SRC_BYTES length text at SOURCE. The resulting
514 text goes to a place pointed by DESTINATION, the length of which
515 should not exceed DST_BYTES. The bytes actually processed is
516 returned as *CONSUMED. The return value is the length of the
517 resulting text. As a side effect, the contents of CCL registers
518 are updated. If SOURCE or DESTINATION is NULL, only operations on
519 registers are permitted. */
520
521#ifdef CCL_DEBUG
522#define CCL_DEBUG_BACKTRACE_LEN 256
523int ccl_backtrace_table[CCL_BACKTRACE_TABLE];
524int ccl_backtrace_idx;
525#endif
526
527struct ccl_prog_stack
528 {
529 int *ccl_prog; /* Pointer to an array of CCL code. */
530 int ic; /* Instruction Counter. */
531 };
532
533ccl_driver (ccl, source, destination, src_bytes, dst_bytes, consumed)
534 struct ccl_program *ccl;
535 unsigned char *source, *destination;
536 int src_bytes, dst_bytes;
537 int *consumed;
538{
539 register int *reg = ccl->reg;
540 register int ic = ccl->ic;
541 register int code, field1, field2;
542 register int *ccl_prog = ccl->prog;
543 unsigned char *src = source, *src_end = src + src_bytes;
544 unsigned char *dst = destination, *dst_end = dst + dst_bytes;
545 int jump_address;
546 int i, j, op;
547 int stack_idx = 0;
548 /* For the moment, we only support depth 256 of stack. */
549 struct ccl_prog_stack ccl_prog_stack_struct[256];
550
551 if (ic >= ccl->eof_ic)
552 ic = CCL_HEADER_MAIN;
553
554#ifdef CCL_DEBUG
555 ccl_backtrace_idx = 0;
556#endif
557
558 for (;;)
559 {
560#ifdef CCL_DEBUG
561 ccl_backtrace_table[ccl_backtrace_idx++] = ic;
562 if (ccl_backtrace_idx >= CCL_DEBUG_BACKTRACE_LEN)
563 ccl_backtrace_idx = 0;
564 ccl_backtrace_table[ccl_backtrace_idx] = 0;
565#endif
566
567 if (!NILP (Vquit_flag) && NILP (Vinhibit_quit))
568 {
569 /* We can't just signal Qquit, instead break the loop as if
570 the whole data is processed. Don't reset Vquit_flag, it
571 must be handled later at a safer place. */
572 if (consumed)
573 src = source + src_bytes;
574 ccl->status = CCL_STAT_QUIT;
575 break;
576 }
577
578 code = XINT (ccl_prog[ic]); ic++;
579 field1 = code >> 8;
580 field2 = (code & 0xFF) >> 5;
581
582#define rrr field2
583#define RRR (field1 & 7)
584#define Rrr ((field1 >> 3) & 7)
585#define ADDR field1
586
587 switch (code & 0x1F)
588 {
589 case CCL_SetRegister: /* 00000000000000000RRRrrrXXXXX */
590 reg[rrr] = reg[RRR];
591 break;
592
593 case CCL_SetShortConst: /* CCCCCCCCCCCCCCCCCCCCrrrXXXXX */
594 reg[rrr] = field1;
595 break;
596
597 case CCL_SetConst: /* 00000000000000000000rrrXXXXX */
598 reg[rrr] = XINT (ccl_prog[ic]);
599 ic++;
600 break;
601
602 case CCL_SetArray: /* CCCCCCCCCCCCCCCCCCCCRRRrrrXXXXX */
603 i = reg[RRR];
604 j = field1 >> 3;
605 if ((unsigned int) i < j)
606 reg[rrr] = XINT (ccl_prog[ic + i]);
607 ic += j;
608 break;
609
610 case CCL_Jump: /* A--D--D--R--E--S--S-000XXXXX */
611 ic += ADDR;
612 break;
613
614 case CCL_JumpCond: /* A--D--D--R--E--S--S-rrrXXXXX */
615 if (!reg[rrr])
616 ic += ADDR;
617 break;
618
619 case CCL_WriteRegisterJump: /* A--D--D--R--E--S--S-rrrXXXXX */
620 i = reg[rrr];
621 CCL_WRITE_CHAR (i);
622 ic += ADDR;
623 break;
624
625 case CCL_WriteRegisterReadJump: /* A--D--D--R--E--S--S-rrrXXXXX */
626 i = reg[rrr];
627 CCL_WRITE_CHAR (i);
628 ic++;
629 CCL_READ_CHAR (reg[rrr]);
630 ic += ADDR - 1;
631 break;
632
633 case CCL_WriteConstJump: /* A--D--D--R--E--S--S-000XXXXX */
634 i = XINT (ccl_prog[ic]);
635 CCL_WRITE_CHAR (i);
636 ic += ADDR;
637 break;
638
639 case CCL_WriteConstReadJump: /* A--D--D--R--E--S--S-rrrXXXXX */
640 i = XINT (ccl_prog[ic]);
641 CCL_WRITE_CHAR (i);
642 ic++;
643 CCL_READ_CHAR (reg[rrr]);
644 ic += ADDR - 1;
645 break;
646
647 case CCL_WriteStringJump: /* A--D--D--R--E--S--S-000XXXXX */
648 j = XINT (ccl_prog[ic]);
649 ic++;
650 CCL_WRITE_STRING (j);
651 ic += ADDR - 1;
652 break;
653
654 case CCL_WriteArrayReadJump: /* A--D--D--R--E--S--S-rrrXXXXX */
655 i = reg[rrr];
656 j = ccl_prog[ic++];
657 if ((unsigned int) i < j)
658 {
659 i = XINT (ccl_prog[ic + i]);
660 CCL_WRITE_CHAR (i);
661 }
662 ic += j + 1;
663 CCL_READ_CHAR (reg[rrr]);
664 ic += ADDR - (j + 2);
665 break;
666
667 case CCL_ReadJump: /* A--D--D--R--E--S--S-rrrYYYYY */
668 CCL_READ_CHAR (reg[rrr]);
669 ic += ADDR;
670 break;
671
672 case CCL_ReadBranch: /* CCCCCCCCCCCCCCCCCCCCrrrXXXXX */
673 CCL_READ_CHAR (reg[rrr]);
674 /* fall through ... */
675 case CCL_Branch: /* CCCCCCCCCCCCCCCCCCCCrrrXXXXX */
676 if ((unsigned int) reg[rrr] < field1)
677 ic += XINT (ccl_prog[ic + reg[rrr]]);
678 else
679 ic += XINT (ccl_prog[ic + field1]);
680 break;
681
682 case CCL_ReadRegister: /* CCCCCCCCCCCCCCCCCCCCrrXXXXX */
683 while (1)
684 {
685 CCL_READ_CHAR (reg[rrr]);
686 if (!field1) break;
687 code = XINT (ccl_prog[ic]); ic++;
688 field1 = code >> 8;
689 field2 = (code & 0xFF) >> 5;
690 }
691 break;
692
693 case CCL_WriteExprConst: /* 1:00000OPERATION000RRR000XXXXX */
694 rrr = 7;
695 i = reg[RRR];
696 j = XINT (ccl_prog[ic]);
697 op = field1 >> 6;
698 ic++;
699 goto ccl_set_expr;
700
701 case CCL_WriteRegister: /* CCCCCCCCCCCCCCCCCCCrrrXXXXX */
702 while (1)
703 {
704 i = reg[rrr];
705 CCL_WRITE_CHAR (i);
706 if (!field1) break;
707 code = XINT (ccl_prog[ic]); ic++;
708 field1 = code >> 8;
709 field2 = (code & 0xFF) >> 5;
710 }
711 break;
712
713 case CCL_WriteExprRegister: /* 1:00000OPERATIONRrrRRR000XXXXX */
714 rrr = 7;
715 i = reg[RRR];
716 j = reg[Rrr];
717 op = field1 >> 6;
718 goto ccl_set_expr;
719
720 case CCL_Call: /* CCCCCCCCCCCCCCCCCCCC000XXXXX */
721 {
722 Lisp_Object slot;
723
724 if (stack_idx >= 256
725 || field1 < 0
726 || field1 >= XVECTOR (Vccl_program_table)->size
727 || (slot = XVECTOR (Vccl_program_table)->contents[field1],
728 !CONSP (slot))
729 || !VECTORP (XCONS (slot)->cdr))
730 {
731 if (stack_idx > 0)
732 {
733 ccl_prog = ccl_prog_stack_struct[0].ccl_prog;
734 ic = ccl_prog_stack_struct[0].ic;
735 }
736 CCL_INVALID_CMD;
737 }
738
739 ccl_prog_stack_struct[stack_idx].ccl_prog = ccl_prog;
740 ccl_prog_stack_struct[stack_idx].ic = ic;
741 stack_idx++;
742 ccl_prog = XVECTOR (XCONS (slot)->cdr)->contents;
743 ic = CCL_HEADER_MAIN;
744 }
745 break;
746
747 case CCL_WriteConstString: /* CCCCCCCCCCCCCCCCCCCCrrrXXXXX */
748 if (!rrr)
749 CCL_WRITE_CHAR (field1);
750 else
751 {
752 CCL_WRITE_STRING (field1);
753 ic += (field1 + 2) / 3;
754 }
755 break;
756
757 case CCL_WriteArray: /* CCCCCCCCCCCCCCCCCCCCrrrXXXXX */
758 i = reg[rrr];
759 if ((unsigned int) i < field1)
760 {
761 j = XINT (ccl_prog[ic + i]);
762 CCL_WRITE_CHAR (j);
763 }
764 ic += field1;
765 break;
766
767 case CCL_End: /* 0000000000000000000000XXXXX */
768 if (stack_idx-- > 0)
769 {
770 ccl_prog = ccl_prog_stack_struct[stack_idx].ccl_prog;
771 ic = ccl_prog_stack_struct[stack_idx].ic;
772 break;
773 }
774 CCL_SUCCESS;
775
776 case CCL_ExprSelfConst: /* 00000OPERATION000000rrrXXXXX */
777 i = XINT (ccl_prog[ic]);
778 ic++;
779 op = field1 >> 6;
780 goto ccl_expr_self;
781
782 case CCL_ExprSelfReg: /* 00000OPERATION000RRRrrrXXXXX */
783 i = reg[RRR];
784 op = field1 >> 6;
785
786 ccl_expr_self:
787 switch (op)
788 {
789 case CCL_PLUS: reg[rrr] += i; break;
790 case CCL_MINUS: reg[rrr] -= i; break;
791 case CCL_MUL: reg[rrr] *= i; break;
792 case CCL_DIV: reg[rrr] /= i; break;
793 case CCL_MOD: reg[rrr] %= i; break;
794 case CCL_AND: reg[rrr] &= i; break;
795 case CCL_OR: reg[rrr] |= i; break;
796 case CCL_XOR: reg[rrr] ^= i; break;
797 case CCL_LSH: reg[rrr] <<= i; break;
798 case CCL_RSH: reg[rrr] >>= i; break;
799 case CCL_LSH8: reg[rrr] <<= 8; reg[rrr] |= i; break;
800 case CCL_RSH8: reg[7] = reg[rrr] & 0xFF; reg[rrr] >>= 8; break;
801 case CCL_DIVMOD: reg[7] = reg[rrr] % i; reg[rrr] /= i; break;
802 case CCL_LS: reg[rrr] = reg[rrr] < i; break;
803 case CCL_GT: reg[rrr] = reg[rrr] > i; break;
804 case CCL_EQ: reg[rrr] = reg[rrr] == i; break;
805 case CCL_LE: reg[rrr] = reg[rrr] <= i; break;
806 case CCL_GE: reg[rrr] = reg[rrr] >= i; break;
807 case CCL_NE: reg[rrr] = reg[rrr] != i; break;
808 default: CCL_INVALID_CMD;
809 }
810 break;
811
812 case CCL_SetExprConst: /* 00000OPERATION000RRRrrrXXXXX */
813 i = reg[RRR];
814 j = XINT (ccl_prog[ic]);
815 op = field1 >> 6;
816 jump_address = ++ic;
817 goto ccl_set_expr;
818
819 case CCL_SetExprReg: /* 00000OPERATIONRrrRRRrrrXXXXX */
820 i = reg[RRR];
821 j = reg[Rrr];
822 op = field1 >> 6;
823 jump_address = ic;
824 goto ccl_set_expr;
825
826 case CCL_ReadJumpCondExprConst: /* A--D--D--R--E--S--S-rrrXXXXX */
827 CCL_READ_CHAR (reg[rrr]);
828 case CCL_JumpCondExprConst: /* A--D--D--R--E--S--S-rrrXXXXX */
829 i = reg[rrr];
830 op = XINT (ccl_prog[ic]);
831 jump_address = ic++ + ADDR;
832 j = XINT (ccl_prog[ic]);
833 ic++;
834 rrr = 7;
835 goto ccl_set_expr;
836
837 case CCL_ReadJumpCondExprReg: /* A--D--D--R--E--S--S-rrrXXXXX */
838 CCL_READ_CHAR (reg[rrr]);
839 case CCL_JumpCondExprReg:
840 i = reg[rrr];
841 op = XINT (ccl_prog[ic]);
842 jump_address = ic++ + ADDR;
843 j = reg[XINT (ccl_prog[ic])];
844 ic++;
845 rrr = 7;
846
847 ccl_set_expr:
848 switch (op)
849 {
850 case CCL_PLUS: reg[rrr] = i + j; break;
851 case CCL_MINUS: reg[rrr] = i - j; break;
852 case CCL_MUL: reg[rrr] = i * j; break;
853 case CCL_DIV: reg[rrr] = i / j; break;
854 case CCL_MOD: reg[rrr] = i % j; break;
855 case CCL_AND: reg[rrr] = i & j; break;
856 case CCL_OR: reg[rrr] = i | j; break;
857 case CCL_XOR: reg[rrr] = i ^ j;; break;
858 case CCL_LSH: reg[rrr] = i << j; break;
859 case CCL_RSH: reg[rrr] = i >> j; break;
860 case CCL_LSH8: reg[rrr] = (i << 8) | j; break;
861 case CCL_RSH8: reg[rrr] = i >> 8; reg[7] = i & 0xFF; break;
862 case CCL_DIVMOD: reg[rrr] = i / j; reg[7] = i % j; break;
863 case CCL_LS: reg[rrr] = i < j; break;
864 case CCL_GT: reg[rrr] = i > j; break;
865 case CCL_EQ: reg[rrr] = i == j; break;
866 case CCL_LE: reg[rrr] = i <= j; break;
867 case CCL_GE: reg[rrr] = i >= j; break;
868 case CCL_NE: reg[rrr] = i != j; break;
869 case CCL_ENCODE_SJIS: ENCODE_SJIS (i, j, reg[rrr], reg[7]); break;
870 case CCL_DECODE_SJIS: DECODE_SJIS (i, j, reg[rrr], reg[7]); break;
871 default: CCL_INVALID_CMD;
872 }
873 code &= 0x1F;
874 if (code == CCL_WriteExprConst || code == CCL_WriteExprRegister)
875 {
876 i = reg[rrr];
877 CCL_WRITE_CHAR (i);
878 }
879 else if (!reg[rrr])
880 ic = jump_address;
881 break;
882
883 default:
884 CCL_INVALID_CMD;
885 }
886 }
887
888 ccl_error_handler:
889 if (destination)
890 {
891 /* We can insert an error message only if DESTINATION is
892 specified and we still have a room to store the message
893 there. */
894 char msg[256];
895 int msglen;
896
897 switch (ccl->status)
898 {
899 case CCL_STAT_INVALID_CMD:
900 sprintf(msg, "\nCCL: Invalid command %x (ccl_code = %x) at %d.",
901 code & 0x1F, code, ic);
902#ifdef CCL_DEBUG
903 {
904 int i = ccl_backtrace_idx - 1;
905 int j;
906
907 msglen = strlen (msg);
908 if (dst + msglen <= dst_end)
909 {
910 bcopy (msg, dst, msglen);
911 dst += msglen;
912 }
913
914 for (j = 0; j < CCL_DEBUG_BACKTRACE_LEN; j++, i--)
915 {
916 if (i < 0) i = CCL_DEBUG_BACKTRACE_LEN - 1;
917 if (ccl_backtrace_table[i] == 0)
918 break;
919 sprintf(msg, " %d", ccl_backtrace_table[i]);
920 msglen = strlen (msg);
921 if (dst + msglen > dst_end)
922 break;
923 bcopy (msg, dst, msglen);
924 dst += msglen;
925 }
926 }
927 goto ccl_finish;
928#endif
929
930 case CCL_STAT_QUIT:
931 sprintf(msg, "\nCCL: Quited.");
932 break;
933
934 default:
935 sprintf(msg, "\nCCL: Unknown error type (%d).", ccl->status);
936 }
937
938 msglen = strlen (msg);
939 if (dst + msglen <= dst_end)
940 {
941 bcopy (msg, dst, msglen);
942 dst += msglen;
943 }
944 }
945
946 ccl_finish:
947 ccl->ic = ic;
948 if (consumed) *consumed = src - source;
949 return dst - destination;
950}
951
952/* Setup fields of the structure pointed by CCL appropriately for the
953 execution of compiled CCL code in VEC (vector of integer). */
954setup_ccl_program (ccl, vec)
955 struct ccl_program *ccl;
956 Lisp_Object vec;
957{
958 int i;
959
960 ccl->size = XVECTOR (vec)->size;
961 ccl->prog = XVECTOR (vec)->contents;
962 ccl->ic = CCL_HEADER_MAIN;
963 ccl->eof_ic = XINT (XVECTOR (vec)->contents[CCL_HEADER_EOF]);
964 ccl->buf_magnification = XINT (XVECTOR (vec)->contents[CCL_HEADER_BUF_MAG]);
965 for (i = 0; i < 8; i++)
966 ccl->reg[i] = 0;
967 ccl->last_block = 0;
968 ccl->status = 0;
969}
970
971#ifdef emacs
972
973DEFUN ("ccl-execute", Fccl_execute, Sccl_execute, 2, 2, 0,
974 "Execute CCL-PROGRAM with registers initialized by REGISTERS.\n\
975CCL-PROGRAM is a compiled code generated by `ccl-compile',\n\
976 no I/O commands should appear in the CCL program.\n\
977REGISTERS is a vector of [R0 R1 ... R7] where RN is an initial value\n\
978 of Nth register.\n\
979As side effect, each element of REGISTER holds the value of\n\
980 corresponding register after the execution.")
981 (ccl_prog, reg)
982 Lisp_Object ccl_prog, reg;
983{
984 struct ccl_program ccl;
985 int i;
986
987 CHECK_VECTOR (ccl_prog, 0);
988 CHECK_VECTOR (reg, 1);
989 if (XVECTOR (reg)->size != 8)
990 error ("Invalid length of vector REGISTERS");
991
992 setup_ccl_program (&ccl, ccl_prog);
993 for (i = 0; i < 8; i++)
994 ccl.reg[i] = (INTEGERP (XVECTOR (reg)->contents[i])
995 ? XINT (XVECTOR (reg)->contents[i])
996 : 0);
997
998 ccl_driver (&ccl, (char *)0, (char *)0, 0, 0, (int *)0);
999 QUIT;
1000 if (ccl.status != CCL_STAT_SUCCESS)
1001 error ("Error in CCL program at %dth code", ccl.ic);
1002
1003 for (i = 0; i < 8; i++)
1004 XSETINT (XVECTOR (reg)->contents[i], ccl.reg[i]);
1005 return Qnil;
1006}
1007
1008DEFUN ("ccl-execute-on-string", Fccl_execute_on_string, Sccl_execute_on_string,
1009 3, 3, 0,
1010 "Execute CCL-PROGRAM with initial STATUS on STRING.\n\
1011CCL-PROGRAM is a compiled code generated by `ccl-compile'.\n\
1012Read buffer is set to STRING, and write buffer is allocated automatically.\n\
1013STATUS is a vector of [R0 R1 ... R7 IC], where\n\
1014 R0..R7 are initial values of corresponding registers,\n\
1015 IC is the instruction counter specifying from where to start the program.\n\
1016If R0..R7 are nil, they are initialized to 0.\n\
1017If IC is nil, it is initialized to head of the CCL program.\n\
1018Returns the contents of write buffer as a string,\n\
1019 and as side effect, STATUS is updated.")
1020 (ccl_prog, status, str)
1021 Lisp_Object ccl_prog, status, str;
1022{
1023 Lisp_Object val;
1024 struct ccl_program ccl;
1025 int i, produced;
1026 int outbufsize;
1027 char *outbuf;
1028 struct gcpro gcpro1, gcpro2, gcpro3;
1029
1030 CHECK_VECTOR (ccl_prog, 0);
1031 CHECK_VECTOR (status, 1);
1032 if (XVECTOR (status)->size != 9)
1033 error ("Invalid length of vector STATUS");
1034 CHECK_STRING (str, 2);
1035 GCPRO3 (ccl_prog, status, str);
1036
1037 setup_ccl_program (&ccl, ccl_prog);
1038 for (i = 0; i < 8; i++)
1039 {
1040 if (NILP (XVECTOR (status)->contents[i]))
1041 XSETINT (XVECTOR (status)->contents[i], 0);
1042 if (INTEGERP (XVECTOR (status)->contents[i]))
1043 ccl.reg[i] = XINT (XVECTOR (status)->contents[i]);
1044 }
1045 if (INTEGERP (XVECTOR (status)->contents[i]))
1046 {
1047 i = XFASTINT (XVECTOR (status)->contents[8]);
1048 if (ccl.ic < i && i < ccl.size)
1049 ccl.ic = i;
1050 }
1051 outbufsize = XSTRING (str)->size * ccl.buf_magnification + 256;
1052 outbuf = (char *) xmalloc (outbufsize);
1053 if (!outbuf)
1054 error ("Not enough memory");
1055 ccl.last_block = 1;
1056 produced = ccl_driver (&ccl, XSTRING (str)->data, outbuf,
1057 XSTRING (str)->size, outbufsize, (int *)0);
1058 for (i = 0; i < 8; i++)
1059 XSET (XVECTOR (status)->contents[i], Lisp_Int, ccl.reg[i]);
1060 XSETINT (XVECTOR (status)->contents[8], ccl.ic);
1061 UNGCPRO;
1062
1063 val = make_string (outbuf, produced);
1064 free (outbuf);
1065 QUIT;
1066 if (ccl.status != CCL_STAT_SUCCESS
1067 && ccl.status != CCL_STAT_SUSPEND)
1068 error ("Error in CCL program at %dth code", ccl.ic);
1069
1070 return val;
1071}
1072
1073DEFUN ("register-ccl-program", Fregister_ccl_program, Sregister_ccl_program,
1074 2, 2, 0,
1075 "Register CCL program PROGRAM of NAME in `ccl-program-table'.
1076PROGRAM should be a compiled code of CCL program, or nil.
1077Return index number of the registered CCL program.")
1078 (name, ccl_prog)
1079 Lisp_Object name, ccl_prog;
1080{
1081 int len = XVECTOR (Vccl_program_table)->size;
1082 int i, idx;
1083
1084 CHECK_SYMBOL (name, 0);
1085 if (!NILP (ccl_prog))
1086 CHECK_VECTOR (ccl_prog, 1);
1087
1088 for (i = 0; i < len; i++)
1089 {
1090 Lisp_Object slot = XVECTOR (Vccl_program_table)->contents[i];
1091
1092 if (!CONSP (slot))
1093 break;
1094
1095 if (EQ (name, XCONS (slot)->car))
1096 {
1097 XCONS (slot)->cdr = ccl_prog;
1098 return make_number (i);
1099 }
1100 }
1101
1102 if (i == len)
1103 {
1104 Lisp_Object new_table = Fmake_vector (len * 2, Qnil);
1105 int j;
1106
1107 for (j = 0; j < len; j++)
1108 XVECTOR (new_table)->contents[j]
1109 = XVECTOR (Vccl_program_table)->contents[j];
1110 Vccl_program_table = new_table;
1111 }
1112
1113 XVECTOR (Vccl_program_table)->contents[i] = Fcons (name, ccl_prog);
1114 return make_number (i);
1115}
1116
1117syms_of_ccl ()
1118{
1119 staticpro (&Vccl_program_table);
1120 Vccl_program_table = Fmake_vector (32, Qnil);
1121
1122 DEFVAR_LISP ("font-ccl-encoder-alist", &Vfont_ccl_encoder_alist,
1123 "Alist of fontname patterns vs corresponding CCL program.\n\
1124Each element looks like (REGEXP . CCL-CODE),\n\
1125 where CCL-CODE is a compiled CCL program.\n\
1126When a font whose name matches REGEXP is used for displaying a character,\n\
1127 CCL-CODE is executed to calculate the code point in the font\n\
1128 from the charset number and position code(s) of the character which are set\n\
1129 in CCL registers R0, R1, and R2 before the execution.\n\
1130The code point in the font is set in CCL registers R1 and R2\n\
1131 when the execution terminated.\n\
1132If the font is single-byte font, the register R2 is not used.");
1133 Vfont_ccl_encoder_alist = Qnil;
1134
1135 defsubr (&Sccl_execute);
1136 defsubr (&Sccl_execute_on_string);
1137 defsubr (&Sregister_ccl_program);
1138}
1139
1140#endif /* emacs */