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