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