source: trunk/third/scrollkeeper/libs/install.c @ 21684

Revision 21684, 17.4 KB checked in by ghudson, 20 years ago (diff)
Apply a patch from Red Hat to disable the warning on invalid OMF files. The Red Hat changelog was: * Thu Aug 7 2003 Havoc Pennington <hp@redhat.com> 0.3.11-6 - remove the warning on invalid OMF files, it's always just some broken translation and happens with every release
Line 
1/* copyright (C) 2000 Sun Microsystems, Inc.*/
2
3/*   
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17 */
18
19#include <config.h>
20#include <libxml/tree.h>
21#include <libxml/parser.h>
22#include <stdlib.h>
23#include <string.h>
24#include <locale.h>
25#include <unistd.h>
26#include <sys/stat.h>
27#include <errno.h>
28#include <libintl.h>
29#include <dirent.h>
30#include <scrollkeeper.h>
31
32#define _(String) gettext (String)
33
34#define SEP             "|"
35#define PATHLEN         256
36
37#ifdef SOLARIS
38/*extern char *strtok_r(char *, const char *, char **);*/
39#endif
40
41static int get_unique_doc_id(char *);
42static void add_doc_to_scrollkeeper_docs(char *, char *, char *, int, char *);
43static void add_doc_to_content_list(xmlNodePtr, char *, char **, char *, char *,
44                                    char *, char *, char *, int, int, char, char **);
45static char *get_doc_property(xmlNodePtr, char *, char *);
46static char *get_doc_parameter_value(xmlNodePtr, char *);
47static char* remove_leading_and_trailing_white_spaces(char *);
48
49static int get_best_locale_dir(char *locale_dir, char *locale_name,
50                                char *scrollkeeper_dir, char *locale)
51{
52    char *loc, *dest_dir, *ptr;
53       
54    dest_dir = malloc (strlen (scrollkeeper_dir) + strlen (locale) + 2);
55    check_ptr(dest_dir, "scrollkeeper-install");
56    snprintf(dest_dir, PATHLEN, "%s/%s", scrollkeeper_dir, locale);
57   
58    if (is_dir(dest_dir))
59    {
60        strncpy(locale_dir, dest_dir, PATHLEN);
61        strncpy(locale_name, locale, PATHLEN);
62        free(dest_dir);
63        return 1;
64    }
65   
66    loc = strdup(locale);
67    check_ptr(loc, "scrollkeeper-install");
68
69    ptr = strrchr(loc, '.');
70    if (ptr != NULL)
71    {
72        *ptr = '\0';
73        snprintf(dest_dir, PATHLEN, "%s/%s", scrollkeeper_dir, loc);
74        if (is_dir(dest_dir))
75        {
76            strncpy(locale_dir, dest_dir, PATHLEN);
77            strncpy(locale_name, loc, PATHLEN);
78            free(dest_dir);
79            free(loc);
80            return 1;
81        }
82    }
83   
84    ptr = strrchr(loc, '_');
85    if (ptr != NULL)
86    {
87        *ptr = '\0';
88        snprintf(dest_dir, PATHLEN, "%s/%s", scrollkeeper_dir, loc);
89        if (is_dir(dest_dir))
90        {
91            strncpy(locale_dir, dest_dir, PATHLEN);
92            strncpy(locale_name, loc, PATHLEN);
93            free(dest_dir);
94            free(loc);
95            return 1;
96        }
97    }
98   
99    free(dest_dir);
100    free(loc);
101    return 0;
102}
103
104static xmlNodePtr create_toc_tree(char *docpath, char outputprefs)
105{
106    xmlDocPtr toc_doc;
107    FILE *config_fid;
108    char command[1024], tocpath[PATHLEN];
109    xmlNodePtr toc_tree;
110    errorSAXFunc xml_error_handler;
111    warningSAXFunc xml_warning_handler;
112    fatalErrorSAXFunc xml_fatal_error_handler;
113   
114    snprintf(command, 1024, "scrollkeeper-get-toc-from-docpath %s", docpath);
115    config_fid = popen(command, "r");
116
117    if (config_fid == NULL)
118        return NULL;
119
120    fscanf(config_fid, "%s", tocpath);
121    if (pclose(config_fid))
122        return NULL;
123   
124    xml_error_handler = xmlDefaultSAXHandler.error;
125    xmlDefaultSAXHandler.error = NULL;
126    xml_warning_handler = xmlDefaultSAXHandler.warning;
127    xmlDefaultSAXHandler.warning = NULL;
128    xml_fatal_error_handler = xmlDefaultSAXHandler.fatalError;
129    xmlDefaultSAXHandler.fatalError = NULL;
130    toc_doc = xmlParseFile(tocpath);
131    xmlDefaultSAXHandler.error = xml_error_handler;
132    xmlDefaultSAXHandler.warning = xml_warning_handler;
133    xmlDefaultSAXHandler.fatalError = xml_fatal_error_handler;
134    if (toc_doc == NULL)
135    {
136        sk_message(outputprefs, SKOUT_DEFAULT, SKOUT_QUIET, "(install)", _("TOC file does not exist, is not readable, or is not well-formed XML: %s\n"), tocpath);
137        return NULL;
138    }
139    toc_tree = toc_doc->children;
140                                 
141   
142    /* XXX this is not documented, but xmlUnlinkNode() does not work for the toplevel node
143       while this one works according to the current libxml source
144    */
145    toc_doc->children = NULL;
146   
147    xmlFreeDoc(toc_doc);
148    return toc_tree;
149}
150
151
152/*
153 * FIXME: This function should be rewritten to provide warnings/errors for all
154 * cases in which it doesn't install an OMF entry. Currently it may fail
155 *  silently for a variety of reasons.
156 */
157int install(char *omf_name, char *scrollkeeper_dir, char *data_dir, char outputprefs)
158{   
159    xmlDocPtr omf_doc;
160    xmlDtdPtr dtd;
161    xmlNodePtr node, omf_node, s_node;
162    char *docpath, *title, *format, str[1024];
163    char cl_filename[PATHLEN], cl_ext_filename[PATHLEN];
164    char locale_dir[PATHLEN], locale_name[PATHLEN], *locale, *ptr;
165    int unique_id;
166    xmlDocPtr cl_doc, cl_ext_doc;
167    char scrollkeeper_docs[PATHLEN];
168    char **stylesheets=NULL, **output_files=NULL, *toc_name;
169    char *toc_stylesheet_name, *index_name, *index_stylesheet_name, *uid;
170
171    /*
172     * Read in OMF file
173     */
174    omf_doc = xmlParseFile(omf_name);
175    if (omf_doc == NULL)
176    {
177        sk_message(outputprefs, SKOUT_DEFAULT, SKOUT_QUIET, "(install)", _("OMF file does not exist, is not readable, or is not well-formed XML: %s\n"), omf_name);
178        return 0;
179    }
180
181    /*
182     * Validate OMF file against ScrollKeeper-OMF DTD
183     */
184    dtd = xmlParseDTD(NULL, (const xmlChar *)SCROLLKEEPER_OMF_DTD);
185    if (dtd == NULL) {
186        sk_message(outputprefs, SKOUT_DEFAULT, SKOUT_QUIET, "(install)", _("Could not parse ScrollKeeper-OMF DTD: %s\n"), SCROLLKEEPER_OMF_DTD);
187        return 0;
188    } else {
189#if 0
190        xmlValidCtxt cvp;
191        cvp.userData = (char *) &outputprefs;
192        cvp.error    = (xmlValidityErrorFunc) sk_dtd_validation_message;
193        cvp.warning  = (xmlValidityWarningFunc) sk_dtd_validation_message;
194        if (!xmlValidateDtd(&cvp, omf_doc, dtd)) {
195            sk_message(outputprefs, SKOUT_DEFAULT, SKOUT_QUIET, "(install)", _("OMF file [%s] does not validate against ScrollKeeper-OMF DTD: %s\n"), omf_name, SCROLLKEEPER_OMF_DTD);
196            return 0;
197        }
198#endif
199    }
200    xmlFreeDtd(dtd);
201                                 
202    snprintf(scrollkeeper_docs, PATHLEN, "%s/scrollkeeper_docs", scrollkeeper_dir);
203   
204    /* We assume that this file is a concatenation of "resource" tags so
205     * they should start from the top node's children.
206     */
207
208    /* Well, sort of. Let's do the right thing when comments are involved. */
209    for(omf_node = omf_doc->children; (omf_node != NULL) && (omf_node->type != XML_ELEMENT_NODE); omf_node = omf_node->next) ;;
210
211    if (!omf_node) {
212        /* This should not happen */
213        sk_message(outputprefs, SKOUT_DEFAULT, SKOUT_QUIET, "(install)", _("Failed to locate an <OMF> element.\n"));
214        return 0;
215    }
216    if (!omf_node->children) {
217        /* This should not happen */
218        sk_message(outputprefs, SKOUT_DEFAULT, SKOUT_QUIET, "(install)", _("<OMF> node has no children.\n"));
219        return 0;
220    }
221
222    for(node = omf_node->children; node != NULL; node = node->next)
223    {
224        if (!xmlStrcmp(node->name, (xmlChar *)"resource"))
225        {
226            /* create full content list path names and read trees */
227            locale = get_doc_property(node, "language", "code");
228            if (locale == NULL)
229                continue;
230            if (!get_best_locale_dir(locale_dir, locale_name, scrollkeeper_dir, locale)) {
231                xmlFree(locale);
232                continue;
233            }
234            xmlFree(locale);
235            snprintf(cl_filename, PATHLEN, "%s/scrollkeeper_cl.xml", locale_dir);
236            snprintf(cl_ext_filename, PATHLEN, "%s/scrollkeeper_extended_cl.xml", locale_dir);
237           
238            if (!is_file(cl_filename))
239                continue;
240               
241            if (!is_file(cl_ext_filename))
242                continue;
243           
244            cl_doc = xmlParseFile(cl_filename);
245            if (cl_doc == NULL)
246            {
247                sk_message(outputprefs, SKOUT_DEFAULT, SKOUT_QUIET, "(install)", _("Content list file does not exist, is not readable, or is not well-formed XML: %s\n"), cl_filename);
248                continue;
249            }
250           
251            cl_ext_doc = xmlParseFile(cl_ext_filename);
252            if (cl_ext_doc == NULL)
253            {
254                sk_message(outputprefs, SKOUT_DEFAULT, SKOUT_QUIET, "(install)", _("Extended content list file does not exist, is not readable, or is not well-formed XML: %s\n"), cl_ext_filename);
255                continue;
256            }
257
258            docpath = get_doc_property(node, "identifier", "url");
259            if (docpath == NULL)
260                continue;
261           
262            /* add to scrollkeeper_docs */
263            unique_id = get_unique_doc_id(scrollkeeper_docs);
264            add_doc_to_scrollkeeper_docs(scrollkeeper_docs, docpath, omf_name, unique_id,
265                                                locale_name);
266                                               
267            format = get_doc_property(node, "format", "mime");
268            if (format && !strcmp(format, "text/xml"))
269            {
270                /* create TOC file and index file */
271
272                if (!strncmp("file:", docpath, 5))
273                    ptr = docpath+5;
274                else
275                    ptr = docpath;
276                               
277                toc_name = malloc((strlen(scrollkeeper_dir)+32)*sizeof(char));
278                check_ptr(toc_name, "scrollkeeper-install");
279                sprintf(toc_name, "%s/TOC/%d", scrollkeeper_dir, unique_id);
280               
281                toc_stylesheet_name = malloc(
282                        (strlen(data_dir)+strlen("/stylesheets/toc.xsl")+1)*sizeof(char));
283                check_ptr(toc_stylesheet_name, "scrollkeeper-install");
284                sprintf(toc_stylesheet_name, "%s/stylesheets/toc.xsl", data_dir);
285               
286                index_name = malloc((strlen(scrollkeeper_dir)+32)*sizeof(char));
287                check_ptr(index_name, "scrollkeeper-install");
288                sprintf(index_name, "%s/index/%d", scrollkeeper_dir, unique_id);
289               
290                index_stylesheet_name = malloc(
291                        (strlen(data_dir)+strlen("/stylesheets/index.xsl")+1)*sizeof(char));
292                check_ptr(index_stylesheet_name, "scrollkeeper-install");
293                sprintf(index_stylesheet_name, "%s/stylesheets/index.xsl", data_dir);
294                /* create stylesheets table and output_files table as
295                   parameters to apply_stylesheets                     */
296       
297                stylesheets=(char **)calloc(2, sizeof(char *));
298                check_ptr(stylesheets, "scrollkeeper-install");
299                output_files=(char **)calloc(2, sizeof(char *));
300                check_ptr(output_files, "scrollkeeper-install");
301
302                stylesheets[0] = toc_stylesheet_name;
303                stylesheets[1] = index_stylesheet_name;
304
305                output_files[0] = toc_name;
306                output_files[1] = index_name;
307
308                apply_stylesheets(ptr, format+5, 2,
309                                        stylesheets, output_files, outputprefs);
310               
311                free(toc_name);
312                free(toc_stylesheet_name);
313                free(index_name);
314                free(index_stylesheet_name);
315                free(stylesheets);
316                free(output_files);
317            }
318           
319            uid = get_doc_property(node, "relation", "seriesid");
320            if (uid == NULL)
321                continue;
322           
323            title = get_doc_parameter_value(node, "title");
324            strncpy(str, title, 1024);
325            title = remove_leading_and_trailing_white_spaces(str);
326                   
327            /* add the doc to the content list */
328            for(s_node = node->children; s_node != NULL; s_node = s_node->next)
329            {
330                /* look for subject nodes */
331                if (!xmlStrcmp(s_node->name, (xmlChar *)"subject"))
332                {
333                    char *category, *token, *rest, *complete_cat_token = NULL;
334
335                    category = (char *)xmlGetProp(s_node, (xmlChar *)"category");
336                    if (category == NULL)
337                        continue;
338                    token = strtok_r(category, SEP, &rest);
339                    add_doc_to_content_list(cl_doc->children->children, token, &rest,
340                    docpath, omf_name, title, format, uid, unique_id, 0, outputprefs,
341                        &complete_cat_token);
342                    xmlFree(category);
343                    free((void *)complete_cat_token);
344                    category = (char *)xmlGetProp(s_node, (xmlChar *)"category");
345                    token = strtok_r(category, SEP, &rest);
346                        complete_cat_token = NULL;
347                    add_doc_to_content_list(cl_ext_doc->children->children, token, &rest,
348                    docpath, omf_name, title, format, uid, unique_id, 1, outputprefs,
349                        &complete_cat_token);
350                    xmlFree(category);
351                    free((void *)complete_cat_token);
352                }
353            }
354           
355            xmlSaveFile(cl_filename, cl_doc);
356            xmlFreeDoc(cl_doc);
357            xmlSaveFile(cl_ext_filename, cl_ext_doc);
358            xmlFreeDoc(cl_ext_doc);
359        xmlFree(docpath);
360        xmlFree(format);
361        xmlFree(uid);
362        }
363    }
364   
365    return 1;
366}
367
368static char* remove_leading_and_trailing_white_spaces(char *str)
369{
370    int i, len;
371   
372    len = strlen(str);
373   
374    for(i = len-1; i >= 0; i--)
375    {
376        if (str[i] == ' ' || str[i] == '\t' ||
377            str[i] == '\n' || str[i] == '\r')
378            str[i] = '\0';
379        else
380            break;
381    }
382       
383    while (*str == ' ' || *str == '\t' ||
384           *str == '\n' || *str == '\r')
385           str++;
386           
387    return str;
388}
389
390static void add_doc_to_scrollkeeper_docs(char *filename, char *doc_name, char *omf_name,
391                                                int unique_id, char *locale)
392{
393    FILE *fid;
394    struct stat buf;
395   
396    fid = fopen(filename, "a");
397    if (fid == NULL)
398        fid = fopen(filename, "w");
399    if (fid == NULL) {
400        perror (filename);
401        exit (EXIT_FAILURE);
402    }
403       
404    stat(omf_name, &buf);
405   
406    fprintf(fid, "%s\t%d\t%s\t%ld\t%s\n", omf_name, unique_id, doc_name, buf.st_mtime,
407                locale);
408   
409    fclose(fid);
410}
411
412static int get_unique_doc_id(char *filename)
413{
414/* TODO implement a method that returns the first unused doc id, rather than incrementing the
415   highest used one
416*/
417
418    FILE *fid;
419    int id = 1, unique_id = 0;
420   
421    fid = fopen(filename, "r");
422   
423    /* this is the first doc added so just return */
424    if (fid == NULL)
425        return unique_id;
426
427    while (1)
428    {
429        fscanf(fid, "%*s%d%*s%*d%*s", &id);
430        if (feof(fid))
431            break;
432           
433        if (id > unique_id)
434            unique_id = id;
435    }
436
437   fclose (fid);
438   return unique_id + 1;
439}
440
441/* do not modify the return value of this routine */
442static char *get_doc_property(xmlNodePtr omf_node, char *tag, char *prop)
443{
444    xmlNodePtr node;
445
446    if (omf_node == NULL)
447        return NULL;
448   
449    for(node = omf_node->children; node != NULL; node = node->next)
450    {   
451        if (node->type == XML_ELEMENT_NODE &&
452            !xmlStrcmp(node->name, (xmlChar *)tag))
453            return (char *)xmlGetProp(node, (xmlChar *)prop);
454    }
455   
456    return NULL;
457}
458
459/* do not modify the return value of this routine */
460static char *get_doc_parameter_value(xmlNodePtr omf_node, char *tag)
461{
462    xmlNodePtr node;
463
464    if (omf_node == NULL)
465        return NULL;
466
467    for(node = omf_node->children; node != NULL; node = node->next)
468    {   
469        if (node->type == XML_ELEMENT_NODE &&
470            !xmlStrcmp(node->name, (xmlChar *)tag) &&
471            node->children != NULL)
472            return (char *)node->children->content;
473    }
474   
475    return NULL;
476}
477
478static xmlNodePtr create_new_doc_node(xmlDocPtr cl_doc, char *docpath, char *omf_name,
479                                        char *title, char *format, char *uid, int id)
480{
481    char str[32];
482    xmlNodePtr node;
483
484    node = xmlNewDocNode(cl_doc, NULL, (xmlChar *)"doc", NULL);
485    snprintf(str, 32, "%d", id);
486    xmlSetProp(node, (xmlChar *)"docid", (xmlChar *)str);
487    xmlNewChild(node, NULL, (xmlChar *)"doctitle", (xmlChar *)title);
488    xmlNewChild(node, NULL, (xmlChar *)"docomf", (xmlChar *)omf_name);
489    xmlNewChild(node, NULL, (xmlChar *)"docsource", (xmlChar *)docpath);
490    xmlNewChild(node, NULL, (xmlChar *)"docformat", (xmlChar *)format);
491    if (uid != NULL) {
492        xmlNewChild(node, NULL, (xmlChar *)"docseriesid", (xmlChar *)uid);
493    }
494   
495    return node;
496}
497
498static void add_doc_to_content_list(xmlNodePtr sect_node, char *cat_token, char **rest,
499                                    char *docpath, char *omf_name,
500                                    char *title, char *format, char *uid,
501                                    int id, int add_toc, char outputprefs, char **complete_cat_token)
502{
503    xmlNodePtr node, new_node, s_node;
504
505    if (sect_node == NULL ||
506        cat_token == NULL)
507        return;
508
509        if (*complete_cat_token == NULL)
510                *complete_cat_token = strdup(cat_token);
511        else {
512                char *ptr;
513                ptr = malloc(strlen(*complete_cat_token) + strlen(cat_token) + 2);
514                sprintf(ptr, "%s%s", *complete_cat_token, cat_token);
515                free(*complete_cat_token);
516                *complete_cat_token = ptr;
517        }
518
519    /* these should all be <sect> nodes */         
520    for(node = sect_node; node != NULL; node = node->next)
521    {
522        if (xmlStrcmp(node->name, (xmlChar *)"sect"))
523            continue;
524       
525        xmlChar *categorycode;
526       
527        categorycode = xmlGetProp(node, (xmlChar *)"categorycode");
528        if (categorycode == NULL)
529            continue;
530       
531        /* these should be the actual titles */
532        if (!xmlStrcmp((xmlChar *)(*complete_cat_token), categorycode))
533        {
534                cat_token = strtok_r(NULL, SEP, rest);
535                if (cat_token == NULL)
536                {
537                    /* we have a match so create a node */
538                     
539                    new_node = create_new_doc_node(node->children->doc, docpath, omf_name, title,
540                                        format, uid, id);
541                                       
542                    if (add_toc)
543                    {
544                        xmlNodePtr toc_tree;
545                   
546                        toc_tree = create_toc_tree(docpath, outputprefs);
547                        if (toc_tree != NULL)
548                            xmlAddChild(new_node, toc_tree);
549                    }
550
551                    xmlAddChild(node, new_node);
552                   
553                    return;
554                }
555                else
556                {
557                    /* partial match, continue on this branch only if there are
558                       any more <sect> nodes
559                    */
560                   
561                    for(s_node = node->children; s_node != NULL; s_node = s_node->next)
562                    {
563                        if (s_node->type == XML_ELEMENT_NODE &&
564                            !xmlStrcmp(s_node->name, (xmlChar *)"sect"))
565                            break;
566                    }
567                   
568                    if (s_node != NULL)
569                        add_doc_to_content_list(s_node, cat_token, rest,
570                                                docpath, omf_name, title, format,
571                                                uid, id, add_toc, outputprefs, complete_cat_token);
572                    return;
573                }
574        }       
575       
576        xmlFree(categorycode);
577    }
578}
Note: See TracBrowser for help on using the repository browser.