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