+#define ENCODE_COMPOSITION_RULE(rule) \
+ do { \
+ int gref = (rule % 0x100) / 12, nref = (rule % 0x100) % 12; \
+ \
+ if (rule < 0x100) /* old format */ \
+ { \
+ if (gref == 10) gref = 4; \
+ if (nref == 10) nref = 4; \
+ charbuf[idx] = 32 + gref * 9 + nref; \
+ charbuf[idx + 1] = -1; \
+ new_chars++; \
+ } \
+ else /* new format */ \
+ { \
+ charbuf[idx] = 32 + 81 + gref; \
+ charbuf[idx + 1] = 32 + nref; \
+ new_chars += 2; \
+ } \
+ } while (0)
+
+/* Finish the current composition as invalid. */
+
+static int finish_composition P_ ((int *, struct composition_status *));
+
+static int
+finish_composition (charbuf, cmp_status)
+ int *charbuf;
+ struct composition_status *cmp_status;
+{
+ int idx = - cmp_status->length;
+ int new_chars;
+
+ /* Recover the original ESC sequence */
+ charbuf[idx++] = ISO_CODE_ESC;
+ charbuf[idx++] = (cmp_status->method == COMPOSITION_RELATIVE ? '0'
+ : cmp_status->method == COMPOSITION_WITH_RULE ? '2'
+ : cmp_status->method == COMPOSITION_WITH_ALTCHARS ? '3'
+ /* cmp_status->method == COMPOSITION_WITH_RULE_ALTCHARS */
+ : '4');
+ charbuf[idx++] = -2;
+ charbuf[idx++] = 0;
+ charbuf[idx++] = -1;
+ new_chars = cmp_status->nchars;
+ if (cmp_status->method >= COMPOSITION_WITH_RULE)
+ for (; idx < 0; idx++)
+ {
+ int elt = charbuf[idx];
+
+ if (elt == -2)
+ {
+ ENCODE_COMPOSITION_RULE (charbuf[idx + 1]);
+ idx++;
+ }
+ else if (elt == -1)
+ {
+ charbuf[idx++] = ISO_CODE_ESC;
+ charbuf[idx] = '0';
+ new_chars += 2;
+ }
+ }
+ cmp_status->state = COMPOSING_NO;
+ return new_chars;
+}
+
+/* If characers are under composition, finish the composition. */
+#define MAYBE_FINISH_COMPOSITION() \
+ do { \
+ if (cmp_status->state != COMPOSING_NO) \
+ char_offset += finish_composition (charbuf, cmp_status); \
+ } while (0)
+
+/* Handle composition start sequence ESC 0, ESC 2, ESC 3, or ESC 4.
+
+ ESC 0 : relative composition : ESC 0 CHAR ... ESC 1
+ ESC 2 : rulebase composition : ESC 2 CHAR RULE CHAR RULE ... CHAR ESC 1
+ ESC 3 : altchar composition : ESC 3 CHAR ... ESC 0 CHAR ... ESC 1
+ ESC 4 : alt&rule composition : ESC 4 CHAR RULE ... CHAR ESC 0 CHAR ... ESC 1
+
+ Produce this annotation sequence now:
+
+ [ -LENGTH(==-4) CODING_ANNOTATE_COMPOSITION_MASK NCHARS(==0) METHOD ]
+*/
+
+#define DECODE_COMPOSITION_START(c1) \
+ do { \
+ if (c1 == '0' \
+ && ((cmp_status->state == COMPOSING_COMPONENT_CHAR \
+ && cmp_status->method == COMPOSITION_WITH_ALTCHARS) \
+ || (cmp_status->state == COMPOSING_COMPONENT_RULE \
+ && cmp_status->method == COMPOSITION_WITH_RULE_ALTCHARS))) \
+ { \
+ *charbuf++ = -1; \
+ *charbuf++= -1; \
+ cmp_status->state = COMPOSING_CHAR; \
+ cmp_status->length += 2; \
+ } \
+ else \
+ { \
+ MAYBE_FINISH_COMPOSITION (); \
+ cmp_status->method = (c1 == '0' ? COMPOSITION_RELATIVE \
+ : c1 == '2' ? COMPOSITION_WITH_RULE \
+ : c1 == '3' ? COMPOSITION_WITH_ALTCHARS \
+ : COMPOSITION_WITH_RULE_ALTCHARS); \
+ cmp_status->state \
+ = (c1 <= '2' ? COMPOSING_CHAR : COMPOSING_COMPONENT_CHAR); \
+ ADD_COMPOSITION_DATA (charbuf, 0, 0, cmp_status->method); \
+ cmp_status->length = MAX_ANNOTATION_LENGTH; \
+ cmp_status->nchars = cmp_status->ncomps = 0; \
+ coding->annotated = 1; \
+ } \
+ } while (0)
+