WS changes for function calls.
[idzebra-moved-to-github.git] / index / retrieve.c
1 /* $Id: retrieve.c,v 1.73 2007-10-29 09:25:40 adam Exp $
2    Copyright (C) 1995-2007
3    Index Data ApS
4
5 This file is part of the Zebra server.
6
7 Zebra is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
10 version.
11
12 Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20
21 */
22
23 #include <stdio.h>
24 #include <assert.h>
25
26 #include <fcntl.h>
27 #ifdef WIN32
28 #include <io.h>
29 #include <process.h>
30 #endif
31 #if HAVE_UNISTD_H
32 #include <unistd.h>
33 #endif
34
35 #include "index.h"
36 #include <yaz/diagbib1.h>
37 #include <yaz/snprintf.h>
38 #include <direntz.h>
39 #include <yaz/oid_db.h>
40
41 #define ZEBRA_XML_HEADER_STR "<record xmlns=\"http://www.indexdata.com/zebra/\""
42
43 static int zebra_create_record_stream(ZebraHandle zh, 
44                                       Record *rec,
45                                       struct ZebraRecStream *stream)
46 {
47     RecordAttr *recordAttr = rec_init_attr(zh->reg->zei, *rec);
48
49     if ((*rec)->size[recInfo_storeData] > 0)
50         zebra_create_stream_mem(stream, (*rec)->info[recInfo_storeData],
51                                 (*rec)->size[recInfo_storeData]);
52     else
53     {
54         char full_rep[1024];
55         int fd;
56             
57         if (zh->path_reg && !yaz_is_abspath((*rec)->info[recInfo_filename])){
58             strcpy(full_rep, zh->path_reg);
59             strcat(full_rep, "/");
60             strcat(full_rep, (*rec)->info[recInfo_filename]);
61         }
62         else
63             strcpy(full_rep, (*rec)->info[recInfo_filename]);
64             
65         if ((fd = open(full_rep, O_BINARY|O_RDONLY)) == -1){
66             yaz_log(YLOG_WARN|YLOG_ERRNO, "Retrieve fail; missing file: %s",
67                      full_rep);
68             rec_free(rec);
69             return YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS;
70         }
71         zebra_create_stream_fd(stream, fd, recordAttr->recordOffset);
72     }
73     return 0;
74 }
75     
76
77
78 static int parse_zebra_elem(const char *elem,
79                             const char **index, size_t *index_len,
80                             const char **type, size_t *type_len)
81 {
82     *index = 0;
83     *index_len = 0;
84
85     *type = 0;
86     *type_len = 0;
87
88     if (elem && *elem)
89     {
90         char *cp;
91         /* verify that '::' is in the beginning of *elem 
92            and something more follows */
93         if (':' != *elem
94             || !(elem +1) || ':' != *(elem +1)
95             || !(elem +2) || '\0' == *(elem +2))
96             return 0;
97  
98         /* pick out info from string after '::' */
99         elem = elem + 2;
100         cp = strchr(elem, ':');
101
102         if (!cp) /* index, no colon, no type */
103         {
104             *index = elem;
105             *index_len = strlen(elem);
106         }
107         else if (cp[1] == '\0') /* colon, but no following type */
108         {
109             return 0;
110         }
111         else  /* index, colon and type */
112         {
113             *index = elem;
114             *index_len = cp - elem;
115             *type = cp+1;
116             *type_len = strlen(cp+1);
117         }
118     }
119     return 1;
120 }
121
122
123 int zebra_special_sort_fetch(ZebraHandle zh, zint sysno, ODR odr,
124                              const char *elemsetname,
125                              const Odr_oid *input_format,
126                              const Odr_oid **output_format,
127                              char **rec_bufp, int *rec_lenp)
128 {
129     const char *retrieval_index;
130     size_t retrieval_index_len; 
131     const char *retrieval_type;
132     size_t retrieval_type_len;
133     char retrieval_index_cstr[256];
134     int ord;
135
136     /* only accept XML and SUTRS requests */
137     if (oid_oidcmp(input_format, yaz_oid_recsyn_xml) 
138         && oid_oidcmp(input_format, yaz_oid_recsyn_sutrs))
139     {
140         yaz_log(YLOG_WARN, "unsupported format for element set zebra::%s", 
141                 elemsetname);
142         *output_format = 0;
143         return YAZ_BIB1_NO_SYNTAXES_AVAILABLE_FOR_THIS_REQUEST;
144     }
145     
146     if (!parse_zebra_elem(elemsetname,
147                           &retrieval_index, &retrieval_index_len,
148                           &retrieval_type,  &retrieval_type_len))
149     {
150         return YAZ_BIB1_SPECIFIED_ELEMENT_SET_NAME_NOT_VALID_FOR_SPECIFIED_;
151     }
152     
153     if (retrieval_type_len == 0)
154         return -1;   /* must have a register type specified */
155     if (!retrieval_index_len ||
156         retrieval_index_len >= sizeof(retrieval_index_cstr)-1)
157     {
158         return YAZ_BIB1_SPECIFIED_ELEMENT_SET_NAME_NOT_VALID_FOR_SPECIFIED_;
159     }
160         
161     memcpy(retrieval_index_cstr, retrieval_index, retrieval_index_len);
162     retrieval_index_cstr[retrieval_index_len] = '\0';
163
164     ord = zebraExplain_lookup_attr_str(zh->reg->zei,
165                                        zinfo_index_category_sort,
166                                        retrieval_type[0],
167                                        retrieval_index_cstr);
168     if (ord == -1)
169         return -1;  /* is not a sort index */
170     else
171     {
172         char dst_buf[IT_MAX_WORD];
173         char str[IT_MAX_WORD];
174         int index_type;
175         const char *db = 0;
176         const char *string_index = 0;
177         WRBUF wrbuf = wrbuf_alloc();
178         
179         zebra_sort_sysno(zh->reg->sort_index, sysno);
180         zebra_sort_type(zh->reg->sort_index, ord);
181         zebra_sort_read(zh->reg->sort_index, str);
182
183         zebraExplain_lookup_ord(zh->reg->zei, ord, &index_type, &db, &string_index);
184         
185         zebra_term_untrans(zh, index_type, dst_buf, str);
186         
187
188         if (!oid_oidcmp(input_format, yaz_oid_recsyn_xml))
189         {
190             *output_format = yaz_oid_recsyn_xml;
191             wrbuf_printf(wrbuf, ZEBRA_XML_HEADER_STR
192                          " sysno=\"" ZINT_FORMAT "\""
193                          " set=\"zebra::index%s/\">\n",
194                          sysno, elemsetname);
195
196             wrbuf_printf(wrbuf, "  <index name=\"%s\"", 
197                          string_index);
198             wrbuf_printf(wrbuf, " type=\"%c\">", index_type);
199             wrbuf_xmlputs(wrbuf, dst_buf);
200             wrbuf_printf(wrbuf, "</index>\n");
201             wrbuf_printf(wrbuf, "</record>\n");
202         }
203         else if (!oid_oidcmp(input_format, yaz_oid_recsyn_sutrs))
204         {
205             *output_format = yaz_oid_recsyn_sutrs;
206             
207             wrbuf_printf(wrbuf, "%s %c %s\n", string_index, index_type,
208                          dst_buf);
209         }
210         *rec_lenp = wrbuf_len(wrbuf);
211         *rec_bufp = odr_malloc(odr, *rec_lenp);
212         memcpy(*rec_bufp, wrbuf_buf(wrbuf), *rec_lenp);
213         wrbuf_destroy(wrbuf);
214         return 0;
215     }
216 }
217                             
218 int zebra_special_index_fetch(ZebraHandle zh, zint sysno, ODR odr,
219                               Record rec,
220                               const char *elemsetname,
221                               const Odr_oid *input_format,
222                               const Odr_oid **output_format,
223                               char **rec_bufp, int *rec_lenp)
224 {
225     const char *retrieval_index;
226     size_t retrieval_index_len; 
227     const char *retrieval_type;
228     size_t retrieval_type_len;
229     zebra_rec_keys_t keys;
230     int ret_code = 0;
231     
232     /* set output variables before processing possible error states */
233     /* *rec_lenp = 0; */
234
235     /* only accept XML and SUTRS requests */
236     if (oid_oidcmp(input_format, yaz_oid_recsyn_xml)
237         && oid_oidcmp(input_format, yaz_oid_recsyn_sutrs))
238     {
239         yaz_log(YLOG_WARN, "unsupported format for element set zebra::%s", 
240                 elemsetname);
241         *output_format = 0;
242         return YAZ_BIB1_NO_SYNTAXES_AVAILABLE_FOR_THIS_REQUEST;
243     }
244
245     if (!parse_zebra_elem(elemsetname,
246                      &retrieval_index, &retrieval_index_len,
247                      &retrieval_type,  &retrieval_type_len))
248         return YAZ_BIB1_SPECIFIED_ELEMENT_SET_NAME_NOT_VALID_FOR_SPECIFIED_;
249
250     if (retrieval_type_len != 0 && retrieval_type_len != 1)
251     {
252         return YAZ_BIB1_SPECIFIED_ELEMENT_SET_NAME_NOT_VALID_FOR_SPECIFIED_;
253     }
254
255     if (retrieval_index_len)
256     {
257         char retrieval_index_cstr[256];
258
259         if (retrieval_index_len < sizeof(retrieval_index_cstr) -1)
260         {
261             memcpy(retrieval_index_cstr, retrieval_index, retrieval_index_len);
262             retrieval_index_cstr[retrieval_index_len] = '\0';
263             
264             if (zebraExplain_lookup_attr_str(zh->reg->zei,
265                                              zinfo_index_category_index,
266                                              (retrieval_type_len == 0 ? -1 : 
267                                               retrieval_type[0]),
268                                              retrieval_index_cstr) == -1)
269                 return YAZ_BIB1_SPECIFIED_ELEMENT_SET_NAME_NOT_VALID_FOR_SPECIFIED_;
270         }
271     }
272
273     keys = zebra_rec_keys_open();
274     zebra_rec_keys_set_buf(keys, rec->info[recInfo_delKeys],
275                            rec->size[recInfo_delKeys], 0);
276
277     if (!zebra_rec_keys_rewind(keys))
278     {
279         ret_code = YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS;
280     }
281     else
282     {
283         size_t slen;
284         const char *str;
285         struct it_key key_in;
286         WRBUF wrbuf = wrbuf_alloc();
287     
288         if (!oid_oidcmp(input_format, yaz_oid_recsyn_xml))
289         {
290             *output_format = input_format;
291             wrbuf_printf(wrbuf, ZEBRA_XML_HEADER_STR
292                          " sysno=\"" ZINT_FORMAT "\""
293                          " set=\"zebra::index%s/\">\n",
294                          sysno, elemsetname);
295         }
296         else if (!oid_oidcmp(input_format, yaz_oid_recsyn_sutrs))
297             *output_format = input_format;
298
299         while (zebra_rec_keys_read(keys, &str, &slen, &key_in))
300         {
301             int i;
302             int ord = CAST_ZINT_TO_INT(key_in.mem[0]);
303             int index_type;
304             const char *db = 0;
305             const char *string_index = 0;
306             size_t string_index_len;
307             char dst_buf[IT_MAX_WORD];
308             
309             zebraExplain_lookup_ord(zh->reg->zei, ord, &index_type, &db,
310                                     &string_index);
311             string_index_len = strlen(string_index);
312
313             /* process only if index is not defined, 
314                or if defined and matching */
315             if (retrieval_index == 0 
316                 || (string_index_len == retrieval_index_len 
317                     && !memcmp(string_index, retrieval_index,
318                                string_index_len)))
319             {
320                 /* process only if type is not defined, or is matching */
321                 if (retrieval_type == 0 
322                     || (retrieval_type_len == 1 
323                         && retrieval_type[0] == index_type))
324                 {
325                     zebra_term_untrans(zh, index_type, dst_buf, str);
326                     if (strlen(dst_buf))
327                     {
328                         if (!oid_oidcmp(input_format, yaz_oid_recsyn_xml))
329                         {
330                             wrbuf_printf(wrbuf, "  <index name=\"%s\"", 
331                                          string_index);
332                             
333                             wrbuf_printf(wrbuf, " type=\"%c\"", index_type);
334                             
335                             wrbuf_printf(wrbuf, " seq=\"" ZINT_FORMAT "\">", 
336                                          key_in.mem[key_in.len -1]);
337                         
338                             wrbuf_xmlputs(wrbuf, dst_buf);
339                             wrbuf_printf(wrbuf, "</index>\n");
340                         }
341                         else 
342                         {
343                             wrbuf_printf(wrbuf, "%s ", string_index);
344                             
345                             wrbuf_printf(wrbuf, "%c", index_type);
346                             
347                             for (i = 1; i < key_in.len; i++)
348                                 wrbuf_printf(wrbuf, " " ZINT_FORMAT, 
349                                              key_in.mem[i]);
350                             
351                             /* zebra_term_untrans(zh, index_type, dst_buf, str); */
352                             wrbuf_printf(wrbuf, " %s", dst_buf);
353                         
354                             wrbuf_printf(wrbuf, "\n");
355                         }
356                     }
357                     
358                 }
359             }
360         }
361         if (!oid_oidcmp(input_format, yaz_oid_recsyn_xml))
362             wrbuf_printf(wrbuf, "</record>\n");
363         *rec_lenp = wrbuf_len(wrbuf);
364         *rec_bufp = odr_malloc(odr, *rec_lenp);
365         memcpy(*rec_bufp, wrbuf_buf(wrbuf), *rec_lenp);
366         wrbuf_destroy(wrbuf);
367     }
368     zebra_rec_keys_close(keys);
369     return ret_code;
370 }
371
372
373 static void retrieve_puts_attr(WRBUF wrbuf, const char *name,
374                                const char *value)
375 {
376     if (value)
377     {
378         wrbuf_printf(wrbuf, " %s=\"", name);
379         wrbuf_xmlputs(wrbuf, value);
380         wrbuf_printf(wrbuf, "\"");
381     }
382 }
383
384 static void retrieve_puts_attr_int(WRBUF wrbuf, const char *name,
385                                const int value)
386 {
387     wrbuf_printf(wrbuf, " %s=\"%i\"", name, value);
388 }
389
390 static void retrieve_puts_str(WRBUF wrbuf, const char *name,
391                                const char *value)
392 {
393     if (value)
394         wrbuf_printf(wrbuf, "%s %s\n", name, value);
395 }
396
397 static void retrieve_puts_int(WRBUF wrbuf, const char *name,
398                                const int value)
399 {
400     wrbuf_printf(wrbuf, "%s %i\n", name, value);
401 }
402
403
404 static void snippet_xml_record(ZebraHandle zh, WRBUF wrbuf, zebra_snippets *doc)
405 {
406     const zebra_snippet_word *doc_w;
407     int mark_state = 0;
408
409     wrbuf_printf(wrbuf, "%s>\n", ZEBRA_XML_HEADER_STR);
410     for (doc_w = zebra_snippets_constlist(doc); doc_w; doc_w = doc_w->next)
411     {
412         if (doc_w->mark)
413         {
414             int index_type;
415             const char *db = 0;
416             const char *string_index = 0;
417
418             zebraExplain_lookup_ord(zh->reg->zei, doc_w->ord, 
419                                     &index_type, &db, &string_index);
420
421             if (mark_state == 0)
422             {
423                 wrbuf_printf(wrbuf, "  <snippet name=\"%s\"",  string_index);
424                 wrbuf_printf(wrbuf, " type=\"%c\">", index_type);
425             }
426             if (doc_w->match)
427                 wrbuf_puts(wrbuf, "<s>");
428             /* not printing leading ws */
429             if (mark_state || !doc_w->ws || doc_w->match) 
430                 wrbuf_xmlputs(wrbuf, doc_w->term);
431             if (doc_w->match)
432                 wrbuf_puts(wrbuf, "</s>");
433         }
434         else if (mark_state == 1)
435         {
436             wrbuf_puts(wrbuf, "</snippet>\n");
437         }
438         mark_state = doc_w->mark;
439     }
440     if (mark_state == 1)
441     {
442         wrbuf_puts(wrbuf, "</snippet>\n");
443     }
444     wrbuf_printf(wrbuf, "</record>");
445 }
446
447 int zebra_get_rec_snippets(ZebraHandle zh, zint sysno,
448                            zebra_snippets *snippets)
449 {
450     int return_code = 0;
451     Record rec = rec_get(zh->reg->records, sysno);
452     if (!rec)
453     {
454         yaz_log(YLOG_WARN, "rec_get fail on sysno=" ZINT_FORMAT, sysno);
455         return_code = YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS;
456     }
457     else
458     {
459         const char *file_type = rec->info[recInfo_fileType];
460         void *recTypeClientData;
461         RecType rt = recType_byName(zh->reg->recTypes, zh->res,
462                                     file_type, &recTypeClientData);
463
464         if (!rt)
465             return_code = YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS;
466         else
467         {
468             struct ZebraRecStream stream;
469             return_code = zebra_create_record_stream(zh, &rec, &stream);
470             if (return_code == 0)
471             {
472                 extract_snippet(zh, snippets, &stream,
473                                 rt, recTypeClientData);
474
475                 stream.destroy(&stream);
476             }
477         }
478         rec_free(&rec);
479     }
480     return return_code;
481 }
482
483 int zebra_special_snippet_fetch(ZebraHandle zh, const char *setname,
484                                 zint sysno, ODR odr,
485                                 const char *elemsetname,
486                                 const Odr_oid *input_format,
487                                 const Odr_oid **output_format,
488                                 char **rec_bufp, int *rec_lenp)
489 {
490     zebra_snippets *rec_snippets = zebra_snippets_create();
491     int return_code = zebra_get_rec_snippets(zh, sysno, rec_snippets);
492
493     if (!return_code)
494     {
495         WRBUF wrbuf = wrbuf_alloc();
496         zebra_snippets *hit_snippet = zebra_snippets_create();
497
498         zebra_snippets_hit_vector(zh, setname, sysno, hit_snippet);
499
500 #if 0
501         /* for debugging purposes */
502         yaz_log(YLOG_LOG, "---------------------------");
503         yaz_log(YLOG_LOG, "REC SNIPPET:");
504         zebra_snippets_log(rec_snippet, YLOG_LOG, 1);
505         yaz_log(YLOG_LOG, "---------------------------");
506         yaz_log(YLOG_LOG, "HIT SNIPPET:");
507         zebra_snippets_log(hit_snippet, YLOG_LOG, 1);
508 #endif
509         
510         zebra_snippets_ring(rec_snippets, hit_snippet, 5, 5);
511         
512 #if 0
513         yaz_log(YLOG_LOG, "---------------------------");
514         yaz_log(YLOG_LOG, "RING SNIPPET:");
515         zebra_snippets_log(rec_snippets, YLOG_LOG, 1);
516 #endif
517         snippet_xml_record(zh, wrbuf, rec_snippets);
518         
519         *output_format = yaz_oid_recsyn_xml;
520         
521         if (return_code == 0)
522         {
523             *rec_lenp = wrbuf_len(wrbuf);
524             *rec_bufp = odr_strdup(odr, wrbuf_cstr(wrbuf));
525         }
526         wrbuf_destroy(wrbuf);
527         zebra_snippets_destroy(hit_snippet);
528     }
529     zebra_snippets_destroy(rec_snippets);
530     return return_code;
531 }
532
533 int zebra_special_fetch(ZebraHandle zh, const char *setname,
534                         zint sysno, int score, ODR odr,
535                         const char *elemsetname,
536                         const Odr_oid *input_format,
537                         const Odr_oid **output_format,
538                         char **rec_bufp, int *rec_lenp)
539 {
540     Record rec;
541     
542     /* set output variables before processing possible error states */
543     /* *rec_lenp = 0; */
544
545
546     if (elemsetname && 0 == strcmp(elemsetname, "snippet"))
547     {
548         return zebra_special_snippet_fetch(zh, setname, sysno, odr,
549                                            elemsetname + 7,
550                                            input_format, output_format,
551                                            rec_bufp, rec_lenp);
552     }
553
554     /* processing zebra::meta::sysno elemset without fetching binary data */
555     if (elemsetname && 0 == strcmp(elemsetname, "meta::sysno"))
556     {
557         int ret = 0;
558         WRBUF wrbuf = wrbuf_alloc();
559         if (!oid_oidcmp(input_format, yaz_oid_recsyn_sutrs))
560         {
561             wrbuf_printf(wrbuf, ZINT_FORMAT, sysno);
562             *output_format = input_format;
563         } 
564         else if (!oid_oidcmp(input_format, yaz_oid_recsyn_xml))
565         {
566             wrbuf_printf(wrbuf, ZEBRA_XML_HEADER_STR
567                          " sysno=\"" ZINT_FORMAT "\"/>\n",
568                          sysno);
569             *output_format = input_format;
570         }
571         *rec_lenp = wrbuf_len(wrbuf);
572         if (*rec_lenp)
573             *rec_bufp = odr_strdup(odr, wrbuf_cstr(wrbuf));
574         else
575             ret = YAZ_BIB1_NO_SYNTAXES_AVAILABLE_FOR_THIS_REQUEST;
576         wrbuf_destroy(wrbuf);
577         return ret;
578     }
579
580     /* processing special elementsetname zebra::index:: for sort elements */
581     if (elemsetname && 0 == strncmp(elemsetname, "index", 5))
582     {
583         int ret = zebra_special_sort_fetch(zh, sysno, odr,
584                                            elemsetname + 5,
585                                            input_format, output_format,
586                                            rec_bufp, rec_lenp);
587         if (ret != -1)
588             return ret;
589         /* not a sort index so we continue to get the full record */
590     }
591
592
593     /* fetching binary record up for all other display elementsets */
594     rec = rec_get(zh->reg->records, sysno);
595     if (!rec)
596     {
597         yaz_log(YLOG_WARN, "rec_get fail on sysno=" ZINT_FORMAT, sysno);
598         return YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS;
599     }
600
601     /* processing special elementsetnames zebra::data */    
602     if (elemsetname && 0 == strcmp(elemsetname, "data"))
603     {
604         struct ZebraRecStream stream;
605         RecordAttr *recordAttr = rec_init_attr(zh->reg->zei, rec); 
606         zebra_create_record_stream(zh, &rec, &stream);
607         *output_format = input_format;
608         *rec_lenp = recordAttr->recordSize;
609         *rec_bufp = (char *) odr_malloc(odr, *rec_lenp);
610         stream.readf(&stream, *rec_bufp, *rec_lenp);
611         stream.destroy(&stream);
612         rec_free(&rec);
613         return 0;
614     }
615
616     /* only accept XML and SUTRS requests from now */
617     if (oid_oidcmp(input_format, yaz_oid_recsyn_xml)
618         && oid_oidcmp(input_format, yaz_oid_recsyn_sutrs))
619     {
620         yaz_log(YLOG_WARN, "unsupported format for element set zebra::%s", 
621                 elemsetname);
622         return YAZ_BIB1_NO_SYNTAXES_AVAILABLE_FOR_THIS_REQUEST;
623     }
624     
625
626     /* processing special elementsetnames zebra::meta:: */
627     if (elemsetname && 0 == strcmp(elemsetname, "meta"))
628     {
629         int ret = 0;
630         WRBUF wrbuf = wrbuf_alloc();
631         RecordAttr *recordAttr = rec_init_attr(zh->reg->zei, rec); 
632
633         if (!oid_oidcmp(input_format, yaz_oid_recsyn_xml))
634         {
635             *output_format = input_format;
636             
637             wrbuf_printf(wrbuf, ZEBRA_XML_HEADER_STR
638                          " sysno=\"" ZINT_FORMAT "\"", sysno);
639             retrieve_puts_attr(wrbuf, "base", rec->info[recInfo_databaseName]);
640             retrieve_puts_attr(wrbuf, "file", rec->info[recInfo_filename]);
641             retrieve_puts_attr(wrbuf, "type", rec->info[recInfo_fileType]);
642             if (score >= 0)
643                 retrieve_puts_attr_int(wrbuf, "score", score);
644            
645             wrbuf_printf(wrbuf,
646                          " rank=\"" ZINT_FORMAT "\""
647                          " size=\"%i\""
648                          " set=\"zebra::%s\"/>\n",
649                          recordAttr->staticrank,
650                          recordAttr->recordSize,
651                          elemsetname);
652         }
653         else if (!oid_oidcmp(input_format, yaz_oid_recsyn_sutrs))
654         {
655             *output_format = input_format;
656             wrbuf_printf(wrbuf, "sysno " ZINT_FORMAT "\n", sysno);
657             retrieve_puts_str(wrbuf, "base", rec->info[recInfo_databaseName]);
658             retrieve_puts_str(wrbuf, "file", rec->info[recInfo_filename]);
659             retrieve_puts_str(wrbuf, "type", rec->info[recInfo_fileType]);
660             if (score >= 0)
661                 retrieve_puts_int(wrbuf, "score", score);
662
663             wrbuf_printf(wrbuf,
664                          "rank " ZINT_FORMAT "\n"
665                          "size %i\n"
666                          "set zebra::%s\n",
667                          recordAttr->staticrank,
668                          recordAttr->recordSize,
669                          elemsetname);
670         }
671         *rec_lenp = wrbuf_len(wrbuf);
672         if (*rec_lenp)
673             *rec_bufp = odr_strdup(odr, wrbuf_cstr(wrbuf));
674         else
675             ret = YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS;
676
677         wrbuf_destroy(wrbuf);
678         rec_free(&rec);
679         return ret;
680     }
681
682     /* processing special elementsetnames zebra::index:: */
683     if (elemsetname && 0 == strncmp(elemsetname, "index", 5))
684     {
685         int ret = zebra_special_index_fetch(zh, sysno, odr, rec,
686                                             elemsetname + 5,
687                                             input_format, output_format,
688                                             rec_bufp, rec_lenp);
689         
690         rec_free(&rec);
691         return ret;
692     }
693
694     if (rec)
695         rec_free(&rec);
696     return YAZ_BIB1_SPECIFIED_ELEMENT_SET_NAME_NOT_VALID_FOR_SPECIFIED_;
697 }
698
699                           
700 int zebra_record_fetch(ZebraHandle zh, const char *setname,
701                        zint sysno, int score,
702                        zebra_snippets *hit_snippet, ODR odr,
703                        const Odr_oid *input_format, Z_RecordComposition *comp,
704                        const Odr_oid **output_format,
705                        char **rec_bufp, int *rec_lenp, char **basenamep,
706                        char **addinfo)
707 {
708     Record rec;
709     char *fname, *file_type, *basename;
710     const char *elemsetname;
711     struct ZebraRecStream stream;
712     RecordAttr *recordAttr;
713     void *clientData;
714     int return_code = 0;
715
716     *basenamep = 0;
717     *addinfo = 0;
718     elemsetname = yaz_get_esn(comp);
719
720     /* processing zebra special elementset names of form 'zebra:: */
721     if (elemsetname && 0 == strncmp(elemsetname, "zebra::", 7))
722         return  zebra_special_fetch(zh, setname, sysno, score, odr,
723                                     elemsetname + 7,
724                                     input_format, output_format,
725                                     rec_bufp, rec_lenp);
726
727
728     /* processing all other element set names */
729     rec = rec_get(zh->reg->records, sysno);
730     if (!rec)
731     {
732         yaz_log(YLOG_WARN, "rec_get fail on sysno=" ZINT_FORMAT, sysno);
733         *basenamep = 0;
734         return YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS;
735     }
736
737
738     recordAttr = rec_init_attr(zh->reg->zei, rec);
739
740     file_type = rec->info[recInfo_fileType];
741     fname = rec->info[recInfo_filename];
742     basename = rec->info[recInfo_databaseName];
743     *basenamep = (char *) odr_malloc(odr, strlen(basename)+1);
744     strcpy(*basenamep, basename);
745
746     yaz_log(YLOG_DEBUG, "retrieve localno=" ZINT_FORMAT " score=%d",
747             sysno, score);
748
749     return_code = zebra_create_record_stream(zh, &rec, &stream);
750
751     if (rec)
752     {
753         zebra_rec_keys_t reckeys = zebra_rec_keys_open();
754         RecType rt;
755         struct recRetrieveCtrl retrieveCtrl;
756
757         retrieveCtrl.stream = &stream;
758         retrieveCtrl.fname = fname;
759         retrieveCtrl.localno = sysno;
760         retrieveCtrl.staticrank = recordAttr->staticrank;
761         retrieveCtrl.score = score;
762         retrieveCtrl.recordSize = recordAttr->recordSize;
763         retrieveCtrl.odr = odr;
764         retrieveCtrl.input_format = retrieveCtrl.output_format = input_format;
765         retrieveCtrl.comp = comp;
766         retrieveCtrl.encoding = zh->record_encoding;
767         retrieveCtrl.diagnostic = 0;
768         retrieveCtrl.addinfo = 0;
769         retrieveCtrl.dh = zh->reg->dh;
770         retrieveCtrl.res = zh->res;
771         retrieveCtrl.rec_buf = 0;
772         retrieveCtrl.rec_len = -1;
773         retrieveCtrl.hit_snippet = hit_snippet;
774         retrieveCtrl.doc_snippet = zebra_snippets_create();
775
776         zebra_rec_keys_set_buf(reckeys,
777                                rec->info[recInfo_delKeys],
778                                rec->size[recInfo_delKeys], 
779                                0);
780         zebra_rec_keys_to_snippets(zh, reckeys, retrieveCtrl.doc_snippet);
781         zebra_rec_keys_close(reckeys);
782
783         if (!(rt = recType_byName(zh->reg->recTypes, zh->res,
784                                   file_type, &clientData)))
785         {
786             char addinfo_str[100];
787
788             sprintf(addinfo_str, "Could not handle record type %.40s",
789                     file_type);
790                     
791             *addinfo = odr_strdup(odr, addinfo_str);
792             return_code = YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS;
793         }
794         else
795         {
796             (*rt->retrieve)(clientData, &retrieveCtrl);
797             return_code = retrieveCtrl.diagnostic;
798
799             *output_format = retrieveCtrl.output_format;
800             *rec_bufp = (char *) retrieveCtrl.rec_buf;
801             *rec_lenp = retrieveCtrl.rec_len;
802             *addinfo = retrieveCtrl.addinfo;
803         }
804
805         zebra_snippets_destroy(retrieveCtrl.doc_snippet);
806
807         stream.destroy(&stream);
808         rec_free(&rec);
809     }
810
811     return return_code;
812 }
813
814 /*
815  * Local variables:
816  * c-basic-offset: 4
817  * indent-tabs-mode: nil
818  * End:
819  * vim: shiftwidth=4 tabstop=8 expandtab
820  */
821