summaryrefslogtreecommitdiffstats
path: root/src/rccxml.c
diff options
context:
space:
mode:
authorSuren A. Chilingaryan <csa@dside.dyndns.org>2005-07-05 03:15:53 +0000
committerSuren A. Chilingaryan <csa@dside.dyndns.org>2005-07-05 03:15:53 +0000
commit9922cef1af71786ae788903b52a8968e5775d510 (patch)
treebadf23fc2701946b61df1d15227736783e44a754 /src/rccxml.c
parenta21deef1c62467b21500f94dfb2ab3d58e69cb85 (diff)
downloadlibrcc-9922cef1af71786ae788903b52a8968e5775d510.tar.gz
librcc-9922cef1af71786ae788903b52a8968e5775d510.tar.bz2
librcc-9922cef1af71786ae788903b52a8968e5775d510.tar.xz
librcc-9922cef1af71786ae788903b52a8968e5775d510.zip
Save / Load
Diffstat (limited to 'src/rccxml.c')
-rw-r--r--src/rccxml.c464
1 files changed, 464 insertions, 0 deletions
diff --git a/src/rccxml.c b/src/rccxml.c
new file mode 100644
index 0000000..8283a39
--- /dev/null
+++ b/src/rccxml.c
@@ -0,0 +1,464 @@
+#include <stdio.h>
+#include <stdarg.h>
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libxml/xpath.h>
+
+#include "internal.h"
+#include "rccconfig.h"
+
+extern char *rcc_home_dir;
+
+#define MAX_HOME_CHARS 96
+#define XPATH_LANGUAGE "//Language[@name]"
+
+static xmlDocPtr xmlctx = NULL;
+
+static const char *rccXmlGetText(xmlNodePtr node) {
+ if ((node)&&(node->children)&&(node->children->type == XML_TEXT_NODE)&&(node->children->content)) return node->children->content;
+}
+
+int rccXmlInit() {
+ FILE *f;
+ char config[MAX_HOME_CHARS + 32];
+
+ xmlXPathContextPtr xpathctx;
+ xmlXPathObjectPtr obj;
+ xmlNodeSetPtr node_set;
+ unsigned long i, nnodes;
+ xmlNodePtr cnode, pnode, node;
+ xmlAttrPtr attr;
+ const char *lang, *fullname;
+ unsigned int pos, cpos, npos;
+
+ xmlInitParser();
+ xmlInitCharEncodingHandlers();
+ xmlKeepBlanksDefault(0);
+
+ if (strlen(rcc_home_dir)>MAX_HOME_CHARS) config[0] = 0;
+ else {
+ sprintf(config, "%s/.rcc/rcc.xml", rcc_home_dir);
+ f = fopen(config, "r");
+ if (f) fclose(f);
+ else config[0] = 0;
+ }
+ if (!config[0]) {
+ strcpy(config, "/etc/rcc.xml");
+ f = fopen(config, "r");
+ if (f) fclose(f);
+ else config[0] = 0;
+ }
+
+
+ // Load Extra Languages
+ if (config[0]) {
+ xmlctx = xmlReadFile(config, NULL, 0);
+ if (!xmlctx) goto clear;
+
+ xpathctx = xmlXPathNewContext(xmlctx);
+ if (!xpathctx) goto clear;
+
+ obj = xmlXPathEvalExpression(XPATH_LANGUAGE, xpathctx);
+ if (!obj) goto clear;
+
+ node_set = obj->nodesetval;
+ if (!node_set) return 0;
+
+ for (pos = 0; rcc_default_languages[pos].sn; pos++);
+ if (pos == RCC_MAX_LANGUAGES) goto clear;
+
+ for (npos = 0; rcc_default_language_names[npos].sn; npos++);
+ puts("+++");
+
+
+ nnodes = node_set->nodeNr;
+ for (i=0;i<nnodes;i++) {
+ pnode = node_set->nodeTab[i];
+ attr = xmlHasProp(pnode, "name");
+ lang = attr->children->content;
+
+ if ((!lang)||(!lang[0])) continue;
+ puts(lang);
+
+ for (cpos=1,fullname=NULL,node=pnode->children;node;node=node->next) {
+ if (node->type != XML_ELEMENT_NODE) continue;
+ puts(node->name);
+ if (!xmlStrcmp(node->name, "Charsets")) {
+ for (cpos = 0, cnode=node->children;cnode;cnode=cnode->next) {
+ if (cnode->type != XML_ELEMENT_NODE) continue;
+ if ((!xmlStrcmp(cnode->name, "Charset"))&&(rccXmlGetText(cnode))&&(cpos<RCC_MAX_CHARSETS)) {
+ rcc_default_languages[pos].charsets[cpos++] = rccXmlGetText(cnode);
+ }
+ }
+ } else if (!xmlStrcmp(node->name, "FullName")) {
+ if (rccXmlGetText(node)) fullname = rccXmlGetText(node);
+ }
+ }
+
+ if (cpos > 1) {
+ rcc_default_languages[pos].sn = lang;
+ rcc_default_languages[pos].charsets[0] = "Default";
+ rcc_default_languages[pos].charsets[cpos] = NULL;
+ rcc_default_languages[pos].engines[0] = &rcc_default_engine;
+ rcc_default_languages[pos].engines[1] = NULL;
+ if ((fullname)&&(npos<RCC_MAX_LANGUAGES)) {
+ rcc_default_language_names[npos].sn = lang;
+ rcc_default_language_names[npos].name = fullname;
+ rcc_default_language_names[++npos].sn = NULL;
+ rcc_default_language_names[npos].name = NULL;
+ }
+
+ rcc_default_languages[++pos].sn = NULL;
+ if (pos == RCC_MAX_LANGUAGES) break;
+ }
+ }
+
+clear:
+ if (xmlctx) {
+ if (xpathctx) {
+ xmlXPathFreeContext(xpathctx);
+ if (obj) {
+ xmlXPathFreeObject(obj);
+ }
+ }
+ }
+ }
+}
+
+void rccXmlFree() {
+ if (xmlctx) {
+ xmlFreeDoc(xmlctx);
+ xmlctx = NULL;
+ }
+
+ xmlCleanupCharEncodingHandlers();
+ xmlCleanupParser();
+}
+
+
+static xmlNodePtr rccNodeFind(xmlXPathContextPtr xpathctx, const char *request, ...) {
+ xmlXPathObjectPtr obj;
+ xmlNodeSetPtr node_set;
+ xmlNodePtr res = NULL;
+
+ unsigned int i, args = 0;
+ unsigned int size = 64;
+ va_list ap;
+ char *req;
+
+ for (req = strstr(request, "%s"); req; req = strstr(req + 1, "%s")) args++;
+
+ if (args) {
+ va_start(ap, request);
+ for (i=0;i<args;i++) {
+ req = va_arg(ap, char*);
+ size += strlen(req);
+ }
+ va_end(ap);
+
+ req = (char*)malloc(size*sizeof(char));
+ if (!req) return NULL;
+
+ va_start(ap, request);
+ vsprintf(req,request,ap);
+ va_end(ap);
+ } else req = (char*)request;
+
+ obj = xmlXPathEvalExpression(req, xpathctx);
+ if (obj) {
+ node_set = obj->nodesetval;
+ if (node_set->nodeNr > 0) {
+ res = node_set->nodeTab[0];
+ }
+ xmlXPathFreeObject(obj);
+ }
+
+ if (args) free(req);
+
+ return res;
+}
+
+#define XPATH_SELECTED "/Config"
+#define XPATH_SELECTED_LANGUAGE "/Config/Language"
+#define XPATH_SELECTED_OPTIONS "/Config/Options"
+#define XPATH_SELECTED_OPTION "/Config/Options/Option[@name=\"%s\"]"
+
+#define XPATH_SELECTED_LANGS "/Config/Languages"
+#define XPATH_SELECTED_LANG "/Config/Languages/Language[@name=\"%s\"]"
+#define XPATH_SELECTED_ENGINE "/Config/Languages/Language[@name=\"%s\"]/Engine"
+#define XPATH_SELECTED_CLASSES "/Config/Languages/Language[@name=\"%s\"]/Classes"
+#define XPATH_SELECTED_CLASS "/Config/Languages/Language[@name=\"%s\"]/Classes/Class[@name=\"%s\"]"
+
+int rccSave(rcc_context ctx, const char *name) {
+ int fd;
+ char *config;
+ struct stat st;
+
+ unsigned int i, j, size;
+
+ rcc_language_ptr *languages;
+ rcc_language_ptr language;
+ rcc_language_config cfg;
+ rcc_class_ptr *classes;
+ rcc_class_ptr cl;
+
+ xmlXPathContextPtr xpathctx;
+ xmlDocPtr doc = NULL;
+ xmlNodePtr pnode, lnode, onode, llnode, cnode, enode, node;
+ unsigned char oflag = 0, llflag = 0, cflag;
+ const char *oname;
+ char value[16];
+
+ int memsize;
+ xmlChar *mem;
+
+ if ((!name)||(!strcmp(name, "rcc"))||(strlen(rcc_home_dir)<3)) name = "default";
+
+ size = strlen(rcc_home_dir) + strlen(name) + 32;
+ config = (char*)malloc(size*sizeof(char));
+ if (!config) return -1;
+
+ sprintf(config,"%s/.rcc/",rcc_home_dir);
+ mkdir(config, 00644);
+
+ sprintf(config,"%s/.rcc/%s.xml",rcc_home_dir,name);
+ fd = open(config, O_CREAT|O_RDWR,00644);
+ if (fd == -1) goto clear;
+ flock(fd, LOCK_EX);
+
+ if ((!fstat(fd, &st))&&(st.st_size)) {
+ doc = xmlReadFd(fd, config, NULL, 0);
+ }
+
+ if (!doc) {
+ doc = xmlNewDoc("1.0");
+ if (!doc) goto clear;
+ }
+
+ xpathctx = xmlXPathNewContext(doc);
+ if (!xpathctx) goto clear;
+
+ pnode = rccNodeFind(xpathctx, XPATH_SELECTED);
+ if (pnode) {
+ lnode = rccNodeFind(xpathctx, XPATH_SELECTED_LANGUAGE);
+ onode = rccNodeFind(xpathctx, XPATH_SELECTED_OPTIONS);
+ llnode = rccNodeFind(xpathctx, XPATH_SELECTED_LANGS);
+ } else {
+ pnode = xmlNewChild((xmlNodePtr)doc, NULL, "Config", NULL);
+ lnode = NULL;
+ onode = NULL;
+ llnode = NULL;
+ }
+
+ if (lnode) xmlNodeSetContent(lnode, rccGetSelectedLanguageName(ctx));
+ else lnode = xmlNewChild(pnode,NULL, "Language", rccGetSelectedLanguageName(ctx));
+
+ if (onode) oflag = 1;
+ else onode = xmlNewChild(pnode, NULL, "Options", NULL);
+
+ for (i=0;i<RCC_MAX_OPTIONS;i++) {
+ oname = rccGetOptionName(i);
+ if (!oname) continue;
+
+ if (oflag) node = rccNodeFind(xpathctx, XPATH_SELECTED_OPTION, oname);
+ else node = NULL;
+
+ if (rccOptionIsDefault(ctx, (rcc_option)i)) strcpy(value, rcc_option_nonconfigured);
+ else sprintf(value, "%i", rccGetOption(ctx, (rcc_option)i));
+
+ if (node) xmlNodeSetContent(node, value);
+ else {
+ node = xmlNewChild(onode, NULL, "Option", value);
+ xmlSetProp(node, "name", oname);
+ }
+ }
+
+ if (llnode) llflag = 1;
+ else llnode = xmlNewChild(pnode, NULL, "Languages", NULL);
+
+ languages = ctx->languages;
+ classes = ctx->classes;
+ for (i=1;languages[i];i++) {
+ language = languages[i];
+ cfg = rccCheckConfig(ctx, (rcc_language_id)i);
+ if (!cfg) continue;
+
+ if (llflag) lnode = rccNodeFind(xpathctx, XPATH_SELECTED_LANG, language->sn);
+ else lnode = NULL;
+
+ if (lnode) {
+ enode = rccNodeFind(xpathctx, XPATH_SELECTED_ENGINE, language->sn);
+ cnode = rccNodeFind(xpathctx, XPATH_SELECTED_CLASSES, language->sn);
+ } else {
+ lnode = xmlNewChild(llnode, NULL, "Language", NULL);
+ xmlSetProp(lnode, "name", language->sn);
+ enode = NULL;
+ cnode = NULL;
+ }
+
+ if (enode) xmlNodeSetContent(enode, rccConfigGetSelectedEngineName(cfg));
+ else xmlNewChild(lnode, NULL, "Engine", rccConfigGetSelectedEngineName(cfg));
+
+ if (cnode) cflag = 1;
+ else {
+ cnode = xmlNewChild(lnode, NULL, "Classes", NULL);
+ cflag = 0;
+ }
+
+ for (j=0;classes[j];j++) {
+ cl = classes[j];
+
+ if (cflag) node = rccNodeFind(xpathctx, XPATH_SELECTED_CLASS, language->sn, cl->name);
+ else node = NULL;
+
+ if (node) xmlNodeSetContent(node, rccConfigGetSelectedCharsetName(cfg, (rcc_class_id)j));
+ else {
+ node = xmlNewChild(cnode, NULL, "Class", rccConfigGetSelectedCharsetName(cfg, (rcc_class_id)j));
+ xmlSetProp(node, "name", cl->name);
+ }
+ }
+ }
+
+ xmlDocDumpFormatMemory(doc,&mem,&memsize,1);
+ ftruncate(fd, 0);
+ lseek(fd, SEEK_SET, 0);
+ if (mem) {
+ write(fd, mem, memsize);
+ free(mem);
+ }
+
+clear:
+ if (config) {
+ if (fd != -1) {
+ if (doc) {
+ if (xpathctx) {
+ xmlXPathFreeContext(xpathctx);
+ }
+ xmlFreeDoc(doc);
+ }
+ fsync(fd);
+ flock(fd, LOCK_UN);
+ close(fd);
+ }
+ free(config);
+ }
+
+ return 0;
+}
+
+int rccLoad(rcc_context ctx, const char *name) {
+ int err;
+
+ int fd;
+ char *config;
+ struct stat st;
+
+ unsigned int i, j, size;
+ const char *tmp;
+ const char *oname;
+
+ rcc_language_config cfg;
+ rcc_language_ptr *languages;
+ rcc_language_ptr language;
+ rcc_class_ptr *classes;
+ rcc_class_ptr cl;
+
+ xmlXPathContextPtr xpathctx;
+ xmlDocPtr doc = NULL;
+ xmlNodePtr node, lnode;
+
+ if ((!name)||(!strcmp(name, "rcc"))||(strlen(rcc_home_dir)<3)) name = "default";
+
+ size = strlen(rcc_home_dir) + strlen(name) + 32;
+ config = (char*)malloc(size*sizeof(char));
+ if (!config) return -1;
+
+ sprintf(config,"%s/.rcc/%s.xml",rcc_home_dir,name);
+ fd = open(config, O_RDONLY);
+ if (fd == -1) goto clear;
+ flock(fd, LOCK_EX);
+
+ if ((!fstat(fd, &st))&&(st.st_size)) {
+ doc = xmlReadFd(fd, config, NULL, 0);
+ } else goto clear;
+
+ xpathctx = xmlXPathNewContext(doc);
+ if (!xpathctx) goto clear;
+
+ node = rccNodeFind(xpathctx, XPATH_SELECTED_LANGUAGE);
+ if (node) {
+ tmp = rccXmlGetText(node);
+ if (tmp) err = rccSetLanguageByName(ctx, tmp);
+ else err = -1;
+ } else err = -1;
+ if (err) rccSetLanguage(ctx, 0);
+
+ for (i=0;i<RCC_MAX_OPTIONS;i++) {
+ oname = rccGetOptionName((rcc_option)i);
+ if (!oname) continue;
+
+ node = rccNodeFind(xpathctx, XPATH_SELECTED_OPTION, oname);
+ if (node) {
+ tmp = rccXmlGetText(node);
+ if ((tmp)&&(strcasecmp(tmp,rcc_option_nonconfigured))) err = rccSetOption(ctx, (rcc_option)i, (rcc_option_value)atoi(tmp));
+ else err = -1;
+ } else err = -1;
+ if (err) rccOptionSetDefault(ctx, (rcc_option)i);
+ }
+
+
+ languages = ctx->languages;
+ classes = ctx->classes;
+ for (i=1;languages[i];i++) {
+ language = languages[i];
+
+ lnode = rccNodeFind(xpathctx, XPATH_SELECTED_LANG, language->sn);
+ if (!lnode) continue;
+
+ cfg = rccGetConfig(ctx, (rcc_language_id)i);
+ if (!cfg) continue;
+
+ node = rccNodeFind(xpathctx, XPATH_SELECTED_ENGINE, language->sn);
+ if (node) {
+ tmp = rccXmlGetText(node);
+ if (tmp) err = rccConfigSetEngineByName(cfg, tmp);
+ else err = -1;
+ } else err = -1;
+ if (err) rccConfigSetEngineByName(cfg, NULL);
+
+ for (j=0;classes[j];j++) {
+ cl = classes[j];
+
+ node = rccNodeFind(xpathctx, XPATH_SELECTED_CLASS, language->sn, cl->name);
+ if (node) {
+ tmp = rccXmlGetText(node);
+ if (tmp) err = rccConfigSetCharsetByName(cfg, (rcc_class_id)j, tmp);
+ else err = -1;
+ } else err = -1;
+ if (err) rccConfigSetCharset(cfg, (rcc_class_id)j, 0);
+ }
+ }
+
+clear:
+ if (config) {
+ if (fd != -1) {
+ if (doc) {
+ if (xpathctx) {
+ xmlXPathFreeContext(xpathctx);
+ }
+ xmlFreeDoc(doc);
+ }
+ close(fd);
+ }
+ free(config);
+ }
+
+ return 0;
+}