19 #include "config_reader.h"
20 #include "dict_group.h"
21 #include "dict_chain.h"
23 #define LINE_BUFFER_SIZE 8192
24 #define CONFIG_DICT_TYPE_OCD "OCD"
25 #define CONFIG_DICT_TYPE_TEXT "TEXT"
27 static config_error errnum = CONFIG_ERROR_VOID;
29 static int qsort_dictionary_buffer_cmp(
const void* a,
const void* b) {
39 static int load_dictionary(
Config* config) {
40 if (config->dicts_count == 0) {
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;
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);
56 dict_group_load(group,
57 config->dicts[i].file_name,
58 config->dicts[i].dict_type);
63 static int parse_add_dict(
Config* config,
size_t index,
const char* dictstr) {
64 const char* pstr = dictstr;
65 while (*pstr !=
'\0' && *pstr !=
' ') {
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;
76 errnum = CONFIG_ERROR_INVALID_DICT_TYPE;
79 while (*pstr !=
'\0' && (*pstr ==
' ' || *pstr ==
'\t')) {
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++;
90 static int parse_property(
Config* config,
const char* key,
const char* value) {
91 if (strncmp(key,
"dict", 4) == 0) {
93 sscanf(key + 4,
"%d", &index);
94 return parse_add_dict(config, index, value);
95 }
else if (strcmp(key,
"title") == 0) {
97 config->title = mstrcpy(value);
99 }
else if (strcmp(key,
"description") == 0) {
100 free(config->description);
101 config->description = mstrcpy(value);
104 errnum = CONFIG_ERROR_NO_PROPERTY;
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 !=
'=')) {
113 size_t key_len = line - line_begin;
114 while (*line !=
'\0' && *line !=
'=') {
120 assert(*line ==
'=');
121 *key = mstrncpy(line_begin, key_len);
123 while (*line !=
'\0' && (*line ==
' ' || *line ==
'\t')) {
130 *value = mstrcpy(line);
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--) {}
143 static int parse(
Config* config,
const char* filename) {
144 char* path = try_open_file(filename);
146 errnum = CONFIG_ERROR_CANNOT_ACCESS_CONFIG_FILE;
149 config->file_path = get_file_path(path);
150 FILE* fp = fopen(path,
"r");
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')) {
162 char* key = NULL, * value = NULL;
163 if (parse_line(trimed_buff, &key, &value) == -1) {
167 errnum = CONFIG_ERROR_PARSE;
170 if (parse_property(config, key, value) == -1) {
184 if (config->dict_chain != NULL) {
185 dict_chain_delete(config->dict_chain);
187 config->dict_chain = dict_chain_new(config);
188 load_dictionary(config);
189 return config->dict_chain;
192 config_error config_errno(
void) {
196 void config_perror(
const char* spec) {
200 case CONFIG_ERROR_VOID:
202 case CONFIG_ERROR_CANNOT_ACCESS_CONFIG_FILE:
203 perror(_(
"Can not access configuration file"));
205 case CONFIG_ERROR_PARSE:
206 perr(_(
"Configuration file parse error"));
208 case CONFIG_ERROR_NO_PROPERTY:
209 perr(_(
"Invalid property"));
211 case CONFIG_ERROR_INVALID_DICT_TYPE:
212 perr(_(
"Invalid dictionary type"));
219 Config* config_open(
const char* filename) {
221 config->title = NULL;
222 config->description = NULL;
223 config->dicts_count = 0;
225 config->dict_chain = NULL;
226 config->file_path = NULL;
227 if (parse(config, filename) == -1) {
228 config_close((
Config*)config);
234 void config_close(
Config* config) {
236 for (i = 0; i < config->dicts_count; i++) {
237 free(config->dicts[i].file_name);
240 free(config->description);
241 free(config->file_path);