cd0ab0ea762be41a387a6bb06a7c9a7a3dd0fb6d
[yaz-moved-to-github.git] / zoom / zoomsh.c
1 /*
2  * $Id: zoomsh.c,v 1.13 2003-02-14 18:49:24 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];
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, *dset;
172         /* display errors if any */
173         if (!c[i])
174             continue;
175         if ((error = ZOOM_connection_error_x(c[i], &errmsg, &addinfo, &dset)))
176             fprintf (stderr, "%s error: %s (%s:%d) %s\n",
177                      ZOOM_connection_option_get(c[i], "host"), errmsg,
178                      dset, 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_package p[MAX_CON];
194     
195     int i;
196     
197     for (i = 0; i<MAX_CON; i++)
198     {
199         if (c[i])
200         {
201             p[i] = ZOOM_connection_package (c[i], 0);
202             ZOOM_package_send(p[i], "itemorder");
203         }
204         else
205             p[i] = 0;
206     }
207
208     while (ZOOM_event (MAX_CON, c))
209         ;
210
211     for (i = 0; i<MAX_CON; i++)
212     {
213         int error;
214         const char *errmsg, *addinfo, *dset;
215         /* display errors if any */
216         if (!p[i])
217             continue;
218         if ((error = ZOOM_connection_error_x(c[i], &errmsg, &addinfo, &dset)))
219             fprintf (stderr, "%s error: %s (%s:%d) %s\n",
220                      ZOOM_connection_option_get(c[i], "host"), errmsg,
221                      dset, error, addinfo);
222         else if (p[i])
223         {
224             printf ("ok\n");
225         }
226         ZOOM_package_destroy (p[i]);
227     }
228 }
229
230 static void cmd_search (ZOOM_connection *c, ZOOM_resultset *r,
231                         ZOOM_options options,
232                         const char **args)
233 {
234     ZOOM_query s;
235     const char *query_str = *args;
236     int i;
237     
238     s = ZOOM_query_create ();
239     while (*query_str == ' ')
240         query_str++;
241     if (memcmp(query_str, "cql:", 4) == 0)
242     {
243         ZOOM_query_cql (s, query_str + 4);
244     }
245     else if (ZOOM_query_prefix (s, query_str))
246     {
247         fprintf (stderr, "Bad PQF: %s\n", query_str);
248         return;
249     }
250     for (i = 0; i<MAX_CON; i++)
251     {
252         if (c[i])
253         {
254             ZOOM_resultset_destroy (r[i]);
255             r[i] = 0;
256         }
257         if (c[i])
258             r[i] = ZOOM_connection_search (c[i], s);
259     }
260
261     while (ZOOM_event (MAX_CON, c))
262         ;
263
264     for (i = 0; i<MAX_CON; i++)
265     {
266         int error;
267         const char *errmsg, *addinfo, *dset;
268         /* display errors if any */
269         if (!c[i])
270             continue;
271         if ((error = ZOOM_connection_error_x(c[i], &errmsg, &addinfo, &dset)))
272             fprintf (stderr, "%s error: %s (%s:%d) %s\n",
273                      ZOOM_connection_option_get(c[i], "host"), errmsg,
274                      dset, error, addinfo);
275         else if (r[i])
276         {
277             /* OK, no major errors. Look at the result count */
278             int start = ZOOM_options_get_int (options, "start", 0);
279             int count = ZOOM_options_get_int (options, "count", 0);
280
281             printf ("%s: %d hits\n", ZOOM_connection_option_get(c[i], "host"),
282                     ZOOM_resultset_size(r[i]));
283             /* and display */
284             display_records (c[i], r[i], start, count);
285         }
286     }
287     ZOOM_query_destroy (s);
288 }
289
290 static void cmd_help (ZOOM_connection *c, ZOOM_resultset *r,
291                       ZOOM_options options,
292                       const char **args)
293 {
294     printf ("connect <zurl>\n");
295     printf ("search <pqf>\n");
296     printf ("show [<start> [<count>]\n");
297     printf ("quit\n");
298     printf ("close <zurl>\n");
299     printf ("set <option> [<value>]\n");
300     printf ("get <option>\n");
301     printf ("\n");
302     printf ("options:\n");
303     printf (" start\n");
304     printf (" count\n");
305     printf (" databaseName\n");
306     printf (" preferredRecordSyntax\n");
307     printf (" proxy\n");
308     printf (" elementSetName\n");
309     printf (" maximumRecordSize\n");
310     printf (" preferredRecordSize\n");
311     printf (" async\n");
312     printf (" piggyback\n");
313     printf (" group\n");
314     printf (" user\n");
315     printf (" pass\n");
316     printf (" implementationName\n");
317     printf (" charset\n");
318     printf (" lang\n");
319 }
320
321 static void cmd_connect (ZOOM_connection *c, ZOOM_resultset *r,
322                          ZOOM_options options,
323                          const char **args)
324 {
325     int error;
326     const char *errmsg, *addinfo;
327     char host[60];
328     int j, i;
329     if (!next_token_copy (args, host, sizeof(host)))
330     {
331         printf ("missing host after connect\n");
332         return ;
333     }
334     for (j = -1, i = 0; i<MAX_CON; i++)
335     {
336         const char *h;
337         if (c[i] && (h = ZOOM_connection_option_get(c[i], "host")) &&
338             !strcmp (h, host))
339         {
340             ZOOM_connection_destroy (c[i]);
341             break;
342         }
343         else if (c[i] == 0 && j == -1)
344             j = i;
345     }
346     if (i == MAX_CON)  /* no match .. */
347     {
348         if (j == -1)
349         {
350             printf ("no more connection available\n");
351             return;
352         }
353         i = j;   /* OK, use this one is available */
354     }
355     c[i] = ZOOM_connection_create (options);
356     ZOOM_connection_connect (c[i], host, 0);
357
358     if ((error = ZOOM_connection_error(c[i], &errmsg, &addinfo)))
359         printf ("%s error: %s (%d) %s\n",
360                 ZOOM_connection_option_get(c[i], "host"),
361                 errmsg, error, addinfo);
362     
363 }
364
365 static int cmd_parse (ZOOM_connection *c, ZOOM_resultset *r,
366                       ZOOM_options options, 
367                       const char **buf)
368 {
369     int cmd_len;
370     const char *cmd_str;
371
372     cmd_len = next_token (buf, &cmd_str);
373     if (!cmd_len)
374         return 1;
375     if (is_command ("quit", cmd_str, cmd_len))
376         return 0;
377     else if (is_command ("set", cmd_str, cmd_len))
378         cmd_set (c, r, options, buf);
379     else if (is_command ("get", cmd_str, cmd_len))
380         cmd_get (c, r, options, buf);
381     else if (is_command ("connect", cmd_str, cmd_len))
382         cmd_connect (c, r, options, buf);
383     else if (is_command ("open", cmd_str, cmd_len))
384         cmd_connect (c, r, options, buf);
385     else if (is_command ("search", cmd_str, cmd_len))
386         cmd_search (c, r, options, buf);
387     else if (is_command ("find", cmd_str, cmd_len))
388         cmd_search (c, r, options, buf);
389     else if (is_command ("show", cmd_str, cmd_len))
390         cmd_show (c, r, options, buf);
391     else if (is_command ("close", cmd_str, cmd_len))
392         cmd_close (c, r, options, buf);
393     else if (is_command ("help", cmd_str, cmd_len))
394         cmd_help(c, r, options, buf);
395     else if (is_command ("ext", cmd_str, cmd_len))
396         cmd_ext(c, r, options, buf);
397     else
398         printf ("unknown command %.*s\n", cmd_len, cmd_str);
399     return 2;
400 }
401
402 void shell(ZOOM_connection *c, ZOOM_resultset *r,
403            ZOOM_options options)
404 {
405     while (1)
406     {
407         char buf[1000];
408         char *cp;
409         const char *bp = buf;
410 #if HAVE_READLINE_READLINE_H
411         char* line_in;
412         line_in=readline("ZOOM>");
413         if (!line_in)
414             break;
415 #if HAVE_READLINE_HISTORY_H
416         if (*line_in)
417             add_history(line_in);
418 #endif
419         if(strlen(line_in) > 999) {
420             fprintf(stderr,"Input line too long\n");
421             break;
422         };
423         strcpy(buf,line_in);
424         free (line_in);
425 #else    
426         printf ("ZOOM>"); fflush (stdout);
427         if (!fgets (buf, 999, stdin))
428             break;
429 #endif 
430         if ((cp = strchr(buf, '\n')))
431             *cp = '\0';
432         if (!cmd_parse (c, r, options, &bp))
433             break;
434     }
435 }
436
437 int main (int argc, char **argv)
438 {
439     ZOOM_options options = ZOOM_options_create();
440     int i, res;
441     ZOOM_connection z39_con[MAX_CON];
442     ZOOM_resultset  z39_res[MAX_CON];
443
444     for (i = 0; i<MAX_CON; i++)
445     {
446         z39_con[i] = 0;
447         z39_res[i] = 0;
448     }
449
450     for (i = 0; i<MAX_CON; i++)
451         z39_con[i] = 0;
452
453     res = 1;
454     for (i = 1; i<argc; i++)
455     {
456         const char *bp = argv[i];
457         res = cmd_parse(z39_con, z39_res, options, &bp);
458         if (res == 0)  /* received quit */
459             break;
460     }
461     if (res)  /* do cmdline shell only if not quitting */
462         shell(z39_con, z39_res, options);
463     ZOOM_options_destroy(options);
464
465     for (i = 0; i<MAX_CON; i++)
466     {
467         ZOOM_connection_destroy(z39_con[i]);
468         ZOOM_resultset_destroy(z39_res[i]);
469     }
470     exit (0);
471 }