Esempio n. 1
0
static int insert_rasqal_triple(struct update_context *uc, rasqal_triple *triple, int row)
{
    fs_rid quad_buf[1][4];
    fs_resource res;
    if (triple->origin) {
        fs_resource_from_rasqal_literal(uc, triple->origin, &res, row);
        quad_buf[0][0] = fs_hash_rasqal_literal(uc, triple->origin, row);
    } else if (uc->op->graph_uri) {
        res.lex = (char *)raptor_uri_as_string(uc->op->graph_uri);
        res.attr = FS_RID_NULL;
        quad_buf[0][0] =
            fs_hash_uri((char *)raptor_uri_as_string(uc->op->graph_uri));
    } else {
        quad_buf[0][0] = fs_c.default_graph;
        res.lex = FS_DEFAULT_GRAPH;
        res.attr = FS_RID_NULL;
    }

    if (quad_buf[0][0] == fs_c.system_config)
        fsp_reload_acl_system(uc->link);

    if (!FS_IS_URI(quad_buf[0][0])) {
        return 1;
    }
    quad_buf[0][1] = fs_hash_rasqal_literal(uc, triple->subject, row);
    if (FS_IS_LITERAL(quad_buf[0][1])) {
        return 1;
    }
    quad_buf[0][2] = fs_hash_rasqal_literal(uc, triple->predicate, row);
    if (!FS_IS_URI(quad_buf[0][2])) {
        return 1;
    }
    quad_buf[0][3] = fs_hash_rasqal_literal(uc, triple->object, row);
    res.rid = quad_buf[0][0];
    if (res.lex) fsp_res_import(uc->link, FS_RID_SEGMENT(quad_buf[0][0], uc->segments), 1, &res);
    res.rid = quad_buf[0][1];
    fs_resource_from_rasqal_literal(uc, triple->subject, &res, 0);
    if (res.lex) fsp_res_import(uc->link, FS_RID_SEGMENT(quad_buf[0][1], uc->segments), 1, &res);
    res.rid = quad_buf[0][2];
    fs_resource_from_rasqal_literal(uc, triple->predicate, &res, 0);
    if (res.lex) fsp_res_import(uc->link, FS_RID_SEGMENT(quad_buf[0][2], uc->segments), 1, &res);
    res.rid = quad_buf[0][3];
    fs_resource_from_rasqal_literal(uc, triple->object, &res, 0);
    if (res.lex) fsp_res_import(uc->link, FS_RID_SEGMENT(quad_buf[0][3], uc->segments), 1, &res);
    fsp_quad_import(uc->link, FS_RID_SEGMENT(quad_buf[0][1], uc->segments), FS_BIND_BY_SUBJECT, 1, quad_buf);
//printf("I %016llx %016llx %016llx %016llx\n", quad_buf[0][0], quad_buf[0][1], quad_buf[0][2], quad_buf[0][3]);

    return 0;
}
Esempio n. 2
0
static unsigned char * handle_new_models (fs_backend *be, fs_segment segment,
                                          unsigned int length,
                                          unsigned char *content)
{
  if (segment > be->segments) {
    fs_error(LOG_ERR, "invalid segment number: %d", segment);
    return fsp_error_new(segment, "invalid segment number");
  }

  if (length < sizeof(fs_rid)) {
    fs_error(LOG_ERR, "new_models(%d) missing model RIDs", segment);
    return fsp_error_new(segment, "missing model RIDs");
  }

  fs_rid *models = (fs_rid *) content;

  int invalid_count = 0;
  for (int k= 0; k < (length / sizeof(fs_rid)); ++k) {
    if (FS_IS_URI(models[k])) {
      fs_backend_model_set_usage(be, segment, models[k], 0);
    } else {
      invalid_count++;
    }
  }
  fs_mhash_flush(be->models);

  if (invalid_count > 0) {
    return fsp_error_new(segment, "one or more model RIDs is not a URI");
  }
  return message_new(FS_DONE_OK, segment, 0);
}
Esempio n. 3
0
fs_value fn_not_equal(fs_query *q, fs_value a, fs_value b)
{
#if 0
fs_value_print(a);
printf(" != ");
fs_value_print(b);
printf("\n");
#endif
    if (a.valid & fs_valid_bit(FS_V_TYPE_ERROR)) {
	return a;
    }
    if (b.valid & fs_valid_bit(FS_V_TYPE_ERROR)) {
	return b;
    }

    if (a.attr == fs_c.xsd_datetime)
        return fn_not(q, fn_datetime_equal(q, a, b));

    if (fs_is_numeric(&a) && fs_is_numeric(&b))
        return fn_not(q, fn_numeric_equal(q, a, b));

    if ((a.attr == fs_c.empty || a.attr == fs_c.xsd_string) &&
        (b.attr == fs_c.empty || b.attr == fs_c.xsd_string)) {
        return fs_value_boolean(strcmp(a.lex, b.lex));
    }

    if ((FS_IS_URI_BN(a.rid) && FS_IS_LITERAL(b.rid)) ||
        (FS_IS_LITERAL(a.rid) && FS_IS_URI_BN(b.rid))) {
        /* ones a URI/bNode and ones a literal, definatly different */
        return fs_value_boolean(1);
    }

    if ((!FS_IS_URI(a.rid) && a.attr != fs_c.empty && FS_IS_LITERAL(a.attr) &&
         !FS_IS_LITERAL(b.attr)) ||
        (!FS_IS_URI(a.rid) && !FS_IS_LITERAL(a.attr) && b.attr != fs_c.empty &&
         FS_IS_LITERAL(b.attr))) {
        /* one has a lang tag and one doesn't, definatly different */
        return fs_value_boolean(1);
    }

    if (FS_IS_URI(a.attr) || FS_IS_URI(b.attr)) {
        /* at least one argument has an unknown datatype */
        return fs_value_boolean(0);
    }

    return fn_not(q, fn_rdfterm_equal(q, a, b));
}
Esempio n. 4
0
void fs_value_print(fs_value v)
{
    if (v.valid & fs_valid_bit(FS_V_TYPE_ERROR)) {
	printf("error");
	if (v.lex) {
	    printf("(%s)", v.lex);
	}

	return;
    }

    if (v.attr == fs_c.xsd_double) {
	printf("db");
    } else if (v.attr == fs_c.xsd_float) {
	printf("fl");
    } else if (v.attr == fs_c.xsd_decimal) {
	printf("de");
    } else if (v.attr == fs_c.xsd_integer) {
	printf("in");
    } else if (v.attr == fs_c.xsd_boolean) {
	printf("bl");
    } else if (v.attr == fs_c.xsd_string) {
	printf("st");
    } else if (v.attr == fs_c.xsd_datetime) {
	printf("dt");
    } else if (v.attr == fs_c.empty || v.attr == FS_RID_NULL) {
	if (v.rid == FS_RID_NULL) {
	    printf("NULL");
	} else if (FS_IS_BNODE(v.rid)) {
	    printf("bnode");
        } else if (FS_IS_URI(v.rid)) {
	    printf("uri");
	} else {
            printf("plain");
	}
    } else {
	printf("attr:%llx", v.attr);
    }

    if (v.valid & fs_valid_bit(FS_V_RID)) {
	printf(" rid:%llx", v.rid);
    }
    if (v.lex) {
	printf(" l:%s", v.lex);
    }
    if (v.valid & fs_valid_bit(FS_V_FP)) {
	printf(" f:%f", v.fp);
    }
    if (v.valid & fs_valid_bit(FS_V_DE)) {
        char *dlex = fs_decimal_to_lex(&v.de);
	printf(" d:%s", dlex);
        free(dlex);
    }
    if (v.valid & fs_valid_bit(FS_V_IN)) {
	printf(" i:%lld", (long long)v.in);
    }
}
Esempio n. 5
0
fs_value fn_cast(fs_query *q, fs_value v, fs_value d)
{
#if 0
printf("CAST ");
fs_value_print(v);
printf(" -> ");
fs_value_print(d);
printf("\n");
#endif
    if (FS_IS_URI(d.rid) && FS_IS_LITERAL(v.rid)) {
	return fn_cast_intl(q, v, d.rid);
    }
    if (d.rid == fs_c.xsd_string && FS_IS_URI(v.rid)) {
        fs_value v2 = fn_cast_intl(q, v, d.rid);
        v2.rid = fs_hash_literal(v.lex, d.rid);
	return v2;
    }

    return fs_value_error(FS_ERROR_INVALID_TYPE, "cast on URI/bNode");
}
Esempio n. 6
0
fs_value fn_is_iri(fs_query *q, fs_value a)
{
    if (a.valid & fs_valid_bit(FS_V_TYPE_ERROR)) {
	return a;
    }
    if (a.valid & fs_valid_bit(FS_V_RID)) {
	return fs_value_boolean(FS_IS_URI(a.rid));
    }
    if (a.attr == FS_RID_NULL) {
	return fs_value_boolean(1);
    }

    return fs_value_boolean(0);
}
Esempio n. 7
0
int fs_is_plain_or_string(fs_value v)
{
    if (fs_is_error(v)) {
        return 0;
    }
    if (FS_IS_BNODE(v.rid) || FS_IS_URI(v.rid)) {
        return 0;
    }
    if (v.attr != fs_c.empty && v.attr != fs_c.xsd_string) {
        return 0;
    }

    return 1;
}
Esempio n. 8
0
fs_value fn_lang(fs_query *q, fs_value a)
{
    if (a.valid & fs_valid_bit(FS_V_TYPE_ERROR)) {
	return a;
    }

    if (a.valid & fs_valid_bit(FS_V_RID) && FS_IS_URI_BN(a.rid)) {
	return fs_value_error(FS_ERROR_INVALID_TYPE, NULL);
    }

    if (a.attr == FS_RID_NULL) {
	return fs_value_error(FS_ERROR_INVALID_TYPE, NULL);
    }

    if (FS_IS_URI(a.attr)) {
	return fs_value_plain("");
    } else {
	if (a.attr == fs_c.lang_en) {
	    return fs_value_plain("en");
	} else if (a.attr == fs_c.lang_fr) {
	    return fs_value_plain("fr");
	} else if (a.attr == fs_c.lang_de) {
	    return fs_value_plain("de");
	} else if (a.attr == fs_c.lang_es) {
	    return fs_value_plain("es");
	} else if (a.attr == fs_c.empty) {
	    return fs_value_plain("");
	}
    }

    fs_rid_vector *r = fs_rid_vector_new(1);
    r->data[0] = a.attr;
    fs_resource res;
    if (fs_query_link(q)) {
        fsp_resolve(fs_query_link(q), FS_RID_SEGMENT(a.attr,
                    fsp_link_segments(fs_query_link(q))), r, &res);
        fs_rid_vector_free(r);
        fs_query_add_freeable(q, res.lex);

        return fs_value_plain(res.lex);
    }

    return fs_value_plain("???");
}
Esempio n. 9
0
void fs_rid_vector_print_resolved(fs_backend *be, fs_rid_vector *v, int flags, FILE *out)
{
    if (!v) {
	fprintf(out, "RID vector: (null)\n");

	return;
    }
    fprintf(out, "RID vector (%d items)\n", v->length);
    for (int i=0; i<v->length; i++) {
	fs_resource res;
	fs_resolve_rid(be, v->data[i] & 0x7, v->data[i], &res);
	if (FS_IS_BNODE(v->data[i])) {
	    fprintf(out, "%4d %llx %s\n", i, v->data[i], res.lex);
	} else if (FS_IS_URI(v->data[i])) {
	    fprintf(out, "%4d %llx <%s>\n", i, v->data[i], res.lex);
	} else if (FS_IS_LITERAL(v->data[i])) {
	    fprintf(out, "%4d %llx \"%s\"\n", i, v->data[i], res.lex);
	} else {
	    fprintf(out, "%4d %llx ?%s?\n", i, v->data[i], res.lex);
	}
    }
}
Esempio n. 10
0
fs_value fs_value_resource(fs_query *q, fs_resource *r)
{
    fs_value v = fs_value_blank();

    v.lex = r->lex;

    if (r->rid == FS_RID_NULL) {
        return fs_value_rid(FS_RID_NULL);
    } if (r->attr == fs_c.xsd_integer) {
        v = fn_cast_intl(q, v, fs_c.xsd_integer);
    } else if (r->attr == fs_c.xsd_float || r->attr == fs_c.xsd_double) {
        v = fn_cast_intl(q, v, fs_c.xsd_double);
    } else if (r->attr == fs_c.xsd_decimal) {
        v = fn_cast_intl(q, v, fs_c.xsd_decimal);
    } else if (r->attr == fs_c.xsd_boolean) {
        if (!strcmp(r->lex, "true") || !strcmp(r->lex, "1")) {
            v = fs_value_boolean(1);
        } else {
            v = fs_value_boolean(0);
        }
    } else if (r->attr == fs_c.xsd_datetime) {
        v = fs_value_datetime_from_string(r->lex);
    }
    if (fs_is_error(v)) {
        v = fs_value_blank();
        v.lex = r->lex;
    }
    v.rid = r->rid;
    if (FS_IS_URI(v.rid) || FS_IS_BNODE(v.rid))
        v.attr = fs_c.empty;
    else
        v.attr = r->attr;
    v.valid |= fs_valid_bit(FS_V_RID) | fs_valid_bit(FS_V_ATTR);

    return v;
}
Esempio n. 11
0
fs_value fn_matches(fs_query *q, fs_value str, fs_value pat, fs_value flags)
{
    if (str.valid & fs_valid_bit(FS_V_TYPE_ERROR)) {
	return str;
    }
    if (pat.valid & fs_valid_bit(FS_V_TYPE_ERROR)) {
	return pat;
    }
    if (flags.valid & fs_valid_bit(FS_V_TYPE_ERROR)) {
	return flags;
    }

    if (!str.lex || !pat.lex) {
	return fs_value_error(FS_ERROR_INVALID_TYPE,
                              "argument to fn:matches has no lexical value");
    }

    if (str.valid & fs_valid_bit(FS_V_RID) && FS_IS_URI(str.rid)) {
	return fs_value_error(FS_ERROR_INVALID_TYPE, NULL);
    }
#if 0
printf("REGEX ");
fs_value_print(str);
printf(", ");
fs_value_print(pat);
printf(", ");
fs_value_print(flags);
printf("\n");
#endif

    int reflags = PCRE_UTF8;
    if (flags.lex) {
	for (char *c = flags.lex; *c; c++) {
	    switch (*c) {
		case 's':
		    reflags |= PCRE_DOTALL;
		    break;
		case 'm':
		    reflags |= PCRE_MULTILINE;
		    break;
		case 'i':
		    reflags |= PCRE_CASELESS;
		    break;
		case 'x':
		    reflags |= PCRE_EXTENDED;
		    break;
		default:
		    fs_error(LOG_ERR, "unknown regex flag '%c'", *c);
		    return fs_value_error(FS_ERROR_INVALID_TYPE, "unrecognised flag in fn:matches");
	    }
	}
    }

    const char *error;
    int erroroffset;
    pcre *re = pcre_compile(pat.lex, reflags, &error, &erroroffset, NULL);
    if (!re) {
        return fs_value_error(FS_ERROR_INVALID_TYPE, error);
    }
    int rc = pcre_exec(re, NULL, str.lex, strlen(str.lex), 0, 0, NULL, 0);
    if (rc == PCRE_ERROR_NOMATCH) {
	return fs_value_boolean(0);
    }
    if (rc < 0) {
        fs_error(LOG_ERR, "internal error %d in pcre_exec", rc);

	return fs_value_error(FS_ERROR_INVALID_TYPE, "internal error in fn:matches");
    }

    return fs_value_boolean(1);
}
Esempio n. 12
0
int fs_order_by_cmp(fs_value va, fs_value vb)
{
    if (va.valid & fs_valid_bit(FS_V_RID) && va.rid == FS_RID_NULL) {
        if (vb.valid & fs_valid_bit(FS_V_RID) && vb.rid == FS_RID_NULL) {
            return 0;
        }
        return -1;
    }
    if (vb.valid & fs_valid_bit(FS_V_RID) && vb.rid == FS_RID_NULL) {
        return 1;
    }
    if (va.valid & fs_valid_bit(FS_V_RID) && FS_IS_BNODE(va.rid)) {
        if (vb.valid & fs_valid_bit(FS_V_RID) && FS_IS_BNODE(vb.rid)) {
            if (va.rid > vb.rid) {
                return 1;
            } else if (va.rid < vb.rid) {
                return -1;
            }
            return 0;
        }
        return -1;
    }
    if (vb.valid & fs_valid_bit(FS_V_RID) && FS_IS_BNODE(vb.rid)) {
        return 1;
    }
    if (va.valid & fs_valid_bit(FS_V_RID) && FS_IS_URI(va.rid)) {
        if (vb.valid & fs_valid_bit(FS_V_RID) && FS_IS_URI(vb.rid)) {
            int cmp = strcmp(va.lex, vb.lex);
            if (cmp != 0) return cmp;
            return 0;
        }
        return -1;
    }
    if (vb.valid & fs_valid_bit(FS_V_RID) && FS_IS_URI(vb.rid)) {
        return 1;
    }

    fs_value cmp = fn_equal(NULL, va, vb);
    if (!(cmp.valid & fs_valid_bit(FS_V_TYPE_ERROR)) && cmp.in) {
        return 0;
    }
    cmp = fn_less_than(NULL, va, vb);
    if (cmp.valid & fs_valid_bit(FS_V_TYPE_ERROR)) {
        if (va.lex && vb.lex) {
            int cmp = strcmp(va.lex, vb.lex);
            if (cmp != 0) {
                return cmp;
            }
        }

        /* TODO check for plain v's typed */
        
        return 0;
    }

    if (cmp.in) {
        return -1;
    } else {
        return 1;
    }
}
Esempio n. 13
0
File: dump.c Progetto: rafl/4store
xmlChar *get_uri(fsp_link *link, fs_rid rid)
{
  if (cache[rid & CACHE_MASK].rid == rid) {
    return (xmlChar *) cache[rid & CACHE_MASK].lex;
  }

  fs_rid_vector onerid = { .length = 1, .size = 1, .data = &rid };
  fs_resource resource;
  fsp_resolve(link, FS_RID_SEGMENT(rid, segments), &onerid, &resource);

  return (xmlChar *) resource.lex;
}

