X-Git-Url: http://git.indexdata.com/?p=yaz-moved-to-github.git;a=blobdiff_plain;f=src%2Fcqltransform.c;h=b5fe140e12ddfd652551dab643b9b67940ad7dfb;hp=b2422c9ee80989cd9ecd4d9f3ec6be809bcaadcf;hb=a2a4b952e0742e1527fcb8c9a0e6c85fe35c65f8;hpb=1254f5913d639e30ac822165196170a9b53748ff diff --git a/src/cqltransform.c b/src/cqltransform.c index b2422c9..b5fe140 100644 --- a/src/cqltransform.c +++ b/src/cqltransform.c @@ -1,5 +1,5 @@ /* This file is part of the YAZ toolkit. - * Copyright (C) 1995-2012 Index Data + * Copyright (C) Index Data * See the file LICENSE for details. */ /** @@ -44,8 +44,7 @@ struct cql_transform_t_ { struct cql_prop_entry *entry; yaz_tok_cfg_t tok_cfg; int error; - char *addinfo; - WRBUF w; + WRBUF addinfo; NMEM nmem; }; @@ -54,9 +53,8 @@ cql_transform_t cql_transform_create(void) { cql_transform_t ct = (cql_transform_t) xmalloc(sizeof(*ct)); ct->tok_cfg = yaz_tok_cfg_create(); - ct->w = wrbuf_alloc(); ct->error = 0; - ct->addinfo = 0; + ct->addinfo = wrbuf_alloc(); ct->entry = 0; ct->nmem = nmem_create(); return ct; @@ -70,8 +68,10 @@ static int cql_transform_parse_tok_line(cql_transform_t ct, Z_AttributeElement *ae[20]; int ret = 0; /* 0=OK, != 0 FAIL */ int t; + WRBUF w = wrbuf_alloc(); + t = yaz_tok_move(tp); - + while (t == YAZ_TOK_STRING && ae_num < 20) { WRBUF type_str = wrbuf_alloc(); @@ -79,30 +79,30 @@ static int cql_transform_parse_tok_line(cql_transform_t ct, Z_AttributeElement *elem = 0; const char *value_str = 0; /* attset type=value OR type=value */ - + elem = (Z_AttributeElement *) nmem_malloc(ct->nmem, sizeof(*elem)); elem->attributeSet = 0; ae[ae_num] = elem; - wrbuf_puts(ct->w, yaz_tok_parse_string(tp)); + wrbuf_puts(w, yaz_tok_parse_string(tp)); wrbuf_puts(type_str, yaz_tok_parse_string(tp)); t = yaz_tok_move(tp); if (t == YAZ_TOK_EOF) { wrbuf_destroy(type_str); if (set_str) - wrbuf_destroy(set_str); + wrbuf_destroy(set_str); break; } - if (t == YAZ_TOK_STRING) - { - wrbuf_puts(ct->w, " "); - wrbuf_puts(ct->w, yaz_tok_parse_string(tp)); + if (t == YAZ_TOK_STRING) + { + wrbuf_puts(w, " "); + wrbuf_puts(w, yaz_tok_parse_string(tp)); set_str = type_str; - + elem->attributeSet = yaz_string_to_oid_nmem(yaz_oid_std(), CLASS_ATTSET, wrbuf_cstr(set_str), ct->nmem); - + type_str = wrbuf_alloc(); wrbuf_puts(type_str, yaz_tok_parse_string(tp)); t = yaz_tok_move(tp); @@ -113,7 +113,7 @@ static int cql_transform_parse_tok_line(cql_transform_t ct, { wrbuf_destroy(type_str); if (set_str) - wrbuf_destroy(set_str); + wrbuf_destroy(set_str); yaz_log(YLOG_WARN, "Expected numeric attribute type"); ret = -1; break; @@ -121,8 +121,8 @@ static int cql_transform_parse_tok_line(cql_transform_t ct, wrbuf_destroy(type_str); if (set_str) - wrbuf_destroy(set_str); - + wrbuf_destroy(set_str); + if (t != '=') { yaz_log(YLOG_WARN, "Expected = after after attribute type"); @@ -159,10 +159,10 @@ static int cql_transform_parse_tok_line(cql_transform_t ct, ca->num_semanticAction = 0; ca->semanticAction = 0; } - wrbuf_puts(ct->w, "="); - wrbuf_puts(ct->w, yaz_tok_parse_string(tp)); + wrbuf_puts(w, "="); + wrbuf_puts(w, yaz_tok_parse_string(tp)); t = yaz_tok_move(tp); - wrbuf_puts(ct->w, " "); + wrbuf_puts(w, " "); ae_num++; } if (ret == 0) /* OK? */ @@ -172,7 +172,7 @@ static int cql_transform_parse_tok_line(cql_transform_t ct, pp = &(*pp)->next; *pp = (struct cql_prop_entry *) xmalloc(sizeof(**pp)); (*pp)->pattern = xstrdup(pattern); - (*pp)->value = xstrdup(wrbuf_cstr(ct->w)); + (*pp)->value = xstrdup(wrbuf_cstr(w)); (*pp)->attr_list.num_attributes = ae_num; if (ae_num == 0) @@ -182,7 +182,7 @@ static int cql_transform_parse_tok_line(cql_transform_t ct, (*pp)->attr_list.attributes = (Z_AttributeElement **) nmem_malloc(ct->nmem, ae_num * sizeof(Z_AttributeElement *)); - memcpy((*pp)->attr_list.attributes, ae, + memcpy((*pp)->attr_list.attributes, ae, ae_num * sizeof(Z_AttributeElement *)); } (*pp)->next = 0; @@ -191,12 +191,12 @@ static int cql_transform_parse_tok_line(cql_transform_t ct, { ODR pr = odr_createmem(ODR_PRINT); Z_AttributeList *alp = &(*pp)->attr_list; - odr_setprint(pr, yaz_log_file()); + odr_setprint_noclose(pr, yaz_log_file()); z_AttributeList(pr, &alp, 0, 0); - odr_setprint(pr, 0); odr_destroy(pr); } } + wrbuf_destroy(w); return ret; } @@ -210,7 +210,7 @@ int cql_transform_define_pattern(cql_transform_t ct, const char *pattern, yaz_tok_parse_destroy(tp); return r; } - + cql_transform_t cql_transform_open_FILE(FILE *f) { cql_transform_t ct = cql_transform_create(); @@ -222,7 +222,6 @@ cql_transform_t cql_transform_open_FILE(FILE *f) { yaz_tok_parse_t tp = yaz_tok_parse_buf(ct->tok_cfg, line); int t; - wrbuf_rewind(ct->w); t = yaz_tok_move(tp); if (t == YAZ_TOK_STRING) { @@ -267,9 +266,8 @@ void cql_transform_close(cql_transform_t ct) xfree(pe); pe = pe_next; } - xfree(ct->addinfo); + wrbuf_destroy(ct->addinfo); yaz_tok_cfg_destroy(ct->tok_cfg); - wrbuf_destroy(ct->w); nmem_destroy(ct->nmem); xfree(ct); } @@ -309,7 +307,7 @@ static int compare_attr(Z_AttributeElement *a, Z_AttributeElement *b) z_AttributeElement(odr_a, &a, 0, 0); z_AttributeElement(odr_b, &b, 0, 0); - + buf_a = odr_getbuf(odr_a, &len_a, 0); buf_b = odr_getbuf(odr_b, &len_b, 0); @@ -320,7 +318,7 @@ static int compare_attr(Z_AttributeElement *a, Z_AttributeElement *b) return ret; } -const char *cql_lookup_reverse(cql_transform_t ct, +const char *cql_lookup_reverse(cql_transform_t ct, const char *category, Z_AttributeList *attributes) { @@ -348,7 +346,7 @@ const char *cql_lookup_reverse(cql_transform_t ct, } if (j == attributes->num_attributes) break; /* i was not found at all.. try next pattern */ - + } if (i == e->attr_list.num_attributes) return e->pattern + clen; @@ -356,7 +354,7 @@ const char *cql_lookup_reverse(cql_transform_t ct, } return 0; } - + static const char *cql_lookup_property(cql_transform_t ct, const char *pat1, const char *pat2, const char *pat3) @@ -374,7 +372,7 @@ static const char *cql_lookup_property(cql_transform_t ct, sprintf(pattern, "%.39s", pat1); else return 0; - + for (e = ct->entry; e; e = e->next) { if (!cql_strcmp(e->pattern, pattern)) @@ -383,7 +381,7 @@ static const char *cql_lookup_property(cql_transform_t ct, return 0; } -int cql_pr_attr_uri(cql_transform_t ct, const char *category, +int cql_pr_attr_uri(cql_transform_t ct, WRBUF addinfo, const char *category, const char *uri, const char *val, const char *default_val, void (*pr)(const char *buf, void *client_data), void *client_data, @@ -392,11 +390,11 @@ int cql_pr_attr_uri(cql_transform_t ct, const char *category, const char *res = 0; const char *eval = val ? val : default_val; const char *prefix = 0; - + if (uri) { struct cql_prop_entry *e; - + for (e = ct->entry; e; e = e->next) if (!memcmp(e->pattern, "set.", 4) && e->value && !strcmp(e->value, uri)) @@ -459,27 +457,23 @@ int cql_pr_attr_uri(cql_transform_t ct, const char *category, while (*cp0 == ' ') cp0++; } - return 1; + return 0; } /* error ... */ - if (errcode && !ct->error) - { - ct->error = errcode; - if (val) - ct->addinfo = xstrdup(val); - else - ct->addinfo = 0; - } - return 0; + if (errcode == 0) + return 1; /* signal error, but do not set addinfo */ + if (val) + wrbuf_puts(addinfo, val); + return errcode; } -int cql_pr_attr(cql_transform_t ct, const char *category, +int cql_pr_attr(cql_transform_t ct, WRBUF addinfo, const char *category, const char *val, const char *default_val, void (*pr)(const char *buf, void *client_data), void *client_data, int errcode) { - return cql_pr_attr_uri(ct, category, 0 /* uri */, + return cql_pr_attr_uri(ct, addinfo, category, 0 /* uri */, val, default_val, pr, client_data, errcode); } @@ -496,12 +490,12 @@ static void cql_pr_int(int val, static int cql_pr_prox(cql_transform_t ct, struct cql_node *mods, + WRBUF addinfo, void (*pr)(const char *buf, void *client_data), void *client_data) { int exclusion = 0; - int distance; /* to be filled in later depending on unit */ - int distance_defined = 0; + int distance = -1; int ordered = 0; int proxrel = 2; /* less than or equal */ int unit = 2; /* word */ @@ -514,26 +508,24 @@ static int cql_pr_prox(cql_transform_t ct, struct cql_node *mods, if (!strcmp(name, "distance")) { distance = strtol(term, (char**) 0, 0); - distance_defined = 1; if (!strcmp(relation, "=")) proxrel = 3; else if (!strcmp(relation, ">")) proxrel = 5; else if (!strcmp(relation, "<")) proxrel = 1; - else if (!strcmp(relation, ">=")) + else if (!strcmp(relation, ">=")) proxrel = 4; else if (!strcmp(relation, "<=")) proxrel = 2; else if (!strcmp(relation, "<>")) proxrel = 6; - else + else { - ct->error = YAZ_SRW_UNSUPP_PROX_RELATION; - ct->addinfo = xstrdup(relation); - return 0; + wrbuf_puts(addinfo, relation); + return YAZ_SRW_UNSUPP_PROX_RELATION; } - } + } else if (!strcmp(name, "ordered")) ordered = 1; else if (!strcmp(name, "unordered")) @@ -548,23 +540,21 @@ static int cql_pr_prox(cql_transform_t ct, struct cql_node *mods, unit = 4; else if (!strcmp(term, "element")) unit = 8; - else + else { - ct->error = YAZ_SRW_UNSUPP_PROX_UNIT; - ct->addinfo = xstrdup(term); - return 0; + wrbuf_puts(addinfo, term); + return YAZ_SRW_UNSUPP_PROX_UNIT; } - } - else + } + else { - ct->error = YAZ_SRW_UNSUPP_BOOLEAN_MODIFIER; - ct->addinfo = xstrdup(name); - return 0; + wrbuf_puts(addinfo, name); + return YAZ_SRW_UNSUPP_BOOLEAN_MODIFIER; } mods = mods->u.st.modifiers; } - if (!distance_defined) + if (distance == -1) distance = (unit == 2) ? 1 : 0; cql_pr_int(exclusion, pr, client_data); @@ -574,28 +564,9 @@ static int cql_pr_prox(cql_transform_t ct, struct cql_node *mods, (*pr)("k ", client_data); cql_pr_int(unit, pr, client_data); - return 1; -} - -/* Returns location of first wildcard character in the `length' - * characters starting at `term', or a null pointer of there are - * none -- like memchr(). - */ -static const char *wcchar(int start, const char *term, int length) -{ - while (length > 0) - { - if (start || term[-1] != '\\') - if (strchr("*?", *term)) - return term; - term++; - length--; - start = 0; - } return 0; } - /* ### checks for CQL relation-name rather than Type-1 attribute */ static int has_modifier(struct cql_node *cn, const char *name) { struct cql_node *mod; @@ -607,200 +578,246 @@ static int has_modifier(struct cql_node *cn, const char *name) { return 0; } - -static void emit_term(cql_transform_t ct, - struct cql_node *cn, - const char *term, int length, - void (*pr)(const char *buf, void *client_data), - void *client_data) +static int emit_term(cql_transform_t ct, + struct cql_node *cn, WRBUF addinfo, + const char *term, int length, + void (*pr)(const char *buf, void *client_data), + void *client_data) { - int i; + int i, r; const char *ns = cn->u.st.index_uri; int z3958_mode = 0; int process_term = 1; if (has_modifier(cn, "regexp")) process_term = 0; + else if (has_modifier(cn, "unmasked")) + process_term = 0; else if (cql_lookup_property(ct, "truncation", 0, "cql")) { process_term = 0; - cql_pr_attr(ct, "truncation", "cql", 0, - pr, client_data, YAZ_SRW_MASKING_CHAR_UNSUPP); + r = cql_pr_attr(ct, addinfo, "truncation", "cql", 0, + pr, client_data, YAZ_SRW_MASKING_CHAR_UNSUPP); + if (r) + return r; } assert(cn->which == CQL_NODE_ST); - if (process_term && length > 0) - { - if (length > 1 && term[0] == '^' && term[length-1] == '^') + if (process_term) + { /* convert term via truncation.things */ + unsigned anchor = 0; + unsigned trunc = 0; + for (i = 0; i < length; i++) { - cql_pr_attr(ct, "position", "firstAndLast", 0, - pr, client_data, YAZ_SRW_ANCHORING_CHAR_IN_UNSUPP_POSITION); + if (term[i] == '\\' && i < length - 1) + i++; + else + { + switch (term[i]) + { + case '^': + if (i == 0) + anchor |= 1; + else if (i == length - 1) + anchor |= 2; + break; + case '*': + if (i == 0) + trunc |= 1; + else if (i == length - 1) + trunc |= 2; + else + z3958_mode = 1; + break; + case '?': + z3958_mode = 1; + break; + } + } + } + if (anchor == 3) + { + r = cql_pr_attr(ct, addinfo, "position", "firstAndLast", 0, + pr, client_data, + YAZ_SRW_ANCHORING_CHAR_IN_UNSUPP_POSITION); + if (r) + return r; term++; length -= 2; } - else if (term[0] == '^') + else if (anchor == 1) { - cql_pr_attr(ct, "position", "first", 0, - pr, client_data, YAZ_SRW_ANCHORING_CHAR_IN_UNSUPP_POSITION); + r = cql_pr_attr(ct, addinfo, "position", "first", 0, + pr, client_data, + YAZ_SRW_ANCHORING_CHAR_IN_UNSUPP_POSITION); + if (r) + return r; term++; length--; } - else if (term[length-1] == '^') + else if (anchor == 2) { - cql_pr_attr(ct, "position", "last", 0, - pr, client_data, YAZ_SRW_ANCHORING_CHAR_IN_UNSUPP_POSITION); + r = cql_pr_attr(ct, addinfo, "position", "last", 0, + pr, client_data, + YAZ_SRW_ANCHORING_CHAR_IN_UNSUPP_POSITION); + if (r) + return r; length--; } else { - cql_pr_attr(ct, "position", "any", 0, - pr, client_data, YAZ_SRW_ANCHORING_CHAR_IN_UNSUPP_POSITION); - } - } - - if (process_term && length > 0) - { - const char *first_wc = wcchar(1, term, length); - const char *second_wc = first_wc ? - wcchar(0, first_wc+1, length-(first_wc-term)-1) : 0; - - /* Check for well-known globbing patterns that represent - * simple truncation attributes as expected by, for example, - * Bath-compliant server. If we find such a pattern but - * there's no mapping for it, that's fine: we just use a - * general pattern-matching attribute. - */ - if (first_wc == term && second_wc == term + length-1 - && *first_wc == '*' && *second_wc == '*' - && cql_pr_attr(ct, "truncation", "both", 0, pr, client_data, 0)) - { - term++; - length -= 2; - } - else if (first_wc == term && second_wc == 0 && *first_wc == '*' - && cql_pr_attr(ct, "truncation", "left", 0, - pr, client_data, 0)) - { - term++; - length--; + r = cql_pr_attr(ct, addinfo, "position", "any", 0, + pr, client_data, + YAZ_SRW_ANCHORING_CHAR_IN_UNSUPP_POSITION); + if (r) + return r; } - else if (first_wc == term + length-1 && second_wc == 0 - && *first_wc == '*' - && cql_pr_attr(ct, "truncation", "right", 0, - pr, client_data, 0)) + if (z3958_mode == 0) { - length--; - } - else if (first_wc) - { - z3958_mode = 1; - cql_pr_attr(ct, "truncation", "z3958", 0, - pr, client_data, YAZ_SRW_MASKING_CHAR_UNSUPP); + if (trunc == 3 && !cql_pr_attr(ct, addinfo, "truncation", + "both", 0, pr, client_data, 0)) + { + term++; + length -= 2; + } + else if (trunc == 1 && !cql_pr_attr(ct, addinfo, "truncation", + "left", 0, pr, client_data, 0)) + { + term++; + length--; + } + else if (trunc == 2 && !cql_pr_attr(ct, addinfo, "truncation", + "right", 0, pr, client_data, 0)) + { + length--; + } + else if (trunc) + z3958_mode = 1; + else + cql_pr_attr(ct, addinfo, "truncation", "none", 0, + pr, client_data, 0); } - else + if (z3958_mode) { - /* No masking characters. Use "truncation.none" if given. */ - cql_pr_attr(ct, "truncation", "none", 0, - pr, client_data, 0); + r = cql_pr_attr(ct, addinfo, "truncation", "z3958", 0, + pr, client_data, YAZ_SRW_MASKING_CHAR_UNSUPP); + if (r) + return r; } } - if (ns) { - cql_pr_attr_uri(ct, "index", ns, - cn->u.st.index, "serverChoice", - pr, client_data, YAZ_SRW_UNSUPP_INDEX); + if (ns) + { + r = cql_pr_attr_uri(ct, addinfo, "index", ns, + cn->u.st.index, "serverChoice", + pr, client_data, YAZ_SRW_UNSUPP_INDEX); + if (r) + return r; } if (cn->u.st.modifiers) { struct cql_node *mod = cn->u.st.modifiers; for (; mod; mod = mod->u.st.modifiers) { - cql_pr_attr(ct, "relationModifier", mod->u.st.index, 0, - pr, client_data, YAZ_SRW_UNSUPP_RELATION_MODIFIER); + r = cql_pr_attr(ct, addinfo, + "relationModifier", mod->u.st.index, 0, + pr, client_data, YAZ_SRW_UNSUPP_RELATION_MODIFIER); + if (r) + return r; } } - - /* produce only \-sequences if: - 1) the output is a Z39.58-trunc reserved character - 2) the output is a PQF reserved character (\\, \") - */ (*pr)("\"", client_data); - for (i = 0; i < length; i++) - { - char x[3]; /* temp buffer */ - if (i > 0 && term[i-1] == '\\') + if (process_term) + for (i = 0; i < length; i++) { - if (term[i] == '\"' || term[i] == '\\') - pr("\\", client_data); - if (z3958_mode && strchr("#?", term[i])) - pr("\\\\", client_data); /* double \\ to survive PQF parse */ - x[0] = term[i]; - x[1] = '\0'; - pr(x, client_data); - } - else if (z3958_mode && term[i] == '*') - { - pr("?", client_data); - /* avoid ?n sequences output (n=[0-9]) because that has - different semantics than just a single ? in Z39.58 - */ - if (i < length - 1 && yaz_isdigit(term[i+1])) - pr("\\\\", client_data); /* double \\ to survive PQF parse */ + char x[2]; /* temp buffer */ + if (term[i] == '\\' && i < length - 1) + { + i++; + if (strchr("\"\\", term[i])) + pr("\\", client_data); + if (z3958_mode && strchr("#?", term[i])) + pr("\\\\", client_data); /* double \\ to survive PQF parse */ + x[0] = term[i]; + x[1] = '\0'; + pr(x, client_data); + } + else if (z3958_mode && term[i] == '*') + { + pr("?", client_data); + if (i < length - 1 && yaz_isdigit(term[i+1])) + pr("\\\\", client_data); /* dbl \\ to survive PQF parse */ + } + else if (z3958_mode && term[i] == '?') + { + pr("#", client_data); + } + else + { + if (term[i] == '\"') + pr("\\", client_data); + if (z3958_mode && strchr("#?", term[i])) + pr("\\\\", client_data); /* dbl \\ to survive PQF parse */ + x[0] = term[i]; + x[1] = '\0'; + pr(x, client_data); + } } - else if (z3958_mode && term[i] == '?') - pr("#", client_data); - else if (term[i] != '\\') + else + { + for (i = 0; i < length; i++) { - if (term[i] == '\"') - pr("\\", client_data); - if (z3958_mode && strchr("#?", term[i])) - pr("\\\\", client_data); /* double \\ to survive PQF parse */ + char x[2]; x[0] = term[i]; x[1] = '\0'; pr(x, client_data); } } (*pr)("\" ", client_data); + return 0; } -static void emit_terms(cql_transform_t ct, - struct cql_node *cn, - void (*pr)(const char *buf, void *client_data), - void *client_data, - const char *op) +static int emit_terms(cql_transform_t ct, struct cql_node *cn, + WRBUF addinfo, + void (*pr)(const char *buf, void *client_data), + void *client_data, + const char *op) { struct cql_node *ne = cn->u.st.extra_terms; + int r; if (ne) { (*pr)("@", client_data); (*pr)(op, client_data); (*pr)(" ", client_data); } - emit_term(ct, cn, cn->u.st.term, strlen(cn->u.st.term), - pr, client_data); - for (; ne; ne = ne->u.st.extra_terms) + r = emit_term(ct, cn, addinfo, cn->u.st.term, strlen(cn->u.st.term), + pr, client_data); + for (; !r && ne; ne = ne->u.st.extra_terms) { if (ne->u.st.extra_terms) { (*pr)("@", client_data); (*pr)(op, client_data); (*pr)(" ", client_data); - } - emit_term(ct, cn, ne->u.st.term, strlen(ne->u.st.term), - pr, client_data); + } + r = emit_term(ct, cn, addinfo, ne->u.st.term, strlen(ne->u.st.term), + pr, client_data); } + return r; } -static void emit_wordlist(cql_transform_t ct, - struct cql_node *cn, - void (*pr)(const char *buf, void *client_data), - void *client_data, - const char *op) +static int emit_wordlist(cql_transform_t ct, struct cql_node *cn, + WRBUF addinfo, + void (*pr)(const char *buf, void *client_data), + void *client_data, + const char *op) { + int r = 0; const char *cp0 = cn->u.st.term; const char *cp1; const char *last_term = 0; int last_length = 0; - while(cp0) + while (!r && cp0) { while (*cp0 == ' ') cp0++; @@ -810,7 +827,8 @@ static void emit_wordlist(cql_transform_t ct, (*pr)("@", client_data); (*pr)(op, client_data); (*pr)(" ", client_data); - emit_term(ct, cn, last_term, last_length, pr, client_data); + r = emit_term(ct, cn, addinfo, last_term, last_length, + pr, client_data); } last_term = cp0; if (cp1) @@ -819,20 +837,22 @@ static void emit_wordlist(cql_transform_t ct, last_length = strlen(cp0); cp0 = cp1; } - if (last_term) - emit_term(ct, cn, last_term, last_length, pr, client_data); + if (!r && last_term) + r = emit_term(ct, cn, addinfo, last_term, last_length, pr, client_data); + return r; } -void cql_transform_r(cql_transform_t ct, - struct cql_node *cn, +static int emit_node(cql_transform_t ct, struct cql_node *cn, + WRBUF addinfo, void (*pr)(const char *buf, void *client_data), void *client_data) { const char *ns; + int r = 0; struct cql_node *mods; if (!cn) - return; + return 0; switch (cn->which) { case CQL_NODE_ST: @@ -845,69 +865,73 @@ void cql_transform_r(cql_transform_t ct, (*pr)("@set \"", client_data); (*pr)(cn->u.st.term, client_data); (*pr)("\" ", client_data); - return ; + return 0; } } else { - if (!ct->error) - { - ct->error = YAZ_SRW_UNSUPP_CONTEXT_SET; - ct->addinfo = 0; - } - } - cql_pr_attr(ct, "always", 0, 0, pr, client_data, 0); - cql_pr_attr(ct, "relation", cn->u.st.relation, 0, pr, client_data, - YAZ_SRW_UNSUPP_RELATION); - cql_pr_attr(ct, "structure", cn->u.st.relation, 0, - pr, client_data, YAZ_SRW_UNSUPP_COMBI_OF_RELATION_AND_TERM); + return YAZ_SRW_UNSUPP_CONTEXT_SET; + } + cql_pr_attr(ct, addinfo, "always", 0, 0, pr, client_data, 0); + r = cql_pr_attr(ct, addinfo, "relation", cn->u.st.relation, 0, + pr, client_data, YAZ_SRW_UNSUPP_RELATION); + if (r) + return r; + r = cql_pr_attr(ct, addinfo, "structure", cn->u.st.relation, 0, + pr, client_data, + YAZ_SRW_UNSUPP_COMBI_OF_RELATION_AND_TERM); + if (r) + return r; if (cn->u.st.relation && !cql_strcmp(cn->u.st.relation, "all")) - emit_wordlist(ct, cn, pr, client_data, "and"); + r = emit_wordlist(ct, cn, addinfo, pr, client_data, "and"); else if (cn->u.st.relation && !cql_strcmp(cn->u.st.relation, "any")) - emit_wordlist(ct, cn, pr, client_data, "or"); + r = emit_wordlist(ct, cn, addinfo, pr, client_data, "or"); else - emit_terms(ct, cn, pr, client_data, "and"); + r = emit_terms(ct, cn, addinfo, pr, client_data, "and"); break; case CQL_NODE_BOOL: (*pr)("@", client_data); (*pr)(cn->u.boolean.value, client_data); (*pr)(" ", client_data); mods = cn->u.boolean.modifiers; - if (!strcmp(cn->u.boolean.value, "prox")) + if (!strcmp(cn->u.boolean.value, "prox")) { - if (!cql_pr_prox(ct, mods, pr, client_data)) - return; - } + r = cql_pr_prox(ct, mods, addinfo, pr, client_data); + if (r) + return r; + } else if (mods) { /* Boolean modifiers other than on proximity not supported */ - ct->error = YAZ_SRW_UNSUPP_BOOLEAN_MODIFIER; - ct->addinfo = xstrdup(mods->u.st.index); - return; + wrbuf_puts(addinfo, mods->u.st.index); + return YAZ_SRW_UNSUPP_BOOLEAN_MODIFIER; } - cql_transform_r(ct, cn->u.boolean.left, pr, client_data); - cql_transform_r(ct, cn->u.boolean.right, pr, client_data); + r = emit_node(ct, cn->u.boolean.left, addinfo, pr, client_data); + if (r) + return r; + r = emit_node(ct, cn->u.boolean.right, addinfo, pr, client_data); + if (r) + return r; break; case CQL_NODE_SORT: - cql_transform_r(ct, cn->u.sort.search, pr, client_data); + r = emit_node(ct, cn->u.sort.search, addinfo, pr, client_data); break; default: fprintf(stderr, "Fatal: impossible CQL node-type %d\n", cn->which); abort(); } + return r; } -int cql_transform(cql_transform_t ct, struct cql_node *cn, - void (*pr)(const char *buf, void *client_data), - void *client_data) +int cql_transform_r(cql_transform_t ct, struct cql_node *cn, + WRBUF addinfo, + void (*pr)(const char *buf, void *client_data), + void *client_data) { struct cql_prop_entry *e; NMEM nmem = nmem_create(); - - ct->error = 0; - xfree(ct->addinfo); - ct->addinfo = 0; + int r; for (e = ct->entry; e ; e = e->next) { @@ -916,11 +940,21 @@ int cql_transform(cql_transform_t ct, struct cql_node *cn, else if (!cql_strcmp(e->pattern, "set")) cql_apply_prefix(nmem, cn, 0, e->value); } - cql_transform_r(ct, cn, pr, client_data); + r = emit_node(ct, cn, addinfo, pr, client_data); nmem_destroy(nmem); - return ct->error; + return r; } +int cql_transform(cql_transform_t ct, struct cql_node *cn, + void (*pr)(const char *buf, void *client_data), + void *client_data) +{ + WRBUF addinfo = wrbuf_alloc(); + int r = cql_transform_r(ct, cn, addinfo, pr, client_data); + cql_transform_set_error(ct, r, wrbuf_cstr(addinfo)); + wrbuf_destroy(addinfo); + return r; +} int cql_transform_FILE(cql_transform_t ct, struct cql_node *cn, FILE *f) { @@ -942,9 +976,8 @@ int cql_transform_buf(cql_transform_t ct, struct cql_node *cn, SRW diagnostic is deprecated, but it's so perfect for our purposes that it would be stupid not to use it. */ char numbuf[30]; - ct->error = YAZ_SRW_TOO_MANY_CHARS_IN_QUERY; sprintf(numbuf, "%ld", (long) info.max); - ct->addinfo = xstrdup(numbuf); + cql_transform_set_error(ct, YAZ_SRW_TOO_MANY_CHARS_IN_QUERY, numbuf); return -1; } if (info.off >= 0) @@ -954,14 +987,15 @@ int cql_transform_buf(cql_transform_t ct, struct cql_node *cn, int cql_transform_error(cql_transform_t ct, const char **addinfo) { - *addinfo = ct->addinfo; + *addinfo = wrbuf_len(ct->addinfo) ? wrbuf_cstr(ct->addinfo) : 0; return ct->error; } void cql_transform_set_error(cql_transform_t ct, int error, const char *addinfo) { - xfree(ct->addinfo); - ct->addinfo = addinfo ? xstrdup(addinfo) : 0; + wrbuf_rewind(ct->addinfo); + if (addinfo) + wrbuf_puts(ct->addinfo, addinfo); ct->error = error; }