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