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