zoomsh: show returned facets (if any).
[yaz-moved-to-github.git] / zoom / zoomsh.c
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) 1995-2011 Index Data
3  * See the file LICENSE for details.
4  */
5 /** \file zoomsh.c
6     \brief ZOOM C command line tool (shell)
7 */
8 #if HAVE_CONFIG_H
9 #include <config.h>
10 #endif
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <yaz/wrbuf.h>
16 #include <yaz/log.h>
17
18 #if HAVE_READLINE_READLINE_H
19 #include <readline/readline.h> 
20 #endif
21 #if HAVE_READLINE_HISTORY_H
22 #include <readline/history.h>
23 #endif
24
25 #include <yaz/log.h>
26 #include <yaz/zoom.h>
27
28 #define MAX_CON 100
29
30 static void process_events(ZOOM_connection *c)
31 {
32     int i;
33
34     yaz_log(YLOG_DEBUG, "process_events");
35     while ((i = ZOOM_event(MAX_CON, c)) != 0)
36     {
37         int peek = ZOOM_connection_peek_event(c[i-1]);
38         int event = ZOOM_connection_last_event(c[i-1]);
39         yaz_log(YLOG_DEBUG, "no = %d peek = %d event = %d %s", i-1,
40                 peek,
41                 event,
42                 ZOOM_get_event_str(event));
43     }
44 }
45
46 static int next_token(const char **cpp, const char **t_start)
47 {
48     int len = 0;
49     const char *cp = *cpp;
50     while (*cp == ' ')
51         cp++;
52     if (*cp == '"')
53     {
54         cp++;
55         *t_start = cp;
56         while (*cp && *cp != '"')
57         {
58             cp++;
59             len++;
60         }
61         if (*cp)
62             cp++;
63     }
64     else
65     {
66         *t_start = cp;
67         while (*cp && *cp != ' ' && *cp != '\r' && *cp != '\n')
68         {
69             cp++;
70             len++;
71         }
72         if (len == 0)
73             len = -1;
74     }
75     *cpp = cp;
76     return len;  /* return -1 if no token was read .. */
77 }
78
79 static WRBUF next_token_new_wrbuf(const char **cpp)
80 {
81     WRBUF w = 0;
82     const char *start;
83     int len = next_token(cpp, &start);
84     if (len < 0)
85         return 0;
86     w = wrbuf_alloc();
87     if (len > 0)
88         wrbuf_write(w, start, len);
89     return w;
90 }
91
92 static int is_command(const char *cmd_str, const char *this_str, int this_len)
93 {
94     int cmd_len = strlen(cmd_str);
95     if (cmd_len != this_len)
96         return 0;
97     if (memcmp(cmd_str, this_str, cmd_len))
98         return 0;
99     return 1;
100 }
101
102 static void cmd_set(ZOOM_connection *c, ZOOM_resultset *r,
103                     ZOOM_options options,
104                     const char **args)
105 {
106     WRBUF key, val;
107
108     if (!(key = next_token_new_wrbuf(args)))
109     {
110         printf("missing argument for set\n");
111         return ;
112     }
113     if ((val = next_token_new_wrbuf(args)))
114     {
115         ZOOM_options_set(options, wrbuf_cstr(key), wrbuf_cstr(val));
116         wrbuf_destroy(val);
117     }
118     else
119         ZOOM_options_set(options, wrbuf_cstr(key), 0);
120     wrbuf_destroy(key);
121 }
122
123 static void cmd_get(ZOOM_connection *c, ZOOM_resultset *r,
124                     ZOOM_options options,
125                     const char **args)
126 {
127     WRBUF key;
128     if (!(key = next_token_new_wrbuf(args)))
129     {
130         printf("missing argument for get\n");
131     }
132     else
133     {
134         const char *val = ZOOM_options_get(options, wrbuf_cstr(key));
135         printf("%s = %s\n", wrbuf_cstr(key), val ? val : "<null>");
136         wrbuf_destroy(key);
137     }
138 }
139
140 static void cmd_rget(ZOOM_connection *c, ZOOM_resultset *r,
141                      ZOOM_options options,
142                      const char **args)
143 {
144     WRBUF key;
145     if (!(key = next_token_new_wrbuf(args)))
146     {
147         printf("missing argument for get\n");
148     }
149     else
150     {
151         int i;
152         for (i = 0; i<MAX_CON; i++)
153         {
154             const char *val;
155             if (!r[i])
156                 continue;
157             
158             val = ZOOM_resultset_option_get(r[i], wrbuf_cstr(key));
159             printf("%s = %s\n", wrbuf_cstr(key), val ? val : "<null>");
160         }
161         wrbuf_destroy(key);
162     }
163 }
164
165 static void cmd_close(ZOOM_connection *c, ZOOM_resultset *r,
166                       ZOOM_options options,
167                       const char **args)
168 {
169     WRBUF host;
170     int i;
171     host = next_token_new_wrbuf(args);
172     for (i = 0; i<MAX_CON; i++)
173     {
174         const char *h;
175         if (!c[i])
176             continue;
177         if (!host)
178         {
179             ZOOM_connection_destroy(c[i]);
180             c[i] = 0;
181         }
182         else if ((h = ZOOM_connection_option_get(c[i], "host"))
183                  && !strcmp(h, wrbuf_cstr(host)))
184         {
185             ZOOM_connection_destroy(c[i]);
186             c[i] = 0;
187         }
188     }
189     if (host)
190         wrbuf_destroy(host);
191 }
192
193 static void display_records(ZOOM_connection c,
194                             ZOOM_resultset r,
195                             size_t start, size_t count, const char *type)
196 {
197     size_t i;
198     for (i = 0; i < count; i++)
199     {
200         size_t pos = i + start;
201         ZOOM_record rec = ZOOM_resultset_record(r, pos);
202         const char *db = ZOOM_record_get(rec, "database", 0);
203         
204         if (ZOOM_record_error(rec, 0, 0, 0))
205         {
206             const char *msg;
207             const char *addinfo;
208             const char *diagset;
209             int error = ZOOM_record_error(rec, &msg, &addinfo, &diagset);
210             
211             printf("%lld %s: %s (%s:%d) %s\n", (long long) pos,
212                    (db ? db : "unknown"),
213                    msg, diagset, error, addinfo ? addinfo : "none");
214         }
215         else
216         {
217             int len;
218             const char *render = ZOOM_record_get(rec, type, &len);
219             const char *syntax = ZOOM_record_get(rec, "syntax", 0);
220             const char *schema = ZOOM_record_get(rec, "schema", 0);
221             /* if rec is non-null, we got a record for display */
222             if (rec)
223             {
224                 printf("%lld database=%s syntax=%s schema=%s\n",
225                        (long long) pos, (db ? db : "unknown"), syntax,
226                        schema ? schema : "unknown");
227                 if (render)
228                 {
229                     if (fwrite(render, 1, len, stdout) != (size_t) len)
230                     {
231                         printf("write to stdout failed\n");
232                     }
233                 }
234                 printf("\n");
235             }
236         }
237     }
238 }
239
240 static void cmd_show(ZOOM_connection *c, ZOOM_resultset *r,
241                      ZOOM_options options,
242                      const char **args)
243 {
244     int i;
245     size_t start = 0, count = 1;
246     const char *type = "render";
247     WRBUF render_str = 0;
248
249     {
250         WRBUF tmp;
251
252         if ((tmp = next_token_new_wrbuf(args)))
253         {
254             start = atoi(wrbuf_cstr(tmp));
255             wrbuf_destroy(tmp);
256         }
257
258         if ((tmp = next_token_new_wrbuf(args)))
259         {
260             count = atoi(wrbuf_cstr(tmp));
261             wrbuf_destroy(tmp);
262         }
263         render_str = next_token_new_wrbuf(args);
264     }
265     if (render_str)
266         type = wrbuf_cstr(render_str);
267
268     for (i = 0; i < MAX_CON; i++)
269         ZOOM_resultset_records(r[i], 0, start, count);
270     process_events(c);
271
272     for (i = 0; i < MAX_CON; i++)
273     {
274         int error;
275         const char *errmsg, *addinfo, *dset;
276         /* display errors if any */
277         if (!c[i])
278             continue;
279         if ((error = ZOOM_connection_error_x(c[i], &errmsg, &addinfo, &dset)))
280             printf("%s error: %s (%s:%d) %s\n",
281                    ZOOM_connection_option_get(c[i], "host"), errmsg,
282                    dset, error, addinfo);
283         else if (r[i])
284         {
285             /* OK, no major errors. Display records... */
286             display_records(c[i], r[i], start, count, type);
287         }
288     }
289     if (render_str)
290         wrbuf_destroy(render_str);
291        
292 }
293
294 static void display_facets(ZOOM_facet_field *facets, int count) {
295     int index;
296     printf("Facets: \n");
297     for (index = 0; index <  count; index++) {
298         int term_index;
299         const char *facet_name = ZOOM_facet_field_name(facets[index]);
300         printf("  %s: \n", facet_name);
301         for (term_index = 0; term_index < ZOOM_facet_field_term_count(facets[index]); term_index++) {
302             int freq = 0;
303             const char *term = ZOOM_facet_field_get_term(facets[index], term_index, &freq);
304             printf("    %s(%d) \n", term,  freq);
305         }
306     }
307 }
308
309 static void cmd_facets(ZOOM_connection *c, ZOOM_resultset *r,
310                      ZOOM_options options,
311                      const char **args)
312 {
313     int i;
314     size_t start = 0, count = 1;
315     const char *type = "render";
316     WRBUF render_str = 0;
317
318     if (0)
319     {
320         WRBUF tmp;
321
322         if ((tmp = next_token_new_wrbuf(args)))
323         {
324             start = atoi(wrbuf_cstr(tmp));
325             wrbuf_destroy(tmp);
326         }
327
328         if ((tmp = next_token_new_wrbuf(args)))
329         {
330             count = atoi(wrbuf_cstr(tmp));
331             wrbuf_destroy(tmp);
332         }
333         render_str = next_token_new_wrbuf(args);
334     }
335     if (render_str)
336         type = wrbuf_cstr(render_str);
337
338     process_events(c);
339
340     for (i = 0; i < MAX_CON; i++)
341     {
342         int error;
343         const char *errmsg, *addinfo, *dset;
344         /* display errors if any */
345         if (!c[i])
346             continue;
347         if ((error = ZOOM_connection_error_x(c[i], &errmsg, &addinfo, &dset)))
348             printf("%s error: %s (%s:%d) %s\n",
349                    ZOOM_connection_option_get(c[i], "host"), errmsg,
350                    dset, error, addinfo);
351         else if (r[i])
352         {
353             int num_facets = ZOOM_resultset_facets_size(r[i]);
354             if (num_facets) {
355                 ZOOM_facet_field  *facets = ZOOM_resultset_facets(r[i]);
356                 display_facets(facets, num_facets);
357             }
358         }
359     }
360     if (render_str)
361         wrbuf_destroy(render_str);
362
363 }
364
365 static void cmd_ext(ZOOM_connection *c, ZOOM_resultset *r,
366                     ZOOM_options options,
367                     const char **args)
368 {
369     ZOOM_package p[MAX_CON];
370     int i;
371     WRBUF ext_type_str = next_token_new_wrbuf(args);
372     
373     for (i = 0; i<MAX_CON; i++)
374     {
375         if (c[i])
376         {
377             p[i] = ZOOM_connection_package(c[i], 0);
378             ZOOM_package_send(p[i], ext_type_str ? wrbuf_cstr(ext_type_str):0);
379         }
380         else
381             p[i] = 0;
382     }
383
384     process_events(c);
385
386     for (i = 0; i<MAX_CON; i++)
387     {
388         int error;
389         const char *errmsg, *addinfo, *dset;
390         /* display errors if any */
391         if (!p[i])
392             continue;
393         if ((error = ZOOM_connection_error_x(c[i], &errmsg, &addinfo, &dset)))
394             printf("%s error: %s (%s:%d) %s\n",
395                    ZOOM_connection_option_get(c[i], "host"), errmsg,
396                    dset, error, addinfo);
397         else if (p[i])
398         {
399             const char *v;
400             printf("ok\n");
401             v = ZOOM_package_option_get(p[i], "targetReference");
402             if (v)
403                 printf("targetReference: %s\n", v);
404             v = ZOOM_package_option_get(p[i], "xmlUpdateDoc");
405             if (v)
406                 printf("xmlUpdateDoc: %s\n", v);
407         }
408         ZOOM_package_destroy(p[i]);
409     }
410     if (ext_type_str)
411         wrbuf_destroy(ext_type_str);
412 }
413
414 static void cmd_debug(ZOOM_connection *c, ZOOM_resultset *r,
415                       ZOOM_options options,
416                       const char **args)
417 {
418     yaz_log_init_level(YLOG_ALL);
419 }
420
421 static void cmd_search(ZOOM_connection *c, ZOOM_resultset *r,
422                        ZOOM_options options,
423                        const char **args)
424 {
425     ZOOM_query s;
426     const char *query_str = *args;
427     int i;
428     
429     s = ZOOM_query_create();
430     while (*query_str == ' ')
431         query_str++;
432     if (memcmp(query_str, "cql:", 4) == 0)
433     {
434         ZOOM_query_cql(s, query_str + 4);
435     }
436     else if (ZOOM_query_prefix(s, query_str))
437     {
438         printf("Bad PQF: %s\n", query_str);
439         return;
440     }
441     for (i = 0; i<MAX_CON; i++)
442     {
443
444         if (c[i])
445         {
446             ZOOM_resultset_destroy(r[i]);
447             r[i] = 0;
448         }
449         if (c[i])
450             r[i] = ZOOM_connection_search(c[i], s);
451     }
452     ZOOM_query_destroy(s);
453
454     process_events(c);
455
456     for (i = 0; i<MAX_CON; i++)
457     {
458         int error;
459         const char *errmsg, *addinfo, *dset;
460         /* display errors if any */
461         if (!c[i])
462             continue;
463         if ((error = ZOOM_connection_error_x(c[i], &errmsg, &addinfo, &dset)))
464             printf("%s error: %s (%s:%d) %s\n",
465                    ZOOM_connection_option_get(c[i], "host"), errmsg,
466                    dset, error, addinfo);
467         else if (r[i])
468         {
469             /* OK, no major errors. Look at the result count */
470             int start = ZOOM_options_get_int(options, "start", 0);
471             int count = ZOOM_options_get_int(options, "count", 0);
472             int facet_num;
473
474             printf("%s: %lld hits\n", ZOOM_connection_option_get(c[i], "host"),
475                    (long long int) ZOOM_resultset_size(r[i]));
476             
477             facet_num = ZOOM_resultset_facets_size(r[i]);
478             if (facet_num)
479             {
480                 ZOOM_facet_field *facets = ZOOM_resultset_facets(r[i]);
481                 int facet_idx;
482                 for (facet_idx = 0; facet_idx < facet_num; facet_idx++)
483                 {
484                     const char *name = ZOOM_facet_field_name(facets[facet_idx]);
485                     size_t term_idx;
486                     size_t term_num = ZOOM_facet_field_term_count(facets[facet_idx]);
487                     printf("facet: %s\n", name);
488                     for (term_idx = 0; term_idx < term_num; term_idx++ )
489                     {
490                         int freq;
491                         const char *term =
492                             ZOOM_facet_field_get_term(facets[facet_idx], term_idx, &freq);
493                         printf("term: %s %d\n", term, freq);
494                     }
495                 }
496             }
497             /* and display */
498             display_records(c[i], r[i], start, count, "render");
499         }
500     }
501 }
502
503 static void cmd_scan(ZOOM_connection *c, ZOOM_resultset *r,
504                      ZOOM_options options,
505                      const char **args)
506 {
507     const char *query_str = *args;
508     ZOOM_query query = ZOOM_query_create();
509     int i;
510     ZOOM_scanset s[MAX_CON];
511     
512     while (*query_str == ' ')
513         query_str++;
514
515     if (memcmp(query_str, "cql:", 4) == 0)
516     {
517         ZOOM_query_cql(query, query_str + 4);
518     }
519     else if (ZOOM_query_prefix(query, query_str))
520     {
521         printf("Bad PQF: %s\n", query_str);
522         return;
523     }
524
525     for (i = 0; i<MAX_CON; i++)
526     {
527         if (c[i])
528             s[i] = ZOOM_connection_scan1(c[i], query);
529         else
530             s[i] = 0;
531     }
532     ZOOM_query_destroy(query);
533
534     process_events(c);
535
536     for (i = 0; i<MAX_CON; i++)
537     {
538         int error;
539         const char *errmsg, *addinfo, *dset;
540         /* display errors if any */
541         if (!c[i])
542             continue;
543         if ((error = ZOOM_connection_error_x(c[i], &errmsg, &addinfo, &dset)))
544             printf("%s error: %s (%s:%d) %s\n",
545                    ZOOM_connection_option_get(c[i], "host"), errmsg,
546                    dset, error, addinfo);
547
548         if (s[i]) {
549             size_t p, sz = ZOOM_scanset_size(s[i]);
550             for (p = 0; p < sz; p++)
551             {
552                 size_t occ = 0;
553                 size_t len = 0;
554                 const char *term = ZOOM_scanset_display_term(s[i], p,
555                                                              &occ, &len);
556                 printf("%.*s %lld\n", (int) len, term, (long long int) occ);
557             }            
558             ZOOM_scanset_destroy(s[i]);
559         }
560     }
561 }
562
563 static void cmd_sort(ZOOM_connection *c, ZOOM_resultset *r,
564                      ZOOM_options options,
565                      const char **args)
566 {
567     const char *sort_spec = *args;
568     int i;
569     
570     while (*sort_spec == ' ')
571         sort_spec++;
572     
573     for (i = 0; i<MAX_CON; i++)
574     {
575         if (r[i])
576             ZOOM_resultset_sort(r[i], "yaz", sort_spec);
577     }
578     process_events(c);
579 }
580
581 static void cmd_help(ZOOM_connection *c, ZOOM_resultset *r,
582                      ZOOM_options options,
583                      const char **args)
584 {
585     printf("connect <zurl>\n");
586     printf("search <pqf>\n");
587     printf("show [<start> [<count> [<type]]]\n");
588     printf("facets\n");
589     printf("scan <term>\n");
590     printf("quit\n");
591     printf("close <zurl>\n");
592     printf("ext <type>\n");
593     printf("set <option> [<value>]\n");
594     printf("get <option>\n");
595     printf("\n");
596     printf("options:\n");
597     printf(" start\n");
598     printf(" count\n");
599     printf(" databaseName\n");
600     printf(" preferredRecordSyntax\n");
601     printf(" proxy\n");
602     printf(" elementSetName\n");
603     printf(" maximumRecordSize\n");
604     printf(" preferredRecordSize\n");
605     printf(" async\n");
606     printf(" piggyback\n");
607     printf(" group\n");
608     printf(" user\n");
609     printf(" password\n");
610     printf(" implementationName\n");
611     printf(" charset\n");
612     printf(" lang\n");
613     printf(" timeout\n");
614     printf(" facets\n");
615 }
616
617 static void cmd_connect(ZOOM_connection *c, ZOOM_resultset *r,
618                         ZOOM_options options,
619                         const char **args)
620 {
621     int error;
622     const char *errmsg, *addinfo, *dset;
623     int j, i;
624     WRBUF host = next_token_new_wrbuf(args);
625     if (!host)
626     {
627         printf("missing host after connect\n");
628         return ;
629     }
630     for (j = -1, i = 0; i<MAX_CON; i++)
631     {
632         const char *h;
633         if (c[i] && (h = ZOOM_connection_option_get(c[i], "host")) &&
634             !strcmp(h, wrbuf_cstr(host)))
635         {
636             ZOOM_connection_destroy(c[i]);
637             break;
638         }
639         else if (c[i] == 0 && j == -1)
640             j = i;
641     }
642     if (i == MAX_CON)  /* no match .. */
643     {
644         if (j == -1)
645         {
646             printf("no more connection available\n");
647             wrbuf_destroy(host);
648             return;
649         }
650         i = j;   /* OK, use this one is available */
651     }
652     c[i] = ZOOM_connection_create(options);
653     ZOOM_connection_connect(c[i], wrbuf_cstr(host), 0);
654         
655     if ((error = ZOOM_connection_error_x(c[i], &errmsg, &addinfo, &dset)))
656         printf("%s error: %s (%s:%d) %s\n",
657                ZOOM_connection_option_get(c[i], "host"), errmsg,
658                dset, error, addinfo);
659     wrbuf_destroy(host);
660 }
661
662 static int cmd_parse(ZOOM_connection *c, ZOOM_resultset *r,
663                      ZOOM_options options, 
664                      const char **buf)
665 {
666     int cmd_len;
667     const char *cmd_str;
668
669     cmd_len = next_token(buf, &cmd_str);
670     if (cmd_len < 0)
671         return 1;
672     if (is_command("quit", cmd_str, cmd_len))
673         return 0;
674     else if (is_command("set", cmd_str, cmd_len))
675         cmd_set(c, r, options, buf);
676     else if (is_command("get", cmd_str, cmd_len))
677         cmd_get(c, r, options, buf);
678     else if (is_command("rget", cmd_str, cmd_len))
679         cmd_rget(c, r, options, buf);
680     else if (is_command("connect", cmd_str, cmd_len))
681         cmd_connect(c, r, options, buf);
682     else if (is_command("open", cmd_str, cmd_len))
683         cmd_connect(c, r, options, buf);
684     else if (is_command("search", cmd_str, cmd_len))
685         cmd_search(c, r, options, buf);
686     else if (is_command("facets", cmd_str, cmd_len))
687         cmd_facets(c, r, options, buf);
688     else if (is_command("find", cmd_str, cmd_len))
689         cmd_search(c, r, options, buf);
690     else if (is_command("show", cmd_str, cmd_len))
691         cmd_show(c, r, options, buf);
692     else if (is_command("close", cmd_str, cmd_len))
693         cmd_close(c, r, options, buf);
694     else if (is_command("help", cmd_str, cmd_len))
695         cmd_help(c, r, options, buf);
696     else if (is_command("ext", cmd_str, cmd_len))
697         cmd_ext(c, r, options, buf);
698     else if (is_command("debug", cmd_str, cmd_len))
699         cmd_debug(c, r, options, buf);
700     else if (is_command("scan", cmd_str, cmd_len))
701         cmd_scan(c, r, options, buf);
702     else if (is_command("sort", cmd_str, cmd_len))
703         cmd_sort(c, r, options, buf);
704     else
705         printf("unknown command %.*s\n", cmd_len, cmd_str);
706     return 2;
707 }
708
709 void shell(ZOOM_connection *c, ZOOM_resultset *r,
710            ZOOM_options options)
711 {
712     while (1)
713     {
714         char buf[1000];
715         char *cp;
716         const char *bp = buf;
717 #if HAVE_READLINE_READLINE_H
718         char* line_in;
719         line_in=readline("ZOOM>");
720         if (!line_in)
721             break;
722 #if HAVE_READLINE_HISTORY_H
723         if (*line_in)
724             add_history(line_in);
725 #endif
726         if(strlen(line_in) > 999) {
727             printf("Input line too long\n");
728             break;
729         };
730         strcpy(buf,line_in);
731         free(line_in);
732 #else    
733         printf("ZOOM>"); fflush(stdout);
734         if (!fgets(buf, 999, stdin))
735             break;
736 #endif 
737         if ((cp = strchr(buf, '\n')))
738             *cp = '\0';
739         if (!cmd_parse(c, r, options, &bp))
740             break;
741     }
742 }
743
744 static void zoomsh(int argc, char **argv)
745 {
746     ZOOM_options options = ZOOM_options_create();
747     int i, res;
748     ZOOM_connection z39_con[MAX_CON];
749     ZOOM_resultset  z39_res[MAX_CON];
750
751     for (i = 0; i<MAX_CON; i++)
752     {
753         z39_con[i] = 0;
754         z39_res[i] = 0;
755     }
756
757     for (i = 0; i<MAX_CON; i++)
758         z39_con[i] = 0;
759
760     res = 1;
761     for (i = 1; i<argc; i++)
762     {
763         const char *bp = argv[i];
764         res = cmd_parse(z39_con, z39_res, options, &bp);
765         if (res == 0)  /* received quit */
766             break;
767     }
768     if (res)  /* do cmdline shell only if not quitting */
769         shell(z39_con, z39_res, options);
770     ZOOM_options_destroy(options);
771
772     for (i = 0; i<MAX_CON; i++)
773     {
774         ZOOM_connection_destroy(z39_con[i]);
775         ZOOM_resultset_destroy(z39_res[i]);
776     }
777 }
778
779 int main(int argc, char **argv)
780 {
781     const char *maskstr = 0;
782     if (argc > 2 && !strcmp(argv[1], "-v"))
783     {
784         maskstr = argv[2];
785         argv += 2;
786         argc -= 2;
787     }
788     else if (argc > 1 && !strncmp(argv[1], "-v", 2))
789     {
790         maskstr = argv[1]+2;
791         argv++;
792         argc--;
793     }
794     if (maskstr)
795     {
796         int mask = yaz_log_mask_str(maskstr);
797         yaz_log_init_level(mask);
798     }
799     zoomsh(argc, argv);
800     exit(0);
801 }
802 /*
803  * Local variables:
804  * c-basic-offset: 4
805  * c-file-style: "Stroustrup"
806  * indent-tabs-mode: nil
807  * End:
808  * vim: shiftwidth=4 tabstop=8 expandtab
809  */
810