Open Chinese Convert  0.4.3
A project for conversion between Traditional and Simplified Chinese
/usr/src/RPM/BUILD/opencc-0.4.3/src/config_reader.c
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 }
 All Data Structures Files Functions Variables Defines