bb816bb42eafab2ebd45464fffe5d872c2089115
[yaz-moved-to-github.git] / ztest / ztest.c
1 /*
2  * Copyright (c) 1995-2001, Index Data.
3  * See the file LICENSE for details.
4  *
5  * NT Service interface by
6  *    Chas Woodfield, Fretwell Downing Datasystems.
7  *
8  * $Log: ztest.c,v $
9  * Revision 1.42  2001-04-06 12:26:46  adam
10  * Optional CCL module. Moved atoi_n to marcdisp.h from yaz-util.h.
11  *
12  * Revision 1.41  2001/04/05 13:08:48  adam
13  * New configure options: --enable-module.
14  *
15  * Revision 1.40  2001/03/25 21:55:13  adam
16  * Added odr_intdup. Ztest server returns TaskPackage for ItemUpdate.
17  *
18  * Revision 1.39  2001/03/12 14:40:57  adam
19  * Minor change of print of item update info.
20  *
21  * Revision 1.38  2001/02/21 13:46:54  adam
22  * C++ fixes.
23  *
24  * Revision 1.37  2001/02/20 11:25:32  adam
25  * Added ill_get_APDU and ill_get_Cancel.
26  *
27  * Revision 1.36  2001/01/30 21:34:18  adam
28  * Added step-size for Scan backend interface.
29  *
30  * Revision 1.35  2000/11/23 10:58:33  adam
31  * SSL comstack support. Separate POSIX thread support library.
32  *
33  * Revision 1.34  2000/09/04 08:58:15  adam
34  * Added prefix yaz_ for most logging utility functions.
35  *
36  * Revision 1.33  2000/08/10 08:41:26  adam
37  * Fixes for ILL.
38  *
39  * Revision 1.32  2000/04/05 07:39:55  adam
40  * Added shared library support (libtool).
41  *
42  * Revision 1.31  2000/01/31 13:15:21  adam
43  * Removed uses of assert(3). Cleanup of ODR. CCL parser update so
44  * that some characters are not surrounded by spaces in resulting term.
45  * ILL-code updates.
46  *
47  * Revision 1.30  2000/01/13 23:05:50  adam
48  * Fixed tagging for member requester-CHECKED-IN in ILL ASN.1 spec.
49  *
50  * Revision 1.29  2000/01/12 14:36:07  adam
51  * Added printing stream (ODR) for backend functions.
52  *
53  * Revision 1.28  1999/12/16 23:36:19  adam
54  * Implemented ILL protocol. Minor updates ASN.1 compiler.
55  *
56  * Revision 1.27  1999/11/30 13:47:12  adam
57  * Improved installation. Moved header files to include/yaz.
58  *
59  * Revision 1.26  1999/08/27 09:40:32  adam
60  * Renamed logf function to yaz_log. Removed VC++ project files.
61  *
62  * Revision 1.25  1999/06/01 14:29:12  adam
63  * Work on Extended Services.
64  *
65  * Revision 1.24  1999/05/27 13:07:54  adam
66  * Fix.
67  *
68  * Revision 1.23  1999/05/27 13:02:20  adam
69  * Assigned OID for old DB Update (VAL_DBUPDATE0).
70  *
71  * Revision 1.22  1999/05/26 13:49:12  adam
72  * DB Update implemented in client (very basic).
73  *
74  * Revision 1.21  1998/12/15 12:45:42  adam
75  * Minor change.
76  *
77  * Revision 1.20  1998/12/14 14:48:05  adam
78  * Fixed memory leak - happened when fetching MARC records.
79  *
80  * Revision 1.19  1998/10/20 15:16:22  adam
81  * Minor change to prevent warning.
82  *
83  * Revision 1.18  1998/10/20 15:13:45  adam
84  * Minor fix regarding output for Item Order.
85  *
86  * Revision 1.17  1998/10/18 22:33:35  quinn
87  * Added diagnostic dump of Item Order Eservice.
88  *
89  * Revision 1.16  1998/10/15 08:26:23  adam
90  * Added type cast to make C++ happy.
91  *
92  * Revision 1.15  1998/10/13 20:05:57  adam
93  * Minor change.
94  *
95  * Revision 1.14  1998/10/13 16:12:25  adam
96  * Added support for Surrogate Diagnostics for Scan Term entries.
97  *
98  * Revision 1.13  1998/08/19 16:10:09  adam
99  * Changed som member names of DeleteResultSetRequest/Response.
100  *
101  * Revision 1.12  1998/07/20 12:38:44  adam
102  * Implemented delete result set service to server API.
103  *
104  * Revision 1.11  1998/06/09 13:55:08  adam
105  * Minor changes.
106  *
107  * Revision 1.10  1998/05/27 16:55:54  adam
108  * Minor changes.
109  *
110  * Revision 1.9  1998/03/31 11:07:45  adam
111  * Furhter work on UNIverse resource report.
112  * Added Extended Services handling in frontend server.
113  *
114  * Revision 1.8  1998/02/11 11:53:36  adam
115  * Changed code so that it compiles as C++.
116  *
117  * Revision 1.7  1998/02/10 11:03:57  adam
118  * Added support for extended handlers in backend server interface.
119  *
120  * Revision 1.6  1998/01/29 13:16:02  adam
121  * Added dummy sort in test server.
122  *
123  * Revision 1.5  1997/11/07 13:31:58  adam
124  * Added NT Service name part of statserv_options_block. Moved NT
125  * service utility to server library.
126  *
127  * Revision 1.4  1997/09/17 12:10:43  adam
128  * YAZ version 1.4.
129  *
130  * Revision 1.3  1997/09/09 10:10:20  adam
131  * Another MSV5.0 port. Changed projects to include proper
132  * library/include paths.
133  * Server starts server in test-mode when no options are given.
134  *
135  * Revision 1.2  1997/09/04 13:50:31  adam
136  * Bug fix in ztest.
137  *
138  */
139
140 /*
141  * Demonstration of simple server
142  */
143
144 #include <stdio.h>
145 #include <stdlib.h>
146 #include <ctype.h>
147
148 #include <yaz/backend.h>
149 #include <yaz/log.h>
150
151 #if YAZ_MODULE_ill
152 #include <yaz/ill.h>
153 #endif
154
155 Z_GenericRecord *read_grs1(FILE *f, ODR o);
156
157 int ztest_search (void *handle, bend_search_rr *rr);
158 int ztest_sort (void *handle, bend_sort_rr *rr);
159 int ztest_present (void *handle, bend_present_rr *rr);
160 int ztest_esrequest (void *handle, bend_esrequest_rr *rr);
161 int ztest_delete (void *handle, bend_delete_rr *rr);
162
163 int ztest_search (void *handle, bend_search_rr *rr)
164 {
165     rr->hits = rand() % 22;
166     return 0;
167 }
168
169 int ztest_present (void *handle, bend_present_rr *rr)
170 {
171     return 0;
172 }
173
174 int ztest_esrequest (void *handle, bend_esrequest_rr *rr)
175 {
176     yaz_log(LOG_LOG, "function: %d", *rr->esr->function);
177     if (rr->esr->packageName)
178         yaz_log(LOG_LOG, "packagename: %s", rr->esr->packageName);
179     yaz_log(LOG_LOG, "Waitaction: %d", *rr->esr->waitAction);
180
181     if (!rr->esr->taskSpecificParameters)
182     {
183         yaz_log (LOG_WARN, "No task specific parameters");
184     }
185     else if (rr->esr->taskSpecificParameters->which == Z_External_itemOrder)
186     {
187         Z_ItemOrder *it = rr->esr->taskSpecificParameters->u.itemOrder;
188         yaz_log (LOG_LOG, "Received ItemOrder");
189         switch (it->which)
190         {
191 #ifdef ASN_COMPILED
192         case Z_IOItemOrder_esRequest:
193 #else
194         case Z_ItemOrder_esRequest:
195 #endif
196         {
197             Z_IORequest *ir = it->u.esRequest;
198             Z_IOOriginPartToKeep *k = ir->toKeep;
199             Z_IOOriginPartNotToKeep *n = ir->notToKeep;
200             
201             if (k && k->contact)
202             {
203                 if (k->contact->name)
204                     yaz_log(LOG_LOG, "contact name %s", k->contact->name);
205                 if (k->contact->phone)
206                     yaz_log(LOG_LOG, "contact phone %s", k->contact->phone);
207                 if (k->contact->email)
208                     yaz_log(LOG_LOG, "contact email %s", k->contact->email);
209             }
210             if (k->addlBilling)
211             {
212                 yaz_log(LOG_LOG, "Billing info (not shown)");
213             }
214             
215             if (n->resultSetItem)
216             {
217                 yaz_log(LOG_LOG, "resultsetItem");
218                 yaz_log(LOG_LOG, "setId: %s", n->resultSetItem->resultSetId);
219                 yaz_log(LOG_LOG, "item: %d", *n->resultSetItem->item);
220             }
221 #if YAZ_MODULE_ill
222             if (n->itemRequest)
223             {
224                 Z_External *r = (Z_External*) n->itemRequest;
225                 ILL_ItemRequest *item_req = 0;
226                 ILL_APDU *ill_apdu = 0;
227                 if (r->direct_reference)
228                 {
229                     oident *ent = oid_getentbyoid(r->direct_reference);
230                     if (ent)
231                         yaz_log(LOG_LOG, "OID %s", ent->desc);
232                     if (ent && ent->value == VAL_TEXT_XML)
233                     {
234                         yaz_log (LOG_LOG, "ILL XML request");
235                         if (r->which == Z_External_octet)
236                             yaz_log (LOG_LOG, "%.*s", r->u.octet_aligned->len,
237                                      r->u.octet_aligned->buf); 
238                     }
239                     if (ent && ent->value == VAL_ISO_ILL_1)
240                     {
241                         yaz_log (LOG_LOG, "Decode ItemRequest begin");
242                         if (r->which == ODR_EXTERNAL_single)
243                         {
244                             odr_setbuf(rr->decode,
245                                        (char *) r->u.single_ASN1_type->buf,
246                                        r->u.single_ASN1_type->len, 0);
247                             
248                             if (!ill_ItemRequest (rr->decode, &item_req, 0, 0))
249                             {
250                                 yaz_log (LOG_LOG,
251                                     "Couldn't decode ItemRequest %s near %d",
252                                        odr_errmsg(odr_geterror(rr->decode)),
253                                        odr_offset(rr->decode));
254 #if 0
255                                 yaz_log(LOG_LOG, "PDU dump:");
256                                 odr_dumpBER(yaz_log_file(),
257                                      r->u.single_ASN1_type->buf,
258                                      r->u.single_ASN1_type->len);
259 #endif
260                             }
261                             else
262                                 yaz_log(LOG_LOG, "Decode ItemRequest OK");
263                             if (rr->print)
264                             {
265                                 ill_ItemRequest (rr->print, &item_req, 0,
266                                     "ItemRequest");
267                                 odr_reset (rr->print);
268                             }
269                         }
270                         if (!item_req && r->which == ODR_EXTERNAL_single)
271                         {
272                             yaz_log (LOG_LOG, "Decode ILL APDU begin");
273                             odr_setbuf(rr->decode,
274                                        (char*) r->u.single_ASN1_type->buf,
275                                        r->u.single_ASN1_type->len, 0);
276                             
277                             if (!ill_APDU (rr->decode, &ill_apdu, 0, 0))
278                             {
279                                 yaz_log (LOG_LOG,
280                                     "Couldn't decode ILL APDU %s near %d",
281                                        odr_errmsg(odr_geterror(rr->decode)),
282                                        odr_offset(rr->decode));
283                                 yaz_log(LOG_LOG, "PDU dump:");
284                                 odr_dumpBER(yaz_log_file(),
285                                      (char *) r->u.single_ASN1_type->buf,
286                                      r->u.single_ASN1_type->len);
287                             }
288                             else
289                                 yaz_log(LOG_LOG, "Decode ILL APDU OK");
290                             if (rr->print)
291                             {
292                                 ill_APDU (rr->print, &ill_apdu, 0,
293                                     "ILL APDU");
294                                 odr_reset (rr->print);
295                             }
296                         }
297                     }
298                 }
299                 if (item_req)
300                 {
301                     yaz_log (LOG_LOG, "ILL protocol version = %d",
302                              *item_req->protocol_version_num);
303                 }
304             }
305 #endif
306         }
307         break;
308         }
309     }
310     else if (rr->esr->taskSpecificParameters->which == Z_External_update)
311     {
312         Z_IUUpdate *up = rr->esr->taskSpecificParameters->u.update;
313         yaz_log (LOG_LOG, "Received DB Update");
314         if (up->which == Z_IUUpdate_esRequest)
315         {
316             Z_IUUpdateEsRequest *esRequest = up->u.esRequest;
317             Z_IUOriginPartToKeep *toKeep = esRequest->toKeep;
318             Z_IUSuppliedRecords *notToKeep = esRequest->notToKeep;
319             
320             yaz_log (LOG_LOG, "action");
321             if (toKeep->action)
322             {
323                 switch (*toKeep->action)
324                 {
325                 case Z_IUOriginPartToKeep_recordInsert:
326                     yaz_log (LOG_LOG, " recordInsert");
327                     break;
328                 case Z_IUOriginPartToKeep_recordReplace:
329                     yaz_log (LOG_LOG, " recordReplace");
330                     break;
331                 case Z_IUOriginPartToKeep_recordDelete:
332                     yaz_log (LOG_LOG, " recordDelete");
333                     break;
334                 case Z_IUOriginPartToKeep_elementUpdate:
335                     yaz_log (LOG_LOG, " elementUpdate");
336                     break;
337                 case Z_IUOriginPartToKeep_specialUpdate:
338                     yaz_log (LOG_LOG, " specialUpdate");
339                     break;
340                 default:
341                     yaz_log (LOG_LOG, " unknown (%d)", *toKeep->action);
342                 }
343             }
344             if (toKeep->databaseName)
345             {
346                 yaz_log (LOG_LOG, "database: %s", toKeep->databaseName);
347                 if (!strcmp(toKeep->databaseName, "fault"))
348                 {
349                     rr->errcode = 109;
350                     rr->errstring = toKeep->databaseName;
351                 }
352                 if (!strcmp(toKeep->databaseName, "accept"))
353                     rr->errcode = -1;
354             }
355             if (toKeep)
356             {
357                 Z_External *ext = odr_malloc (rr->stream, sizeof(*ext));
358                 Z_IUOriginPartToKeep *keep =
359                     odr_malloc (rr->stream, sizeof(*keep));
360                 Z_IUTargetPart *targetPart =
361                     odr_malloc (rr->stream, sizeof(*targetPart));
362                 rr->taskPackage = odr_malloc (rr->stream, sizeof(*rr->taskPackage));
363                 rr->taskPackage->packageType =
364                     odr_oiddup (rr->stream, rr->esr->packageType);
365                 rr->taskPackage->packageName = 0;
366                 rr->taskPackage->userId = 0;
367                 rr->taskPackage->retentionTime = 0;
368                 rr->taskPackage->permissions = 0;
369                 rr->taskPackage->description = 0;
370                 rr->taskPackage->targetReference = (Odr_oct *)
371                     odr_malloc (rr->stream, sizeof(Odr_oct));
372                 rr->taskPackage->targetReference->buf =
373                     odr_strdup (rr->stream, "123");
374                 rr->taskPackage->targetReference->len =
375                     rr->taskPackage->targetReference->size =
376                     strlen(rr->taskPackage->targetReference->buf);
377                 rr->taskPackage->creationDateTime = 0;
378                 rr->taskPackage->taskStatus = odr_intdup(rr->stream, 0);
379                 rr->taskPackage->packageDiagnostics = 0;
380                 rr->taskPackage->taskSpecificParameters = ext;
381
382                 ext->direct_reference =
383                     odr_oiddup (rr->stream, rr->esr->packageType);
384                 ext->indirect_reference = 0;
385                 ext->descriptor = 0;
386                 ext->which = Z_External_update;
387                 ext->u.update = (Z_IUUpdate *)
388                     odr_malloc (rr->stream, sizeof(*ext->u.update));
389                 ext->u.update->which = Z_IUUpdate_taskPackage;
390                 ext->u.update->u.taskPackage =  (Z_IUUpdateTaskPackage *)
391                     odr_malloc (rr->stream, sizeof(Z_IUUpdateTaskPackage));
392                 ext->u.update->u.taskPackage->originPart = keep;
393                 ext->u.update->u.taskPackage->targetPart = targetPart;
394
395                 keep->action = odr_malloc (rr->stream, sizeof(int));
396                 *keep->action = *toKeep->action;
397                 keep->databaseName =
398                     odr_strdup (rr->stream, toKeep->databaseName);
399                 keep->schema = 0;
400                 keep->elementSetName = 0;
401                 keep->actionQualifier = 0;
402
403                 targetPart->updateStatus = odr_intdup (rr->stream, 1);
404                 targetPart->num_globalDiagnostics = 0;
405                 targetPart->globalDiagnostics = odr_nullval();
406                 targetPart->num_taskPackageRecords = 0;
407                 targetPart->taskPackageRecords = odr_nullval();
408             }
409             if (notToKeep)
410             {
411                 int i;
412                 for (i = 0; i < notToKeep->num; i++)
413                 {
414                     Z_External *rec = notToKeep->elements[i]->record;
415
416                     if (rec->direct_reference)
417                     {
418                         struct oident *oident;
419                         oident = oid_getentbyoid(rec->direct_reference);
420                         if (oident)
421                             yaz_log (LOG_LOG, "record %d type %s", i,
422                                      oident->desc);
423                     }
424                     switch (rec->which)
425                     {
426                     case Z_External_sutrs:
427                         if (rec->u.octet_aligned->len > 170)
428                             yaz_log (LOG_LOG, "%d bytes:\n%.168s ...",
429                                      rec->u.sutrs->len,
430                                      rec->u.sutrs->buf);
431                         else
432                             yaz_log (LOG_LOG, "%d bytes:\n%s",
433                                      rec->u.sutrs->len,
434                                      rec->u.sutrs->buf);
435                         break;
436                     case Z_External_octet        :
437                         if (rec->u.octet_aligned->len > 170)
438                             yaz_log (LOG_LOG, "%d bytes:\n%.168s ...",
439                                      rec->u.octet_aligned->len,
440                                      rec->u.octet_aligned->buf);
441                         else
442                             yaz_log (LOG_LOG, "%d bytes\n%s",
443                                      rec->u.octet_aligned->len,
444                                      rec->u.octet_aligned->buf);
445                     }
446                 }
447             }
448         }
449     }
450     else
451     {
452         yaz_log (LOG_WARN, "Unknown Extended Service(%d)",
453                  rr->esr->taskSpecificParameters->which);
454         
455     }
456     return 0;
457 }
458
459 int ztest_delete (void *handle, bend_delete_rr *rr)
460 {
461     if (rr->num_setnames == 1 && !strcmp (rr->setnames[0], "1"))
462         rr->delete_status = Z_DeleteStatus_success;
463     else
464         rr->delete_status = Z_DeleteStatus_resultSetDidNotExist;
465     return 0;
466 }
467
468 /* Our sort handler really doesn't sort... */
469 int ztest_sort (void *handle, bend_sort_rr *rr)
470 {
471     rr->errcode = 0;
472     rr->sort_status = Z_SortStatus_success;
473     return 0;
474 }
475
476 static int atoin (const char *buf, int n)
477 {
478     int val = 0;
479     while (--n >= 0)
480     {
481         if (isdigit(*buf))
482             val = val*10 + (*buf - '0');
483         buf++;
484     }
485     return val;
486 }
487
488 char *marc_read(FILE *inf, ODR odr)
489 {
490     char length_str[5];
491     size_t size;
492     char *buf;
493
494     if (fread (length_str, 1, 5, inf) != 5)
495         return NULL;
496     size = atoin (length_str, 5);
497     if (size <= 6)
498         return NULL;
499     if (!(buf = (char*) odr_malloc (odr, size+1)))
500         return NULL;
501     if (fread (buf+5, 1, size-5, inf) != (size-5))
502     {
503         xfree (buf);
504         return NULL;
505     }
506     memcpy (buf, length_str, 5);
507     buf[size] = '\0';
508     return buf;
509 }
510
511 static char *dummy_database_record (int num, ODR odr)
512 {
513     FILE *inf = fopen ("dummy-records", "r");
514     char *buf = 0;
515
516     if (!inf)
517         return NULL;
518     while (--num >= 0)
519     {
520         if (num == 98)
521         {
522             buf = (char*) odr_malloc(odr, 2101);
523             memset(buf, 'A', 2100);
524             buf[2100] = '\0';
525             break;
526         }
527         else
528             buf = marc_read (inf, odr);
529         if (!num || !buf)
530             break;
531     }
532     fclose(inf);
533     if (num < 0)
534         return 0;
535     return buf;
536 }
537
538 static Z_GenericRecord *dummy_grs_record (int num, ODR o)
539 {
540     FILE *f = fopen("dummy-grs", "r");
541     char line[512];
542     Z_GenericRecord *r = 0;
543     int n;
544
545     if (!f)
546         return 0;
547     while (fgets(line, 512, f))
548         if (*line == '#' && sscanf(line, "#%d", &n) == 1 && n == num)
549         {
550             r = read_grs1(f, o);
551             break;
552         }
553     fclose(f);
554     return r;
555 }
556
557 int ztest_fetch(void *handle, bend_fetch_rr *r)
558 {
559     char *cp;
560     r->errstring = 0;
561     r->last_in_set = 0;
562     r->basename = "DUMMY";
563     r->output_format = r->request_format;  
564     if (r->request_format == VAL_SUTRS)
565     {
566 #if 0
567 /* this section returns a huge record (for testing non-blocking write, etc) */
568         r->len = 980000;
569         r->record = odr_malloc (r->stream, r->len);
570         memset (r->record, 'x', r->len);
571 #else
572 /* this section returns a small record */
573         char buf[100];
574
575         sprintf(buf, "This is dummy SUTRS record number %d\n", r->number);
576
577         r->len = strlen(buf);
578         r->record = (char *) odr_malloc (r->stream, r->len+1);
579         strcpy(r->record, buf);
580 #endif
581     }
582     else if (r->request_format == VAL_GRS1)
583     {
584         r->len = -1;
585         r->record = (char*) dummy_grs_record(r->number, r->stream);
586         if (!r->record)
587         {
588             r->errcode = 13;
589             return 0;
590         }
591     }
592     else if ((cp = dummy_database_record(r->number, r->stream)))
593     {
594         r->len = strlen(cp);
595         r->record = cp;
596         r->output_format = VAL_USMARC;
597     }
598     else
599     {
600         r->errcode = 13;
601         return 0;
602     }
603     r->errcode = 0;
604     return 0;
605 }
606
607 /*
608  * silly dummy-scan what reads words from a file.
609  */
610 int ztest_scan(void *handle, bend_scan_rr *q)
611 {
612     static FILE *f = 0;
613     static struct scan_entry list[200];
614     static char entries[200][80];
615     int hits[200];
616     char term[80], *p;
617     int i, pos;
618     int term_position_req = q->term_position;
619     int num_entries_req = q->num_entries;
620
621     q->errcode = 0;
622     q->errstring = 0;
623     q->entries = list;
624     q->status = BEND_SCAN_SUCCESS;
625     if (!f && !(f = fopen("dummy-words", "r")))
626     {
627         perror("dummy-words");
628         exit(1);
629     }
630     if (q->term->term->which != Z_Term_general)
631     {
632         q->errcode = 229; /* unsupported term type */
633         return 0;
634     }
635     if (*q->step_size != 0)
636     {
637         q->errcode = 205; /*Only zero step size supported for Scan */
638         return 0;
639     }
640     if (q->term->term->u.general->len >= 80)
641     {
642         q->errcode = 11; /* term too long */
643         return 0;
644     }
645     if (q->num_entries > 200)
646     {
647         q->errcode = 31;
648         return 0;
649     }
650     memcpy(term, q->term->term->u.general->buf, q->term->term->u.general->len);
651     term[q->term->term->u.general->len] = '\0';
652     for (p = term; *p; p++)
653         if (islower(*p))
654             *p = toupper(*p);
655
656     fseek(f, 0, SEEK_SET);
657     q->num_entries = 0;
658
659     for (i = 0, pos = 0; fscanf(f, " %79[^:]:%d", entries[pos], &hits[pos]) == 2;
660         i++, pos < 199 ? pos++ : (pos = 0))
661     {
662         if (!q->num_entries && strcmp(entries[pos], term) >= 0) /* s-point fnd */
663         {
664             if ((q->term_position = term_position_req) > i + 1)
665             {
666                 q->term_position = i + 1;
667                 q->status = BEND_SCAN_PARTIAL;
668             }
669             for (; q->num_entries < q->term_position; q->num_entries++)
670             {
671                 int po;
672
673                 po = pos - q->term_position + q->num_entries+1; /* find pos */
674                 if (po < 0)
675                     po += 200;
676
677                 if (!strcmp (term, "SD") && q->num_entries == 2)
678                 {
679                     list[q->num_entries].term = entries[pos];
680                     list[q->num_entries].occurrences = -1;
681                     list[q->num_entries].errcode = 233;
682                     list[q->num_entries].errstring = "SD for Scan Term";
683                 }
684                 else
685                 {
686                     list[q->num_entries].term = entries[po];
687                     list[q->num_entries].occurrences = hits[po];
688                 }
689             }
690         }
691         else if (q->num_entries)
692         {
693             list[q->num_entries].term = entries[pos];
694             list[q->num_entries].occurrences = hits[pos];
695             q->num_entries++;
696         }
697         if (q->num_entries >= num_entries_req)
698             break;
699     }
700     if (feof(f))
701         q->status = BEND_SCAN_PARTIAL;
702     return 0;
703 }
704
705 bend_initresult *bend_init(bend_initrequest *q)
706 {
707     bend_initresult *r = (bend_initresult *) odr_malloc (q->stream, sizeof(*r));
708     static char *dummy = "Hej fister";
709
710     r->errcode = 0;
711     r->errstring = 0;
712     r->handle = dummy;
713     q->bend_sort = ztest_sort;              /* register sort handler */
714     q->bend_search = ztest_search;          /* register search handler */
715     q->bend_present = ztest_present;        /* register present handle */
716     q->bend_esrequest = ztest_esrequest;
717     q->bend_delete = ztest_delete;
718     q->bend_fetch = ztest_fetch;
719     q->bend_scan = ztest_scan;
720     return r;
721 }
722
723 void bend_close(void *handle)
724 {
725     return;
726 }
727
728 int main(int argc, char **argv)
729 {
730     return statserv_main(argc, argv, bend_init, bend_close);
731 }