xmlChar *get_attr(fsp_link *link, fs_rid rid)
{
  if (attr_cache[rid & CACHE_MASK].rid == rid) {
    return (xmlChar *) attr_cache[rid & CACHE_MASK].lex;
  }

  fs_rid_vector onerid = { .length = 1, .size = 1, .data = &rid };
  fs_resource resource;

  fsp_resolve(link, FS_RID_SEGMENT(rid, segments), &onerid, &resource);
  memcpy(&attr_cache[rid & ATTR_CACHE_MASK], &resource, sizeof(fs_resource));

  return (xmlChar *) resource.lex;
}

xmlChar *get_literal(fsp_link *link, fs_rid rid, fs_rid *attr)
{
  if (cache[rid & CACHE_MASK].rid == rid) {
    *attr = cache[rid & CACHE_MASK].attr;
    return (xmlChar *) cache[rid & CACHE_MASK].lex;
  }

  fs_rid_vector onerid = { .length = 1, .size = 1, .data = &rid };
  fs_resource resource;

  fsp_resolve(link, FS_RID_SEGMENT(rid, segments), &onerid, &resource);
  *attr = resource.attr;

  return (xmlChar *) resource.lex;
}

void resolve_triples(fsp_link *link, fs_rid_vector **rids)
{
  int quads = rids[0]->length;
  fs_rid_vector *todo[segments];
  fs_segment segment;

  for (segment = 0; segment < segments; ++segment) {
    todo[segment] = fs_rid_vector_new(0);
  }
  for (int c = 0; c < 3; ++c) {
    for (int k = 0; k < quads; ++k) {
      const fs_rid rid = rids[c]->data[k];
      if (FS_IS_BNODE(rid) || cache[rid & CACHE_MASK].rid == rid) continue;
      fs_rid_vector_append(todo[FS_RID_SEGMENT(rid, segments)], rid);
      cache[rid & CACHE_MASK].rid = rid; /* well, it will be soon */
    }
  } 

  int length[segments];
  fs_resource *resources[segments];
  for (segment = 0; segment < segments; ++segment) {
    length[segment] = todo[segment]->length;
    resources[segment] = calloc(length[segment], sizeof(fs_resource));
  }

  fsp_resolve_all(link, todo, resources);

  for (segment = 0; segment < segments; ++segment) {
    fs_resource *res = resources[segment];
    for (int k = 0; k < length[segment]; ++k) {
      free(cache[res[k].rid & CACHE_MASK].lex);
      memcpy(&cache[res[k].rid & CACHE_MASK], &res[k], sizeof(fs_resource));
    }

    fs_rid_vector_free(todo[segment]);
    free(resources[segment]);
  }
}

