1 /* This file is part of the YAZ toolkit.
2 * Copyright (C) 1995-2011 Index Data
3 * See the file LICENSE for details.
6 \brief ZOOM C command line tool (shell)
15 #include <yaz/wrbuf.h>
17 #include <yaz/options.h>
19 #if HAVE_READLINE_READLINE_H
20 #include <readline/readline.h>
22 #if HAVE_READLINE_HISTORY_H
23 #include <readline/history.h>
31 static void process_events(ZOOM_connection *c)
35 yaz_log(YLOG_DEBUG, "process_events");
36 while ((i = ZOOM_event(MAX_CON, c)) != 0)
38 int peek = ZOOM_connection_peek_event(c[i-1]);
39 int event = ZOOM_connection_last_event(c[i-1]);
40 yaz_log(YLOG_DEBUG, "no = %d peek = %d event = %d %s", i-1,
43 ZOOM_get_event_str(event));
47 static int next_token_chars(const char **cpp, const char **t_start,
48 const char *tok_chars)
51 const char *cp = *cpp;
58 while (*cp && *cp != '"')
69 while (*cp && !strchr(tok_chars, *cp))
78 return len; /* return -1 if no token was read .. */
81 static int next_token(const char **cpp, const char **t_start)
83 return next_token_chars(cpp, t_start, "\r\n ");
87 static WRBUF next_token_new_wrbuf(const char **cpp)
91 int len = next_token(cpp, &start);
96 wrbuf_write(w, start, len);
100 static int is_command(const char *cmd_str, const char *this_str, int this_len)
102 int cmd_len = strlen(cmd_str);
103 if (cmd_len != this_len)
105 if (memcmp(cmd_str, this_str, cmd_len))
110 static int cmd_set(ZOOM_connection *c, ZOOM_resultset *r,
111 ZOOM_options options,
118 if (!(key = next_token_new_wrbuf(args)))
120 printf("missing argument for set\n");
123 val_len = next_token_chars(args, &val_buf, "");
125 ZOOM_options_setl(options, wrbuf_cstr(key), val_buf, val_len);
127 ZOOM_options_set(options, wrbuf_cstr(key), 0);
132 static int cmd_get(ZOOM_connection *c, ZOOM_resultset *r,
133 ZOOM_options options,
137 if (!(key = next_token_new_wrbuf(args)))
139 printf("missing argument for get\n");
144 const char *val = ZOOM_options_get(options, wrbuf_cstr(key));
145 printf("%s = %s\n", wrbuf_cstr(key), val ? val : "<null>");
151 static int cmd_rget(ZOOM_connection *c, ZOOM_resultset *r,
152 ZOOM_options options,
156 if (!(key = next_token_new_wrbuf(args)))
158 printf("missing argument for get\n");
164 for (i = 0; i<MAX_CON; i++)
170 val = ZOOM_resultset_option_get(r[i], wrbuf_cstr(key));
171 printf("%s = %s\n", wrbuf_cstr(key), val ? val : "<null>");
178 static int cmd_close(ZOOM_connection *c, ZOOM_resultset *r,
179 ZOOM_options options,
184 host = next_token_new_wrbuf(args);
185 for (i = 0; i<MAX_CON; i++)
192 ZOOM_connection_destroy(c[i]);
195 else if ((h = ZOOM_connection_option_get(c[i], "host"))
196 && !strcmp(h, wrbuf_cstr(host)))
198 ZOOM_connection_destroy(c[i]);
207 static void display_records(ZOOM_connection c,
209 size_t start, size_t count, const char *type)
212 for (i = 0; i < count; i++)
214 size_t pos = i + start;
215 ZOOM_record rec = ZOOM_resultset_record(r, pos);
216 const char *db = ZOOM_record_get(rec, "database", 0);
218 if (ZOOM_record_error(rec, 0, 0, 0))
223 int error = ZOOM_record_error(rec, &msg, &addinfo, &diagset);
225 printf("%lld %s: %s (%s:%d) %s\n", (long long) pos,
226 (db ? db : "unknown"),
227 msg, diagset, error, addinfo ? addinfo : "none");
232 const char *render = ZOOM_record_get(rec, type, &len);
233 const char *syntax = ZOOM_record_get(rec, "syntax", 0);
234 const char *schema = ZOOM_record_get(rec, "schema", 0);
235 /* if rec is non-null, we got a record for display */
238 printf("%lld database=%s syntax=%s schema=%s\n",
239 (long long) pos, (db ? db : "unknown"), syntax,
240 schema ? schema : "unknown");
243 if (fwrite(render, 1, len, stdout) != (size_t) len)
245 printf("write to stdout failed\n");
254 static int cmd_show(ZOOM_connection *c, ZOOM_resultset *r,
255 ZOOM_options options,
259 size_t start = 0, count = 1;
260 const char *type = "render";
261 WRBUF render_str = 0;
267 if ((tmp = next_token_new_wrbuf(args)))
269 start = atoi(wrbuf_cstr(tmp));
273 if ((tmp = next_token_new_wrbuf(args)))
275 count = atoi(wrbuf_cstr(tmp));
278 render_str = next_token_new_wrbuf(args);
281 type = wrbuf_cstr(render_str);
283 for (i = 0; i < MAX_CON; i++)
284 ZOOM_resultset_records(r[i], 0, start, count);
287 for (i = 0; i < MAX_CON; i++)
290 const char *errmsg, *addinfo, *dset;
291 /* display errors if any */
294 if ((error = ZOOM_connection_error_x(c[i], &errmsg, &addinfo, &dset)))
296 printf("%s error: %s (%s:%d) %s\n",
297 ZOOM_connection_option_get(c[i], "host"), errmsg,
298 dset, error, addinfo);
303 /* OK, no major errors. Display records... */
304 display_records(c[i], r[i], start, count, type);
308 wrbuf_destroy(render_str);
312 static void display_facets(ZOOM_facet_field *facets, int count) {
314 printf("Facets: \n");
315 for (index = 0; index < count; index++) {
317 const char *facet_name = ZOOM_facet_field_name(facets[index]);
318 printf(" %s: \n", facet_name);
319 for (term_index = 0; term_index < ZOOM_facet_field_term_count(facets[index]); term_index++) {
321 const char *term = ZOOM_facet_field_get_term(facets[index], term_index, &freq);
322 printf(" %s(%d) \n", term, freq);
327 static int cmd_facets(ZOOM_connection *c, ZOOM_resultset *r,
328 ZOOM_options options,
336 for (i = 0; i < MAX_CON; i++)
339 const char *errmsg, *addinfo, *dset;
340 /* display errors if any */
343 if ((error = ZOOM_connection_error_x(c[i], &errmsg, &addinfo, &dset)))
345 printf("%s error: %s (%s:%d) %s\n",
346 ZOOM_connection_option_get(c[i], "host"), errmsg,
347 dset, error, addinfo);
352 int num_facets = ZOOM_resultset_facets_size(r[i]);
354 ZOOM_facet_field *facets = ZOOM_resultset_facets(r[i]);
355 display_facets(facets, num_facets);
362 static int cmd_ext(ZOOM_connection *c, ZOOM_resultset *r,
363 ZOOM_options options,
366 ZOOM_package p[MAX_CON];
369 WRBUF ext_type_str = next_token_new_wrbuf(args);
371 for (i = 0; i<MAX_CON; i++)
375 p[i] = ZOOM_connection_package(c[i], 0);
376 ZOOM_package_send(p[i], ext_type_str ? wrbuf_cstr(ext_type_str):0);
384 for (i = 0; i<MAX_CON; i++)
387 const char *errmsg, *addinfo, *dset;
388 /* display errors if any */
391 if ((error = ZOOM_connection_error_x(c[i], &errmsg, &addinfo, &dset)))
393 printf("%s error: %s (%s:%d) %s\n",
394 ZOOM_connection_option_get(c[i], "host"), errmsg,
395 dset, error, addinfo);
402 v = ZOOM_package_option_get(p[i], "targetReference");
404 printf("targetReference: %s\n", v);
405 v = ZOOM_package_option_get(p[i], "xmlUpdateDoc");
407 printf("xmlUpdateDoc: %s\n", v);
409 ZOOM_package_destroy(p[i]);
412 wrbuf_destroy(ext_type_str);
416 static int cmd_debug(ZOOM_connection *c, ZOOM_resultset *r,
417 ZOOM_options options,
420 yaz_log_init_level(YLOG_ALL);
424 static int cmd_search(ZOOM_connection *c, ZOOM_resultset *r,
425 ZOOM_options options,
429 const char *query_str = *args;
433 s = ZOOM_query_create();
434 while (*query_str == ' ')
436 if (memcmp(query_str, "cql:", 4) == 0)
438 ZOOM_query_cql(s, query_str + 4);
440 else if (ZOOM_query_prefix(s, query_str))
442 printf("Bad PQF: %s\n", query_str);
443 ZOOM_query_destroy(s);
446 for (i = 0; i<MAX_CON; i++)
451 ZOOM_resultset_destroy(r[i]);
455 r[i] = ZOOM_connection_search(c[i], s);
457 ZOOM_query_destroy(s);
461 for (i = 0; i<MAX_CON; i++)
464 const char *errmsg, *addinfo, *dset;
465 /* display errors if any */
468 if ((error = ZOOM_connection_error_x(c[i], &errmsg, &addinfo, &dset)))
470 printf("%s error: %s (%s:%d) %s\n",
471 ZOOM_connection_option_get(c[i], "host"), errmsg,
472 dset, error, addinfo);
477 /* OK, no major errors. Look at the result count */
478 int start = ZOOM_options_get_int(options, "start", 0);
479 int count = ZOOM_options_get_int(options, "count", 0);
482 printf("%s: %lld hits\n", ZOOM_connection_option_get(c[i], "host"),
483 (long long int) ZOOM_resultset_size(r[i]));
485 facet_num = ZOOM_resultset_facets_size(r[i]);
488 ZOOM_facet_field *facets = ZOOM_resultset_facets(r[i]);
490 for (facet_idx = 0; facet_idx < facet_num; facet_idx++)
492 const char *name = ZOOM_facet_field_name(facets[facet_idx]);
494 size_t term_num = ZOOM_facet_field_term_count(facets[facet_idx]);
495 printf("facet: %s\n", name);
496 for (term_idx = 0; term_idx < term_num; term_idx++ )
500 ZOOM_facet_field_get_term(facets[facet_idx], term_idx, &freq);
501 printf("term: %s %d\n", term, freq);
506 display_records(c[i], r[i], start, count, "render");
512 static int cmd_scan(ZOOM_connection *c, ZOOM_resultset *r,
513 ZOOM_options options,
516 const char *query_str = *args;
517 ZOOM_query query = ZOOM_query_create();
520 ZOOM_scanset s[MAX_CON];
522 while (*query_str == ' ')
525 if (memcmp(query_str, "cql:", 4) == 0)
527 ZOOM_query_cql(query, query_str + 4);
529 else if (ZOOM_query_prefix(query, query_str))
531 printf("Bad PQF: %s\n", query_str);
532 ZOOM_query_destroy(query);
536 for (i = 0; i<MAX_CON; i++)
539 s[i] = ZOOM_connection_scan1(c[i], query);
543 ZOOM_query_destroy(query);
547 for (i = 0; i<MAX_CON; i++)
550 const char *errmsg, *addinfo, *dset;
551 /* display errors if any */
554 if ((error = ZOOM_connection_error_x(c[i], &errmsg, &addinfo, &dset)))
556 printf("%s error: %s (%s:%d) %s\n",
557 ZOOM_connection_option_get(c[i], "host"), errmsg,
558 dset, error, addinfo);
563 size_t p, sz = ZOOM_scanset_size(s[i]);
564 for (p = 0; p < sz; p++)
568 const char *term = ZOOM_scanset_display_term(s[i], p,
570 printf("%.*s %lld\n", (int) len, term, (long long int) occ);
572 ZOOM_scanset_destroy(s[i]);
578 static int cmd_sort(ZOOM_connection *c, ZOOM_resultset *r,
579 ZOOM_options options,
582 const char *sort_spec = *args;
586 while (*sort_spec == ' ')
589 for (i = 0; i<MAX_CON; i++)
592 ZOOM_resultset_sort(r[i], "yaz", sort_spec);
598 static int cmd_help(ZOOM_connection *c, ZOOM_resultset *r,
599 ZOOM_options options,
602 printf("connect <zurl>\n");
603 printf("search <pqf>\n");
604 printf("show [<start> [<count> [<type]]]\n");
606 printf("scan <term>\n");
608 printf("close <zurl>\n");
609 printf("ext <type>\n");
610 printf("set <option> [<value>]\n");
611 printf("get <option>\n");
613 printf("options:\n");
616 printf(" databaseName\n");
617 printf(" preferredRecordSyntax\n");
619 printf(" elementSetName\n");
620 printf(" maximumRecordSize\n");
621 printf(" preferredRecordSize\n");
623 printf(" piggyback\n");
626 printf(" password\n");
627 printf(" implementationName\n");
628 printf(" charset\n");
630 printf(" timeout\n");
635 static int cmd_connect(ZOOM_connection *c, ZOOM_resultset *r,
636 ZOOM_options options,
641 const char *errmsg, *addinfo, *dset;
643 WRBUF host = next_token_new_wrbuf(args);
646 printf("missing host after connect\n");
649 for (j = -1, i = 0; i<MAX_CON; i++)
652 if (c[i] && (h = ZOOM_connection_option_get(c[i], "host")) &&
653 !strcmp(h, wrbuf_cstr(host)))
655 ZOOM_connection_destroy(c[i]);
658 else if (c[i] == 0 && j == -1)
661 if (i == MAX_CON) /* no match .. */
665 printf("no more connection available\n");
669 i = j; /* OK, use this one is available */
671 c[i] = ZOOM_connection_create(options);
672 ZOOM_connection_connect(c[i], wrbuf_cstr(host), 0);
674 if ((error = ZOOM_connection_error_x(c[i], &errmsg, &addinfo, &dset)))
676 printf("%s error: %s (%s:%d) %s\n",
677 ZOOM_connection_option_get(c[i], "host"), errmsg,
678 dset, error, addinfo);
685 /** \brief parse and execute zoomsh command
688 \param options ZOOM options
689 \param buf command string and arguments
691 \retval 1 failure to execute
692 \retval -1 EOF (no more commands or quit seen)
694 static int cmd_parse(ZOOM_connection *c, ZOOM_resultset *r,
695 ZOOM_options options,
702 cmd_len = next_token(buf, &cmd_str);
705 if (is_command("quit", cmd_str, cmd_len))
707 else if (is_command("set", cmd_str, cmd_len))
708 ret = cmd_set(c, r, options, buf);
709 else if (is_command("get", cmd_str, cmd_len))
710 ret = cmd_get(c, r, options, buf);
711 else if (is_command("rget", cmd_str, cmd_len))
712 ret = cmd_rget(c, r, options, buf);
713 else if (is_command("connect", cmd_str, cmd_len))
714 ret = cmd_connect(c, r, options, buf);
715 else if (is_command("open", cmd_str, cmd_len))
716 ret = cmd_connect(c, r, options, buf);
717 else if (is_command("search", cmd_str, cmd_len))
718 ret = cmd_search(c, r, options, buf);
719 else if (is_command("facets", cmd_str, cmd_len))
720 ret = cmd_facets(c, r, options, buf);
721 else if (is_command("find", cmd_str, cmd_len))
722 ret = cmd_search(c, r, options, buf);
723 else if (is_command("show", cmd_str, cmd_len))
724 ret = cmd_show(c, r, options, buf);
725 else if (is_command("close", cmd_str, cmd_len))
726 ret = cmd_close(c, r, options, buf);
727 else if (is_command("help", cmd_str, cmd_len))
728 ret = cmd_help(c, r, options, buf);
729 else if (is_command("ext", cmd_str, cmd_len))
730 ret = cmd_ext(c, r, options, buf);
731 else if (is_command("debug", cmd_str, cmd_len))
732 ret = cmd_debug(c, r, options, buf);
733 else if (is_command("scan", cmd_str, cmd_len))
734 ret = cmd_scan(c, r, options, buf);
735 else if (is_command("sort", cmd_str, cmd_len))
736 ret = cmd_sort(c, r, options, buf);
739 printf("unknown command %.*s\n", cmd_len, cmd_str);
745 static int shell(ZOOM_connection *c, ZOOM_resultset *r,
746 ZOOM_options options, int exit_on_error)
753 const char *bp = buf;
754 #if HAVE_READLINE_READLINE_H
756 line_in = readline("ZOOM>");
762 #if HAVE_READLINE_HISTORY_H
764 add_history(line_in);
766 if (strlen(line_in) > 999)
768 printf("Input line too long\n");
775 printf("ZOOM>"); fflush(stdout);
776 if (!fgets(buf, 999, stdin))
782 if ((cp = strchr(buf, '\n')))
784 res = cmd_parse(c, r, options, &bp);
787 if (!exit_on_error && res > 0)
793 static int zoomsh(int argc, char **argv)
795 ZOOM_options zoom_options = ZOOM_options_create();
796 int i, res = 0; /* -1: EOF; 0 = OK, > 0 ERROR */
797 int exit_on_error = 0;
798 ZOOM_connection z39_con[MAX_CON];
799 ZOOM_resultset z39_res[MAX_CON];
801 for (i = 0; i<MAX_CON; i++)
810 int option_ret = options("ev:", argv, argc, &arg);
811 const char *bp = arg;
815 res = cmd_parse(z39_con, z39_res, zoom_options, &bp);
816 /* returns res == -1 on quit */
817 if (!exit_on_error && res > 0)
818 res = 0; /* hide error */
820 case YAZ_OPTIONS_EOF:
821 res = shell(z39_con, z39_res, zoom_options, exit_on_error);
827 mask = yaz_log_mask_str(arg);
828 yaz_log_init_level(mask);
831 fprintf(stderr, "zoomsh: [-e] [-v] [commands]\n");
836 for (i = 0; i<MAX_CON; i++)
838 ZOOM_connection_destroy(z39_con[i]);
839 ZOOM_resultset_destroy(z39_res[i]);
841 ZOOM_options_destroy(zoom_options);
842 if (res == -1) /* quit .. which is not an error */
847 int main(int argc, char **argv)
849 int ret = zoomsh(argc, argv);
855 * c-file-style: "Stroustrup"
856 * indent-tabs-mode: nil
858 * vim: shiftwidth=4 tabstop=8 expandtab