Changed the index type to a string everywhere.
[idzebra-moved-to-github.git] / index / retrieve.c
1 /* $Id: retrieve.c,v 1.75 2007-10-31 16:56:14 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     char retrieval_type_cstr[256];
135     int ord;
136
137     /* only accept XML and SUTRS requests */
138     if (oid_oidcmp(input_format, yaz_oid_recsyn_xml) 
139         && oid_oidcmp(input_format, yaz_oid_recsyn_sutrs))
140     {
141         yaz_log(YLOG_WARN, "unsupported format for element set zebra::%s", 
142                 elemsetname);
143         *output_format = 0;
144         return YAZ_BIB1_NO_SYNTAXES_AVAILABLE_FOR_THIS_REQUEST;
145     }
146     
147     if (!parse_zebra_elem(elemsetname,
148                           &retrieval_index, &retrieval_index_len,
149                           &retrieval_type,  &retrieval_type_len))
150     {
151         return YAZ_BIB1_SPECIFIED_ELEMENT_SET_NAME_NOT_VALID_FOR_SPECIFIED_;
152     }
153     
154     if (retrieval_type_len == 0)
155         return -1;   /* must have a register type specified */
156     if (!retrieval_index_len ||
157         retrieval_index_len >= sizeof(retrieval_index_cstr)-1)
158     {
159         return YAZ_BIB1_SPECIFIED_ELEMENT_SET_NAME_NOT_VALID_FOR_SPECIFIED_;
160     }
161         
162     memcpy(retrieval_index_cstr, retrieval_index, retrieval_index_len);
163     retrieval_index_cstr[retrieval_index_len] = '\0';
164
165     memcpy(retrieval_type_cstr, retrieval_type, retrieval_type_len);
166     retrieval_type_cstr[retrieval_type_len] = '\0';
167
168     ord = zebraExplain_lookup_attr_str(zh->reg->zei,
169                                        zinfo_index_category_sort,
170                                        retrieval_type_cstr,
171                                        retrieval_index_cstr);
172     if (ord == -1)
173         return -1;  /* is not a sort index */
174     else
175     {
176         char dst_buf[IT_MAX_WORD];
177         char str[IT_MAX_WORD];
178         const char *index_type;
179         const char *db = 0;
180         const char *string_index = 0;
181         WRBUF wrbuf = wrbuf_alloc();
182         
183         zebra_sort_sysno(zh->reg->sort_index, sysno);
184         zebra_sort_type(zh->reg->sort_index, ord);
185         zebra_sort_read(zh->reg->sort_index, str);
186
187         zebraExplain_lookup_ord(zh->reg->zei, ord, &index_type, &db, &string_index);
188         
189         zebra_term_untrans(zh, index_type, dst_buf, str);
190
191         if (!oid_oidcmp(input_format, yaz_oid_recsyn_xml))
192         {
193             *output_format = yaz_oid_recsyn_xml;
194             wrbuf_printf(wrbuf, ZEBRA_XML_HEADER_STR
195                          " sysno=\"" ZINT_FORMAT "\""
196                          " set=\"zebra::index%s/\">\n",
197                          sysno, elemsetname);
198
199             wrbuf_printf(wrbuf, "  <index name=\"%s\"", 
200                          string_index);
201             wrbuf_printf(wrbuf, " type=\"%s\">", index_type);
202             wrbuf_xmlputs(wrbuf, dst_buf);
203             wrbuf_printf(wrbuf, "</index>\n");
204             wrbuf_printf(wrbuf, "</record>\n");
205         }
206         else if (!oid_oidcmp(input_format, yaz_oid_recsyn_sutrs))
207         {
208             *output_format = yaz_oid_recsyn_sutrs;
209             
210             wrbuf_printf(wrbuf, "%s %s %s\n", string_index, index_type,
211                          dst_buf);
212         }
213         *rec_lenp = wrbuf_len(wrbuf);
214         *rec_bufp = odr_malloc(odr, *rec_lenp);
215         memcpy(*rec_bufp, wrbuf_buf(wrbuf), *rec_lenp);
216         wrbuf_destroy(wrbuf);
217         return 0;
218     }
219 }
220                             
221 int zebra_special_index_fetch(ZebraHandle zh, zint sysno, ODR odr,
222                               Record rec,
223                               const char *elemsetname,
224                               const Odr_oid *input_format,
225                               const Odr_oid **output_format,
226                               char **rec_bufp, int *rec_lenp)
227 {
228     const char *retrieval_index;
229     size_t retrieval_index_len; 
230     const char *retrieval_type;
231     size_t retrieval_type_len;
232     zebra_rec_keys_t keys;
233     int ret_code = 0;
234     char retrieval_type_cstr[256];
235     
236     /* set output variables before processing possible error states */
237     /* *rec_lenp = 0; */
238
239     /* only accept XML and SUTRS requests */
240     if (oid_oidcmp(input_format, yaz_oid_recsyn_xml)
241         && oid_oidcmp(input_format, yaz_oid_recsyn_sutrs))
242     {
243         yaz_log(YLOG_WARN, "unsupported format for element set zebra::%s", 
244                 elemsetname);
245         *output_format = 0;
246         return YAZ_BIB1_NO_SYNTAXES_AVAILABLE_FOR_THIS_REQUEST;
247     }
248
249     if (!parse_zebra_elem(elemsetname,
250                      &retrieval_index, &retrieval_index_len,
251                      &retrieval_type,  &retrieval_type_len))
252         return YAZ_BIB1_SPECIFIED_ELEMENT_SET_NAME_NOT_VALID_FOR_SPECIFIED_;
253
254     if (retrieval_type_len)
255     {
256         memcpy(retrieval_type_cstr, retrieval_type, retrieval_type_len);
257         retrieval_type_cstr[retrieval_type_len] = '\0';
258     }
259     
260     if (retrieval_index_len)
261     {
262         char retrieval_index_cstr[256];
263
264         if (retrieval_index_len < sizeof(retrieval_index_cstr) -1)
265         {
266             memcpy(retrieval_index_cstr, retrieval_index, retrieval_index_len);
267             retrieval_index_cstr[retrieval_index_len] = '\0';
268             
269             if (zebraExplain_lookup_attr_str(zh->reg->zei,
270                                              zinfo_index_category_index,
271                                              (retrieval_type_len == 0 ? 0 : 
272                                               retrieval_type_cstr),
273                                              retrieval_index_cstr) == -1)
274                 return YAZ_BIB1_SPECIFIED_ELEMENT_SET_NAME_NOT_VALID_FOR_SPECIFIED_;
275         }
276     }
277
278     keys = zebra_rec_keys_open();
279     zebra_rec_keys_set_buf(keys, rec->info[recInfo_delKeys],
280                            rec->size[recInfo_delKeys], 0);
281
282     if (!zebra_rec_keys_rewind(keys))
283     {
284         ret_code = YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS;
285     }
286     else
287     {
288         size_t slen;
289         const char *str;
290         struct it_key key_in;
291         WRBUF wrbuf = wrbuf_alloc();
292     
293         if (!oid_oidcmp(input_format, yaz_oid_recsyn_xml))
294         {
295             *output_format = input_format;
296             wrbuf_printf(wrbuf, ZEBRA_XML_HEADER_STR
297                          " sysno=\"" ZINT_FORMAT "\""
298                          " set=\"zebra::index%s/\">\n",
299                          sysno, elemsetname);
300         }
301         else if (!oid_oidcmp(input_format, yaz_oid_recsyn_sutrs))
302             *output_format = input_format;
303
304         while (zebra_rec_keys_read(keys, &str, &slen, &key_in))
305         {
306             int i;
307             int ord = CAST_ZINT_TO_INT(key_in.mem[0]);
308             const char *index_type;
309             const char *db = 0;
310             const char *string_index = 0;
311             size_t string_index_len;
312             char dst_buf[IT_MAX_WORD];
313             
314             zebraExplain_lookup_ord(zh->reg->zei, ord, &index_type, &db,
315                                     &string_index);
316             string_index_len = strlen(string_index);
317
318             /* process only if index is not defined, 
319                or if defined and matching */
320             if (retrieval_index == 0 
321                 || (string_index_len == retrieval_index_len 
322                     && !memcmp(string_index, retrieval_index,
323                                string_index_len)))
324             {
325                 /* process only if type is not defined, or is matching */
326                 if (retrieval_type == 0 
327                     || !strcmp(retrieval_type_cstr, index_type))
328                 {
329                     zebra_term_untrans(zh, index_type, dst_buf, str);
330                     if (strlen(dst_buf))
331                     {
332                         if (!oid_oidcmp(input_format, yaz_oid_recsyn_xml))
333                         {
334                             wrbuf_printf(wrbuf, "  <index name=\"%s\"", 
335                                          string_index);
336                             
337                             wrbuf_printf(wrbuf, " type=\"%s\"", index_type);
338                             
339                             wrbuf_printf(wrbuf, " seq=\"" ZINT_FORMAT "\">", 
340                                          key_in.mem[key_in.len -1]);
341                         
342                             wrbuf_xmlputs(wrbuf, dst_buf);
343                             wrbuf_printf(wrbuf, "</index>\n");
344                         }
345                         else 
346                         {
347                             wrbuf_printf(wrbuf, "%s ", string_index);
348                             
349                             wrbuf_printf(wrbuf, "%s", index_type);
350                             
351                             for (i = 1; i < key_in.len; i++)
352                                 wrbuf_printf(wrbuf, " " ZINT_FORMAT, 
353                                              key_in.mem[i]);
354                             
355                             /* zebra_term_untrans(zh, index_type, dst_buf, str); */
356                             wrbuf_printf(wrbuf, " %s", dst_buf);
357                         
358                             wrbuf_printf(wrbuf, "\n");
359                         }
360                     }
361                     
362                 }
363             }
364         }
365         if (!oid_oidcmp(input_format, yaz_oid_recsyn_xml))
366             wrbuf_printf(wrbuf, "</record>\n");
367         *rec_lenp = wrbuf_len(wrbuf);
368         *rec_bufp = odr_malloc(odr, *rec_lenp);
369         memcpy(*rec_bufp, wrbuf_buf(wrbuf), *rec_lenp);
370         wrbuf_destroy(wrbuf);
371     }
372     zebra_rec_keys_close(keys);
373     return ret_code;
374 }
375
376
377 static void retrieve_puts_attr(WRBUF wrbuf, const char *name,
378                                const char *value)
379 {
380     if (value)
381     {
382         wrbuf_printf(wrbuf, " %s=\"", name);
383         wrbuf_xmlputs(wrbuf, value);
384         wrbuf_printf(wrbuf, "\"");
385     }
386 }
387
388 static void retrieve_puts_attr_int(WRBUF wrbuf, const char *name,
389                                const int value)
390 {
391     wrbuf_printf(wrbuf, " %s=\"%i\"", name, value);
392 }
393
394 static void retrieve_puts_str(WRBUF wrbuf, const char *name,
395                                const char *value)
396 {
397     if (value)
398         wrbuf_printf(wrbuf, "%s %s\n", name, value);
399 }
400
401 static void retrieve_puts_int(WRBUF wrbuf, const char *name,
402                                const int value)
403 {
404     wrbuf_printf(wrbuf, "%s %i\n", name, value);
405 }
406
407
408 static void snippet_xml_record(ZebraHandle zh, WRBUF wrbuf, zebra_snippets *doc)
409 {
410     const zebra_snippet_word *doc_w;
411     int mark_state = 0;
412
413     wrbuf_printf(wrbuf, "%s>\n", ZEBRA_XML_HEADER_STR);
414     for (doc_w = zebra_snippets_constlist(doc); doc_w; doc_w = doc_w->next)
415     {
416         if (doc_w->mark)
417         {
418             const char *index_type;
419             const char *db = 0;
420             const char *string_index = 0;
421
422             zebraExplain_lookup_ord(zh->reg->zei, doc_w->ord, 
423                                     &index_type, &db, &string_index);
424
425             if (mark_state == 0)
426             {
427                 wrbuf_printf(wrbuf, "  <snippet name=\"%s\"",  string_index);
428                 wrbuf_printf(wrbuf, " type=\"%s\">", index_type);
429             }
430             if (doc_w->match)
431                 wrbuf_puts(wrbuf, "<s>");
432             /* not printing leading ws */
433             if (mark_state || !doc_w->ws || doc_w->match) 
434                 wrbuf_xmlputs(wrbuf, doc_w->term);
435             if (doc_w->match)
436                 wrbuf_puts(wrbuf, "</s>");
437         }
438         else if (mark_state == 1)
439         {
440             wrbuf_puts(wrbuf, "</snippet>\n");
441         }
442         mark_state = doc_w->mark;
443     }
444     if (mark_state == 1)
445     {
446         wrbuf_puts(wrbuf, "</snippet>\n");
447     }
448     wrbuf_printf(wrbuf, "</record>");
449 }
450
451 int zebra_get_rec_snippets(ZebraHandle zh, zint sysno,
452                            zebra_snippets *snippets)
453 {
454     int return_code = 0;
455     Record rec = rec_get(zh->reg->records, sysno);
456     if (!rec)
457     {
458         yaz_log(YLOG_WARN, "rec_get fail on sysno=" ZINT_FORMAT, sysno);
459         return_code = YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS;
460     }
461     else
462     {
463         const char *file_type = rec->info[recInfo_fileType];
464         void *recTypeClientData;
465         RecType rt = recType_byName(zh->reg->recTypes, zh->res,
466                                     file_type, &recTypeClientData);
467
468         if (!rt)
469             return_code = YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS;
470         else
471         {
472             struct ZebraRecStream stream;
473             return_code = zebra_create_record_stream(zh, &rec, &stream);
474             if (return_code == 0)
475             {
476                 extract_snippet(zh, snippets, &stream,
477                                 rt, recTypeClientData);
478
479                 stream.destroy(&stream);
480             }
481         }
482         rec_free(&rec);
483     }
484     return return_code;
485 }
486
487 int zebra_special_snippet_fetch(ZebraHandle zh, const char *setname,
488                                 zint sysno, ODR odr,
489                                 const char *elemsetname,
490                                 const Odr_oid *input_format,
491                                 const Odr_oid **output_format,
492                                 char **rec_bufp, int *rec_lenp)
493 {
494     zebra_snippets *rec_snippets = zebra_snippets_create();
495     int return_code = zebra_get_rec_snippets(zh, sysno, rec_snippets);
496
497     if (!return_code)
498     {
499         WRBUF wrbuf = wrbuf_alloc();
500         zebra_snippets *hit_snippet = zebra_snippets_create();
501
502         zebra_snippets_hit_vector(zh, setname, sysno, hit_snippet);
503
504 #if 0
505         /* for debugging purposes */
506         yaz_log(YLOG_LOG, "---------------------------");
507         yaz_log(YLOG_LOG, "REC SNIPPET:");
508         zebra_snippets_log(rec_snippet, YLOG_LOG, 1);
509         yaz_log(YLOG_LOG, "---------------------------");
510         yaz_log(YLOG_LOG, "HIT SNIPPET:");
511         zebra_snippets_log(hit_snippet, YLOG_LOG, 1);
512 #endif
513         
514         zebra_snippets_ring(rec_snippets, hit_snippet, 5, 5);
515         
516 #if 0
517         yaz_log(YLOG_LOG, "---------------------------");
518         yaz_log(YLOG_LOG, "RING SNIPPET:");
519         zebra_snippets_log(rec_snippets, YLOG_LOG, 1);
520 #endif
521         snippet_xml_record(zh, wrbuf, rec_snippets);
522         
523         *output_format = yaz_oid_recsyn_xml;
524         
525         if (return_code == 0)
526         {
527             *rec_lenp = wrbuf_len(wrbuf);
528             *rec_bufp = odr_strdup(odr, wrbuf_cstr(wrbuf));
529         }
530         wrbuf_destroy(wrbuf);
531         zebra_snippets_destroy(hit_snippet);
532     }
533     zebra_snippets_destroy(rec_snippets);
534     return return_code;
535 }
536
537 int zebra_special_fetch(ZebraHandle zh, const char *setname,
538                         zint sysno, int score, ODR odr,
539                         const char *elemsetname,
540                         const Odr_oid *input_format,
541                         const Odr_oid **output_format,
542                         char **rec_bufp, int *rec_lenp)
543 {
544     Record rec;
545     
546     /* set output variables before processing possible error states */
547     /* *rec_lenp = 0; */
548
549
550     if (elemsetname && 0 == strcmp(elemsetname, "snippet"))
551     {
552         return zebra_special_snippet_fetch(zh, setname, sysno, odr,
553                                            elemsetname + 7,
554                                            input_format, output_format,
555                                            rec_bufp, rec_lenp);
556     }
557
558     /* processing zebra::meta::sysno elemset without fetching binary data */
559     if (elemsetname && 0 == strcmp(elemsetname, "meta::sysno"))
560     {
561         int ret = 0;
562         WRBUF wrbuf = wrbuf_alloc();
563         if (!oid_oidcmp(input_format, yaz_oid_recsyn_sutrs))
564         {
565             wrbuf_printf(wrbuf, ZINT_FORMAT, sysno);
566             *output_format = input_format;
567         } 
568         else if (!oid_oidcmp(input_format, yaz_oid_recsyn_xml))
569         {
570             wrbuf_printf(wrbuf, ZEBRA_XML_HEADER_STR
571                          " sysno=\"" ZINT_FORMAT "\"/>\n",
572                          sysno);
573             *output_format = input_format;
574         }
575         *rec_lenp = wrbuf_len(wrbuf);
576         if (*rec_lenp)
577             *rec_bufp = odr_strdup(odr, wrbuf_cstr(wrbuf));
578         else
579             ret = YAZ_BIB1_NO_SYNTAXES_AVAILABLE_FOR_THIS_REQUEST;
580         wrbuf_destroy(wrbuf);
581         return ret;
582     }
583
584     /* processing special elementsetname zebra::index:: for sort elements */
585     if (elemsetname && 0 == strncmp(elemsetname, "index", 5))
586     {
587         int ret = zebra_special_sort_fetch(zh, sysno, odr,
588                                            elemsetname + 5,
589                                            input_format, output_format,
590                                            rec_bufp, rec_lenp);
591         if (ret != -1)
592             return ret;
593         /* not a sort index so we continue to get the full record */
594     }
595
596
597     /* fetching binary record up for all other display elementsets */
598     rec = rec_get(zh->reg->records, sysno);
599     if (!rec)
600     {
601         yaz_log(YLOG_WARN, "rec_get fail on sysno=" ZINT_FORMAT, sysno);
602         return YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS;
603     }
604
605     /* processing special elementsetnames zebra::data */    
606     if (elemsetname && 0 == strcmp(elemsetname, "data"))
607     {
608         struct ZebraRecStream stream;
609         RecordAttr *recordAttr = rec_init_attr(zh->reg->zei, rec); 
610         zebra_create_record_stream(zh, &rec, &stream);
611         *output_format = input_format;
612         *rec_lenp = recordAttr->recordSize;
613         *rec_bufp = (char *) odr_malloc(odr, *rec_lenp);
614         stream.readf(&stream, *rec_bufp, *rec_lenp);
615         stream.destroy(&stream);
616         rec_free(&rec);
617         return 0;
618     }
619
620     /* only accept XML and SUTRS requests from now */
621     if (oid_oidcmp(input_format, yaz_oid_recsyn_xml)
622         && oid_oidcmp(input_format, yaz_oid_recsyn_sutrs))
623     {
624         yaz_log(YLOG_WARN, "unsupported format for element set zebra::%s", 
625                 elemsetname);
626         return YAZ_BIB1_NO_SYNTAXES_AVAILABLE_FOR_THIS_REQUEST;
627     }
628     
629
630     /* processing special elementsetnames zebra::meta:: */
631     if (elemsetname && 0 == strcmp(elemsetname, "meta"))
632     {
633         int ret = 0;
634         WRBUF wrbuf = wrbuf_alloc();
635         RecordAttr *recordAttr = rec_init_attr(zh->reg->zei, rec); 
636
637         if (!oid_oidcmp(input_format, yaz_oid_recsyn_xml))
638         {
639             *output_format = input_format;
640             
641             wrbuf_printf(wrbuf, ZEBRA_XML_HEADER_STR
642                          " sysno=\"" ZINT_FORMAT "\"", sysno);
643             retrieve_puts_attr(wrbuf, "base", rec->info[recInfo_databaseName]);
644             retrieve_puts_attr(wrbuf, "file", rec->info[recInfo_filename]);
645             retrieve_puts_attr(wrbuf, "type", rec->info[recInfo_fileType]);
646             if (score >= 0)
647                 retrieve_puts_attr_int(wrbuf, "score", score);
648            
649             wrbuf_printf(wrbuf,
650                          " rank=\"" ZINT_FORMAT "\""
651                          " size=\"%i\""
652                          " set=\"zebra::%s\"/>\n",
653                          recordAttr->staticrank,
654                          recordAttr->recordSize,
655                          elemsetname);
656         }
657         else if (!oid_oidcmp(input_format, yaz_oid_recsyn_sutrs))
658         {
659             *output_format = input_format;
660             wrbuf_printf(wrbuf, "sysno " ZINT_FORMAT "\n", sysno);
661             retrieve_puts_str(wrbuf, "base", rec->info[recInfo_databaseName]);
662             retrieve_puts_str(wrbuf, "file", rec->info[recInfo_filename]);
663             retrieve_puts_str(wrbuf, "type", rec->info[recInfo_fileType]);
664             if (score >= 0)
665                 retrieve_puts_int(wrbuf, "score", score);
666
667             wrbuf_printf(wrbuf,
668                          "rank " ZINT_FORMAT "\n"
669                          "size %i\n"
670                          "set zebra::%s\n",
671                          recordAttr->staticrank,
672                          recordAttr->recordSize,
673                          elemsetname);
674         }
675         *rec_lenp = wrbuf_len(wrbuf);
676         if (*rec_lenp)
677             *rec_bufp = odr_strdup(odr, wrbuf_cstr(wrbuf));
678         else
679             ret = YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS;
680
681         wrbuf_destroy(wrbuf);
682         rec_free(&rec);
683         return ret;
684     }
685
686     /* processing special elementsetnames zebra::index:: */
687     if (elemsetname && 0 == strncmp(elemsetname, "index", 5))
688     {
689         int ret = zebra_special_index_fetch(zh, sysno, odr, rec,
690                                             elemsetname + 5,
691                                             input_format, output_format,
692                                             rec_bufp, rec_lenp);
693         
694         rec_free(&rec);
695         return ret;
696     }
697
698     if (rec)
699         rec_free(&rec);
700     return YAZ_BIB1_SPECIFIED_ELEMENT_SET_NAME_NOT_VALID_FOR_SPECIFIED_;
701 }
702
703                           
704 int zebra_record_fetch(ZebraHandle zh, const char *setname,
705                        zint sysno, int score,
706                        zebra_snippets *hit_snippet, ODR odr,
707                        const Odr_oid *input_format, Z_RecordComposition *comp,
708                        const Odr_oid **output_format,
709                        char **rec_bufp, int *rec_lenp, char **basenamep,
710                        char **addinfo)
711 {
712     Record rec;
713     char *fname, *file_type, *basename;
714     const char *elemsetname;
715     struct ZebraRecStream stream;
716     RecordAttr *recordAttr;
717     void *clientData;
718     int return_code = 0;
719
720     *basenamep = 0;
721     *addinfo = 0;
722     elemsetname = yaz_get_esn(comp);
723
724     /* processing zebra special elementset names of form 'zebra:: */
725     if (elemsetname && 0 == strncmp(elemsetname, "zebra::", 7))
726         return  zebra_special_fetch(zh, setname, sysno, score, odr,
727                                     elemsetname + 7,
728                                     input_format, output_format,
729                                     rec_bufp, rec_lenp);
730
731
732     /* processing all other element set names */
733     rec = rec_get(zh->reg->records, sysno);
734     if (!rec)
735     {
736         yaz_log(YLOG_WARN, "rec_get fail on sysno=" ZINT_FORMAT, sysno);
737         *basenamep = 0;
738         return YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS;
739     }
740
741
742     recordAttr = rec_init_attr(zh->reg->zei, rec);
743
744     file_type = rec->info[recInfo_fileType];
745     fname = rec->info[recInfo_filename];
746     basename = rec->info[recInfo_databaseName];
747     *basenamep = (char *) odr_malloc(odr, strlen(basename)+1);
748     strcpy(*basenamep, basename);
749
750     yaz_log(YLOG_DEBUG, "retrieve localno=" ZINT_FORMAT " score=%d",
751             sysno, score);
752
753     return_code = zebra_create_record_stream(zh, &rec, &stream);
754
755     if (rec)
756     {
757         zebra_rec_keys_t reckeys = zebra_rec_keys_open();
758         RecType rt;
759         struct recRetrieveCtrl retrieveCtrl;
760
761         retrieveCtrl.stream = &stream;
762         retrieveCtrl.fname = fname;
763         retrieveCtrl.localno = sysno;
764         retrieveCtrl.staticrank = recordAttr->staticrank;
765         retrieveCtrl.score = score;
766         retrieveCtrl.recordSize = recordAttr->recordSize;
767         retrieveCtrl.odr = odr;
768         retrieveCtrl.input_format = retrieveCtrl.output_format = input_format;
769         retrieveCtrl.comp = comp;
770         retrieveCtrl.encoding = zh->record_encoding;
771         retrieveCtrl.diagnostic = 0;
772         retrieveCtrl.addinfo = 0;
773         retrieveCtrl.dh = zh->reg->dh;
774         retrieveCtrl.res = zh->res;
775         retrieveCtrl.rec_buf = 0;
776         retrieveCtrl.rec_len = -1;
777         retrieveCtrl.hit_snippet = hit_snippet;
778         retrieveCtrl.doc_snippet = zebra_snippets_create();
779
780         zebra_rec_keys_set_buf(reckeys,
781                                rec->info[recInfo_delKeys],
782                                rec->size[recInfo_delKeys], 
783                                0);
784         zebra_rec_keys_to_snippets(zh, reckeys, retrieveCtrl.doc_snippet);
785         zebra_rec_keys_close(reckeys);
786
787         if (!(rt = recType_byName(zh->reg->recTypes, zh->res,
788                                   file_type, &clientData)))
789         {
790             char addinfo_str[100];
791
792             sprintf(addinfo_str, "Could not handle record type %.40s",
793                     file_type);
794                     
795             *addinfo = odr_strdup(odr, addinfo_str);
796             return_code = YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS;
797         }
798         else
799         {
800             (*rt->retrieve)(clientData, &retrieveCtrl);
801             return_code = retrieveCtrl.diagnostic;
802
803             *output_format = retrieveCtrl.output_format;
804             *rec_bufp = (char *) retrieveCtrl.rec_buf;
805             *rec_lenp = retrieveCtrl.rec_len;
806             *addinfo = retrieveCtrl.addinfo;
807         }
808
809         zebra_snippets_destroy(retrieveCtrl.doc_snippet);
810
811         stream.destroy(&stream);
812         rec_free(&rec);
813     }
814
815     return return_code;
816 }
817
818 /*
819  * Local variables:
820  * c-basic-offset: 4
821  * indent-tabs-mode: nil
822  * End:
823  * vim: shiftwidth=4 tabstop=8 expandtab
824  */
825