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