void dump_model(fsp_link *link, fs_rid model, xmlTextWriterPtr xml)
{
  fs_rid_vector none = { .length = 0, .size = 0, .data = 0 };
  fs_rid_vector one = { .length = 1, .size = 1, .data = &model };

  fs_rid_vector **results;

  double then; /* for time keeping */

  then = fs_time();
  fsp_bind_first_all(link, BIND_SPO, &one, &none, &none, &none, &results, QUAD_LIMIT);
  time_bind_first += (fs_time() - then);

  while (results != NULL) {

    long length = results[0]->length;

    if (length == 0) break;

    then = fs_time();
    resolve_triples(link, results);
    time_resolving += (fs_time() - then);

    then = fs_time();
    for (int k = 0; k < length; ++k) {
      xmlTextWriterStartElement(xml, (xmlChar *) "triple");

      for (int r = 0; r < 3; ++r) {
        fs_rid rid = results[r]->data[k];
        if (FS_IS_BNODE(rid)) {
          unsigned long long node = FS_BNODE_NUM(rid);
          xmlTextWriterWriteFormatElement(xml, (xmlChar *) "id", "%llu", node);
        } else if (FS_IS_URI(rid)) {
          xmlChar *uri = get_uri(link, rid);
          xmlTextWriterWriteElement(xml, (xmlChar *) "uri", uri);
        } else if (FS_IS_LITERAL(rid)) {
          fs_rid attr;
          xmlChar *lex = get_literal(link, rid, &attr);
          if (attr == fs_c.empty) {
            xmlTextWriterWriteElement(xml, (xmlChar *) "plainLiteral", lex);
          } else if (FS_IS_URI(attr)) {
            xmlChar *type = get_uri(link, attr);
            xmlTextWriterStartElement(xml, (xmlChar *) "typedLiteral");
            xmlTextWriterWriteString(xml, (xmlChar *) lex);
            xmlTextWriterWriteAttribute(xml, (xmlChar *) "datatype", type);
            xmlTextWriterEndElement(xml);
          } else if (FS_IS_LITERAL(attr)) {
            xmlChar *lang = get_attr(link, attr);
            xmlTextWriterStartElement(xml, (xmlChar *) "plainLiteral");
            xmlTextWriterWriteAttribute(xml, (xmlChar *) "xml:lang", lang);
            xmlTextWriterWriteString(xml, (xmlChar *) lex);
            xmlTextWriterEndElement(xml);
          }
        }
      }
      xmlTextWriterEndElement(xml);
      xmlTextWriterWriteString(xml, (xmlChar *) "\n");

    }
    time_write_out += (fs_time() - then);

    fs_rid_vector_free(results[0]);
    fs_rid_vector_free(results[1]);
    fs_rid_vector_free(results[2]);
    free(results);

    then = fs_time();
    fsp_bind_next_all(link, BIND_SPO, &results, QUAD_LIMIT);
    time_bind_next += (fs_time() - then);
  }

  fsp_bind_done_all(link);
}

