1 /*
2 LibRCC - module handling XML configuration
3
4 Copyright (C) 2005-2008 Suren A. Chilingaryan <csa@dside.dyndns.org>
5
6 This library is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License version 2.1 or later
8 as published by the Free Software Foundation.
9
10 This library is distributed in the hope that it will be useful, but WITHOUT
11 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
13 for more details.
14
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include <stdio.h>
21 #include <stdarg.h>
22 #include <errno.h>
23
24 #include <string.h>
25 #ifdef HAVE_STRINGS_H
26 # include <strings.h>
27 #endif /* HAVE_STRINGS_H */
28
29 #include "../config.h"
30
31 #ifdef HAVE_UNISTD_H
32 # include <unistd.h>
33 #endif /* HAVE_UNISTD_H */
34
35 #ifdef HAVE_FCNTL_H
36 # include <fcntl.h>
37 #endif /* HAVE_FCNTL_H */
38
39 #ifdef HAVE_SYS_TYPES_H
40 # include <sys/types.h>
41 #endif /* HAVE_SYS_TYPES_H */
42
43 #ifdef HAVE_SYS_STAT_H
44 # include <sys/stat.h>
45 #endif /* HAVE_SYS_STAT_H */
46
47 #ifdef HAVE_SYS_FILE_H
48 # include <sys/file.h>
49 #endif /* HAVE_SYS_FILE_H */
50
51 #include <libxml/parser.h>
52 #include <libxml/tree.h>
53 #include <libxml/xpath.h>
54
55 #include "internal.h"
56 #include "rccconfig.h"
57 #include "plugin.h"
58 #include "rcchome.h"
59
60 #define MAX_HOME_CHARS 96
61 #define XPATH_LANGUAGE "//Language[@name]"
62
63 static xmlDocPtr xmlctx = NULL;
64
rccGetConfiguration()65 rcc_config rccGetConfiguration() {
66 return (rcc_config)xmlctx;
67 }
68
rccXmlGetText(xmlNodePtr node)69 static const char *rccXmlGetText(xmlNodePtr node) {
70 if ((node)&&(node->children)&&(node->children->type == XML_TEXT_NODE)&&(node->children->content)) return (const char*)node->children->content;
71 return NULL;
72 }
73
rccXmlInit(int LoadConfiguration)74 int rccXmlInit(int LoadConfiguration) {
75 FILE *f;
76 char config[MAX_HOME_CHARS + 32];
77
78 xmlXPathContextPtr xpathctx = NULL;
79 xmlXPathObjectPtr obj = NULL;
80 xmlNodeSetPtr node_set;
81 unsigned long i, nnodes;
82 xmlNodePtr enode, cnode, pnode, node;
83 xmlAttrPtr attr;
84 const char *lang, *engine_name;
85 unsigned int pos, lpos, epos, cpos;
86 const char *alias, *parent;
87 unsigned int j, apos, rpos;
88
89 rcc_engine *engine;
90
91 xmlInitParser();
92 xmlInitCharEncodingHandlers();
93 xmlKeepBlanksDefault(0);
94
95 if (LoadConfiguration) {
96 if (strlen(rcc_home_dir)>MAX_HOME_CHARS) config[0] = 0;
97 else {
98 sprintf(config, "%s/.rcc/rcc.xml", rcc_home_dir);
99 f = fopen(config, "r");
100 if (f) fclose(f);
101 else config[0] = 0;
102 }
103 if (!config[0]) {
104 strcpy(config, "/etc/rcc.xml");
105 f = fopen(config, "r");
106 if (f) fclose(f);
107 else config[0] = 0;
108 }
109 } else config[0] = 0;
110
111
112 for (apos=0;rcc_default_aliases[apos].alias;apos++);
113
114 // Load Extra Languages
115 if (config[0]) {
116 xmlctx = xmlReadFile(config, NULL, 0);
117 if (!xmlctx) goto clear;
118
119 xpathctx = xmlXPathNewContext(xmlctx);
120 if (!xpathctx) goto clear;
121
122 obj = xmlXPathEvalExpression((xmlChar*)XPATH_LANGUAGE, xpathctx);
123 if (!obj) goto clear;
124
125 node_set = obj->nodesetval;
126 if (!node_set) goto clear;
127
128 for (lpos = 0; rcc_default_languages[lpos].sn; lpos++);
129
130 nnodes = node_set->nodeNr;
131 for (i=0;i<nnodes;i++) {
132 pnode = node_set->nodeTab[i];
133 attr = xmlHasProp(pnode, (xmlChar*)"name");
134 lang = (const char*)attr->children->content;
135
136 if ((!lang)||(!lang[0])) continue;
137
138 pos = rccDefaultGetLanguageByName(lang);
139 if (!pos) continue;
140 if (pos == (rcc_language_id)-1) {
141 for (rpos=0;rcc_default_relations[rpos].lang;rpos++);
142 if (rpos < RCC_MAX_RELATIONS) {
143 rcc_default_relations[rpos].parent = rcc_english_language_sn;
144 rcc_default_relations[rpos++].lang = lang;
145 rcc_default_relations[rpos].parent = NULL;
146 rcc_default_relations[rpos].lang = NULL;
147 }
148
149 pos = lpos;
150 }
151 else if (pos == RCC_MAX_LANGUAGES) continue;
152
153 for (epos = 1, cpos = 1,node=pnode->children;node;node=node->next) {
154 if (node->type != XML_ELEMENT_NODE) continue;
155 if (!xmlStrcmp(node->name, (xmlChar*)"Charsets")) {
156 for (cnode=node->children;cnode;cnode=cnode->next) {
157 if (cnode->type != XML_ELEMENT_NODE) continue;
158 if ((!xmlStrcmp(cnode->name, (xmlChar*)"Charset"))&&(rccXmlGetText(cnode))&&(cpos<RCC_MAX_CHARSETS)) {
159 rcc_default_languages[pos].charsets[cpos++] = rccXmlGetText(cnode);
160 }
161 }
162 }
163 else if (!xmlStrcmp(node->name, (xmlChar*)"Engines")) {
164 for (enode=node->children;enode;enode=enode->next) {
165 if (enode->type != XML_ELEMENT_NODE) continue;
166 if ((!xmlStrcmp(enode->name, (xmlChar*)"Engine"))&&(epos<RCC_MAX_ENGINES)) {
167 engine_name = rccXmlGetText(enode);
168 if (!engine_name) continue;
169 engine = rccPluginEngineGetInfo(engine_name, lang);
170 if (!engine) continue;
171
172 rcc_default_languages[pos].engines[epos++] = engine;
173 }
174 }
175 }
176 else if (!xmlStrcmp(node->name, (xmlChar*)"Aliases")) {
177 for (enode=node->children;enode;enode=enode->next) {
178 if (enode->type != XML_ELEMENT_NODE) continue;
179 if ((!xmlStrcmp(enode->name, (xmlChar*)"Alias"))&&(apos<RCC_MAX_ALIASES)) {
180 alias = rccXmlGetText(enode);
181 if (!alias) continue;
182 for (j=0;j<apos;j++)
183 if (!strcasecmp(alias, rcc_default_aliases[j].alias)) break;
184 if (j<apos) {
185 rcc_default_aliases[j].lang = lang;
186 } else {
187 rcc_default_aliases[apos].alias = alias;
188 rcc_default_aliases[apos++].lang = lang;
189 rcc_default_aliases[apos].alias = NULL;
190 rcc_default_aliases[apos].lang = NULL;
191 }
192 }
193 }
194 }
195 else if (!xmlStrcmp(node->name, (xmlChar*)"Relations")) {
196 rpos = rccDefaultDropLanguageRelations(lang);
197 for (enode=node->children;enode;enode=enode->next) {
198 if (enode->type != XML_ELEMENT_NODE) continue;
199 if ((!xmlStrcmp(enode->name, (xmlChar*)"Parrent"))&&(rpos<RCC_MAX_RELATIONS)) {
200 parent = rccXmlGetText(enode);
201 if (!parent) continue;
202 rcc_default_relations[rpos].parent = parent;
203 rcc_default_relations[rpos++].lang = lang;
204 rcc_default_relations[rpos].parent = NULL;
205 rcc_default_relations[rpos].lang = NULL;
206 }
207 }
208 }
209 }
210
211 if ((cpos > 1)||(epos > 1)) {
212 rcc_default_languages[pos].sn = lang;
213 rcc_default_languages[pos].charsets[0] = rcc_default_charset;
214 if (cpos > 1) rcc_default_languages[pos].charsets[cpos] = NULL;
215 else {
216 rcc_default_languages[pos].charsets[1] = rcc_utf8_charset;
217 rcc_default_languages[pos].charsets[2] = NULL;
218 }
219 rcc_default_languages[pos].engines[0] = &rcc_default_engine;
220 rcc_default_languages[pos].engines[epos] = NULL;
221
222 if (pos == lpos) rcc_default_languages[++lpos].sn = NULL;
223 }
224 }
225
226 clear:
227 if (xmlctx) {
228 if (xpathctx) {
229 xmlXPathFreeContext(xpathctx);
230 if (obj) {
231 xmlXPathFreeObject(obj);
232 }
233 }
234 }
235 }
236
237 return 0;
238 }
239
rccXmlFree()240 void rccXmlFree() {
241 if (xmlctx) {
242 xmlFreeDoc(xmlctx);
243 xmlctx = NULL;
244 }
245
246 xmlCleanupCharEncodingHandlers();
247 xmlCleanupParser();
248 }
249
250
rccNodeFind(xmlXPathContextPtr xpathctx,const char * request,...)251 static xmlNodePtr rccNodeFind(xmlXPathContextPtr xpathctx, const char *request, ...) {
252 xmlXPathObjectPtr obj;
253 xmlNodeSetPtr node_set;
254 xmlNodePtr res = NULL;
255
256 unsigned int i, args = 0;
257 unsigned int size = 64;
258 va_list ap;
259 char *req;
260
261 if (!xpathctx) return NULL;
262
263 for (req = strstr(request, "%s"); req; req = strstr(req + 1, "%s")) args++;
264
265 if (args) {
266 va_start(ap, request);
267 for (i=0;i<args;i++) {
268 req = va_arg(ap, char*);
269 size += strlen(req);
270 }
271 va_end(ap);
272
273 req = (char*)malloc(size*sizeof(char));
274 if (!req) return NULL;
275
276 va_start(ap, request);
277 vsprintf(req,request,ap);
278 va_end(ap);
279 } else req = (char*)request;
280
281 obj = xmlXPathEvalExpression((xmlChar*)req, xpathctx);
282 if (obj) {
283 node_set = obj->nodesetval;
284 if ((node_set)&&(node_set->nodeNr > 0)) {
285 res = node_set->nodeTab[0];
286 }
287 xmlXPathFreeObject(obj);
288 }
289
290 if (args) free(req);
291
292 return res;
293 }
294
295 #define XPATH_SELECTED "/Config"
296 #define XPATH_SELECTED_LANGUAGE "/Config/Language"
297 #define XPATH_SELECTED_OPTIONS "/Config/Options"
298 #define XPATH_SELECTED_OPTION "/Config/Options/Option[@name=\"%s\"]"
299
300 #define XPATH_SELECTED_LANGS "/Config/Languages"
301 #define XPATH_SELECTED_LANG "/Config/Languages/Language[@name=\"%s\"]"
302 #define XPATH_SELECTED_ENGINE "/Config/Languages/Language[@name=\"%s\"]/Engine"
303 #define XPATH_SELECTED_CLASSES "/Config/Languages/Language[@name=\"%s\"]/Classes"
304 #define XPATH_SELECTED_CLASS "/Config/Languages/Language[@name=\"%s\"]/Classes/Class[@name=\"%s\"]"
305
rccSave(rcc_context ctx,const char * name)306 int rccSave(rcc_context ctx, const char *name) {
307 int fd;
308 char *config;
309 struct stat st;
310
311 unsigned int i, j, size;
312
313 rcc_language_ptr *languages;
314 rcc_language_ptr language;
315 rcc_language_config cfg;
316 rcc_class_ptr *classes;
317 rcc_class_ptr cl;
318
319 xmlXPathContextPtr xpathctx = NULL;
320 xmlDocPtr doc = NULL;
321 xmlNodePtr pnode, lnode, onode, llnode, cnode, enode, node;
322 unsigned char oflag = 0, llflag = 0, cflag;
323 rcc_option_description *odesc;
324 rcc_option_value ovalue;
325 const char *oname, *ovname;
326 char value[16];
327
328 int memsize;
329 xmlChar *mem;
330
331 if (!ctx) {
332 if (rcc_default_ctx) ctx = rcc_default_ctx;
333 else return -1;
334 }
335
336 if ((!name)||(!strcmp(name, "rcc"))||(strlen(rcc_home_dir)<3)) name = "default";
337
338 size = strlen(rcc_home_dir) + strlen(name) + 32;
339 config = (char*)malloc(size*sizeof(char));
340 if (!config) return -1;
341
342 sprintf(config,"%s/.rcc/",rcc_home_dir);
343 mkdir(config, 00755);
344
345 sprintf(config,"%s/.rcc/%s.xml",rcc_home_dir,name);
346 fd = open(config, O_CREAT|O_RDWR,00644);
347 if (fd == -1) goto clear;
348
349 #if defined(HAVE_FLOCK)
350 flock(fd, LOCK_EX);
351 #elif defined(HAVE_LOCKF)
352 lockf(fd, F_LOCK, 1);
353 #endif
354
355 if ((!fstat(fd, &st))&&(st.st_size)) {
356 doc = xmlReadFd(fd, config, NULL, 0);
357 }
358
359 if (!doc) {
360 doc = xmlNewDoc((xmlChar*)"1.0");
361 if (!doc) goto clear;
362 pnode = NULL;
363 } else {
364 xpathctx = xmlXPathNewContext(doc);
365 pnode = rccNodeFind(xpathctx, XPATH_SELECTED);
366 }
367
368 if (pnode) {
369 lnode = rccNodeFind(xpathctx, XPATH_SELECTED_LANGUAGE);
370 onode = rccNodeFind(xpathctx, XPATH_SELECTED_OPTIONS);
371 llnode = rccNodeFind(xpathctx, XPATH_SELECTED_LANGS);
372 } else {
373 pnode = xmlNewChild((xmlNodePtr)doc, NULL, (xmlChar*)"Config", NULL);
374 lnode = NULL;
375 onode = NULL;
376 llnode = NULL;
377 }
378
379 if (lnode) xmlNodeSetContent(lnode, (xmlChar*)rccGetSelectedLanguageName(ctx));
380 else lnode = xmlNewChild(pnode,NULL, (xmlChar*)"Language", (xmlChar*)rccGetSelectedLanguageName(ctx));
381
382 if (onode) oflag = 1;
383 else onode = xmlNewChild(pnode, NULL, (xmlChar*)"Options", NULL);
384
385 for (i=0;i<RCC_MAX_OPTIONS;i++) {
386 odesc = rccGetOptionDescription(i);
387 if (!odesc) continue;
388
389 oname = rccOptionDescriptionGetName(odesc);
390 if (!oname) continue;
391
392
393 if (oflag) node = rccNodeFind(xpathctx, XPATH_SELECTED_OPTION, oname);
394 else node = NULL;
395
396 if (rccOptionIsDefault(ctx, (rcc_option)i)) strcpy(value, rcc_option_nonconfigured);
397 else {
398 ovalue = rccGetOption(ctx, (rcc_option)i);
399 ovname = rccOptionDescriptionGetValueName(odesc, ovalue);
400 if (ovname) strcpy(value, ovname);
401 else sprintf(value, "%i", ovalue);
402 }
403
404 if (node) xmlNodeSetContent(node, (xmlChar*)value);
405 else {
406 node = xmlNewChild(onode, NULL, (xmlChar*)"Option", (xmlChar*)value);
407 xmlSetProp(node, (xmlChar*)"name", (xmlChar*)oname);
408 }
409 }
410
411 if (llnode) llflag = 1;
412 else llnode = xmlNewChild(pnode, NULL, (xmlChar*)"Languages", NULL);
413
414 languages = ctx->languages;
415 classes = ctx->classes;
416 for (i=1;languages[i];i++) {
417 language = languages[i];
418 cfg = rccCheckConfig(ctx, (rcc_language_id)i);
419 if ((!cfg)||(!cfg->configured)) continue;
420
421 if (llflag) lnode = rccNodeFind(xpathctx, XPATH_SELECTED_LANG, language->sn);
422 else lnode = NULL;
423
424 if (lnode) {
425 enode = rccNodeFind(xpathctx, XPATH_SELECTED_ENGINE, language->sn);
426 cnode = rccNodeFind(xpathctx, XPATH_SELECTED_CLASSES, language->sn);
427 } else {
428 lnode = xmlNewChild(llnode, NULL, (xmlChar*)"Language", NULL);
429 xmlSetProp(lnode, (xmlChar*)"name", (xmlChar*)language->sn);
430 enode = NULL;
431 cnode = NULL;
432 }
433
434 if (enode) xmlNodeSetContent(enode, (xmlChar*)rccConfigGetSelectedEngineName(cfg));
435 else xmlNewChild(lnode, NULL, (xmlChar*)"Engine", (xmlChar*)rccConfigGetSelectedEngineName(cfg));
436
437 if (cnode) cflag = 1;
438 else {
439 cnode = xmlNewChild(lnode, NULL, (xmlChar*)"Classes", NULL);
440 cflag = 0;
441 }
442
443 for (j=0;classes[j];j++) {
444 cl = classes[j];
445 if (cl->flags&RCC_CLASS_FLAG_SKIP_SAVELOAD) continue;
446
447 if (cflag) node = rccNodeFind(xpathctx, XPATH_SELECTED_CLASS, language->sn, cl->name);
448 else node = NULL;
449
450 if (node) xmlNodeSetContent(node, (xmlChar*)rccConfigGetSelectedCharsetName(cfg, (rcc_class_id)j));
451 else {
452 node = xmlNewChild(cnode, NULL, (xmlChar*)"Class", (xmlChar*)rccConfigGetSelectedCharsetName(cfg, (rcc_class_id)j));
453 xmlSetProp(node, (xmlChar*)"name", (xmlChar*)cl->name);
454 }
455 }
456 }
457
458 xmlDocDumpFormatMemory(doc,&mem,&memsize,1);
459
460 if (ftruncate(fd, 0) < 0)
461 goto clear;
462
463 if (lseek(fd, SEEK_SET, 0))
464 goto clear;
465
466 if (mem) {
467 ssize_t ret = write(fd, mem, memsize);
468 // Retry once on signals
469 if ((ret < 0)&&(errno = EINTR))
470 ret = write(fd, mem, memsize);
471 free(mem);
472 }
473
474 clear:
475 if (config) {
476 if (fd != -1) {
477 if (doc) {
478 if (xpathctx) {
479 xmlXPathFreeContext(xpathctx);
480 }
481 xmlFreeDoc(doc);
482 }
483
484 #ifdef HAVE_FSYNC
485 fsync(fd);
486 #endif /* HAVE_FSYNC */
487
488 #if defined(HAVE_FLOCK)
489 flock(fd, LOCK_UN);
490 #elif defined(HAVE_LOCKF)
491 lockf(fd, F_ULOCK, 1);
492 #endif
493
494 close(fd);
495 }
496 free(config);
497 }
498
499 return 0;
500 }
501
rccLoad(rcc_context ctx,const char * name)502 int rccLoad(rcc_context ctx, const char *name) {
503 int err;
504
505 int fd, sysfd;
506 char *config;
507 struct stat st;
508
509 unsigned int i, j, size;
510 const char *tmp;
511
512 rcc_option_description *odesc;
513 rcc_option_value ovalue;
514 const char *oname;
515
516 rcc_language_config cfg;
517 rcc_language_ptr *languages;
518 rcc_language_ptr language;
519 rcc_class_ptr *classes;
520 rcc_class_ptr cl;
521
522 xmlXPathContextPtr xpathctx = NULL, sysxpathctx = NULL, curxpathctx;
523 xmlDocPtr doc = NULL, sysdoc = NULL;
524 xmlNodePtr node, lnode;
525
526 if (!ctx) {
527 if (rcc_default_ctx) ctx = rcc_default_ctx;
528 else return -1;
529 }
530
531 if ((!name)||(!strcmp(name, "rcc"))||(strlen(rcc_home_dir)<3)) name = "default";
532
533 size = strlen(rcc_home_dir) + strlen(name) + 32;
534 config = (char*)malloc(size*sizeof(char));
535 if (!config) return -1;
536
537 sprintf(config,"%s/.rcc/%s.xml",rcc_home_dir,name);
538 fd = open(config, O_RDONLY);
539
540 sprintf(config, "/etc/rcc/%s.xml",name);
541 sysfd = open(config, O_RDONLY);
542
543 free(config);
544
545 if (fd != -1) {
546 #if defined(HAVE_FLOCK)
547 flock(fd, LOCK_EX);
548 #elif defined(HAVE_LOCKF)
549 lockf(fd, F_LOCK, 1);
550 #endif
551
552 if ((!fstat(fd, &st))&&(st.st_size)) {
553 doc = xmlReadFd(fd, name, NULL, 0);
554 }
555
556 #if defined(HAVE_FLOCK)
557 flock(fd, LOCK_UN);
558 #elif defined(HAVE_LOCKF)
559 lockf(fd, F_ULOCK, 1);
560 #endif
561
562 close(fd);
563
564 if (doc) {
565 xpathctx = xmlXPathNewContext(doc);
566 if (!xpathctx) {
567 xmlFreeDoc(doc);
568 doc = NULL;
569 }
570 }
571 }
572
573 if (sysfd != -1) {
574 #if defined(HAVE_FLOCK)
575 flock(sysfd, LOCK_EX);
576 #elif defined(HAVE_LOCKF)
577 lockf(sysfd, F_LOCK, 1);
578 #endif
579
580 if ((!fstat(sysfd, &st))&&(st.st_size)) {
581 sysdoc = xmlReadFd(sysfd, name, NULL, 0);
582 }
583
584 #if defined(HAVE_FLOCK)
585 flock(sysfd, LOCK_UN);
586 #elif defined(HAVE_LOCKF)
587 lockf(sysfd, F_ULOCK, 1);
588 #endif
589
590 close(sysfd);
591
592 if (sysdoc) {
593 sysxpathctx = xmlXPathNewContext(sysdoc);
594 if (!sysxpathctx) {
595 xmlFreeDoc(sysdoc);
596 sysdoc = NULL;
597 }
598 }
599 }
600
601 if ((!doc)&&(!sysdoc)) goto clear;
602
603 node = rccNodeFind(xpathctx, XPATH_SELECTED_LANGUAGE);
604 if (!node) node = rccNodeFind(sysxpathctx, XPATH_SELECTED_LANGUAGE);
605 if (node) {
606 tmp = rccXmlGetText(node);
607 if (tmp) err = rccSetLanguageByName(ctx, tmp);
608 else err = -1;
609 } else err = -1;
610 if (err) rccSetLanguage(ctx, 0);
611
612 for (i=0;i<RCC_MAX_OPTIONS;i++) {
613 odesc = rccGetOptionDescription(i);
614 if (!odesc) continue;
615
616 oname = rccOptionDescriptionGetName(odesc);
617 if (!oname) continue;
618
619 node = rccNodeFind(xpathctx, XPATH_SELECTED_OPTION, oname);
620 if (!node) node = rccNodeFind(sysxpathctx, XPATH_SELECTED_OPTION, oname);
621 if (node) {
622 tmp = rccXmlGetText(node);
623 if ((tmp)&&(strcasecmp(tmp,rcc_option_nonconfigured))) {
624 ovalue = rccOptionDescriptionGetValueByName(odesc, tmp);
625 if (ovalue == (rcc_option_value)-1) ovalue = (rcc_option_value)atoi(tmp);
626 err = rccSetOption(ctx, (rcc_option)i, ovalue);
627 } else err = -1;
628 } else err = -1;
629 if (err) rccOptionSetDefault(ctx, (rcc_option)i);
630 }
631
632
633 languages = ctx->languages;
634 classes = ctx->classes;
635 for (i=1;languages[i];i++) {
636 language = languages[i];
637
638 lnode = rccNodeFind(xpathctx, XPATH_SELECTED_LANG, language->sn);
639 if (lnode) curxpathctx = xpathctx;
640 else {
641 lnode = rccNodeFind(sysxpathctx, XPATH_SELECTED_LANG, language->sn);
642 if (lnode) curxpathctx = sysxpathctx;
643 else continue;
644 }
645
646 cfg = rccGetConfig(ctx, (rcc_language_id)i);
647 if (!cfg) continue;
648
649 node = rccNodeFind(curxpathctx, XPATH_SELECTED_ENGINE, language->sn);
650 if (node) {
651 tmp = rccXmlGetText(node);
652 if (tmp) err = rccConfigSetEngineByName(cfg, tmp);
653 else err = -1;
654 } else err = -1;
655 if (err) rccConfigSetEngineByName(cfg, NULL);
656
657 for (j=0;classes[j];j++) {
658 cl = classes[j];
659 if (cl->flags&RCC_CLASS_FLAG_SKIP_SAVELOAD) continue;
660
661 node = rccNodeFind(curxpathctx, XPATH_SELECTED_CLASS, language->sn, cl->name);
662 if (node) {
663 tmp = rccXmlGetText(node);
664 if (tmp) err = rccConfigSetCharsetByName(cfg, (rcc_class_id)j, tmp);
665 else err = -1;
666 } else err = -1;
667 if (err) rccConfigSetCharset(cfg, (rcc_class_id)j, 0);
668 }
669 }
670
671 clear:
672
673 if (sysdoc) {
674 if (sysxpathctx) {
675 xmlXPathFreeContext(sysxpathctx);
676 }
677 xmlFreeDoc(sysdoc);
678 }
679 if (doc) {
680 if (xpathctx) {
681 xmlXPathFreeContext(xpathctx);
682 }
683 xmlFreeDoc(doc);
684 }
685
686 if ((!ctx->current_language)&&(rccGetOption(ctx, RCC_OPTION_CONFIGURED_LANGUAGES_ONLY))) {
687 ctx->current_config = rccGetCurrentConfig(ctx);
688 ctx->configure = 1;
689 }
690
691 return 0;
692 }
693