+ if (!pazpar2_decref(&service->ref_count, service->mutex))
+ {
+ service_xslt_destroy(service);
+ pp2_charset_fact_destroy(service->charsets);
+ ccl_qual_rm(&service->ccl_bibset);
+ yaz_mutex_destroy(&service->mutex);
+ nmem_destroy(service->nmem);
+ }
+ }
+}
+
+void service_incref(struct conf_service *service)
+{
+ pazpar2_incref(&service->ref_count, service->mutex);
+}
+
+static int parse_metadata(struct conf_service *service, xmlNode *n,
+ int *md_node, int *sk_node)
+{
+ enum conf_metadata_type type = Metadata_type_generic;
+ enum conf_metadata_merge merge = Metadata_merge_no;
+ enum conf_setting_type setting = Metadata_setting_no;
+ enum conf_metadata_mergekey mergekey_type = Metadata_mergekey_no;
+ int brief = 0;
+ int termlist = 0;
+ int sortkey_offset = 0;
+ xmlChar *xml_name = 0;
+ xmlChar *xml_brief = 0;
+ xmlChar *xml_sortkey = 0;
+ xmlChar *xml_merge = 0;
+ xmlChar *xml_type = 0;
+ xmlChar *xml_termlist = 0;
+ xmlChar *xml_rank = 0;
+ xmlChar *xml_setting = 0;
+ xmlChar *xml_mergekey = 0;
+ xmlChar *xml_limitmap = 0;
+ xmlChar *xml_limitcluster = 0;
+ xmlChar *xml_icu_chain = 0;
+
+ struct _xmlAttr *attr;
+
+ assert(service);
+
+ for (attr = n->properties; attr; attr = attr->next)
+ {
+ if (!xmlStrcmp(attr->name, BAD_CAST "name") &&
+ attr->children && attr->children->type == XML_TEXT_NODE)
+ xml_name = attr->children->content;
+ else if (!xmlStrcmp(attr->name, BAD_CAST "brief") &&
+ attr->children && attr->children->type == XML_TEXT_NODE)
+ xml_brief = attr->children->content;
+ else if (!xmlStrcmp(attr->name, BAD_CAST "sortkey") &&
+ attr->children && attr->children->type == XML_TEXT_NODE)
+ xml_sortkey = attr->children->content;
+ else if (!xmlStrcmp(attr->name, BAD_CAST "merge") &&
+ attr->children && attr->children->type == XML_TEXT_NODE)
+ xml_merge = attr->children->content;
+ else if (!xmlStrcmp(attr->name, BAD_CAST "type") &&
+ attr->children && attr->children->type == XML_TEXT_NODE)
+ xml_type = attr->children->content;
+ else if (!xmlStrcmp(attr->name, BAD_CAST "termlist") &&
+ attr->children && attr->children->type == XML_TEXT_NODE)
+ xml_termlist = attr->children->content;
+ else if (!xmlStrcmp(attr->name, BAD_CAST "rank") &&
+ attr->children && attr->children->type == XML_TEXT_NODE)
+ xml_rank = attr->children->content;
+ else if (!xmlStrcmp(attr->name, BAD_CAST "setting") &&
+ attr->children && attr->children->type == XML_TEXT_NODE)
+ xml_setting = attr->children->content;
+ else if (!xmlStrcmp(attr->name, BAD_CAST "mergekey") &&
+ attr->children && attr->children->type == XML_TEXT_NODE)
+ xml_mergekey = attr->children->content;
+ else if (!xmlStrcmp(attr->name, BAD_CAST "facetrule") &&
+ attr->children && attr->children->type == XML_TEXT_NODE)
+ xml_icu_chain = attr->children->content;
+ else if (!xmlStrcmp(attr->name, BAD_CAST "limitmap") &&
+ attr->children && attr->children->type == XML_TEXT_NODE)
+ xml_limitmap = attr->children->content;
+ else if (!xmlStrcmp(attr->name, BAD_CAST "limitcluster") &&
+ attr->children && attr->children->type == XML_TEXT_NODE)
+ xml_limitcluster = attr->children->content;
+ else
+ {
+ yaz_log(YLOG_FATAL, "Unknown metadata attribute '%s'", attr->name);
+ return -1;
+ }
+ }
+
+ // now do the parsing logic
+ if (!xml_name)
+ {
+ yaz_log(YLOG_FATAL, "Must specify name in metadata element");
+ return -1;
+ }
+ if (xml_brief)
+ {
+ if (!strcmp((const char *) xml_brief, "yes"))
+ brief = 1;
+ else if (strcmp((const char *) xml_brief, "no"))
+ {
+ yaz_log(YLOG_FATAL, "metadata/brief must be yes or no");
+ return -1;
+ }
+ }
+
+ if (xml_termlist)
+ {
+ if (!strcmp((const char *) xml_termlist, "yes"))
+ termlist = 1;
+ else if (strcmp((const char *) xml_termlist, "no"))
+ {
+ yaz_log(YLOG_FATAL, "metadata/termlist must be yes or no");
+ return -1;
+ }
+ }
+
+ if (xml_type)
+ {
+ if (!strcmp((const char *) xml_type, "generic"))
+ type = Metadata_type_generic;
+ else if (!strcmp((const char *) xml_type, "year"))
+ type = Metadata_type_year;
+ else if (!strcmp((const char *) xml_type, "date"))
+ type = Metadata_type_date;
+ else if (!strcmp((const char *) xml_type, "float"))
+ type = Metadata_type_float;
+ else
+ {
+ yaz_log(YLOG_FATAL,
+ "Unknown value for metadata/type: %s", xml_type);
+ return -1;
+ }
+ }
+
+ if (xml_merge)
+ {
+ if (!strcmp((const char *) xml_merge, "no"))
+ merge = Metadata_merge_no;
+ else if (!strcmp((const char *) xml_merge, "unique"))
+ merge = Metadata_merge_unique;
+ else if (!strcmp((const char *) xml_merge, "longest"))
+ merge = Metadata_merge_longest;
+ else if (!strcmp((const char *) xml_merge, "range"))
+ merge = Metadata_merge_range;
+ else if (!strcmp((const char *) xml_merge, "all"))
+ merge = Metadata_merge_all;
+ else if (!strcmp((const char *) xml_merge, "first"))
+ merge = Metadata_merge_first;
+ else
+ {
+ yaz_log(YLOG_FATAL,
+ "Unknown value for metadata/merge: %s", xml_merge);
+ return -1;
+ }
+ }
+
+ if (xml_setting)
+ {
+ if (!strcmp((const char *) xml_setting, "no"))
+ setting = Metadata_setting_no;
+ else if (!strcmp((const char *) xml_setting, "postproc"))
+ setting = Metadata_setting_postproc;
+ else if (!strcmp((const char *) xml_setting, "parameter"))
+ setting = Metadata_setting_parameter;
+ else
+ {
+ yaz_log(YLOG_FATAL,
+ "Unknown value for metadata/setting: %s", xml_setting);
+ return -1;
+ }
+ }
+
+ // add a sortkey if so specified
+ if (xml_sortkey && strcmp((const char *) xml_sortkey, "no"))
+ {
+ enum conf_metadata_type sk_type = type;
+ if (merge == Metadata_merge_no)
+ {
+ yaz_log(YLOG_FATAL,
+ "Can't specify sortkey on a non-merged field");
+ return -1;
+ }
+ if (!strcmp((const char *) xml_sortkey, "yes"))
+ ;
+ if (!strcmp((const char *) xml_sortkey, "numeric"))
+ ;
+ else if (!strcmp((const char *) xml_sortkey, "skiparticle"))
+ {
+ if (sk_type == Metadata_type_generic)
+ sk_type = Metadata_type_skiparticle;
+ else
+ {
+ yaz_log(YLOG_FATAL,
+ "skiparticle only supported for type=generic: %s",
+ xml_type);
+ return -1;
+ }
+ }
+ else
+ {
+ yaz_log(YLOG_FATAL,
+ "Unknown sortkey in metadata element: %s",
+ xml_sortkey);
+ return -1;
+ }
+ sortkey_offset = *sk_node;
+
+ conf_service_add_sortkey(service, *sk_node,
+ (const char *) xml_name, sk_type);
+ (*sk_node)++;
+ }
+ else
+ sortkey_offset = -1;
+
+ if (xml_mergekey)
+ {
+ if (!strcmp((const char *) xml_mergekey, "required"))
+ mergekey_type = Metadata_mergekey_required;
+ else if (!strcmp((const char *) xml_mergekey, "optional"))
+ mergekey_type = Metadata_mergekey_optional;
+ else if (!strcmp((const char *) xml_mergekey, "no"))
+ mergekey_type = Metadata_mergekey_no;
+ else
+ {
+ yaz_log(YLOG_FATAL, "Unknown value for mergekey: %s", xml_mergekey);
+ return -1;
+ }