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