#ifndef lint static char sccs_id[] = "%W% (TriChlor) %G% %U%"; #endif /* lint */ /* * Vncompos.c is an implementation of the efficient and flexible * composition algorithm due to Dr. Hoc Ngo of the Viet-Std group. */ #ifdef _WINDOWS #include #endif #include #include "portable.h" #include "charset.h" #include "vnkeys.h" #include "vncompos.h" /* short-hand definitions */ #define C_state (Co_data->state) #define C1 (Co_data->c1) #define C2 (Co_data->c2) #define C3 (Co_data->c3) #define I1 (Co_data->i1) #define I2 (Co_data->i2) #define I3 (Co_data->i3) static u_char orig_icode[256]; static u_char icode[256]; /*********** RHcode **********/ static u_char RHcode[37] = { /* RHcode[all others] */ 0x00, /* RHcode[C_D] */ 0x40, /* RHcode[C_A] */ 0x1f, /* RHcode[C_A_breve] */ 0x07, /* RHcode[C_A_circumflex] */ 0x07, /* skipped */ 0x00, /* RHcode[C_E] */ 0x17, /* RHcode[C_I] */ 0x07, /* RHcode[C_E_circumflex] */ 0x07, /* RHcode[C_O] */ 0x37, /* RHcode[C_U] */ 0x27, /* RHcode[C_O_circumflex] */ 0x07, /* RHcode[C_O_horn] */ 0x07, /* RHcode[C_U_horn] */ 0x07, /* RHcode[C_Y] */ 0x07, /* RHcode[C_d] */ 0x40, /* RHcode[C_a] */ 0x1f, /* RHcode[C_a_breve] */ 0x07, /* RHcode[C_a_circumflex] */ 0x07, /* skipped */ 0x00, /* RHcode[C_e] */ 0x17, /* RHcode[C_i] */ 0x07, /* RHcode[C_e_circumflex] */ 0x07, /* RHcode[C_o] */ 0x37, /* RHcode[C_u] */ 0x27, /* RHcode[C_o_circumflex] */ 0x07, /* RHcode[C_o_horn] */ 0x07, /* RHcode[C_u_horn] */ 0x07, /* RHcode[C_y] */ 0x07, /* RHcode[CO_ACUTE] */ 0x00, /* RHcode[CO_GRAVE] */ 0x00, /* RHcode[CO_HOOK_ABOVE] */ 0x00, /* RHcode[CO_TILDE] */ 0x00, /* RHcode[CO_DOT_BELOW] */ 0x00, /* RHcode[CO_BREVE] */ 0x07, /* RHcode[CO_CIRCUMFLEX] */ 0x07, /* RHcode[CO_HORN] */ 0x07, }; /*********** LHcode **********/ static u_char LHcode[37] = { /* LHcode[all others] */ 0x00, /* LHcode[C_D] */ 0x40, /* LHcode[C_A] */ 0x00, /* LHcode[C_A_breve] */ 0x00, /* LHcode[C_A_circumflex] */ 0x00, /* skipped */ 0x00, /* LHcode[C_E] */ 0x00, /* LHcode[C_I] */ 0x00, /* LHcode[C_E_circumflex] */ 0x00, /* LHcode[C_O] */ 0x00, /* LHcode[C_U] */ 0x00, /* LHcode[C_O_circumflex] */ 0x00, /* LHcode[C_O_horn] */ 0x00, /* LHcode[C_U_horn] */ 0x00, /* LHcode[C_Y] */ 0x00, /* LHcode[C_d] */ 0x40, /* LHcode[C_a] */ 0x00, /* LHcode[C_a_breve] */ 0x00, /* LHcode[C_a_circumflex] */ 0x00, /* skipped */ 0x00, /* LHcode[C_e] */ 0x00, /* LHcode[C_i] */ 0x00, /* LHcode[C_e_circumflex] */ 0x00, /* LHcode[C_o] */ 0x00, /* LHcode[C_u] */ 0x00, /* LHcode[C_o_circumflex] */ 0x00, /* LHcode[C_o_horn] */ 0x00, /* LHcode[C_u_horn] */ 0x00, /* LHcode[C_y] */ 0x00, /* LHcode[CO_ACUTE] */ 0x01, /* LHcode[CO_GRAVE] */ 0x02, /* LHcode[CO_HOOK_ABOVE] */ 0x03, /* LHcode[CO_TILDE] */ 0x04, /* LHcode[CO_DOT_BELOW] */ 0x05, /* LHcode[CO_BREVE] */ 0x08, /* LHcode[CO_CIRCUMFLEX] */ 0x10, /* LHcode[CO_HORN] */ 0x20, }; /*********** offset **********/ static u_char offset[37] = { /* offset[all others] */ 0, /* offset[C_D] */ 4, /* offset[C_A] */ 0, /* offset[C_A_breve] */ 0, /* offset[C_A_circumflex] */ 0, /* skipped */ 0, /* offset[C_E] */ 0, /* offset[C_I] */ 0, /* offset[C_E_circumflex] */ 0, /* offset[C_O] */ 0, /* offset[C_U] */ 0, /* offset[C_O_circumflex] */ 0, /* offset[C_O_horn] */ 0, /* offset[C_U_horn] */ 0, /* offset[C_Y] */ 0, /* offset[C_d] */ 4, /* offset[C_a] */ 0, /* offset[C_a_breve] */ 0, /* offset[C_a_circumflex] */ 0, /* skipped */ 0, /* offset[C_e] */ 0, /* offset[C_i] */ 0, /* offset[C_e_circumflex] */ 0, /* offset[C_o] */ 0, /* offset[C_u] */ 0, /* offset[C_o_circumflex] */ 0, /* offset[C_o_horn] */ 0, /* offset[C_u_horn] */ 0, /* offset[C_y] */ 0, /* offset[CO_ACUTE] */ 0, /* offset[CO_GRAVE] */ 0, /* offset[CO_HOOK_ABOVE] */ 0, /* offset[CO_TILDE] */ 0, /* offset[CO_DOT_BELOW] */ 0, /* offset[CO_BREVE] */ 1, /* offset[CO_CIRCUMFLEX] */ 2, /* offset[CO_HORN] */ 3, }; /****** Resultant table *******/ static u_char table[29][6] = { /* 00 */ { 0, 0, 0, 0, 0, 0 }, /* save a subtraction to get the index */ /****** upper case *******/ /* 01 */ { C_D, 0, 0, 0, 0, 0}, /* 02 */ { C_A, C_A_acute, C_A_grave, C_A_hook_above, C_A_tilde, C_A_dot_below }, /* 03 */ { C_A_breve, C_A_breve_acute, C_A_breve_grave, C_A_breve_hook_above, C_A_breve_tilde, C_A_breve_dot_below }, /* 04 */ { C_A_circumflex, C_A_circumflex_acute, C_A_circumflex_grave, C_A_circumflex_hook_above, C_A_circumflex_tilde, C_A_circumflex_dot_below }, /* 05 */ { C_D_bar, 0, 0, 0, 0, 0}, /* 06 */ { C_E, C_E_acute, C_E_grave, C_E_hook_above, C_E_tilde, C_E_dot_below }, /* 07 */ { C_I, C_I_acute, C_I_grave, C_I_hook_above, C_I_tilde, C_I_dot_below }, /* 08 */ { C_E_circumflex, C_E_circumflex_acute, C_E_circumflex_grave, C_E_circumflex_hook_above, C_E_circumflex_tilde, C_E_circumflex_dot_below }, /* 09 */ { C_O, C_O_acute, C_O_grave, C_O_hook_above, C_O_tilde, C_O_dot_below }, /* 10 */ { C_U, C_U_acute, C_U_grave, C_U_hook_above, C_U_tilde, C_U_dot_below }, /* 11 */ { C_O_circumflex, C_O_circumflex_acute, C_O_circumflex_grave, C_O_circumflex_hook_above, C_O_circumflex_tilde, C_O_circumflex_dot_below }, /* 12 */ { C_O_horn, C_O_horn_acute, C_O_horn_grave, C_O_horn_hook_above, C_O_horn_tilde, C_O_horn_dot_below }, /* 13 */ { C_U_horn, C_U_horn_acute, C_U_horn_grave, C_U_horn_hook_above, C_U_horn_tilde, C_U_horn_dot_below }, /* 14 */ { C_Y, C_Y_acute, C_Y_grave, C_Y_hook_above, C_Y_tilde, C_Y_dot_below }, /******* lower case ******/ /* 15 */ { C_d, 0, 0, 0, 0, 0}, /* 16 */ { C_a, C_a_acute, C_a_grave, C_a_hook_above, C_a_tilde, C_a_dot_below }, /* 17 */ { C_a_breve, C_a_breve_acute, C_a_breve_grave, C_a_breve_hook_above, C_a_breve_tilde, C_a_breve_dot_below }, /* 18 */ { C_a_circumflex, C_a_circumflex_acute, C_a_circumflex_grave, C_a_circumflex_hook_above, C_a_circumflex_tilde, C_a_circumflex_dot_below }, /* 19 */ { C_d_bar, 0, 0, 0, 0, 0}, /* 20 */ { C_e, C_e_acute, C_e_grave, C_e_hook_above, C_e_tilde, C_e_dot_below }, /* 21 */ { C_i, C_i_acute, C_i_grave, C_i_hook_above, C_i_tilde, C_i_dot_below }, /* 22 */ { C_e_circumflex, C_e_circumflex_acute, C_e_circumflex_grave, C_e_circumflex_hook_above, C_e_circumflex_tilde, C_e_circumflex_dot_below }, /* 23 */ { C_o, C_o_acute, C_o_grave, C_o_hook_above, C_o_tilde, C_o_dot_below }, /* 24 */ { C_u, C_u_acute, C_u_grave, C_u_hook_above, C_u_tilde, C_u_dot_below }, /* 25 */ { C_o_circumflex, C_o_circumflex_acute, C_o_circumflex_grave, C_o_circumflex_hook_above, C_o_circumflex_tilde, C_o_circumflex_dot_below }, /* 26 */ { C_o_horn, C_o_horn_acute, C_o_horn_grave, C_o_horn_hook_above, C_o_horn_tilde, C_o_horn_dot_below }, /* 27 */ { C_u_horn, C_u_horn_acute, C_u_horn_grave, C_u_horn_hook_above, C_u_horn_tilde, C_u_horn_dot_below }, /* 28 */ { C_y, C_y_acute, C_y_grave, C_y_hook_above, C_y_tilde, C_y_dot_below }, }; /* end of table[][] */ u_char FAR PASCAL #ifdef ANSI_C vncompose(Co_Data FAR *Co_data, u_char inchar, int FAR *fl_compose, int FAR *fl_erase) #else vncompose(Co_data, inchar, fl_compose, fl_erase) Co_Data FAR *Co_data; u_char inchar; int FAR *fl_compose; int FAR *fl_erase; #endif { u_char tonemark; while (1) { switch(C_state) { /***************************************/ case CO_ST_LEVEL1: C1 = inchar; I1 = icode[C1]; if (I1 == 0 || I1 > 28) { /* won't compose w/ anything, e.g., "n" */ *fl_compose = 0; /* not composing */ } else { /* C1 might compose, e.g., "e" */ *fl_compose = 1; C_state = CO_ST_LEVEL2; } *fl_erase = 0; /* no erase */ return(C1); /***************************************/ case CO_ST_LEVEL2: C2 = inchar; I2 = icode[C2]; if ((RHcode[I1] & LHcode[I2]) == 0) { /* C1 & C2 won't combine, e.g., en */ C_state = CO_ST_LEVEL1; /* go back to level 1 and process */ break; } /* C1 & C2 do combine, e.g., e^ or e' */ I1 = I1 + offset[I2]; if (LHcode[I2] & 0x38) { /* C2 is a modifier, e.g., e^ */ C_state = CO_ST_LEVEL3; *fl_compose = 1; } else { /* C2 is a tone mark, e.g., e' */ *fl_compose = 0; C_state = CO_ST_LEVEL1; } tonemark = LHcode[I2] & (u_char) 0x07; *fl_erase = 1; return(table[I1][tonemark]); /***************************************/ case CO_ST_LEVEL3: C_state = CO_ST_LEVEL1; C3 = inchar; I3 = icode[C3]; tonemark = LHcode[I3] & (u_char) 0x07; if (tonemark == 0) { /* C3 is not a tone mark, e.g., e^n */ break; } /* C3 is a tone mark, e.g., e^' */ *fl_compose = 0; *fl_erase = 1; return(table[I1][tonemark]); } } /* forever */ } void FAR PASCAL #ifdef ANSI_C vncompose_init(Co_Data FAR *Co_data) #else vncompose_init(Co_data) Co_Data FAR *Co_data; #endif { int n; u_char *ptr1, *ptr2; C_state = CO_ST_LEVEL1; /*********** icode **********/ for (n = sizeof(icode); n; n--) { orig_icode[n] = 0; } orig_icode[C_D] = 1; orig_icode[C_A] = 2; orig_icode[C_A_breve] = 3; orig_icode[C_A_circumflex] = 4; orig_icode[C_E] = 6; orig_icode[C_I] = 7; orig_icode[C_E_circumflex] = 8; orig_icode[C_O] = 9; orig_icode[C_U] = 10; orig_icode[C_O_circumflex] = 11; orig_icode[C_O_horn] = 12; orig_icode[C_U_horn] = 13; orig_icode[C_Y] = 14; orig_icode[C_d] = 15; orig_icode[C_a] = 16; orig_icode[C_a_breve] = 17; orig_icode[C_a_circumflex] = 18; orig_icode[C_e] = 20; orig_icode[C_i] = 21; orig_icode[C_e_circumflex] = 22; orig_icode[C_o] = 23; orig_icode[C_u] = 24; orig_icode[C_o_circumflex] = 25; orig_icode[C_o_horn] = 26; orig_icode[C_u_horn] = 27; orig_icode[C_y] = 28; orig_icode[CO_ACUTE] = 29; orig_icode[CO_GRAVE] = 30; orig_icode[CO_HOOK_ABOVE] = 31; orig_icode[CO_TILDE] = 32; orig_icode[CO_DOT_BELOW] = 33; orig_icode[CO_BREVE] = 34; orig_icode[CO_CIRCUMFLEX] = 35; orig_icode[CO_HORN] = 36; for (n = sizeof(icode); n; n--) { icode[n] = orig_icode[n]; } /*********** characters used for diacritics **********/ Co_data->acute = CO_ACUTE; Co_data->grave = CO_GRAVE; Co_data->hook_above = CO_HOOK_ABOVE; Co_data->tilde = CO_TILDE; Co_data->dot_below = CO_DOT_BELOW; Co_data->breve = CO_BREVE; Co_data->circumflex = CO_CIRCUMFLEX; Co_data->horn = CO_HORN; } /* * vncompose_set() allows a character to be specified for a particular * diacritic. The caller must pass in the Co_data composition structure. * It operates by swapping the icode[] index of the characters. * If successful, it returns 1. Else zero. * */ int FAR PASCAL #ifdef ANSI_C vncompose_set(int diacritic, u_char newchar, Co_Data FAR *Co_data) #else vncompose_set(diacritic, newchar, Co_data) int diacritic; u_char newchar; Co_Data FAR *Co_data; #endif { u_char currentchar; u_char FAR *ptr; switch(diacritic) { case CO_BREVE: currentchar = Co_data->breve; ptr = (u_char FAR *) &(Co_data->breve); break; case CO_CIRCUMFLEX: currentchar = Co_data->circumflex; ptr = (u_char FAR *) &(Co_data->circumflex); break; case CO_HORN: currentchar = Co_data->horn; ptr = (u_char FAR *) &(Co_data->horn); break; case CO_ACUTE: currentchar = Co_data->acute; ptr = (u_char FAR *) &(Co_data->acute); break; case CO_GRAVE: currentchar = Co_data->grave; ptr = (u_char FAR *) &(Co_data->grave); break; case CO_HOOK_ABOVE: currentchar = Co_data->hook_above; ptr = (u_char FAR *) &(Co_data->hook_above); break; case CO_TILDE: currentchar = Co_data->tilde; ptr = (u_char FAR *) &(Co_data->tilde); break; case CO_DOT_BELOW: currentchar = Co_data->dot_below; ptr = (u_char FAR *) &(Co_data->dot_below); break; default: return 0; } if (newchar != currentchar) { icode[newchar] = icode[currentchar]; icode[currentchar] = orig_icode[currentchar]; *ptr = newchar; } return(1); } /* vncompose_set */