/* vi: set sw=4 ts=4: */ /* * CCE - Console Chinese Environment - * Copyright (C) 1998-2003 Rui He (rhe@3eti.com) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE TERRENCE R. LAMBERT BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include int EnableFuzzyPinyin; /* global option z-c-s zh-ch-sh */ unsigned char *InputKeyMap[] = { "", /* auto */ "abcdefghijklmnopqrstuvwxyz'" "`-/=\\", /* "012345", */ "abcdefghijklmnopqrstuvwxyz';" "`-/=\\", /* added ; for shuangpin */ "1qaz2wsxedcrfv5tgbyhn" "8ik,9ol.0p;/-" "ujm" " 6347", /* 7 is light tone */ "bpmfdtnlvkhg7c,./j;'s" "aorwiqzy890-=" "exu" " 2341", "2wsx3edcrfvtgb6yhnujm" "8ik,9ol.0p;/=" "-['" " qaz1", "1234567890-qwertyuiop" "fghjkl;zxcvbn" "asd" " m,./", "bpmfdtnlgkhjqxzcsr123" "a4567890o-=[;" "ewu" " ,./'", "bpmfdtnlvkhgvcgycjqws" "aorwiqzpmntlh" "exu" " dfjk", "bpmfdtnlgkhjvcjvcrzas" "yhgeiawomnkll" "exu" " dfjs", }; unsigned char Big5PhoneChars[]= "£t£u£v£w£x£y£z£{£|£}£~£¡£¢£££¤£¥£¦£§£¨£©£ª" "£«£¬£­£®£¯£°£±£²£³£´£µ£¶£·" "£¸£¹£º" "¡@£½£¾£¿£»"; unsigned char GBPhoneChars[] = "¨Å¨Æ¨Ç¨È¨É¨Ê¨Ë¨Ì¨Í¨Î¨Ï¨Ð¨Ñ¨Ò¨Ó¨Ô¨Õ¨Ö¨×¨Ø¨Ù" "¨Ú¨Û¨Ü¨Ý¨Þ¨ß¨à¨á¨â¨ã¨ä¨å¨æ" "¨ç¨è¨é" "¡¡£¯¡¦£Ü£®"; unsigned char *ZYSymbolToPYString[38] = { "", "b", "p", "m", "f", "d", "t", "n", "l", "g", "k", "h", "j", "q", "x", "zh", "ch", "sh", "r", "z", "c", "s", "a", "o", "e", "e" /* like ye*/, "ai", "ei", "ao", "ou", "an", "en", "ang", "eng", "er", "i", "u", "v", }; static int FindOnePinyin(u_char *py); static int ConvertOneSPToQP(int KBIndex, u_char *py, u_char *npy); int ConvertZhuyinStrToKeys(u_char *buf, u_char key[]) { int i, total = 0; unsigned char *p, *s; p = buf; while(*p == ' ' || *p == '\t') p++; if (*p != 0xA3 && *p != 0xA8) { fprintf(stderr, "ERROR! Not a valid phonetic symbol: *p=0x%02X%02X\n", *p, p[1]); return 0; } while(*p == 0xA3 || *p == 0xA8) /* A3 is Big5 A8 is GB/GBK */ { i = 1; s = (*p == 0xA3 ? Big5PhoneChars : GBPhoneChars); while(s) { if (strncmp(p, s, 2) == 0) { key[total++] = i; break; } s += 2; i++; } if (!s) fprintf(stderr, "ERROR NOT A VALID PHONETIC SYMBOL!\n"); p += 2; if (i > 37 || total >= MAX_ZY_LEN ) break; } if (key[total-1] < 38) /* last one not tone */ { if (*p == '0') { key[total++] = 42; /* 5th tone, light tone */ p++; } else if (*p >= '1' && *p <= '5') { key[total++] = (*p) - '1' + 38; p++; } else key[total++] = 38; /* no tone, will use 1st tone */ } key[total] = '\0'; return (u_int)p - (u_int)buf; } int IsValidPinyinZhuyinKey( int KBIndex, int EngPos, int BufLen, u_char ch ) { if (ch == KEYCODE_CONTROL_H || ch == KEYCODE_BACKSPACE /* BackSpace */ || strchr(InputKeyMap[KBIndex], ch)) /* a valid input key */ return 1; if (!IS_KB_PINYIN(KBIndex)) return 0; /* only pinyin supports PY++ style Eng-mode */ if (EngPos > 0) { if (VALID_ENG_CHARS(ch)) return 1; } else { if ((ch >= 'A' && ch <= 'Z') ) return 1; } return 0; } int ConvertOneET26OrHsu25Yin(int index, u_char key[], u_char nkey[]) { int i, offset = 0; u_short map, tmpyin, yin = 0; if (key[0] >= 1 && key[0] <= 34 && key[0] != 25) /* a valid bpmf...aoe non iuv */ { yin = (u_short)( key[0] << (5+2)); offset++; if ((key[1] >= 35 && key[1] <= 37) || key[1] == 25) /* i u v */ { tmpyin = yin | ((u_short)(key[1]==25? 1: key[1]-34) << 5); if (!ET26HSU25Map[index][tmpyin]) goto go_out; yin = tmpyin; offset++; } if (key[offset] >= 1 && key[offset] <=34) { tmpyin = yin | ((u_short)key[offset] << 0); if (!ET26HSU25Map[index][tmpyin]) goto go_out; yin = tmpyin; offset++; } } else if ((key[0] >= 35 && key[0] <= 37) || key[0] == 25) /* a valid iuv, we may have 3rd key */ { yin = (u_short)( (key[0]==25 ? 1 : key[0]-34) << 5); offset++; if (key[1] >= 1 && key[1] <= 34) /* a valid aoe stuff */ { tmpyin = yin | ( (u_short)key[1] << 0); if (!ET26HSU25Map[index][tmpyin]) goto go_out; yin = tmpyin; offset++; } } go_out: map = ET26HSU25Map[index][yin]; i = 0; if (map & BPMF_MASK) nkey[i++] = (map & BPMF_MASK) >> BPMF_OFFSET; if (map & IUV_MASK) nkey[i++] = ((map & IUV_MASK) >> IUV_OFFSET) + 34; if (map & AOE_MASK) nkey[i++] = ((map & AOE_MASK) >> AOE_OFFSET) + 21; switch(index) { case 0: /* ETen26 dfjk for tones */ if (key[offset] == 38) /*SPACE*/ nkey[i++] = 38; else if (key[offset] == 5) /* d */ nkey[i++] = 39; else if (key[offset] == 4) /* f */ nkey[i++] = 40; else if (key[offset] == 18) /* j */ nkey[i++] = 41; else if (key[offset] == 10) /* k */ nkey[i++] = 42; break; case 1: /* HSU25 dfjs for tones */ if (key[offset] == 38) /* SPACE*/ nkey[i++] = 38; else if (key[offset] == 5) /* d */ nkey[i++] = 39; else if (key[offset] == 4) /* f */ nkey[i++] = 40; else if (key[offset] == 12) /* j */ nkey[i++] = 41; else if (key[offset] == 21) /* s */ nkey[i++] = 42; break; } nkey[i] = 0; return i; } int ParseOneZhuyin(u_char key[], ZYString zhuyin, u_short yin[], u_short mask[]) { int offset = 0; u_short zy; zhuyin[0] = '\0'; yin[0] = 0; mask[0] = BPMF_MASK | IUV_MASK | AOE_MASK; /* default is exact-match except bpmfdtnlkghjqx */ if (key[0] >= 1 && key[0] <= 21) /* a valid bpmf... */ { yin[0] = (u_short)( key[0] << BPMF_OFFSET); offset++; if (key[1] >= 35 && key[1] <= 37) /* i u v */ { zy = ((u_short)(key[1]-34) << IUV_OFFSET); if (!ZYToPYMap[zy | yin[0]]) goto get_out; yin[0] |= zy; offset++; } if (key[offset] >= 22 && key[offset] <=34) { zy = ((u_short)(key[offset]-21) << AOE_OFFSET); if (!ZYToPYMap[zy | yin[0] ]) goto get_out; yin[0] |= zy; offset++; } } else if (key[0] >= 35 && key[0] <= 37) /* a valid iuv, we may have 3rd key */ { yin[0] = (u_short)( (key[0] - 34) << IUV_OFFSET); offset++; if (key[1] >= 22 && key[1] <= 34) /* a valid aoe */ { zy = ( (u_short)(key[1]-21) << AOE_OFFSET); if (!ZYToPYMap[zy | yin[0]]) goto get_out; yin[0] |= zy; offset++; } } else if (key[0] >= 22 && key[0] <= 34) /* a valid aoe... */ { yin[0] = (u_short)( (key[0]-21) << AOE_OFFSET); offset++; } get_out: if (offset == 1 && key[0] < 15) /* bpmfdtnlkghjqx 14 letters only, do prefix-match */ mask[0] &= ~(IUV_MASK | AOE_MASK); if (key[offset] >= 38 && key[offset] <= 42) { mask[0] |= (u_short)( 1 << (key[offset]-38 + TONE_OFFSET)); /*TONE_MASK; */ yin[0] |= (u_short)( 1 << (key[offset]-38 + TONE_OFFSET)); offset++; } if (key[0] <= 37) /* not starting with a tone symbol */ { strncpy(zhuyin, key, offset); zhuyin[offset] = '\0'; } return offset; } int ParseZhuyinKeys(int KBIndex, u_char key[], ZYString zhuyin[], u_short yin[], u_short mask[], int nMax) { int offset; int total = 0; while(key[0] && total < nMax) { if (KBIndex == KEYBOARD_MAP_ET26ZY || KBIndex == KEYBOARD_MAP_HSU25ZY) { u_char nkey[10]; /* for one zhuyin */ ConvertOneET26OrHsu25Yin(KBIndex - KEYBOARD_MAP_ET26ZY, key, nkey); offset = ParseOneZhuyin(nkey, zhuyin[total], yin+total, mask+total); } else offset = ParseOneZhuyin(key, zhuyin[total], yin+total, mask+total); if (key[0] <= 37) /* not starting with a tone symbol */ { key += offset; total++; } else key++; /* ignore this key! */ } /* while */ return total; } int ConvertOnePinyinToZhuyin( u_char pybuf[], int count, ZYString zy, /* huyin, */ u_short yin[], u_short mask[], u_char pystr[MAX_PY_LEN+3]) { int i, ahead, tone; int zykey = 0; u_char t; strncpy(pystr, pybuf, count); /* security patch! */ pystr[count] = '\0'; ahead = pybuf[0] - 'a'; for(i = 0; PYMap[ahead][i].key; i++) { if (!strcmp(pystr, PYMap[ahead][i].py)) /* full match */ { zykey = PYMap[ahead][i].zykey; break; } } if (zykey == 0) return count; /* no zhuyin map found, iuv? */ i = 0; if ((zy[0] = (zykey & BPMF_MASK) >> BPMF_OFFSET)) i++; /* 1~21 */ if ((zy[i] = (zykey & IUV_MASK) >> IUV_OFFSET)) zy[i++] += 34; /* 35~37 */ if ((zy[i] = (zykey & AOE_MASK) >> AOE_OFFSET)) zy[i++] += 21; /* 22~34 */ yin[0] = zykey; if ((count == 1 && strchr("bpmfdtnlkghjqxzcsryw", pybuf[0])) || (count == 2 && pystr[1] == 'h' && strchr("zcs", pybuf[0]))) /* zh/ch/sh? */ { mask[0] = BPMF_MASK; /* prefix match */ } else mask[0] = BPMF_MASK | IUV_MASK | AOE_MASK; /* exact match */ t = pybuf[count]; if (t >= '0' && t <= '5') { pystr[count++] = t; pystr[count] = '\0'; tone = (t == '0' ? 4 : t - '1'); /* 0~4 */ zy[i++] = 38 + tone; /* 38~42 */ mask[0] |= (u_short)( 1 << (tone + TONE_OFFSET)); yin[0] |= (u_short)( 1 << (tone + TONE_OFFSET)); } if (pybuf[count] == '\'') { if (!strchr("012345", pystr[count-1] )) /* will only allow one */ { pystr[count++] = '\''; pystr[count] = '\0'; } else count++; /* skip it */ } return count; } int ConvertPinyinKeysToZhuyin(int KBIndex, u_char pybuf[], ZYString zhuyin[], u_short yin[], u_short mask[], u_char pystr[][MAX_PY_LEN+3], SPString spstr[],int nMax) { int len, total = 0; int offset, count; u_char npybuf[MAX_PY_LEN+3]; len = strlen(pybuf); if (len < 1 || len > MAX_ZYPHRASE_LEN * MAX_PY_LEN ) return 0; while(*pybuf) { if (IS_KB_SHUANGPIN(KBIndex)) { int pycnt; count = ConvertOneSPToQP(KBIndex, pybuf, npybuf); pycnt = strlen(npybuf); if (pybuf[count] >= '0' && pybuf[count] <= '5') { count++; pycnt--; } if (pybuf[count] == '\'') { count++; pycnt--; } if (spstr) { strncpy(spstr[total], pybuf, count); /* save sp string */ spstr[total][count] = '\0'; } offset = ConvertOnePinyinToZhuyin(npybuf, pycnt, zhuyin[total], yin+total, mask+total, pystr[total]); if (offset > 0) { pybuf += count; /* shuangpin */ total++; } else pybuf++; /* ignore this key */ } else { count = FindOnePinyin(pybuf); offset = ConvertOnePinyinToZhuyin(pybuf, count, zhuyin[total], yin+total, mask+total, pystr[total]); if (offset > 0) { pybuf += offset; total++; } else pybuf++; /* ignore this key */ } } return total; } #ifdef ENABLE_IUV_PINYIN void HandleIUVPinyin(char *destpy, char *srcpy) { if (*srcpy == 'v') { *destpy++ = 'y'; *destpy++ = 'u'; srcpy++; /* v->yu */ } else if (*srcpy == 'i') { *destpy++ = 'y'; if (srcpy[1] == 'a' || srcpy[1] == 'o' || srcpy[1] == 'e') srcpy++; } else if (*srcpy == 'u') { *destpy++ = 'w'; if (srcpy[1] == 'a' || srcpy[1] == 'o') srcpy++; } while(*srcpy) /* copy the trailing */ *destpy++ = *srcpy++; *destpy = '\0'; } #endif static int FindOnePinyin(u_char *py) { int i, ahead, count, valid; u_char *py1; #ifdef ENABLE_IUV_PINYIN u_char ch; #endif py1 = py+1; /* first letter always valid */ #ifdef ENABLE_IUV_PINYIN ch = py[0]; /* first letter */ if (ch == 'v') { py[0] = 'u'; ahead = 'y' - 'a'; py1 = py; /* ->yuX */ } else if (ch == 'i') { ahead = 'y' - 'a'; if (py[1] != 'a' && py[1] != 'o' && py[1] != 'e') py1 = py; } else if (ch == 'u') { ahead = 'w' - 'a'; if (py[1] != 'a' && py[1] != 'o') py1 = py; } else #endif { ahead = py[0] - 'a'; if (py[1] == 'v' && py[2] == 'e') /* ve->ue jqxnl + ue (ue==ve) */ py[1] = 'u'; /* will change the display! */ } if (ahead < 0 || ahead > 25) return 0; /* not allowed to begins with ' */ for(count = 1; py1[count-1]; count++) { valid = 0; for(i=0; PYMap[ahead][i].key; i++) { if ( !strncmp(PYMap[ahead][i].py+1, py1, count) ) { valid = 1; break; } } if (!valid) break; } #ifdef ENABLE_IUV_PINYIN py[0] = ch; /* recover 'v' */ if (py1 == py) count--; /* count the leading y/w */ #endif return count; } static int FillExactMatchPinyinArray(u_char *py, int PYLen, u_short PYAry[]) { int TmpKey; int j; int ahead; int PYAryCnt; u_char ch, *curpy; ch = py[0]; ahead = ch - 'a'; if (ahead < 0 || ahead > 25) return -1; /* for safety, if not a-z */ PYAryCnt = 0 /* 1 */; /* starting from 0(prefix-match) */ PYAry[0] = 0; for(j=0; (TmpKey = PYMap[ahead][j].key); j++) { curpy = PYMap[ahead][j].py; if (!strcmp(py, curpy)) /* exact match, will have only one */ { PYAry[/* 0 */ PYAryCnt++] = TmpKey; /* only one possible */ } else if (ch == 'z' || ch == 'c' || ch == 's') /* special handling for zcs */ { if (py[1] != 'h') /* z/c/s only, will match zcsXYZ (x!= h if EnableFuzzyPinyin not on) */ { if (PYLen == 1 && curpy[1] != 'h') /* Do not match zh/ch/shXYZ */ PYAry[PYAryCnt++] = TmpKey; } else /*zh/ch/shXYZ */ { if (PYLen == 2 && curpy[1] == 'h') /* zh/ch/sh only, will match zcshXYZ */ PYAry[PYAryCnt++] = TmpKey; } } else if (PYLen == 1 && strchr("bpmfdtnlgkhjqxr", ch)) /* prefix-match, shengmu only */ { PYAry[PYAryCnt++] = TmpKey; } } /* for j */ PYAry[PYAryCnt] = 0; return PYAryCnt; } static int FillPrefixMatchPinyinArray(u_char *py, int PYLen, u_short PYAry[]) { int TmpKey; int j; int ahead; int PYAryCnt; u_char ch, *curpy; ch = py[0]; ahead = ch - 'a'; if (ahead < 0 || ahead > 25) return -1; /* for safety, if not a-z */ PYAryCnt = 1; PYAry[0] = 0; for(j=0; (TmpKey = PYMap[ahead][j].key); j++) { curpy = PYMap[ahead][j].py; if (!strcmp(py, curpy)) { PYAry[0] = TmpKey; /* only one possible */ } else if (PYLen == 1 || !strncmp(py, curpy, PYLen)) { PYAry[PYAryCnt++] = TmpKey; } else if (EnableFuzzyPinyin && (ch == 'z' || ch == 'c' || ch == 's')) { if (py[1] != 'h') /* z,c,s->zh,ch,sh */ { if (curpy[1] == 'h' && !strncmp(py+1, curpy+2, PYLen-1)) PYAry[PYAryCnt++] = TmpKey; } else /* zh,ch,sh->z,c,s */ { if (curpy[1] != 'h' && !strncmp(py+2, curpy+1, PYLen-2)) PYAry[PYAryCnt++] = TmpKey; } } } /* for j */ PYAry[PYAryCnt] = 0; return PYAryCnt; } int FindMatchPinyins(int KBIndex, u_char *py, u_short PYAry[]) { u_char str[MAX_PY_LEN+5]; int PYLen; int i, count, total; #ifdef ENABLE_IUV_PINYIN HandleIUVPinyin(str, py); /* i->yi, u->wu, v->yu */ #else if (strchr("iuv", py[0])) return -1; /* ignore the i/u/v beginning */ strcpy(str, py); /* won't overrun */ #endif PYLen = strlen(str); while (PYLen > 0 && strchr("012345'", str[PYLen-1])) str[--PYLen] = '\0'; /* ignore the tone and ' */ if (PYLen == 0) return -1; /* strange nothing? */ if (KBIndex == KEYBOARD_MAP_PINYIN) return FillPrefixMatchPinyinArray(str, PYLen, PYAry); count = FillExactMatchPinyinArray(str, PYLen, PYAry); if (count < 0) return -1; /* error */ total = count; if (EnableFuzzyPinyin) { if (strchr("zcs", str[0])) /* zcs/zhchsh fuzzy */ { if (str[1] != 'h') /* z/c/s */ { for(i = PYLen; i > 0; i--) str[i+1] = str[i]; str[1] = 'h'; PYLen++; } else /* zh/ch/sh */ { for(i = 2; i <= PYLen; i++) str[i-1] = str[i]; PYLen--; } count = FillExactMatchPinyinArray(str, PYLen, PYAry + total); if (count < 0) return -1; total += count; } } return total; } int ParsePinyinKeys( int KBIndex, char *pybuf, PYString pinyin[], SPString sp[]) { int len, total = 0; int count; u_char npybuf[MAX_PY_LEN+3]; len = strlen(pybuf); if (len < 1 || len > MAX_PYPHRASE_LEN * MAX_PY_LEN ) return 0; while(*pybuf) { if (IS_KB_SHUANGPIN(KBIndex)) { count = ConvertOneSPToQP(KBIndex, pybuf, npybuf); if (count > 0) { strncpy(pinyin[total], npybuf, sizeof(pinyin[0])); if (pybuf[count] == '\'') count++; strncpy(sp[total], pybuf, count); sp[total][count] = '\0'; } } else { count = FindOnePinyin(pybuf); if (count > 0) { if (pybuf[count] == '\'') count++; /* add it at the end */ strncpy(pinyin[total], pybuf, count); pinyin[total][count] = '\0'; } } if (count > 0) { pybuf += count; total++; } else pybuf++; /* skip this key */ } return total; } int ConvertZhuyinKeysToPinyin( int KBIndex, char *key, PYString pinyin[], ZYString zhuyin[]) { int len, i, py, total = 0; int count; u_short yin[MAX_PYPHRASE_LEN+1], mask[MAX_PYPHRASE_LEN+1]; len = strlen(key); if (len < 1 || len > MAX_PYPHRASE_LEN * MAX_ZY_LEN ) return 0; count = ParseZhuyinKeys(KBIndex, key, zhuyin, yin, mask, MAX_PYPHRASE_LEN); for(i = 0; i < count; i++) { py = ZYToPYMap[yin[i] & 0x07FF]; if (py) { strcpy(pinyin[total++], GET_PYMAP_PY(py)); } } return total; } static int ConvertOneSPToQP(int KBIndex, u_char *py, u_char *npy) { int count = 1; int n, k1, k2, len; if (py[0] < 'a' || py[0] > 'z') return 0; k1 = py[0]-'a'; /* 0 ~ 25 */ k2 = (py[1] == ';' ? 27 : (py[1] >= 'a' && py[1] <= 'z' ? py[1]-'a'+1: 0) ); /* 0,1-26(a-z), 27(;) */ n = SPToPYKeyMap[k1][k2]; if (k2 > 0 && n == 0) /* two keys not valid */ { k2 = 0; /* single key only */ n = SPToPYKeyMap[k1][0]; } if (n > 0) { strcpy(npy, GET_PYMAP_PY(n)); /* copy the py, won't overflow */ len = strlen(npy); } else { npy[0] = py[0]; /* just copy the 1st letter! (like just input aoeiuv and it's not defined for ShengMu) */ npy[1] = '\0'; len = 1; } if (k2 > 0) count = 2; /* two letters */ if (py[count] >= '0' && py[count] <= '5') { npy[len++] = py[count++]; npy[len] = '\0'; } if (py[count] == '\'') { npy[len++] = '\''; npy[len] = '\0'; } return (k2 > 0 ? 2 : 1); } static u_char ShengMu[26][3]; /* aoeiuv is open 18+yw+6=26 */ static int SearchPYKey(u_char *py) { int i; int ahead = py[0] - 'a'; for(i=0; PYMap[ahead][i].key; i++) { if ( !strcmp(PYMap[ahead][i].py, py) ) /* exact match */ return (ahead << 8) | (i+1); } return 0; /* not found */ } static int AddToSPTable(u_char *py, int l1, int l2) { int n = SearchPYKey(py); if (n == 0) { return -1; } if (SPToPYKeyMap[l1][l2] && strlen(py) < strlen(GET_PYMAP_PY(SPToPYKeyMap[l1][l2]))) return -1; /* will keep the long one(er, etc), not aoev etc */ SPToPYKeyMap[l1][l2] = n; return 0; } static int AddToShuangPinTable(u_char *py, u_char *key) { u_char pystr[MAX_PY_LEN+4]; int i, l1, l2; l1 = (key[0] == ';' ? 26: key[0] - 'a'); if (!strcmp(py, "zh") || !strcmp(py, "ch") || !strcmp(py, "sh")) { if (ShengMu[l1][0]) /* already has a mapping */ { fprintf(stderr, "%c is used for shengmu %s already!\n", key[0], ShengMu[l1]); return -1; } else strncpy(ShengMu[l1], py, sizeof(ShengMu[0])); } else if (!key[1]) /* key len == 1, YunMu definition sometimes they use a different letter for v(DOS/MSPY) */ { for(i = 0; i < 26; i++) { if (!ShengMu[i][0]) continue; /* skip */ strcpy(pystr, ShengMu[i]); /* won't overflow, tested length before */ strcat(pystr, py); AddToSPTable(pystr, i, l1+1); } return 0; } else /* 0-ShengMu definition */ { l2 = (key[1] == ';' ? 27: key[1]-'a'+1); AddToSPTable(py, l1, l2); return 0; } return -1; } int LoadShuangPinData(u_char *filename) { u_char *p, *py, *l; u_char buf[128]; FILE *fp; int i, n; if (!filename || !(fp = fopen(filename, R_CNTRL))) return -1; fprintf(stderr, "CCE> Now loading ShuangPin map file %s\n", filename); memset(SPToPYKeyMap, 0, sizeof(SPToPYKeyMap)); memset(ShengMu, 0, sizeof(ShengMu)); for(i = 0; i < 26; i++) ShengMu[i][0] = ( strchr("aoeiuv", i+'a') ? '\0' : i+'a'); while(!feof(fp)) { if (!fgets(buf, sizeof(buf), fp)) break; /* eof? */ p = buf; while (*p == ' ' || *p == '\t') p++; if (!*p || !((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z'))) continue; /* ignore everything except */ py = p; l = NULL; while(*p) { *p = tolower(*p); if (*p == '=' && l == NULL) { *p++ = '\0'; /* terminate the py string */ l = p; /* l is the letter string */ continue; } if ((l == NULL && (*p < 'a' || *p > 'z')) || (l && *p != ';' && (*p < 'a' || *p > 'z'))) { *p = '\0'; /* terminate l */ break; } p++; } if (l == NULL || !py[0] || !l[0] || strlen(py) > 4 || strlen(l) > 2) { fprintf(stderr, "Error shuangpin definition: %s=%s\n", py, l); continue; } AddToShuangPinTable(py, l); } AddToShuangPinTable("a", "a"); AddToShuangPinTable("o", "o"); AddToShuangPinTable("e", "e"); AddToShuangPinTable("i", "i"); AddToShuangPinTable("u", "u"); AddToShuangPinTable("v", "v"); for(i = 0; i < 26; i++) { n = 0; if (ShengMu[i][0]) n = SearchPYKey(ShengMu[i]); else { } if (n == 0) continue; /* not a valid one!? */ SPToPYKeyMap[i][0] = n; } fclose(fp); return 0; } #define INDEX2CAPITAL(j) ((j) == 0 ? ' ' : ((j) == 27 ? ';' : (j)+'A'-1)) void PrintSPKeyMapTable(FILE *fp) { int i,j; if (!fp) return; fprintf(fp, "\nu_short SPToPYKeyMap[26][28]=\n" ); fprintf(fp, "{ /* First Key: a-z(0-25) Second Key: none(0) a-z(1-26) ;(27) */\n"); for(i = 0; i < 26; i++) { fprintf(fp, "\n { "); for(j = 0; j < 28; j++) { fprintf(fp, "0x%04X,%s", SPToPYKeyMap[i][j], j%8==7? "\n " : " "); } fprintf(fp, "}, /* %2d: %c */\n", i, i+'a'); } fprintf(fp, "};\n"); } void TestShuangPinCompleteness(FILE *fout) { int i, j, m, n; int found, m1, n1; fprintf(stderr, "\nTesting ShuangPin Table...\n"); for(i = 0; i < 26; i++) { for(j = 0; PYMap[i][j].key; j++) { found = m1 = n1 = 0; for(m = 0; m < 26; m++) for(n = 0; n < 28; n++) { if (!strcmp(GET_PYMAP_PY(SPToPYKeyMap[m][n]), PYMap[i][j].py)) { if (found) { /* duplicate SP->PY map found */ fprintf(stderr, "Duplicate SP To PY map detected: %s -> %c%c & %c%c.\n", PYMap[i][j].py, INDEX2CAPITAL(m1+1), INDEX2CAPITAL(n1), INDEX2CAPITAL(m+1), INDEX2CAPITAL(n)); } else { found = 1; m1 = m; n1 = n; } } } if (!found) fprintf(stderr, "Pinyin %s not in SPToPYMap.\n", PYMap[i][j].py); } } }