1 /* This file is part of the YAZ toolkit.
2 * Copyright (C) Index Data
3 * See the file LICENSE for details.
6 \brief ZOOM C command line tool (shell)
19 #include <yaz/wrbuf.h>
21 #include <yaz/options.h>
23 #if HAVE_READLINE_READLINE_H
24 #include <readline/readline.h>
26 #if HAVE_READLINE_HISTORY_H
27 #include <readline/history.h>
35 static void process_events(ZOOM_connection *c)
39 yaz_log(YLOG_DEBUG, "process_events");
40 while ((i = ZOOM_event(MAX_CON, c)) != 0)
42 int peek = ZOOM_connection_peek_event(c[i-1]);
43 int event = ZOOM_connection_last_event(c[i-1]);
44 yaz_log(YLOG_DEBUG, "no = %d peek = %d event = %d %s", i-1,
47 ZOOM_get_event_str(event));
51 static int next_token_chars(const char **cpp, const char **t_start,
52 const char *tok_chars)
55 const char *cp = *cpp;
62 while (*cp && *cp != '"')
73 while (*cp && !strchr(tok_chars, *cp))
82 return len; /* return -1 if no token was read .. */
85 static int next_token(const char **cpp, const char **t_start)
87 return next_token_chars(cpp, t_start, "\r\n ");
91 static WRBUF next_token_new_wrbuf(const char **cpp)
95 int len = next_token(cpp, &start);
100 wrbuf_write(w, start, len);
104 static int is_command(const char *cmd_str, const char *this_str, int this_len)
106 int cmd_len = strlen(cmd_str);
107 if (cmd_len != this_len)
109 if (memcmp(cmd_str, this_str, cmd_len))
114 static int cmd_set(ZOOM_connection *c, ZOOM_resultset *r,
115 ZOOM_options options,
122 if (!(key = next_token_new_wrbuf(args)))
124 printf("missing argument for set\n");
127 val_len = next_token_chars(args, &val_buf, "");
129 ZOOM_options_setl(options, wrbuf_cstr(key), val_buf, val_len);
131 ZOOM_options_set(options, wrbuf_cstr(key), 0);
136 static int cmd_get(ZOOM_connection *c, ZOOM_resultset *r,
137 ZOOM_options options,
141 if (!(key = next_token_new_wrbuf(args)))
143 printf("missing argument for get\n");
148 const char *val = ZOOM_options_get(options, wrbuf_cstr(key));
149 printf("%s = %s\n", wrbuf_cstr(key), val ? val : "<null>");
155 static int cmd_shell(ZOOM_connection *c, ZOOM_resultset *r,
156 ZOOM_options options, const char **args)
158 int ret = system(*args);
160 printf("system command returned %d\n", ret);
164 static int cmd_rget(ZOOM_connection *c, ZOOM_resultset *r,
165 ZOOM_options options,
169 if (!(key = next_token_new_wrbuf(args)))
171 printf("missing argument for get\n");
177 for (i = 0; i<MAX_CON; i++)
183 val = ZOOM_resultset_option_get(r[i], wrbuf_cstr(key));
184 printf("%s = %s\n", wrbuf_cstr(key), val ? val : "<null>");
191 static int cmd_close(ZOOM_connection *c, ZOOM_resultset *r,
192 ZOOM_options options,
197 host = next_token_new_wrbuf(args);
198 for (i = 0; i<MAX_CON; i++)
205 ZOOM_connection_destroy(c[i]);
208 else if ((h = ZOOM_connection_option_get(c[i], "host"))
209 && !strcmp(h, wrbuf_cstr(host)))
211 ZOOM_connection_destroy(c[i]);
220 static void display_records(ZOOM_connection c,
222 size_t start, size_t count, const char *type)
225 for (i = 0; i < count; i++)
227 size_t pos = i + start;
228 ZOOM_record rec = ZOOM_resultset_record(r, pos);
229 const char *db = ZOOM_record_get(rec, "database", 0);
231 if (ZOOM_record_error(rec, 0, 0, 0))
236 int error = ZOOM_record_error(rec, &msg, &addinfo, &diagset);
238 printf("%lld %s: %s (%s:%d) %s\n", (long long) pos,
239 (db ? db : "unknown"),
240 msg, diagset, error, addinfo ? addinfo : "none");
245 const char *render = ZOOM_record_get(rec, type, &len);
246 const char *syntax = ZOOM_record_get(rec, "syntax", 0);
247 const char *schema = ZOOM_record_get(rec, "schema", 0);
248 /* if rec is non-null, we got a record for display */
251 printf("%lld database=%s syntax=%s schema=%s\n",
252 (long long) pos, (db ? db : "unknown"), syntax,
253 schema ? schema : "unknown");
256 if (fwrite(render, 1, len, stdout) != (size_t) len)
258 printf("write to stdout failed\n");
267 static int cmd_show(ZOOM_connection *c, ZOOM_resultset *r,
268 ZOOM_options options,
272 size_t start = 0, count = 1;
273 const char *type = "render";
274 WRBUF render_str = 0;
280 if ((tmp = next_token_new_wrbuf(args)))
282 start = atoi(wrbuf_cstr(tmp));
286 if ((tmp = next_token_new_wrbuf(args)))
288 count = atoi(wrbuf_cstr(tmp));
291 render_str = next_token_new_wrbuf(args);
294 type = wrbuf_cstr(render_str);
296 for (i = 0; i < MAX_CON; i++)
297 ZOOM_resultset_records(r[i], 0, start, count);
300 for (i = 0; i < MAX_CON; i++)
303 const char *errmsg, *addinfo, *dset;
304 /* display errors if any */
307 if ((error = ZOOM_connection_error_x(c[i], &errmsg, &addinfo, &dset)))
309 printf("%s error: %s (%s:%d) %s\n",
310 ZOOM_connection_option_get(c[i], "host"), errmsg,
311 dset, error, addinfo);
316 /* OK, no major errors. Display records... */
317 display_records(c[i], r[i], start, count, type);
321 wrbuf_destroy(render_str);
325 static void display_facets(ZOOM_facet_field *facets, int count) {
327 printf("Facets: \n");
328 for (index = 0; index < count; index++) {
330 const char *facet_name = ZOOM_facet_field_name(facets[index]);
331 printf(" %s: \n", facet_name);
332 for (term_index = 0; term_index < ZOOM_facet_field_term_count(facets[index]); term_index++) {
334 const char *term = ZOOM_facet_field_get_term(facets[index], term_index, &freq);
335 printf(" %s(%d) \n", term, freq);
340 static int cmd_facets(ZOOM_connection *c, ZOOM_resultset *r,
341 ZOOM_options options,
349 for (i = 0; i < MAX_CON; i++)
352 const char *errmsg, *addinfo, *dset;
353 /* display errors if any */
356 if ((error = ZOOM_connection_error_x(c[i], &errmsg, &addinfo, &dset)))
358 printf("%s error: %s (%s:%d) %s\n",
359 ZOOM_connection_option_get(c[i], "host"), errmsg,
360 dset, error, addinfo);
365 int num_facets = ZOOM_resultset_facets_size(r[i]);
367 ZOOM_facet_field *facets = ZOOM_resultset_facets(r[i]);
368 display_facets(facets, num_facets);
375 static int cmd_suggestions(ZOOM_connection *c, ZOOM_resultset *r, ZOOM_options options, const char **args)
382 for (i = 0; i < MAX_CON; i++)
385 const char *errmsg, *addinfo, *dset;
386 /* display errors if any */
389 if ((error = ZOOM_connection_error_x(c[i], &errmsg, &addinfo, &dset)))
391 printf("%s error: %s (%s:%d) %s\n",
392 ZOOM_connection_option_get(c[i], "host"), errmsg,
393 dset, error, addinfo);
398 const char *suggestions = ZOOM_resultset_option_get(r[i], "suggestions");
400 printf("Suggestions: \n%s\n", suggestions);
408 static int cmd_ext(ZOOM_connection *c, ZOOM_resultset *r,
409 ZOOM_options options,
412 ZOOM_package p[MAX_CON];
415 WRBUF ext_type_str = next_token_new_wrbuf(args);
419 printf("es: missing type "
420 "(itemorder, create, drop, commit, update, xmlupdate)\n");
423 for (i = 0; i<MAX_CON; i++)
427 p[i] = ZOOM_connection_package(c[i], 0);
428 ZOOM_package_send(p[i], ext_type_str ? wrbuf_cstr(ext_type_str):0);
436 for (i = 0; i<MAX_CON; i++)
439 const char *errmsg, *addinfo, *dset;
440 /* display errors if any */
443 if ((error = ZOOM_connection_error_x(c[i], &errmsg, &addinfo, &dset)))
445 printf("%s error: %s (%s:%d) %s\n",
446 ZOOM_connection_option_get(c[i], "host"), errmsg,
447 dset, error, addinfo);
454 v = ZOOM_package_option_get(p[i], "targetReference");
456 printf("targetReference: %s\n", v);
457 v = ZOOM_package_option_get(p[i], "xmlUpdateDoc");
459 printf("xmlUpdateDoc: %s\n", v);
461 ZOOM_package_destroy(p[i]);
464 wrbuf_destroy(ext_type_str);
468 static int cmd_debug(ZOOM_connection *c, ZOOM_resultset *r,
469 ZOOM_options options,
472 yaz_log_init_level(YLOG_ALL);
476 static int cmd_search(ZOOM_connection *c, ZOOM_resultset *r,
477 ZOOM_options options,
481 const char *query_str = *args;
485 s = ZOOM_query_create();
486 while (*query_str == ' ')
488 if (memcmp(query_str, "cql:", 4) == 0)
490 ZOOM_query_cql(s, query_str + 4);
492 else if (ZOOM_query_prefix(s, query_str))
494 printf("Bad PQF: %s\n", query_str);
495 ZOOM_query_destroy(s);
498 for (i = 0; i<MAX_CON; i++)
503 ZOOM_resultset_destroy(r[i]);
507 r[i] = ZOOM_connection_search(c[i], s);
509 ZOOM_query_destroy(s);
513 for (i = 0; i<MAX_CON; i++)
516 const char *errmsg, *addinfo, *dset;
517 /* display errors if any */
520 if ((error = ZOOM_connection_error_x(c[i], &errmsg, &addinfo, &dset)))
522 printf("%s error: %s (%s:%d) %s\n",
523 ZOOM_connection_option_get(c[i], "host"), errmsg,
524 dset, error, addinfo);
529 /* OK, no major errors. Look at the result count */
530 int start = ZOOM_options_get_int(options, "start", 0);
531 int count = ZOOM_options_get_int(options, "count", 0);
534 printf("%s: %lld hits\n", ZOOM_connection_option_get(c[i], "host"),
535 (long long int) ZOOM_resultset_size(r[i]));
537 facet_num = ZOOM_resultset_facets_size(r[i]);
540 ZOOM_facet_field *facets = ZOOM_resultset_facets(r[i]);
542 for (facet_idx = 0; facet_idx < facet_num; facet_idx++)
544 const char *name = ZOOM_facet_field_name(facets[facet_idx]);
546 size_t term_num = ZOOM_facet_field_term_count(facets[facet_idx]);
547 printf("facet: %s\n", name);
548 for (term_idx = 0; term_idx < term_num; term_idx++ )
552 ZOOM_facet_field_get_term(facets[facet_idx], term_idx, &freq);
553 printf("term: %s %d\n", term, freq);
558 display_records(c[i], r[i], start, count, "render");
564 static int cmd_scan(ZOOM_connection *c, ZOOM_resultset *r,
565 ZOOM_options options,
568 const char *query_str = *args;
569 ZOOM_query query = ZOOM_query_create();
572 ZOOM_scanset s[MAX_CON];
574 while (*query_str == ' ')
577 if (memcmp(query_str, "cql:", 4) == 0)
579 ZOOM_query_cql(query, query_str + 4);
581 else if (ZOOM_query_prefix(query, query_str))
583 printf("Bad PQF: %s\n", query_str);
584 ZOOM_query_destroy(query);
588 for (i = 0; i<MAX_CON; i++)
591 s[i] = ZOOM_connection_scan1(c[i], query);
595 ZOOM_query_destroy(query);
599 for (i = 0; i<MAX_CON; i++)
602 const char *errmsg, *addinfo, *dset;
603 /* display errors if any */
606 if ((error = ZOOM_connection_error_x(c[i], &errmsg, &addinfo, &dset)))
608 printf("%s error: %s (%s:%d) %s\n",
609 ZOOM_connection_option_get(c[i], "host"), errmsg,
610 dset, error, addinfo);
615 size_t p, sz = ZOOM_scanset_size(s[i]);
616 for (p = 0; p < sz; p++)
620 const char *term = ZOOM_scanset_display_term(s[i], p,
622 printf("%.*s %lld\n", (int) len, term, (long long int) occ);
624 ZOOM_scanset_destroy(s[i]);
630 static int cmd_sort(ZOOM_connection *c, ZOOM_resultset *r,
631 ZOOM_options options,
634 const char *sort_spec = *args;
638 while (*sort_spec == ' ')
641 for (i = 0; i<MAX_CON; i++)
644 ZOOM_resultset_sort(r[i], "yaz", sort_spec);
650 static int cmd_help(ZOOM_connection *c, ZOOM_resultset *r,
651 ZOOM_options options,
654 printf("connect <zurl>\n");
655 printf("search <pqf>\n");
656 printf("show [<start> [<count> [<type]]]\n");
658 printf("scan <term>\n");
660 printf("close <zurl>\n");
661 printf("ext <type>\n");
662 printf("set <option> [<value>]\n");
663 printf("get <option>\n");
664 printf("shell cmdline\n");
666 printf("options:\n");
669 printf(" databaseName\n");
670 printf(" preferredRecordSyntax\n");
672 printf(" elementSetName\n");
673 printf(" maximumRecordSize\n");
674 printf(" preferredRecordSize\n");
676 printf(" piggyback\n");
679 printf(" password\n");
680 printf(" implementationName\n");
681 printf(" charset\n");
683 printf(" timeout\n");
685 printf(" extraArgs\n");
686 printf(" suggestions\n");
690 static int cmd_connect(ZOOM_connection *c, ZOOM_resultset *r,
691 ZOOM_options options,
696 const char *errmsg, *addinfo, *dset;
698 WRBUF host = next_token_new_wrbuf(args);
701 printf("missing host after connect\n");
704 for (j = -1, i = 0; i<MAX_CON; i++)
707 if (c[i] && (h = ZOOM_connection_option_get(c[i], "host")) &&
708 !strcmp(h, wrbuf_cstr(host)))
710 ZOOM_connection_destroy(c[i]);
713 else if (c[i] == 0 && j == -1)
716 if (i == MAX_CON) /* no match .. */
720 printf("no more connection available\n");
724 i = j; /* OK, use this one is available */
726 c[i] = ZOOM_connection_create(options);
727 ZOOM_connection_connect(c[i], wrbuf_cstr(host), 0);
729 if ((error = ZOOM_connection_error_x(c[i], &errmsg, &addinfo, &dset)))
731 printf("%s error: %s (%s:%d) %s\n",
732 ZOOM_connection_option_get(c[i], "host"), errmsg,
733 dset, error, addinfo);
740 /** \brief parse and execute zoomsh command
743 \param options ZOOM options
744 \param buf command string and arguments
746 \retval 1 failure to execute
747 \retval -1 EOF (no more commands or quit seen)
749 static int cmd_parse(ZOOM_connection *c, ZOOM_resultset *r,
750 ZOOM_options options,
757 cmd_len = next_token(buf, &cmd_str);
760 if (is_command("quit", cmd_str, cmd_len))
762 else if (is_command("set", cmd_str, cmd_len))
763 ret = cmd_set(c, r, options, buf);
764 else if (is_command("get", cmd_str, cmd_len))
765 ret = cmd_get(c, r, options, buf);
766 else if (is_command("rget", cmd_str, cmd_len))
767 ret = cmd_rget(c, r, options, buf);
768 else if (is_command("connect", cmd_str, cmd_len))
769 ret = cmd_connect(c, r, options, buf);
770 else if (is_command("open", cmd_str, cmd_len))
771 ret = cmd_connect(c, r, options, buf);
772 else if (is_command("search", cmd_str, cmd_len))
773 ret = cmd_search(c, r, options, buf);
774 else if (is_command("facets", cmd_str, cmd_len))
775 ret = cmd_facets(c, r, options, buf);
776 else if (is_command("find", cmd_str, cmd_len))
777 ret = cmd_search(c, r, options, buf);
778 else if (is_command("show", cmd_str, cmd_len))
779 ret = cmd_show(c, r, options, buf);
780 else if (is_command("suggestions", cmd_str, cmd_len))
781 ret = cmd_suggestions(c, r, options, buf);
782 else if (is_command("close", cmd_str, cmd_len))
783 ret = cmd_close(c, r, options, buf);
784 else if (is_command("help", cmd_str, cmd_len))
785 ret = cmd_help(c, r, options, buf);
786 else if (is_command("ext", cmd_str, cmd_len))
787 ret = cmd_ext(c, r, options, buf);
788 else if (is_command("debug", cmd_str, cmd_len))
789 ret = cmd_debug(c, r, options, buf);
790 else if (is_command("scan", cmd_str, cmd_len))
791 ret = cmd_scan(c, r, options, buf);
792 else if (is_command("sort", cmd_str, cmd_len))
793 ret = cmd_sort(c, r, options, buf);
794 else if (is_command("shell", cmd_str, cmd_len))
795 ret = cmd_shell(c, r, options, buf);
798 printf("unknown command %.*s\n", cmd_len, cmd_str);
804 static int shell(ZOOM_connection *c, ZOOM_resultset *r,
805 ZOOM_options options, int exit_on_error)
812 const char *bp = buf;
814 #if HAVE_READLINE_READLINE_H
817 line_in = readline("ZOOM>");
824 #if HAVE_READLINE_HISTORY_H
826 add_history(line_in);
828 if (strlen(line_in) > sizeof(buf)-1)
830 printf("Input line too long\n");
838 if (!line_in) /* no line buffer via readline or not enabled at all */
840 printf("ZOOM>"); fflush(stdout);
841 if (!fgets(buf, sizeof(buf)-1, stdin))
847 if ((cp = strchr(buf, '\n')))
849 res = cmd_parse(c, r, options, &bp);
852 if (!exit_on_error && res > 0)
858 static int zoomsh(int argc, char **argv)
860 ZOOM_options zoom_options = ZOOM_options_create();
861 int i, res = 0; /* -1: EOF; 0 = OK, > 0 ERROR */
862 int exit_on_error = 0;
863 ZOOM_connection z39_con[MAX_CON];
864 ZOOM_resultset z39_res[MAX_CON];
866 for (i = 0; i<MAX_CON; i++)
875 int option_ret = options("ev:", argv, argc, &arg);
876 const char *bp = arg;
880 res = cmd_parse(z39_con, z39_res, zoom_options, &bp);
881 /* returns res == -1 on quit */
882 if (!exit_on_error && res > 0)
883 res = 0; /* hide error */
885 case YAZ_OPTIONS_EOF:
886 res = shell(z39_con, z39_res, zoom_options, exit_on_error);
892 mask = yaz_log_mask_str(arg);
893 yaz_log_init_level(mask);
896 fprintf(stderr, "zoomsh: [-e] [-v] [commands]\n");
901 for (i = 0; i<MAX_CON; i++)
903 ZOOM_connection_destroy(z39_con[i]);
904 ZOOM_resultset_destroy(z39_res[i]);
906 ZOOM_options_destroy(zoom_options);
907 if (res == -1) /* quit .. which is not an error */
912 int main(int argc, char **argv)
914 int ret = zoomsh(argc, argv);
920 * c-file-style: "Stroustrup"
921 * indent-tabs-mode: nil
923 * vim: shiftwidth=4 tabstop=8 expandtab