void dump_trix(fsp_link *link, xmlTextWriterPtr xml)
{
  fs_rid_vector **models;
  fs_rid_vector none = { .length = 0, .size = 0, .data = 0 };

  fsp_bind_all(link, FS_BIND_DISTINCT | FS_BIND_MODEL | FS_BIND_BY_SUBJECT, &none, &none, &none, &none, &models);

  fs_rid_vector_sort(models[0]);
  fs_rid_vector_uniq(models[0], 1);

  long length = models[0]->length;

  for (int k = 0; k < length; ++k) {
    fs_rid model = models[0]->data[k];
    xmlChar *model_uri = get_uri(link, model);
    xmlTextWriterStartElement(xml, (xmlChar *) "graph");
    if (FS_IS_URI(model)) {
      xmlTextWriterWriteElement(xml, (xmlChar *) "uri", model_uri);
    } else {
      fs_error(LOG_WARNING, "model %lld is not a URI", model);
    }

    dump_model(link, model, xml);
    xmlTextWriterEndElement(xml);
    xmlTextWriterWriteString(xml, (xmlChar *) "\n");
printf("%5d/%ld: %4.5f %4.5f %4.5f %4.5f\n", k + 1, length, time_resolving, time_bind_first, time_bind_next, time_write_out);
  }
}

