summaryrefslogtreecommitdiff
path: root/librarian/rarian-reg-full.c
diff options
context:
space:
mode:
Diffstat (limited to 'librarian/rarian-reg-full.c')
-rw-r--r--librarian/rarian-reg-full.c760
1 files changed, 760 insertions, 0 deletions
diff --git a/librarian/rarian-reg-full.c b/librarian/rarian-reg-full.c
new file mode 100644
index 0000000..f3abe9a
--- /dev/null
+++ b/librarian/rarian-reg-full.c
@@ -0,0 +1,760 @@
+/*
+ * rarian-reg-full.c
+ * This file is part of Rarian
+ *
+ * Copyright (C) 2006 - Don Scorgie
+ *
+ * Rarian is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * Rarian is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+/* TODO: Figure out why this is required here */
+#define I_KNOW_RARIAN_0_8_IS_UNSTABLE
+#include "rarian-reg-full.h"
+#include "rarian-reg-utils.h"
+#include "rarian-utils.h"
+
+
+static void process_line_full (char *line, RrnRegFull *reg);
+static void process_pair_full (RrnRegFull *reg, char *key, char *value);
+
+static void process_sect_line_full (char *line, RrnSectFull *sect);
+static void process_sect_pair_full (RrnSectFull *sect, char *key,
+ char *value);
+static int rrn_reg_add_sect_full (RrnRegFull *reg, RrnSectFull *sect);
+static RrnSectFull * rrn_sect_new_full ();
+static void rrn_sect_free_full (RrnSectFull *sect);
+static void process_path_full (RrnRegFull *reg);
+static void process_section_path_full (RrnListEntry *owner_paths, RrnSectFull *section);
+
+RrnRegFull *
+rrn_reg_new_full ()
+{
+ RrnRegFull *reg;
+
+ reg = malloc (sizeof (RrnRegFull));
+ reg->name = NULL;
+ reg->uri = NULL;
+ reg->comment = NULL;
+ reg->identifier = NULL;
+ reg->type = NULL;
+ reg->icon = NULL;
+ reg->categories = NULL;
+ reg->weight = 0;
+ reg->heritage = NULL;
+ reg->lang = NULL;
+ reg->children = NULL;
+
+ return reg;
+}
+
+RrnRegFull *
+rrn_reg_parse_file_full (char *filename)
+{
+ RrnRegFull *reg = NULL;
+ RrnSectFull *sect = NULL;
+ RrnSectFull *orphaned_sections = NULL;
+ int mode = 0;
+ FILE *file;
+ char *buf;
+
+ if (access(filename, R_OK)) {
+ fprintf (stderr, "WARNING: cannot access file %s\n", filename);
+ return NULL;
+ }
+ reg = rrn_reg_new_full ();
+
+ file = fopen (filename, "r");
+
+ buf = malloc (sizeof (char) * 1024);
+ while (fgets (buf, 1023, file)) {
+ char *real = NULL;
+ while (buf[strlen(buf)-1] != '\n') {
+ char *tmp;
+ char *result = NULL;
+ tmp = strdup (buf);
+ buf = fgets (buf, 1023, file);
+ result = malloc (sizeof (char) * (strlen(tmp)+strlen(buf)+2));
+ strcpy (result, tmp);
+ strcat (result, buf);
+ free (tmp);
+ free (buf);
+ buf = result;
+ }
+ real = buf;
+ while (*real && isspace(*real) && *real != '\n') {
+ real++;
+ }
+ if (!real || real[0] == '\n' || real[0] == '#') {
+ /* Black Line or comment. Ignore. */
+ } else if (real[0] == '[') {
+ if (!strncmp (real, "[Document]", 10)) {
+ mode = 0;
+
+ if (sect) {
+ if (rrn_reg_add_sect_full (reg, sect) == 1) {
+ sect->prev = NULL;
+ sect->next = orphaned_sections;
+ if (orphaned_sections)
+ orphaned_sections->prev = sect;
+ orphaned_sections = sect;
+ }
+ sect = NULL;
+ }
+ } else if (!strncmp (real, "[Section]", 9)) {
+ mode = 1;
+ if (sect) {
+ if (rrn_reg_add_sect_full (reg, sect) == 1) {
+ sect->prev = NULL;
+ sect->next = orphaned_sections;
+ if (orphaned_sections)
+ orphaned_sections->prev = sect;
+ orphaned_sections = sect;
+ }
+ sect = NULL;
+ }
+ sect = rrn_sect_new_full ();
+ } else {
+ fprintf (stderr, "Unknown section header: %s. Ignoring\n", real);
+ }
+ } else if (strchr ( real, '=')) {
+ if (mode == 0) {
+ process_line_full (buf, reg);
+ } else {
+ process_sect_line_full (buf, sect);
+ }
+ } else {
+ fprintf (stdout, "WARNING: Don't know how to handle line: %s\n", buf);
+ }
+ }
+ fclose (file);
+ free (buf);
+ if (sect) {
+ if (rrn_reg_add_sect_full (reg, sect) == 1) {
+ sect->prev = NULL;
+ sect->next = orphaned_sections;
+ if (orphaned_sections)
+ orphaned_sections->prev = sect;
+ orphaned_sections = sect;
+ }
+ }
+
+ if (!reg->name || !reg->uri || !reg->type || !reg->categories ) {
+ rrn_reg_free_full (reg);
+ reg = NULL;
+ }
+ sect = orphaned_sections;
+ while (sect) {
+ if (rrn_reg_add_sect_full (reg, sect) == 1) {
+ fprintf (stderr, "Error: Orphaned section %s not added.\n",
+ sect->name);
+ }
+ sect = sect->next;
+ }
+
+ if (reg && !reg->identifier) {
+ char *last;
+ char *sep;
+ char *basename;
+
+ sep = strrchr (filename, '/');
+ last = strrchr (filename, '.');
+ if (!last || !sep || last < sep) {
+ fprintf (stderr, "Error: Can't cut put basename properly\n");
+ rrn_reg_free_full (reg);
+ return NULL;
+ }
+ basename = rrn_strndup (sep + 1, last - (sep + 1));
+ reg->identifier = malloc (sizeof (char)*(strlen(basename)+11));
+ sprintf (reg->identifier, "org.other.%s", basename);
+ free (basename);
+
+ }
+ if (reg)
+ process_path_full (reg);
+
+
+ return reg;
+}
+
+static void
+process_line_full (char *line, RrnRegFull *reg)
+{
+ char *ret = NULL;
+ char *key;
+ char *value;
+ char *tmp;
+
+ tmp = strchr (line, '=');
+ if (!tmp) {
+ fprintf (stderr, "WARNING: Malformed line: \n%s\n", line);
+ return;
+ }
+
+ if (line[strlen(line)-1] == '\n') {
+ line[strlen(line)-1] = '\0';
+ }
+
+ key = rrn_strndup (line, tmp - line);
+ tmp++;
+ value = strdup (tmp);
+ process_pair_full (reg, key, value);
+ free (key);
+ free (value);
+
+ return;
+}
+
+static char *
+find_language (char *key)
+{
+ char *lbrace = NULL, *rbrace = NULL;
+ char *result;
+
+ result = strdup ("C");
+ lbrace = strchr (key, '[');
+ if (!lbrace)
+ return result;
+ lbrace++;
+ rbrace = strchr (key, ']');
+ if (!rbrace)
+ return result;
+ free (result);
+ result = rrn_strndup (lbrace, rbrace-lbrace);
+ return result;
+}
+
+RrnListEntry *
+rrn_full_add_field (RrnListEntry *current, char *text, char *lang)
+{
+ RrnListEntry *entry = NULL;
+ RrnListEntry *iter = NULL;
+ iter = current;
+ while (iter) {
+ if (!strcmp(iter->lang, lang))
+ return current;
+ iter = iter->next;
+ }
+ entry = malloc (sizeof (RrnListEntry));
+ if (text) {
+ entry->text = strdup (text);
+ } else {
+ entry->text = strdup ("");
+ }
+ entry->lang = strdup (lang);
+ entry->next = current;
+
+ return entry;
+
+}
+
+static char **
+process_categories_full (char *cat_string)
+{
+ char **result = NULL;
+ char **tmp = NULL;
+ int ncats = 0;
+ char *current_break = cat_string;
+ char *semi;
+ int i;
+ do {
+ semi = strchr (current_break, ';');
+ if (result) {
+ tmp = malloc (sizeof (char *)*ncats);
+ for (i=0; i< ncats; i++) {
+ tmp[i] = strdup (result[i]);
+ free (result[i]);
+ }
+ free (result);
+ }
+ ncats += 1;
+ result = malloc (sizeof (char *)*(ncats+1));
+ if (tmp) {
+ for (i=0; i<ncats-1; i++) {
+ result[i] = strdup (tmp[i]);
+ free (tmp[i]);
+ }
+ free (tmp);
+ }
+ result[ncats-1] = rrn_strndup (current_break, semi - current_break);
+ result[ncats] = NULL;
+ current_break = semi+1;
+ } while (semi);
+
+ return result;
+}
+
+static void
+process_pair_full (RrnRegFull *reg, char *key, char *value)
+{
+ char *lang = NULL;
+
+ lang = find_language (key);
+
+ if (!strncmp (key, "Name", 4)) {
+ reg->name = rrn_full_add_field (reg->name, value, lang);
+ } else if (!strncmp (key, "Comment", 7)) {
+ reg->comment = rrn_full_add_field (reg->comment, value, lang);
+ } else if (!strncmp (key, "DocPath", 7)) {
+ reg->uri = rrn_full_add_field (reg->uri, value, lang);
+ } else if (!strcmp (key, "DocIdentifier")) {
+ reg->identifier = strdup (value);
+ } else if (!strcmp (key, "DocType")) {
+ reg->type = strdup (value);
+ } else if (!strcmp (key, "Categories")) {
+ reg->categories = process_categories_full (value);
+ } else if (!strcmp (key, "DocWeight")) {
+ reg->weight = atoi (value);
+ } else if (!strcmp (key, "DocHeritage")) {
+ reg->heritage = strdup (value);
+ } else if (!strcmp (key, "NoDisplay")) {
+ reg->hidden = TRUE;
+ } else if (!strcmp (key, "DocDefaultSection")) {
+ reg->default_section = strdup (value);
+ } else if (!strcmp (key, "DocLang")) {
+ if (!reg->lang) {
+ reg->lang = strdup (value);
+ }
+ } else if (!strcmp (key, "Icon")){
+ reg->icon = strdup (value);
+ } else {
+ fprintf (stderr, "WARNING: Unknown element %s: %s\n", key, value);
+ }
+ return;
+}
+
+void
+rrn_reg_free_full (RrnRegFull *reg)
+{
+ RrnSectFull *sect = reg->children;
+ char **tmp = reg->categories;
+ free (reg->name);
+ free (reg->comment);
+ free (reg->uri);
+ free (reg->type);
+ free (reg->identifier);
+ free (reg->heritage);
+ free (reg->lang);
+ if (tmp) {
+ while (*tmp) {
+ free (*tmp);
+ tmp++;
+ }
+ }
+ free (reg->categories);
+ while (sect) {
+ RrnSectFull *s1 = sect->next;
+ rrn_sect_free_full (sect);
+ sect = s1;
+ }
+ free (reg);
+ return;
+}
+
+/* Section stuff */
+RrnSectFull *
+rrn_sect_new_full ()
+{
+ RrnSectFull * sect;
+ sect = malloc (sizeof (RrnSectFull));
+
+ sect->name = NULL;
+ sect->identifier = NULL;
+ sect->uri = NULL;
+ sect->next = NULL;
+ sect->prev = NULL;
+ sect->children = NULL;
+ sect->owner = NULL;
+
+ return sect;
+}
+
+static RrnSectFull *
+find_sect_full (RrnSectFull *start, char *id)
+{
+ RrnSectFull *ret = start;
+
+ while (ret) {
+ if (!strcmp (ret->identifier, id)) {
+ return ret;
+ }
+ ret = ret->next;
+ }
+ return NULL;
+}
+
+static void
+rrn_reg_add_sections_full (RrnRegFull *reg, RrnSectFull *sects)
+{
+ RrnSectFull *real_orphans = NULL;
+ RrnSectFull *next = NULL;
+ int depth = 0;
+ do {
+ depth ++;
+ if (depth > 4) {
+ /* The pathological case where someone's done something really,
+ * stupid and defined a subsection with the section without
+ * definind the section.
+ * We break after 4 iterations.
+ */
+ return;
+ }
+ next = sects;
+ while (sects) {
+ next = sects->next;
+ if (rrn_reg_add_sect_full (reg, sects) == 1) {
+ sects->prev = NULL;
+ sects->next = real_orphans;
+ if (real_orphans)
+ real_orphans->prev = sects;
+ real_orphans = sects;
+ };
+ sects = next;
+ }
+ sects = real_orphans;
+ } while (sects);
+ return;
+}
+
+static int
+rrn_sects_add_sect_full (RrnSectFull *current, RrnSectFull *sect)
+{
+ char *cur_sect = NULL;
+ RrnSectFull *append_sect;
+ char *tmp = NULL;
+ char *dot = NULL;
+
+ cur_sect = sect->owner;
+
+ append_sect = current;
+ do {
+ dot = strchr (cur_sect, '.');
+ tmp = rrn_strndup (cur_sect, dot-cur_sect);
+ append_sect = find_sect_full (append_sect, tmp);
+ cur_sect = dot;
+ free (tmp);
+ } while (cur_sect && append_sect);
+ if (append_sect) {
+ sect->prev = NULL;
+ sect->next = append_sect->children;
+ if (append_sect->children)
+ append_sect->children->prev = sect;
+ append_sect->children = sect;
+ } else {
+ return 1;
+ }
+ return 0;
+}
+
+static int
+rrn_reg_add_sect_full (RrnRegFull *reg, RrnSectFull *sect)
+{
+ if (!sect->owner || !strcmp (reg->identifier, sect->owner)) {
+ sect->prev = NULL;
+ sect->next = reg->children;
+ if (reg->children)
+ reg->children->prev = sect;
+ reg->children = sect;
+ } else {
+ char *cur_sect = NULL;
+ RrnSectFull *append_sect;
+ char *tmp = NULL;
+ char *dot = NULL;
+
+ if (!strncmp (sect->owner, reg->identifier, strlen (reg->identifier))) {
+ cur_sect = &sect->owner[strlen(reg->identifier)+1];
+ } else {
+ cur_sect = sect->owner;
+ }
+ append_sect = reg->children;
+ do {
+ dot = strchr (cur_sect, '.');
+ tmp = rrn_strndup (cur_sect, dot-cur_sect);
+ append_sect = find_sect_full (append_sect, tmp);
+ cur_sect = dot;
+ free (tmp);
+ } while (cur_sect && append_sect);
+ if (append_sect) {
+ sect->prev = NULL;
+ sect->next = append_sect->children;
+ if (append_sect->children)
+ append_sect->children->prev = sect;
+ append_sect->children = sect;
+ } else {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+RrnSectFull *
+rrn_sect_parse_file_full (char *filename)
+{
+ RrnSectFull *sect = NULL;
+ RrnSectFull *orphaned_sections = NULL;
+ FILE *file;
+ char *buf;
+ char *real_owner = NULL;
+
+ if (access(filename, R_OK)) {
+ fprintf (stderr, "WARNING: cannot access file %s\n", filename);
+ return NULL;
+ }
+
+ file = fopen (filename, "r");
+
+ buf = malloc (sizeof (char) * 1024);
+ while (fgets (buf, 1023, file)) {
+ char *real = NULL;
+ while (buf[strlen(buf)-1] != '\n') {
+ char *tmp;
+ char *result = NULL;
+ tmp = strdup (buf);
+ buf = fgets (buf, 1023, file);
+ result = malloc (sizeof (char) * (strlen(tmp)+strlen(buf)+2));
+ strcpy (result, tmp);
+ strcat (result, buf);
+ free (tmp);
+ free (buf);
+ buf = result;
+ }
+ real = buf;
+ while (*real && isspace(*real) && *real != '\n') {
+ real++;
+ }
+ if (!real || real[0] == '\n' || real[0] == '#') {
+ /* Black Line or comment. Ignore. */
+ } else if (real[0] == '[') {
+ if (!strncmp (real, "[Section]", 9)) {
+ if (sect) {
+ if (rrn_sects_add_sect_full (orphaned_sections, sect) == 1) {
+ sect->prev = NULL;
+ sect->next = orphaned_sections;
+ if (orphaned_sections)
+ orphaned_sections->prev = sect;
+ orphaned_sections = sect;
+ }
+ }
+
+ sect = rrn_sect_new_full ();
+ } else {
+ fprintf (stderr, "Unknown section header: !%s!. Ignoring\n", real);
+ }
+ } else if (strchr ( real, '=')) {
+ process_sect_line_full (buf, sect);
+ } else {
+ fprintf (stderr, "WARNING: Don't know how to handle line: %s\n", buf);
+ }
+ }
+ fclose (file);
+ free (buf);
+
+ if (sect) {
+ if (rrn_sects_add_sect_full (orphaned_sections, sect) == 1) {
+ sect->prev = NULL;
+ sect->next = orphaned_sections;
+ if (orphaned_sections)
+ orphaned_sections->prev = sect;
+ orphaned_sections = sect;
+ }
+ }
+
+ return orphaned_sections;
+}
+
+static void
+process_sect_line_full (char *line, RrnSectFull *sect)
+{
+ char *ret = NULL;
+ char *key;
+ char *value;
+ char *tmp;
+
+ tmp = strchr (line, '=');
+ if (!tmp) {
+ fprintf (stderr, "WARNING: Malformed line: \n%s\n", line);
+ return;
+ }
+
+ if (line[strlen(line)-1] == '\n') {
+ line[strlen(line)-1] = '\0';
+ }
+
+ key = rrn_strndup (line, tmp - line);
+ tmp++;
+ value = strdup (tmp);
+ process_sect_pair_full (sect, key, value);
+ free (key);
+ free (value);
+
+ return;
+
+}
+
+static void
+process_sect_pair_full (RrnSectFull *sect, char *key, char *value)
+{
+ char *lang = NULL;
+
+ lang = find_language (key);
+
+ if (!strncmp (key, "SectionName", 11) || !strncmp (key, "sectionname", 11)) {
+ sect->name = rrn_full_add_field (sect->name, value, lang);
+ } else if (!strcmp (key, "SectionIdentifier") || !strcmp (key, "sectionidentifier")) {
+ sect->identifier = strdup (value);
+ } else if (!strncmp (key, "SectionPath", 11) || !strncmp (key, "sectionpath", 11)) {
+ sect->uri = rrn_full_add_field (sect->uri, value, lang);
+ } else if (!strcmp (key, "SectionDocument") || !strcmp (key, "sectiondocument")) {
+ sect->owner = strdup (value);
+ } else {
+ fprintf (stderr, "WARNING: Unknown element for section %s: %s\n", key, value);
+ }
+ return;
+}
+
+static void
+process_path_full (RrnRegFull *reg)
+{
+ char *prefix = NULL;
+ RrnSectFull *child = reg->children;
+ RrnListEntry *entry = reg->uri;
+ while (entry) {
+ if (!strncmp ("file:", entry->text, 5)) {
+ /* No processing needs done. The URI is already in the file: scheme */
+ return;
+ }
+ if ((prefix = strchr (entry->text, ':')) && (prefix-(entry->text) < 7)) {
+ /* Probably has another (non-file:) URI scheme. If so, we're going to
+ * return as is
+ */
+ return;
+ }
+ /* Otherwise, promote to file: URI scheme, reusing the prefix vble */
+ prefix = malloc (sizeof (char) * (strlen(entry->text)+6));
+ sprintf (prefix, "file:%s", entry->text);
+ free (entry->text);
+ entry->text = prefix;
+ entry = entry->next;
+ }
+ while (child) {
+ process_section_path_full (reg->uri, child);
+ child = child->next;
+ }
+}
+
+static void
+process_section_path_full (RrnListEntry *owner_paths, RrnSectFull *section)
+{
+ char *tmp = NULL;
+ char *new_uri = NULL;
+ char *prefix = NULL;
+ char *filename = NULL;
+ char *owner_path = NULL;
+
+ RrnSectFull *child = section->children;
+
+ RrnListEntry *entry = section->uri;
+
+ while (entry) {
+ RrnListEntry *parent_entry = owner_paths;
+
+ while (parent_entry && strcmp (parent_entry->lang, entry->lang)) {
+ parent_entry = parent_entry->next;
+ }
+ if (!parent_entry) {
+ parent_entry = owner_paths;
+ while (strcmp (parent_entry->lang, "C")) {
+ parent_entry = parent_entry->next;
+ }
+ if (!parent_entry) {
+ fprintf (stderr, "Error: Cannot find a suitable parent for child %s\n"
+ "This usually results from bad script files. Please correct and\n"
+ "try again. Ignoring this child (and it's children) completely.\n",
+ entry->text);
+ return;
+ }
+ }
+ owner_path = parent_entry->text;
+
+ if (!strncmp ("file:", entry->text, 5))
+ goto done;
+ if ((prefix = strchr (entry->text, ':')) && (prefix-(entry->text) < 7)) {
+ /* Probably has another (non-file:) URI scheme. If so, we're going to
+ * return as is
+ */
+ goto done;
+ }
+ if (entry->text[0] == '/') {
+ /* Absolute path */
+ new_uri = malloc (sizeof (char) * strlen(entry->text)+6);
+ sprintf (new_uri, "file:/%s", entry->text);
+ free (entry->text);
+ entry->text = new_uri;
+ goto done;
+ }
+
+ /* If we get through to here, the path is relative to the parents
+ * own path. We need to disect and repair
+ */
+
+ /* First, cut out the owner's file */
+ tmp = strrchr (owner_path, '/');
+ prefix = rrn_strndup (owner_path, tmp-owner_path);
+ if (!tmp) {
+ fprintf (stderr, "Warning: cannot cut up path for the %s section\n"
+ "This generally indicates a problem with the scroll\n"
+ " file for this section, or its parent document.\n"
+ "The path will not be fixed.\n", entry->text);
+ return;
+ }
+ new_uri = malloc (sizeof (char) * (strlen(prefix)+strlen(entry->text)+2));
+ sprintf (new_uri, "%s/%s", prefix, entry->text);
+ free (entry->text);
+ entry->text = new_uri;
+done:
+ entry = entry->next;
+ }
+
+ /* In all cases, we want to iterate through the children of the children
+ * just to make sure they're all right
+ */
+ while (child) {
+ process_section_path_full (section->uri, child);
+ child = child->next;
+ }
+}
+
+
+
+void
+rrn_sect_free_full (RrnSectFull *sect)
+{
+ RrnSectFull *child = sect->children;
+ free (sect->name);
+ free (sect->identifier);
+ free (sect->uri);
+ free (sect->owner);
+ while (child) {
+ RrnSectFull *c1 = child->next;
+ rrn_sect_free_full (child);
+ child = c1;
+ }
+ free (sect);
+}