Open Chinese Convert
0.4.3
A project for conversion between Traditional and Simplified Chinese
|
00001 /* 00002 * Open Chinese Convert 00003 * 00004 * Copyright 2010-2013 BYVoid <byvoid@byvoid.com> 00005 * 00006 * Licensed under the Apache License, Version 2.0 (the "License"); 00007 * you may not use this file except in compliance with the License. 00008 * You may obtain a copy of the License at 00009 * 00010 * http://www.apache.org/licenses/LICENSE-2.0 00011 * 00012 * Unless required by applicable law or agreed to in writing, software 00013 * distributed under the License is distributed on an "AS IS" BASIS, 00014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00015 * See the License for the specific language governing permissions and 00016 * limitations under the License. 00017 */ 00018 00019 #include "config_reader.h" 00020 #include "dict_group.h" 00021 #include "dict_chain.h" 00022 00023 #define LINE_BUFFER_SIZE 8192 00024 #define CONFIG_DICT_TYPE_OCD "OCD" 00025 #define CONFIG_DICT_TYPE_TEXT "TEXT" 00026 00027 static config_error errnum = CONFIG_ERROR_VOID; 00028 00029 static int qsort_dictionary_buffer_cmp(const void* a, const void* b) { 00030 if (((DictMeta*)a)->index < ((DictMeta*)b)->index) { 00031 return -1; 00032 } 00033 if (((DictMeta*)a)->index > ((DictMeta*)b)->index) { 00034 return 1; 00035 } 00036 return ((DictMeta*)a)->stamp < ((DictMeta*)b)->stamp ? -1 : 1; 00037 } 00038 00039 static int load_dictionary(Config* config) { 00040 if (config->dicts_count == 0) { 00041 return 0; 00042 } 00043 // Sort dictionaries 00044 qsort(config->dicts, 00045 config->dicts_count, 00046 sizeof(config->dicts[0]), 00047 qsort_dictionary_buffer_cmp); 00048 DictGroup* group = dict_chain_add_group(config->dict_chain); 00049 size_t last_index = 0; 00050 size_t i; 00051 for (i = 0; i < config->dicts_count; i++) { 00052 if (config->dicts[i].index > last_index) { 00053 last_index = config->dicts[i].index; 00054 group = dict_chain_add_group(config->dict_chain); 00055 } 00056 dict_group_load(group, 00057 config->dicts[i].file_name, 00058 config->dicts[i].dict_type); 00059 } 00060 return 0; 00061 } 00062 00063 static int parse_add_dict(Config* config, size_t index, const char* dictstr) { 00064 const char* pstr = dictstr; 00065 while (*pstr != '\0' && *pstr != ' ') { 00066 pstr++; 00067 } 00068 opencc_dictionary_type dict_type; 00069 if (strncmp(dictstr, CONFIG_DICT_TYPE_OCD, 00070 sizeof(CONFIG_DICT_TYPE_OCD) - 1) == 0) { 00071 dict_type = OPENCC_DICTIONARY_TYPE_DATRIE; 00072 } else if (strncmp(dictstr, CONFIG_DICT_TYPE_TEXT, 00073 sizeof(CONFIG_DICT_TYPE_OCD) - 1) == 0) { 00074 dict_type = OPENCC_DICTIONARY_TYPE_TEXT; 00075 } else { 00076 errnum = CONFIG_ERROR_INVALID_DICT_TYPE; 00077 return -1; 00078 } 00079 while (*pstr != '\0' && (*pstr == ' ' || *pstr == '\t')) { 00080 pstr++; 00081 } 00082 size_t i = config->dicts_count++; 00083 config->dicts[i].dict_type = dict_type; 00084 config->dicts[i].file_name = mstrcpy(pstr); 00085 config->dicts[i].index = index; 00086 config->dicts[i].stamp = config->stamp++; 00087 return 0; 00088 } 00089 00090 static int parse_property(Config* config, const char* key, const char* value) { 00091 if (strncmp(key, "dict", 4) == 0) { 00092 int index = 0; 00093 sscanf(key + 4, "%d", &index); 00094 return parse_add_dict(config, index, value); 00095 } else if (strcmp(key, "title") == 0) { 00096 free(config->title); 00097 config->title = mstrcpy(value); 00098 return 0; 00099 } else if (strcmp(key, "description") == 0) { 00100 free(config->description); 00101 config->description = mstrcpy(value); 00102 return 0; 00103 } 00104 errnum = CONFIG_ERROR_NO_PROPERTY; 00105 return -1; 00106 } 00107 00108 static int parse_line(const char* line, char** key, char** value) { 00109 const char* line_begin = line; 00110 while (*line != '\0' && (*line != ' ' && *line != '\t' && *line != '=')) { 00111 line++; 00112 } 00113 size_t key_len = line - line_begin; 00114 while (*line != '\0' && *line != '=') { 00115 line++; 00116 } 00117 if (*line == '\0') { 00118 return -1; 00119 } 00120 assert(*line == '='); 00121 *key = mstrncpy(line_begin, key_len); 00122 line++; 00123 while (*line != '\0' && (*line == ' ' || *line == '\t')) { 00124 line++; 00125 } 00126 if (*line == '\0') { 00127 free(*key); 00128 return -1; 00129 } 00130 *value = mstrcpy(line); 00131 return 0; 00132 } 00133 00134 static char* parse_trim(char* str) { 00135 for (; *str != '\0' && (*str == ' ' || *str == '\t'); str++) {} 00136 register char* prs = str; 00137 for (; *prs != '\0' && *prs != '\n' && *prs != '\r'; prs++) {} 00138 for (prs--; prs > str && (*prs == ' ' || *prs == '\t'); prs--) {} 00139 *(++prs) = '\0'; 00140 return str; 00141 } 00142 00143 static int parse(Config* config, const char* filename) { 00144 char* path = try_open_file(filename); 00145 if (path == NULL) { 00146 errnum = CONFIG_ERROR_CANNOT_ACCESS_CONFIG_FILE; 00147 return -1; 00148 } 00149 config->file_path = get_file_path(path); 00150 FILE* fp = fopen(path, "r"); 00151 assert(fp != NULL); 00152 free(path); 00153 skip_utf8_bom(fp); 00154 static char buff[LINE_BUFFER_SIZE]; 00155 while (fgets(buff, LINE_BUFFER_SIZE, fp) != NULL) { 00156 char* trimed_buff = parse_trim(buff); 00157 if ((*trimed_buff == ';') || (*trimed_buff == '#') || 00158 (*trimed_buff == '\0')) { 00159 /* Comment Line or empty line */ 00160 continue; 00161 } 00162 char* key = NULL, * value = NULL; 00163 if (parse_line(trimed_buff, &key, &value) == -1) { 00164 free(key); 00165 free(value); 00166 fclose(fp); 00167 errnum = CONFIG_ERROR_PARSE; 00168 return -1; 00169 } 00170 if (parse_property(config, key, value) == -1) { 00171 free(key); 00172 free(value); 00173 fclose(fp); 00174 return -1; 00175 } 00176 free(key); 00177 free(value); 00178 } 00179 fclose(fp); 00180 return 0; 00181 } 00182 00183 DictChain* config_get_dict_chain(Config* config) { 00184 if (config->dict_chain != NULL) { 00185 dict_chain_delete(config->dict_chain); 00186 } 00187 config->dict_chain = dict_chain_new(config); 00188 load_dictionary(config); 00189 return config->dict_chain; 00190 } 00191 00192 config_error config_errno(void) { 00193 return errnum; 00194 } 00195 00196 void config_perror(const char* spec) { 00197 perr(spec); 00198 perr("\n"); 00199 switch (errnum) { 00200 case CONFIG_ERROR_VOID: 00201 break; 00202 case CONFIG_ERROR_CANNOT_ACCESS_CONFIG_FILE: 00203 perror(_("Can not access configuration file")); 00204 break; 00205 case CONFIG_ERROR_PARSE: 00206 perr(_("Configuration file parse error")); 00207 break; 00208 case CONFIG_ERROR_NO_PROPERTY: 00209 perr(_("Invalid property")); 00210 break; 00211 case CONFIG_ERROR_INVALID_DICT_TYPE: 00212 perr(_("Invalid dictionary type")); 00213 break; 00214 default: 00215 perr(_("Unknown")); 00216 } 00217 } 00218 00219 Config* config_open(const char* filename) { 00220 Config* config = (Config*)malloc(sizeof(Config)); 00221 config->title = NULL; 00222 config->description = NULL; 00223 config->dicts_count = 0; 00224 config->stamp = 0; 00225 config->dict_chain = NULL; 00226 config->file_path = NULL; 00227 if (parse(config, filename) == -1) { 00228 config_close((Config*)config); 00229 return (Config*)-1; 00230 } 00231 return (Config*)config; 00232 } 00233 00234 void config_close(Config* config) { 00235 size_t i; 00236 for (i = 0; i < config->dicts_count; i++) { 00237 free(config->dicts[i].file_name); 00238 } 00239 free(config->title); 00240 free(config->description); 00241 free(config->file_path); 00242 free(config); 00243 }