00001
00002
00003
00004
00005
00021 #include <assert.h>
00022 #include <stdlib.h>
00023 #include <string.h>
00024 #include <ctype.h>
00025 #include <yaz/rpn2cql.h>
00026 #include <yaz/xmalloc.h>
00027 #include <yaz/diagsrw.h>
00028 #include <yaz/tokenizer.h>
00029 #include <yaz/wrbuf.h>
00030 #include <yaz/z-core.h>
00031 #include <yaz/matchstr.h>
00032 #include <yaz/oid_db.h>
00033 #include <yaz/log.h>
00034
00035 struct cql_prop_entry {
00036 char *pattern;
00037 char *value;
00038 Z_AttributeList attr_list;
00039 struct cql_prop_entry *next;
00040 };
00041
00042 struct cql_transform_t_ {
00043 struct cql_prop_entry *entry;
00044 yaz_tok_cfg_t tok_cfg;
00045 int error;
00046 char *addinfo;
00047 WRBUF w;
00048 NMEM nmem;
00049 };
00050
00051
00052 cql_transform_t cql_transform_create(void)
00053 {
00054 cql_transform_t ct = (cql_transform_t) xmalloc(sizeof(*ct));
00055 ct->tok_cfg = yaz_tok_cfg_create();
00056 ct->w = wrbuf_alloc();
00057 ct->error = 0;
00058 ct->addinfo = 0;
00059 ct->entry = 0;
00060 ct->nmem = nmem_create();
00061 return ct;
00062 }
00063
00064 static int cql_transform_parse_tok_line(cql_transform_t ct,
00065 const char *pattern,
00066 yaz_tok_parse_t tp)
00067 {
00068 int ae_num = 0;
00069 Z_AttributeElement *ae[20];
00070 int ret = 0;
00071 int t;
00072 t = yaz_tok_move(tp);
00073
00074 while (t == YAZ_TOK_STRING && ae_num < 20)
00075 {
00076 WRBUF type_str = wrbuf_alloc();
00077 WRBUF set_str = 0;
00078 Z_AttributeElement *elem = 0;
00079 const char *value_str = 0;
00080
00081
00082 elem = (Z_AttributeElement *) nmem_malloc(ct->nmem, sizeof(*elem));
00083 elem->attributeSet = 0;
00084 ae[ae_num] = elem;
00085 wrbuf_puts(ct->w, yaz_tok_parse_string(tp));
00086 wrbuf_puts(type_str, yaz_tok_parse_string(tp));
00087 t = yaz_tok_move(tp);
00088 if (t == YAZ_TOK_EOF)
00089 {
00090 wrbuf_destroy(type_str);
00091 if (set_str)
00092 wrbuf_destroy(set_str);
00093 break;
00094 }
00095 if (t == YAZ_TOK_STRING)
00096 {
00097 wrbuf_puts(ct->w, " ");
00098 wrbuf_puts(ct->w, yaz_tok_parse_string(tp));
00099 set_str = type_str;
00100
00101 elem->attributeSet =
00102 yaz_string_to_oid_nmem(yaz_oid_std(), CLASS_ATTSET,
00103 wrbuf_cstr(set_str), ct->nmem);
00104
00105 type_str = wrbuf_alloc();
00106 wrbuf_puts(type_str, yaz_tok_parse_string(tp));
00107 t = yaz_tok_move(tp);
00108 }
00109 elem->attributeType = nmem_intdup(ct->nmem, 0);
00110 if (sscanf(wrbuf_cstr(type_str), "%d", elem->attributeType)
00111 != 1)
00112 {
00113 wrbuf_destroy(type_str);
00114 if (set_str)
00115 wrbuf_destroy(set_str);
00116 yaz_log(YLOG_WARN, "Expected numeric attribute type");
00117 ret = -1;
00118 break;
00119 }
00120
00121 wrbuf_destroy(type_str);
00122 if (set_str)
00123 wrbuf_destroy(set_str);
00124
00125 if (t != '=')
00126 {
00127 yaz_log(YLOG_WARN, "Expected = after after attribute type");
00128 ret = -1;
00129 break;
00130 }
00131 t = yaz_tok_move(tp);
00132 if (t != YAZ_TOK_STRING)
00133 {
00134 yaz_log(YLOG_WARN, "Missing attribute value");
00135 ret = -1;
00136 break;
00137 }
00138 value_str = yaz_tok_parse_string(tp);
00139 if (isdigit(*value_str))
00140 {
00141 elem->which = Z_AttributeValue_numeric;
00142 elem->value.numeric =
00143 nmem_intdup(ct->nmem, atoi(value_str));
00144 }
00145 else
00146 {
00147 Z_ComplexAttribute *ca = (Z_ComplexAttribute *)
00148 nmem_malloc(ct->nmem, sizeof(*ca));
00149 elem->which = Z_AttributeValue_complex;
00150 elem->value.complex = ca;
00151 ca->num_list = 1;
00152 ca->list = (Z_StringOrNumeric **)
00153 nmem_malloc(ct->nmem, sizeof(Z_StringOrNumeric *));
00154 ca->list[0] = (Z_StringOrNumeric *)
00155 nmem_malloc(ct->nmem, sizeof(Z_StringOrNumeric));
00156 ca->list[0]->which = Z_StringOrNumeric_string;
00157 ca->list[0]->u.string = nmem_strdup(ct->nmem, value_str);
00158 ca->num_semanticAction = 0;
00159 ca->semanticAction = 0;
00160 }
00161 wrbuf_puts(ct->w, "=");
00162 wrbuf_puts(ct->w, yaz_tok_parse_string(tp));
00163 t = yaz_tok_move(tp);
00164 wrbuf_puts(ct->w, " ");
00165 ae_num++;
00166 }
00167 if (ret == 0)
00168 {
00169 struct cql_prop_entry **pp = &ct->entry;
00170 while (*pp)
00171 pp = &(*pp)->next;
00172 *pp = (struct cql_prop_entry *) xmalloc(sizeof(**pp));
00173 (*pp)->pattern = xstrdup(pattern);
00174 (*pp)->value = xstrdup(wrbuf_cstr(ct->w));
00175
00176 (*pp)->attr_list.num_attributes = ae_num;
00177 if (ae_num == 0)
00178 (*pp)->attr_list.attributes = 0;
00179 else
00180 {
00181 (*pp)->attr_list.attributes = (Z_AttributeElement **)
00182 nmem_malloc(ct->nmem,
00183 ae_num * sizeof(Z_AttributeElement *));
00184 memcpy((*pp)->attr_list.attributes, ae,
00185 ae_num * sizeof(Z_AttributeElement *));
00186 }
00187 (*pp)->next = 0;
00188
00189 if (0)
00190 {
00191 ODR pr = odr_createmem(ODR_PRINT);
00192 Z_AttributeList *alp = &(*pp)->attr_list;
00193 odr_setprint(pr, yaz_log_file());
00194 z_AttributeList(pr, &alp, 0, 0);
00195 odr_setprint(pr, 0);
00196 odr_destroy(pr);
00197 }
00198 }
00199 return ret;
00200 }
00201
00202 int cql_transform_define_pattern(cql_transform_t ct, const char *pattern,
00203 const char *value)
00204 {
00205 int r;
00206 yaz_tok_parse_t tp = yaz_tok_parse_buf(ct->tok_cfg, value);
00207 yaz_tok_cfg_single_tokens(ct->tok_cfg, "=");
00208 r = cql_transform_parse_tok_line(ct, pattern, tp);
00209 yaz_tok_parse_destroy(tp);
00210 return r;
00211 }
00212
00213 cql_transform_t cql_transform_open_FILE(FILE *f)
00214 {
00215 cql_transform_t ct = cql_transform_create();
00216 char line[1024];
00217
00218 yaz_tok_cfg_single_tokens(ct->tok_cfg, "=");
00219
00220 while (fgets(line, sizeof(line)-1, f))
00221 {
00222 yaz_tok_parse_t tp = yaz_tok_parse_buf(ct->tok_cfg, line);
00223 int t;
00224 wrbuf_rewind(ct->w);
00225 t = yaz_tok_move(tp);
00226 if (t == YAZ_TOK_STRING)
00227 {
00228 char * pattern = xstrdup(yaz_tok_parse_string(tp));
00229 t = yaz_tok_move(tp);
00230 if (t != '=')
00231 {
00232 yaz_tok_parse_destroy(tp);
00233 cql_transform_close(ct);
00234 return 0;
00235 }
00236 if (cql_transform_parse_tok_line(ct, pattern, tp))
00237 {
00238 yaz_tok_parse_destroy(tp);
00239 cql_transform_close(ct);
00240 return 0;
00241 }
00242 xfree(pattern);
00243 }
00244 else if (t != YAZ_TOK_EOF)
00245 {
00246 yaz_tok_parse_destroy(tp);
00247 cql_transform_close(ct);
00248 return 0;
00249 }
00250 yaz_tok_parse_destroy(tp);
00251 }
00252 return ct;
00253 }
00254
00255 void cql_transform_close(cql_transform_t ct)
00256 {
00257 struct cql_prop_entry *pe;
00258 if (!ct)
00259 return;
00260 pe = ct->entry;
00261 while (pe)
00262 {
00263 struct cql_prop_entry *pe_next = pe->next;
00264 xfree(pe->pattern);
00265 xfree(pe->value);
00266 xfree(pe);
00267 pe = pe_next;
00268 }
00269 xfree(ct->addinfo);
00270 yaz_tok_cfg_destroy(ct->tok_cfg);
00271 wrbuf_destroy(ct->w);
00272 nmem_destroy(ct->nmem);
00273 xfree(ct);
00274 }
00275
00276 cql_transform_t cql_transform_open_fname(const char *fname)
00277 {
00278 cql_transform_t ct;
00279 FILE *f = fopen(fname, "r");
00280 if (!f)
00281 return 0;
00282 ct = cql_transform_open_FILE(f);
00283 fclose(f);
00284 return ct;
00285 }
00286
00287 #if 0
00288 struct Z_AttributeElement {
00289 Z_AttributeSetId *attributeSet;
00290 int *attributeType;
00291 int which;
00292 union {
00293 int *numeric;
00294 Z_ComplexAttribute *complex;
00295 #define Z_AttributeValue_numeric 1
00296 #define Z_AttributeValue_complex 2
00297 } value;
00298 };
00299 #endif
00300
00301 static int compare_attr(Z_AttributeElement *a, Z_AttributeElement *b)
00302 {
00303 ODR odr_a = odr_createmem(ODR_ENCODE);
00304 ODR odr_b = odr_createmem(ODR_ENCODE);
00305 int len_a, len_b;
00306 char *buf_a, *buf_b;
00307 int ret;
00308
00309 z_AttributeElement(odr_a, &a, 0, 0);
00310 z_AttributeElement(odr_b, &b, 0, 0);
00311
00312 buf_a = odr_getbuf(odr_a, &len_a, 0);
00313 buf_b = odr_getbuf(odr_b, &len_b, 0);
00314
00315 ret = yaz_memcmp(buf_a, buf_b, len_a, len_b);
00316
00317 odr_destroy(odr_a);
00318 odr_destroy(odr_b);
00319 return ret;
00320 }
00321
00322 const char *cql_lookup_reverse(cql_transform_t ct,
00323 const char *category,
00324 Z_AttributeList *attributes)
00325 {
00326 struct cql_prop_entry *e;
00327 size_t clen = strlen(category);
00328 for (e = ct->entry; e; e = e->next)
00329 {
00330 if (!strncmp(e->pattern, category, clen))
00331 {
00332
00333
00334 int i;
00335 for (i = 0; i < e->attr_list.num_attributes; i++)
00336 {
00337
00338 Z_AttributeElement *e_ae = e->attr_list.attributes[i];
00339 int j;
00340 for (j = 0; j < attributes->num_attributes; j++)
00341 {
00342
00343 Z_AttributeElement *a_ae = attributes->attributes[j];
00344 int r = compare_attr(e_ae, a_ae);
00345 if (r == 0)
00346 break;
00347 }
00348 if (j == attributes->num_attributes)
00349 break;
00350
00351 }
00352 if (i == e->attr_list.num_attributes)
00353 return e->pattern;
00354 }
00355 }
00356 return 0;
00357 }
00358
00359 static const char *cql_lookup_property(cql_transform_t ct,
00360 const char *pat1, const char *pat2,
00361 const char *pat3)
00362 {
00363 char pattern[120];
00364 struct cql_prop_entry *e;
00365
00366 if (pat1 && pat2 && pat3)
00367 sprintf(pattern, "%.39s.%.39s.%.39s", pat1, pat2, pat3);
00368 else if (pat1 && pat2)
00369 sprintf(pattern, "%.39s.%.39s", pat1, pat2);
00370 else if (pat1 && pat3)
00371 sprintf(pattern, "%.39s.%.39s", pat1, pat3);
00372 else if (pat1)
00373 sprintf(pattern, "%.39s", pat1);
00374 else
00375 return 0;
00376
00377 for (e = ct->entry; e; e = e->next)
00378 {
00379 if (!cql_strcmp(e->pattern, pattern))
00380 return e->value;
00381 }
00382 return 0;
00383 }
00384
00385 int cql_pr_attr_uri(cql_transform_t ct, const char *category,
00386 const char *uri, const char *val, const char *default_val,
00387 void (*pr)(const char *buf, void *client_data),
00388 void *client_data,
00389 int errcode)
00390 {
00391 const char *res = 0;
00392 const char *eval = val ? val : default_val;
00393 const char *prefix = 0;
00394
00395 if (uri)
00396 {
00397 struct cql_prop_entry *e;
00398
00399 for (e = ct->entry; e; e = e->next)
00400 if (!memcmp(e->pattern, "set.", 4) && e->value &&
00401 !strcmp(e->value, uri))
00402 {
00403 prefix = e->pattern+4;
00404 break;
00405 }
00406
00407 }
00408
00409 if (!uri || prefix)
00410 {
00411 if (!res)
00412 res = cql_lookup_property(ct, category, prefix, eval);
00413
00414 if (!res && !prefix && !strcmp(category, "relation"))
00415 {
00416 if (!strcmp(val, "=="))
00417 res = cql_lookup_property(ct, category, prefix, "exact");
00418 if (!strcmp(val, "="))
00419 res = cql_lookup_property(ct, category, prefix, "eq");
00420 if (!strcmp(val, "<="))
00421 res = cql_lookup_property(ct, category, prefix, "le");
00422 if (!strcmp(val, ">="))
00423 res = cql_lookup_property(ct, category, prefix, "ge");
00424 }
00425 if (!res)
00426 res = cql_lookup_property(ct, category, prefix, "*");
00427 }
00428 if (res)
00429 {
00430 char buf[64];
00431
00432 const char *cp0 = res, *cp1;
00433 while ((cp1 = strchr(cp0, '=')))
00434 {
00435 int i;
00436 while (*cp1 && *cp1 != ' ')
00437 cp1++;
00438 if (cp1 - cp0 >= sizeof(buf))
00439 break;
00440 memcpy(buf, cp0, cp1 - cp0);
00441 buf[cp1-cp0] = 0;
00442 (*pr)("@attr ", client_data);
00443
00444 for (i = 0; buf[i]; i++)
00445 {
00446 if (buf[i] == '*')
00447 (*pr)(eval, client_data);
00448 else
00449 {
00450 char tmp[2];
00451 tmp[0] = buf[i];
00452 tmp[1] = '\0';
00453 (*pr)(tmp, client_data);
00454 }
00455 }
00456 (*pr)(" ", client_data);
00457 cp0 = cp1;
00458 while (*cp0 == ' ')
00459 cp0++;
00460 }
00461 return 1;
00462 }
00463
00464 if (errcode && !ct->error)
00465 {
00466 ct->error = errcode;
00467 if (val)
00468 ct->addinfo = xstrdup(val);
00469 else
00470 ct->addinfo = 0;
00471 }
00472 return 0;
00473 }
00474
00475 int cql_pr_attr(cql_transform_t ct, const char *category,
00476 const char *val, const char *default_val,
00477 void (*pr)(const char *buf, void *client_data),
00478 void *client_data,
00479 int errcode)
00480 {
00481 return cql_pr_attr_uri(ct, category, 0 ,
00482 val, default_val, pr, client_data, errcode);
00483 }
00484
00485
00486 static void cql_pr_int(int val,
00487 void (*pr)(const char *buf, void *client_data),
00488 void *client_data)
00489 {
00490 char buf[21];
00491 sprintf(buf, "%d", val);
00492 (*pr)(buf, client_data);
00493 (*pr)(" ", client_data);
00494 }
00495
00496
00497 static int cql_pr_prox(cql_transform_t ct, struct cql_node *mods,
00498 void (*pr)(const char *buf, void *client_data),
00499 void *client_data)
00500 {
00501 int exclusion = 0;
00502 int distance;
00503 int distance_defined = 0;
00504 int ordered = 0;
00505 int proxrel = 2;
00506 int unit = 2;
00507
00508 while (mods)
00509 {
00510 const char *name = mods->u.st.index;
00511 const char *term = mods->u.st.term;
00512 const char *relation = mods->u.st.relation;
00513
00514 if (!strcmp(name, "distance")) {
00515 distance = strtol(term, (char**) 0, 0);
00516 distance_defined = 1;
00517 if (!strcmp(relation, "="))
00518 proxrel = 3;
00519 else if (!strcmp(relation, ">"))
00520 proxrel = 5;
00521 else if (!strcmp(relation, "<"))
00522 proxrel = 1;
00523 else if (!strcmp(relation, ">="))
00524 proxrel = 4;
00525 else if (!strcmp(relation, "<="))
00526 proxrel = 2;
00527 else if (!strcmp(relation, "<>"))
00528 proxrel = 6;
00529 else
00530 {
00531 ct->error = YAZ_SRW_UNSUPP_PROX_RELATION;
00532 ct->addinfo = xstrdup(relation);
00533 return 0;
00534 }
00535 }
00536 else if (!strcmp(name, "ordered"))
00537 ordered = 1;
00538 else if (!strcmp(name, "unordered"))
00539 ordered = 0;
00540 else if (!strcmp(name, "unit"))
00541 {
00542 if (!strcmp(term, "word"))
00543 unit = 2;
00544 else if (!strcmp(term, "sentence"))
00545 unit = 3;
00546 else if (!strcmp(term, "paragraph"))
00547 unit = 4;
00548 else if (!strcmp(term, "element"))
00549 unit = 8;
00550 else
00551 {
00552 ct->error = YAZ_SRW_UNSUPP_PROX_UNIT;
00553 ct->addinfo = xstrdup(term);
00554 return 0;
00555 }
00556 }
00557 else
00558 {
00559 ct->error = YAZ_SRW_UNSUPP_BOOLEAN_MODIFIER;
00560 ct->addinfo = xstrdup(name);
00561 return 0;
00562 }
00563 mods = mods->u.st.modifiers;
00564 }
00565
00566 if (!distance_defined)
00567 distance = (unit == 2) ? 1 : 0;
00568
00569 cql_pr_int(exclusion, pr, client_data);
00570 cql_pr_int(distance, pr, client_data);
00571 cql_pr_int(ordered, pr, client_data);
00572 cql_pr_int(proxrel, pr, client_data);
00573 (*pr)("k ", client_data);
00574 cql_pr_int(unit, pr, client_data);
00575
00576 return 1;
00577 }
00578
00579
00580
00581
00582
00583 static const char *wcchar(int start, const char *term, int length)
00584 {
00585 while (length > 0)
00586 {
00587 if (start || term[-1] != '\\')
00588 if (strchr("*?", *term))
00589 return term;
00590 term++;
00591 length--;
00592 start = 0;
00593 }
00594 return 0;
00595 }
00596
00597
00598
00599 static int has_modifier(struct cql_node *cn, const char *name) {
00600 struct cql_node *mod;
00601 for (mod = cn->u.st.modifiers; mod != 0; mod = mod->u.st.modifiers) {
00602 if (!strcmp(mod->u.st.index, name))
00603 return 1;
00604 }
00605
00606 return 0;
00607 }
00608
00609
00610 void emit_term(cql_transform_t ct,
00611 struct cql_node *cn,
00612 const char *term, int length,
00613 void (*pr)(const char *buf, void *client_data),
00614 void *client_data)
00615 {
00616 int i;
00617 const char *ns = cn->u.st.index_uri;
00618 int process_term = !has_modifier(cn, "regexp");
00619 char *z3958_mem = 0;
00620
00621 assert(cn->which == CQL_NODE_ST);
00622
00623 if (process_term && length > 0)
00624 {
00625 if (length > 1 && term[0] == '^' && term[length-1] == '^')
00626 {
00627 cql_pr_attr(ct, "position", "firstAndLast", 0,
00628 pr, client_data, YAZ_SRW_ANCHORING_CHAR_IN_UNSUPP_POSITION);
00629 term++;
00630 length -= 2;
00631 }
00632 else if (term[0] == '^')
00633 {
00634 cql_pr_attr(ct, "position", "first", 0,
00635 pr, client_data, YAZ_SRW_ANCHORING_CHAR_IN_UNSUPP_POSITION);
00636 term++;
00637 length--;
00638 }
00639 else if (term[length-1] == '^')
00640 {
00641 cql_pr_attr(ct, "position", "last", 0,
00642 pr, client_data, YAZ_SRW_ANCHORING_CHAR_IN_UNSUPP_POSITION);
00643 length--;
00644 }
00645 else
00646 {
00647 cql_pr_attr(ct, "position", "any", 0,
00648 pr, client_data, YAZ_SRW_ANCHORING_CHAR_IN_UNSUPP_POSITION);
00649 }
00650 }
00651
00652 if (process_term && length > 0)
00653 {
00654 const char *first_wc = wcchar(1, term, length);
00655 const char *second_wc = first_wc ?
00656 wcchar(0, first_wc+1, length-(first_wc-term)-1) : 0;
00657
00658
00659
00660
00661
00662
00663
00664 if (first_wc == term && second_wc == term + length-1
00665 && *first_wc == '*' && *second_wc == '*'
00666 && cql_pr_attr(ct, "truncation", "both", 0, pr, client_data, 0))
00667 {
00668 term++;
00669 length -= 2;
00670 }
00671 else if (first_wc == term && second_wc == 0 && *first_wc == '*'
00672 && cql_pr_attr(ct, "truncation", "left", 0,
00673 pr, client_data, 0))
00674 {
00675 term++;
00676 length--;
00677 }
00678 else if (first_wc == term + length-1 && second_wc == 0
00679 && *first_wc == '*'
00680 && cql_pr_attr(ct, "truncation", "right", 0,
00681 pr, client_data, 0))
00682 {
00683 length--;
00684 }
00685 else if (first_wc)
00686 {
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696 int i;
00697 cql_pr_attr(ct, "truncation", "z3958", 0,
00698 pr, client_data, YAZ_SRW_MASKING_CHAR_UNSUPP);
00699 z3958_mem = (char *) xmalloc(length+1);
00700 for (i = 0; i < length; i++)
00701 {
00702 if (i > 0 && term[i-1] == '\\')
00703 z3958_mem[i] = term[i];
00704 else if (term[i] == '*')
00705 z3958_mem[i] = '?';
00706 else if (term[i] == '?')
00707 z3958_mem[i] = '#';
00708 else
00709 z3958_mem[i] = term[i];
00710 }
00711 z3958_mem[length] = '\0';
00712 term = z3958_mem;
00713 }
00714 else {
00715
00716 cql_pr_attr(ct, "truncation", "none", 0,
00717 pr, client_data, 0);
00718 }
00719 }
00720 if (ns) {
00721 cql_pr_attr_uri(ct, "index", ns,
00722 cn->u.st.index, "serverChoice",
00723 pr, client_data, YAZ_SRW_UNSUPP_INDEX);
00724 }
00725 if (cn->u.st.modifiers)
00726 {
00727 struct cql_node *mod = cn->u.st.modifiers;
00728 for (; mod; mod = mod->u.st.modifiers)
00729 {
00730 cql_pr_attr(ct, "relationModifier", mod->u.st.index, 0,
00731 pr, client_data, YAZ_SRW_UNSUPP_RELATION_MODIFIER);
00732 }
00733 }
00734
00735 (*pr)("\"", client_data);
00736 for (i = 0; i<length; i++)
00737 {
00738
00739
00740
00741 char buf[2];
00742
00743 buf[0] = term[i];
00744 buf[1] = '\0';
00745 (*pr)(buf, client_data);
00746 }
00747 (*pr)("\" ", client_data);
00748 xfree(z3958_mem);
00749 }
00750
00751 void emit_terms(cql_transform_t ct,
00752 struct cql_node *cn,
00753 void (*pr)(const char *buf, void *client_data),
00754 void *client_data,
00755 const char *op)
00756 {
00757 struct cql_node *ne = cn->u.st.extra_terms;
00758 if (ne)
00759 {
00760 (*pr)("@", client_data);
00761 (*pr)(op, client_data);
00762 (*pr)(" ", client_data);
00763 }
00764 emit_term(ct, cn, cn->u.st.term, strlen(cn->u.st.term),
00765 pr, client_data);
00766 for (; ne; ne = ne->u.st.extra_terms)
00767 {
00768 if (ne->u.st.extra_terms)
00769 {
00770 (*pr)("@", client_data);
00771 (*pr)(op, client_data);
00772 (*pr)(" ", client_data);
00773 }
00774 emit_term(ct, cn, ne->u.st.term, strlen(ne->u.st.term),
00775 pr, client_data);
00776 }
00777 }
00778
00779 void emit_wordlist(cql_transform_t ct,
00780 struct cql_node *cn,
00781 void (*pr)(const char *buf, void *client_data),
00782 void *client_data,
00783 const char *op)
00784 {
00785 const char *cp0 = cn->u.st.term;
00786 const char *cp1;
00787 const char *last_term = 0;
00788 int last_length = 0;
00789 while(cp0)
00790 {
00791 while (*cp0 == ' ')
00792 cp0++;
00793 cp1 = strchr(cp0, ' ');
00794 if (last_term)
00795 {
00796 (*pr)("@", client_data);
00797 (*pr)(op, client_data);
00798 (*pr)(" ", client_data);
00799 emit_term(ct, cn, last_term, last_length, pr, client_data);
00800 }
00801 last_term = cp0;
00802 if (cp1)
00803 last_length = cp1 - cp0;
00804 else
00805 last_length = strlen(cp0);
00806 cp0 = cp1;
00807 }
00808 if (last_term)
00809 emit_term(ct, cn, last_term, last_length, pr, client_data);
00810 }
00811
00812 void cql_transform_r(cql_transform_t ct,
00813 struct cql_node *cn,
00814 void (*pr)(const char *buf, void *client_data),
00815 void *client_data)
00816 {
00817 const char *ns;
00818 struct cql_node *mods;
00819
00820 if (!cn)
00821 return;
00822 switch (cn->which)
00823 {
00824 case CQL_NODE_ST:
00825 ns = cn->u.st.index_uri;
00826 if (ns)
00827 {
00828 if (!strcmp(ns, cql_uri())
00829 && cn->u.st.index && !cql_strcmp(cn->u.st.index, "resultSet"))
00830 {
00831 (*pr)("@set \"", client_data);
00832 (*pr)(cn->u.st.term, client_data);
00833 (*pr)("\" ", client_data);
00834 return ;
00835 }
00836 }
00837 else
00838 {
00839 if (!ct->error)
00840 {
00841 ct->error = YAZ_SRW_UNSUPP_CONTEXT_SET;
00842 ct->addinfo = 0;
00843 }
00844 }
00845 cql_pr_attr(ct, "always", 0, 0, pr, client_data, 0);
00846 cql_pr_attr(ct, "relation", cn->u.st.relation, 0, pr, client_data,
00847 YAZ_SRW_UNSUPP_RELATION);
00848 cql_pr_attr(ct, "structure", cn->u.st.relation, 0,
00849 pr, client_data, YAZ_SRW_UNSUPP_COMBI_OF_RELATION_AND_TERM);
00850 if (cn->u.st.relation && !cql_strcmp(cn->u.st.relation, "all"))
00851 emit_wordlist(ct, cn, pr, client_data, "and");
00852 else if (cn->u.st.relation && !cql_strcmp(cn->u.st.relation, "any"))
00853 emit_wordlist(ct, cn, pr, client_data, "or");
00854 else
00855 emit_terms(ct, cn, pr, client_data, "and");
00856 break;
00857 case CQL_NODE_BOOL:
00858 (*pr)("@", client_data);
00859 (*pr)(cn->u.boolean.value, client_data);
00860 (*pr)(" ", client_data);
00861 mods = cn->u.boolean.modifiers;
00862 if (!strcmp(cn->u.boolean.value, "prox"))
00863 {
00864 if (!cql_pr_prox(ct, mods, pr, client_data))
00865 return;
00866 }
00867 else if (mods)
00868 {
00869
00870 ct->error = YAZ_SRW_UNSUPP_BOOLEAN_MODIFIER;
00871 ct->addinfo = xstrdup(mods->u.st.index);
00872 return;
00873 }
00874
00875 cql_transform_r(ct, cn->u.boolean.left, pr, client_data);
00876 cql_transform_r(ct, cn->u.boolean.right, pr, client_data);
00877 break;
00878
00879 default:
00880 fprintf(stderr, "Fatal: impossible CQL node-type %d\n", cn->which);
00881 abort();
00882 }
00883 }
00884
00885 int cql_transform(cql_transform_t ct, struct cql_node *cn,
00886 void (*pr)(const char *buf, void *client_data),
00887 void *client_data)
00888 {
00889 struct cql_prop_entry *e;
00890 NMEM nmem = nmem_create();
00891
00892 ct->error = 0;
00893 xfree(ct->addinfo);
00894 ct->addinfo = 0;
00895
00896 for (e = ct->entry; e ; e = e->next)
00897 {
00898 if (!cql_strncmp(e->pattern, "set.", 4))
00899 cql_apply_prefix(nmem, cn, e->pattern+4, e->value);
00900 else if (!cql_strcmp(e->pattern, "set"))
00901 cql_apply_prefix(nmem, cn, 0, e->value);
00902 }
00903 cql_transform_r(ct, cn, pr, client_data);
00904 nmem_destroy(nmem);
00905 return ct->error;
00906 }
00907
00908
00909 int cql_transform_FILE(cql_transform_t ct, struct cql_node *cn, FILE *f)
00910 {
00911 return cql_transform(ct, cn, cql_fputs, f);
00912 }
00913
00914 int cql_transform_buf(cql_transform_t ct, struct cql_node *cn, char *out, int max)
00915 {
00916 struct cql_buf_write_info info;
00917 int r;
00918
00919 info.off = 0;
00920 info.max = max;
00921 info.buf = out;
00922 r = cql_transform(ct, cn, cql_buf_write_handler, &info);
00923 if (info.off < 0) {
00924
00925
00926
00927 char numbuf[30];
00928 ct->error = YAZ_SRW_TOO_MANY_CHARS_IN_QUERY;
00929 sprintf(numbuf, "%ld", (long) info.max);
00930 ct->addinfo = xstrdup(numbuf);
00931 return -1;
00932 }
00933 if (info.off >= 0)
00934 info.buf[info.off] = '\0';
00935 return r;
00936 }
00937
00938 int cql_transform_error(cql_transform_t ct, const char **addinfo)
00939 {
00940 *addinfo = ct->addinfo;
00941 return ct->error;
00942 }
00943
00944 void cql_transform_set_error(cql_transform_t ct, int error, const char *addinfo)
00945 {
00946 xfree(ct->addinfo);
00947 ct->addinfo = addinfo ? xstrdup(addinfo) : 0;
00948 ct->error = error;
00949 }
00950
00951
00952
00953
00954
00955
00956
00957
00958