void dump_file(fsp_link *link, char *filename)
{
  xmlTextWriterPtr xml  = xmlNewTextWriterFilename(filename, TRUE);

  if (!xml) {
    fs_error(LOG_ERR, "Couldn't write output file, giving up");
    exit(4);
  }

  xmlTextWriterStartDocument(xml, NULL, NULL, NULL);
  xmlTextWriterStartElement(xml, (xmlChar *) "TriX");
  dump_trix(link, xml);
  xmlTextWriterEndDocument(xml); /* also closes TriX */
  xmlFreeTextWriter(xml);
}

int main(int argc, char *argv[])
{
  char *password = fsp_argv_password(&argc, argv);

  if (argc != 3) {
    fprintf(stderr, "%s revision %s\n", argv[0], FS_FRONTEND_VER);
    fprintf(stderr, "Usage: %s <kbname> <uri>\n", argv[0]);
    exit(1);
  }

  fsp_link *link = fsp_open_link(argv[1], password, FS_OPEN_HINT_RO);

  if (!link) {
    fs_error (LOG_ERR, "couldn't connect to “%s”", argv[1]);
    exit(2);
  }

  fs_hash_init(fsp_hash_type(link));
  segments = fsp_link_segments(link);
  dump_file(link, argv[2]);

  fsp_close_link(link);
}