+
+/** \brief Parse a fromstring clause */
+static yaz_nfa_state *parse_fromstring(yaz_nfa *nfa,
+ xmlNodePtr node, const char *filename, int rulenumber )
+{
+ yaz_nfa_char buf[MAXDATALEN];
+ yaz_nfa_state *state;
+ int bufidx=utf16_content(node, buf, MAXDATALEN, filename, rulenumber);
+ if (bufidx<0)
+ return 0;
+ state=yaz_nfa_add_sequence(nfa, 0, buf, bufidx);
+ return state;
+} /* parse_fromstring */
+
+/** \brief Parse a tostring clause */
+static yaz_nfa_converter *parse_tostring(yaz_nfa *nfa,
+ xmlNodePtr node, const char *filename, int rulenumber )
+{
+ yaz_nfa_char buf[MAXDATALEN];
+ yaz_nfa_converter *conv;
+ int bufidx=utf16_content(node, buf, MAXDATALEN, filename, rulenumber);
+ if (bufidx<0)
+ return 0;
+ conv=yaz_nfa_create_string_converter(nfa, buf, bufidx);
+ return conv;
+} /* parse_tostring */
+
+static yaz_nfa_state * parse_fromrange(yaz_nfa *nfa,
+ xmlNodePtr node,
+ yaz_nfa_char *from_begin,
+ yaz_nfa_char *from_end,
+ const char *filename, int rulenumber )
+{
+ yaz_nfa_char begin;
+ yaz_nfa_char end;
+ yaz_nfa_state *state;
+ int rc;
+ rc=parse_range(node, &begin, &end, filename, rulenumber);
+ if (!rc)
+ return 0;
+ *from_begin=begin;
+ *from_end=end; /* save for calculating the to-range */
+ state=yaz_nfa_add_range(nfa, 0, begin, end);
+ return state;
+} /* parse_fromrange */
+
+static yaz_nfa_converter *parse_torange(yaz_nfa *nfa,
+ xmlNodePtr node, yaz_nfa_char from_begin, yaz_nfa_char from_end,
+ const char *filename, int rulenumber )
+{
+ yaz_nfa_char begin;
+ yaz_nfa_char end;
+ yaz_nfa_converter *conv;
+ int rc;
+ rc=parse_range(node, &begin, &end, filename, rulenumber);
+ if (!rc)
+ return 0;
+ if ( from_end - from_begin != end - begin ) {
+ yaz_log(YLOG_FATAL,"From-range not as long as to-range: "
+ "from=%x-%x to=%x-%x in rule %d in %s",
+ from_begin, from_end, begin, end, rulenumber, filename);
+ return 0;
+ }
+ conv=yaz_nfa_create_range_converter(nfa, 0, from_begin, begin);
+ return conv;
+} /* parse_torange */
+
+/** \brief Parse one rule from an XML node */
+static int parse_rule(yaz_nfa *nfa, xmlNodePtr rulenode,
+ const char *filename, int rulenumber )
+{
+ yaz_nfa_state *state=0;
+ yaz_nfa_converter *conv=0;
+ yaz_nfa_char range_begin=0, range_end=0;
+ xmlNodePtr node;
+ int clauses=0;
+ for (node = rulenode->children; node; node = node->next)
+ {
+ if (node->type != XML_ELEMENT_NODE)
+ continue;
+ clauses++;
+ if (!strcmp((const char *) node->name, "fromstring"))
+ {
+ state = parse_fromstring(nfa, node, filename, rulenumber );
+ if (!state)
+ return 0;
+ } else if (!strcmp((const char *) node->name, "tostring"))
+ {
+ conv = parse_tostring(nfa, node, filename, rulenumber );
+ if (!conv)
+ return 0;
+ } else if (!strcmp((const char *) node->name, "fromrange"))
+ {
+ state = parse_fromrange(nfa, node,
+ &range_begin, &range_end, filename, rulenumber );
+ if (!state)
+ return 0;
+ } else if (!strcmp((const char *) node->name, "torange"))
+ {
+ conv = parse_torange(nfa, node,
+ range_begin, range_end, filename, rulenumber );
+ if (!conv)
+ return 0;
+ } else {
+ yaz_log(YLOG_FATAL,"Unknown clause '%s' in %s rule %d",
+ node->name, filename,rulenumber);
+ return 0;
+ }
+ } /* for child */
+ if (!state) {
+ yaz_log(YLOG_FATAL,"No 'from' clause in a rule %d in %s",
+ rulenumber,filename);
+ return 0;
+ }
+ if (!conv) {
+ yaz_log(YLOG_FATAL,"No 'to' clause in a rule %d in %s",
+ rulenumber,filename);
+ return 0;
+ }
+ if (clauses != 2) {
+ yaz_log(YLOG_FATAL,"Must have exactly one 'from' and one 'to' clause "
+ "in rule %d in %s", rulenumber,filename);
+ return 0;
+ }
+ if ( YAZ_NFA_SUCCESS == yaz_nfa_set_result(nfa,state,conv))
+ return 1;
+ yaz_log(YLOG_FATAL,"Conflicting rules in %s rule %d",
+ filename, rulenumber);