Open Chinese Convert 0.4.3 A project for conversion between Traditional and Simplified Chinese

- Main Page
- Related Pages
- Modules
- Data Structures
- Files
- Examples

- File List
- Globals

All Data Structures Files Functions Variables Groups Pages
config_reader.c
1 /*
2 * Open Chinese Convert
3 *
4 * Copyright 2010-2013 BYVoid <byvoid@byvoid.com>
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19 #include "config_reader.h"
20 #include "dict_group.h"
21 #include "dict_chain.h"
22
23 #define LINE_BUFFER_SIZE 8192
24 #define CONFIG_DICT_TYPE_OCD "OCD"
25 #define CONFIG_DICT_TYPE_TEXT "TEXT"
26
27 static config_error errnum = CONFIG_ERROR_VOID;
28
29 static int qsort_dictionary_buffer_cmp(const void* a, const void* b) {
30 if (((DictMeta*)a)->index < ((DictMeta*)b)->index) {
31 return -1;
32 }
33 if (((DictMeta*)a)->index > ((DictMeta*)b)->index) {
34 return 1;
35 }
36 return ((DictMeta*)a)->stamp < ((DictMeta*)b)->stamp ? -1 : 1;
37 }
38
39 static int load_dictionary(Config* config) {
40 if (config->dicts_count == 0) {
41 return 0;
42 }
43 // Sort dictionaries
44 qsort(config->dicts,
45 config->dicts_count,
46 sizeof(config->dicts[0]),
47 qsort_dictionary_buffer_cmp);
48 DictGroup* group = dict_chain_add_group(config->dict_chain);
49 size_t last_index = 0;
50 size_t i;
51 for (i = 0; i < config->dicts_count; i++) {
52 if (config->dicts[i].index > last_index) {
53 last_index = config->dicts[i].index;
54 group = dict_chain_add_group(config->dict_chain);
55 }
56 dict_group_load(group,
57 config->dicts[i].file_name,
58 config->dicts[i].dict_type);
59 }
60 return 0;
61 }
62
63 static int parse_add_dict(Config* config, size_t index, const char* dictstr) {
64 const char* pstr = dictstr;
65 while (*pstr != '\0' && *pstr != ' ') {
66 pstr++;
67 }
68 opencc_dictionary_type dict_type;
69 if (strncmp(dictstr, CONFIG_DICT_TYPE_OCD,
70 sizeof(CONFIG_DICT_TYPE_OCD) - 1) == 0) {
71 dict_type = OPENCC_DICTIONARY_TYPE_DATRIE;
72 } else if (strncmp(dictstr, CONFIG_DICT_TYPE_TEXT,
73 sizeof(CONFIG_DICT_TYPE_OCD) - 1) == 0) {
74 dict_type = OPENCC_DICTIONARY_TYPE_TEXT;
75 } else {
76 errnum = CONFIG_ERROR_INVALID_DICT_TYPE;
77 return -1;
78 }
79 while (*pstr != '\0' && (*pstr == ' ' || *pstr == '\t')) {
80 pstr++;
81 }
82 size_t i = config->dicts_count++;
83 config->dicts[i].dict_type = dict_type;
84 config->dicts[i].file_name = mstrcpy(pstr);
85 config->dicts[i].index = index;
86 config->dicts[i].stamp = config->stamp++;
87 return 0;
88 }
89
90 static int parse_property(Config* config, const char* key, const char* value) {
91 if (strncmp(key, "dict", 4) == 0) {
92 int index = 0;
93 sscanf(key + 4, "%d", &index);
94 return parse_add_dict(config, index, value);
95 } else if (strcmp(key, "title") == 0) {
96 free(config->title);
97 config->title = mstrcpy(value);
98 return 0;
99 } else if (strcmp(key, "description") == 0) {
100 free(config->description);
101 config->description = mstrcpy(value);
102 return 0;
103 }
104 errnum = CONFIG_ERROR_NO_PROPERTY;
105 return -1;
106 }
107
108 static int parse_line(const char* line, char** key, char** value) {
109 const char* line_begin = line;
110 while (*line != '\0' && (*line != ' ' && *line != '\t' && *line != '=')) {
111 line++;
112 }
113 size_t key_len = line - line_begin;
114 while (*line != '\0' && *line != '=') {
115 line++;
116 }
117 if (*line == '\0') {
118 return -1;
119 }
120 assert(*line == '=');
121 *key = mstrncpy(line_begin, key_len);
122 line++;
123 while (*line != '\0' && (*line == ' ' || *line == '\t')) {
124 line++;
125 }
126 if (*line == '\0') {
127 free(*key);
128 return -1;
129 }
130 *value = mstrcpy(line);
131 return 0;
132 }
133
134 static char* parse_trim(char* str) {
135 for (; *str != '\0' && (*str == ' ' || *str == '\t'); str++) {}
136 register char* prs = str;
137 for (; *prs != '\0' && *prs != '\n' && *prs != '\r'; prs++) {}
138 for (prs--; prs > str && (*prs == ' ' || *prs == '\t'); prs--) {}
139 *(++prs) = '\0';
140 return str;
141 }
142
143 static int parse(Config* config, const char* filename) {
144 char* path = try_open_file(filename);
145 if (path == NULL) {
146 errnum = CONFIG_ERROR_CANNOT_ACCESS_CONFIG_FILE;
147 return -1;
148 }
149 config->file_path = get_file_path(path);
150 FILE* fp = fopen(path, "r");
151 assert(fp != NULL);
152 free(path);
153 skip_utf8_bom(fp);
154 static char buff[LINE_BUFFER_SIZE];
155 while (fgets(buff, LINE_BUFFER_SIZE, fp) != NULL) {
156 char* trimed_buff = parse_trim(buff);
157 if ((*trimed_buff == ';') || (*trimed_buff == '#') ||
158 (*trimed_buff == '\0')) {
159 /* Comment Line or empty line */
160 continue;
161 }
162 char* key = NULL, * value = NULL;
163 if (parse_line(trimed_buff, &key, &value) == -1) {
164 free(key);
165 free(value);
166 fclose(fp);
167 errnum = CONFIG_ERROR_PARSE;
168 return -1;
169 }
170 if (parse_property(config, key, value) == -1) {
171 free(key);
172 free(value);
173 fclose(fp);
174 return -1;
175 }
176 free(key);
177 free(value);
178 }
179 fclose(fp);
180 return 0;
181 }
182
183 DictChain* config_get_dict_chain(Config* config) {
184 if (config->dict_chain != NULL) {
185 dict_chain_delete(config->dict_chain);
186 }
187 config->dict_chain = dict_chain_new(config);
188 load_dictionary(config);
189 return config->dict_chain;
190 }
191
192 config_error config_errno(void) {
193 return errnum;
194 }
195
196 void config_perror(const char* spec) {
197 perr(spec);
198 perr("\n");
199 switch (errnum) {
200 case CONFIG_ERROR_VOID:
201 break;
202 case CONFIG_ERROR_CANNOT_ACCESS_CONFIG_FILE:
203 perror(_("Can not access configuration file"));
204 break;
205 case CONFIG_ERROR_PARSE:
206 perr(_("Configuration file parse error"));
207 break;
208 case CONFIG_ERROR_NO_PROPERTY:
209 perr(_("Invalid property"));
210 break;
211 case CONFIG_ERROR_INVALID_DICT_TYPE:
212 perr(_("Invalid dictionary type"));
213 break;
214 default:
215 perr(_("Unknown"));
216 }
217 }
218
219 Config* config_open(const char* filename) {
220 Config* config = (Config*)malloc(sizeof(Config));
221 config->title = NULL;
222 config->description = NULL;
223 config->dicts_count = 0;
224 config->stamp = 0;
225 config->dict_chain = NULL;
226 config->file_path = NULL;
227 if (parse(config, filename) == -1) {
228 config_close((Config*)config);
229 return (Config*)-1;
230 }
231 return (Config*)config;
232 }
233
234 void config_close(Config* config) {
235 size_t i;
236 for (i = 0; i < config->dicts_count; i++) {
237 free(config->dicts[i].file_name);
238 }
239 free(config->title);
240 free(config->description);
241 free(config->file_path);
242 free(config);
243 }
SDictChain
Definition: common.h:71
SDictMeta
Definition: common.h:77
SConfig
Definition: common.h:84
SDictGroup
Definition: common.h:64