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