1 /* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 3 * 4 * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved. 5 * 6 * The contents of this file are subject to the terms of either the GNU Lesser 7 * General Public License Version 2.1 only ("LGPL") or the Common Development and 8 * Distribution License ("CDDL")(collectively, the "License"). You may not use this 9 * file except in compliance with the License. You can obtain a copy of the CDDL at 10 * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at 11 * http://www.opensource.org/licenses/lgpl-license.php. See the License for the 12 * specific language governing permissions and limitations under the License. When 13 * distributing the software, include this License Header Notice in each file and 14 * include the full text of the License in the License file as well as the 15 * following notice: 16 * 17 * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE 18 * (CDDL) 19 * For Covered Software in this distribution, this License shall be governed by the 20 * laws of the State of California (excluding conflict-of-law provisions). 21 * Any litigation relating to this License shall be subject to the jurisdiction of 22 * the Federal Courts of the Northern District of California and the state courts 23 * of the State of California, with venue lying in Santa Clara County, California. 24 * 25 * Contributor(s): 26 * 27 * If you wish your version of this file to be governed by only the CDDL or only 28 * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to 29 * include this software in this distribution under the [CDDL or LGPL Version 2.1] 30 * license." If you don't indicate a single choice of license, a recipient has the 31 * option to distribute your version of this file under either the CDDL or the LGPL 32 * Version 2.1, or to extend the choice of license to its licensees as provided 33 * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL 34 * Version 2 license, then the option applies only if the new code is made subject 35 * to such option by the copyright holder. 36 */ 37 38 #ifdef HAVE_CONFIG_H 39 #include <config.h> 40 #endif 41 42 #include <algorithm> 43 #include <sys/types.h> 44 #include <sys/stat.h> 45 #include <unistd.h> 46 #include <cassert> 47 48 #include "imi_option_keys.h" 49 #include "imi_keys.h" 50 #include "imi_options.h" 51 #include "imi_view_classic.h" 52 53 CSimplifiedChinesePolicy::CSimplifiedChinesePolicy() 54 : m_bLoaded(false), m_bTried(false), m_csLevel(3), 55 m_bEnableFullSymbol(false), m_bEnableFullPunct(true) 56 {} 57 58 bool 59 CSimplifiedChinesePolicy::loadResources() 60 { 61 if (m_bLoaded || m_bTried) 62 return m_bLoaded; 63 64 bool suc = true; 65 suc &= m_coreData.loadResource (SUNPINYIN_DATA_DIR"/lm_sc.t3g", SUNPINYIN_DATA_DIR"/pydict_sc.bin"); 66 67 char path[256]; 68 const char *home = getenv ("HOME"); 69 snprintf (path, sizeof(path), "%s/%s", home, SUNPINYIN_USERDATA_DIR_PREFIX); 70 suc &= createDirectory(path); 71 72 CBigramHistory::initClass(); 73 snprintf (path, sizeof(path), "%s/%s/history", home, SUNPINYIN_USERDATA_DIR_PREFIX); 74 suc &= m_historyCache.loadFromFile (path); 75 76 snprintf (path, sizeof(path), "%s/%s/userdict", home, SUNPINYIN_USERDATA_DIR_PREFIX); 77 suc &= m_userDict.load (path); 78 79 m_bTried = true; 80 return m_bLoaded = suc; 81 } 82 83 CIMIContext * 84 CSimplifiedChinesePolicy::createContext() 85 { 86 CIMIContext* pic = new CIMIContext (); 87 pic->setCoreData (&m_coreData); 88 pic->setHistoryMemory (&m_historyCache); 89 pic->setUserDict (&m_userDict); 90 91 pic->setFullSymbolForwarding (m_bEnableFullSymbol); 92 pic->setGetFullSymbolOp (&m_getFullSymbolOp); 93 94 pic->setFullPunctForwarding (m_bEnableFullPunct); 95 pic->setGetFullPunctOp (&m_getFullPunctOp); 96 return pic; 97 } 98 99 void 100 CSimplifiedChinesePolicy::destroyContext (CIMIContext *context) 101 { 102 assert(context != NULL); 103 saveUserHistory(); 104 delete context; 105 } 106 107 bool 108 CSimplifiedChinesePolicy::onConfigChanged (const COptionEvent& event) 109 { 110 if (event.name == PINYIN_PUNCTMAPPING_MAPPINGS) { 111 CPairParser parser; 112 size_t num = parser.parse(event); 113 setPunctMapping(parser.get_pairs()); 114 return true; 115 } 116 return false; 117 } 118 119 bool 120 CSimplifiedChinesePolicy::saveUserHistory () 121 { 122 char path[256]; 123 const char *home = getenv ("HOME"); 124 snprintf (path, sizeof(path), "%s/%s/history", home, SUNPINYIN_USERDATA_DIR_PREFIX); 125 return m_historyCache.saveToFile(path); 126 } 127 128 bool 129 CSimplifiedChinesePolicy::createDirectory(char *path) { 130 char *p = path; 131 while (p = strchr(p+1, '/')) { 132 *p = 0; 133 if (access(path, F_OK) != 0 && mkdir(path, S_IRWXU) != 0) { 134 perror("unabled to mkdir() for user history"); 135 return false; 136 } 137 *p = '/'; 138 } 139 return !(access(path, F_OK) != 0 && mkdir(path, S_IRWXU) != 0); 140 } 141 142 CShuangpinSchemePolicy::CShuangpinSchemePolicy() 143 : m_shuangpinType(MS2003) 144 {} 145 146 bool 147 CQuanpinSchemePolicy::onConfigChanged(const COptionEvent& event) 148 { 149 if (event.name == QUANPIN_FUZZY_ENABLED) { 150 setFuzzyForwarding(event.get_bool()); 151 } else if (event.name == QUANPIN_FUZZY_PINYINS) { 152 CPairParser parser; 153 size_t num = parser.parse(event); 154 setFuzzyPinyinPairs(parser.get_pairs(), num); 155 } else if (event.name == QUANPIN_AUTOCORRECTION_ENABLED) { 156 setAutoCorrecting(event.get_bool()); 157 } else if (event.name == QUANPIN_AUTOCORRECTION_PINYINS) { 158 CPairParser parser; 159 size_t num = parser.parse(event); 160 setAutoCorrectionPairs(parser.get_pairs(), num); 161 } else { 162 return false; 163 } 164 return true; 165 } 166 167 bool 168 CShuangpinSchemePolicy::onConfigChanged(const COptionEvent& event) 169 { 170 if (event.name == SHUANGPIN_TYPE) { 171 setShuangpinType( (EShuangpinType) event.get_int()); 172 return true; 173 } 174 return false; 175 } 176 177 size_t 178 CPairParser::parse(const COptionEvent& event) 179 { 180 return parse(event.get_string_list()); 181 } 182 183 size_t 184 CPairParser::parse(const std::vector<std::string> pairs) 185 { 186 assert(m_free == m_buf); 187 188 size_t npairs = std::min(sizeof(m_pairs)/sizeof(m_pairs[0]), 189 pairs.size()); 190 memset(m_pairs, 0, sizeof(m_pairs)); 191 int i = 0; 192 for (;i < npairs; ++i) { 193 const std::string& pair = pairs[i]; 194 std::string::size_type found = pair.find(':'); 195 if (found == pair.npos) 196 continue; 197 const std::string key = pair.substr(0, found); 198 const std::string val = pair.substr(found+1); 199 char *skey = strdup(key); 200 char *sval = strdup(val); 201 if (skey && sval) { 202 m_pairs[2*i] = skey; 203 m_pairs[2*i+1] = sval; 204 } else { 205 // running out of memory 206 break; 207 } 208 } 209 // reclaim the used memory 210 m_free = m_buf; 211 return i; 212 } 213 214 const char* const* 215 CPairParser::get_pairs() const 216 { 217 return m_pairs; 218 } 219 220 char* 221 CPairParser::strdup(const std::string& s) 222 { 223 size_t len = s.length() + 1; 224 char* str = alloc(len); 225 if (str) { 226 strncpy(str, s.c_str(), s.length()); 227 str[s.length()] = '\0'; 228 } 229 return str; 230 } 231 232 char* 233 CPairParser::alloc(size_t size) 234 { 235 char *result = NULL; 236 char *new_free = m_free + size; 237 if (m_end > new_free) { 238 result = m_free; 239 m_free = new_free; 240 } 241 return result; 242 } 243