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>
46 static void process_events(struct zoom_sh *sh)
52 for (number = 0, db = sh->list; db; db = db->next)
55 c = xmalloc(sizeof(*c) * number);
57 for (i = 0, db = sh->list; db; db = db->next)
61 yaz_log(YLOG_DEBUG, "process_events");
62 while ((i = ZOOM_event(number, c)) != 0)
64 int peek = ZOOM_connection_peek_event(c[i-1]);
65 int event = ZOOM_connection_last_event(c[i-1]);
66 yaz_log(YLOG_DEBUG, "no = %d peek = %d event = %d %s", i-1,
69 ZOOM_get_event_str(event));
74 static int next_token_chars(const char **cpp, const char **t_start,
75 const char *tok_chars)
78 const char *cp = *cpp;
85 while (*cp && *cp != '"')
96 while (*cp && !strchr(tok_chars, *cp))
105 return len; /* return -1 if no token was read .. */
108 static int next_token(const char **cpp, const char **t_start)
110 return next_token_chars(cpp, t_start, "\r\n ");
114 static WRBUF next_token_new_wrbuf(const char **cpp)
118 int len = next_token(cpp, &start);
123 wrbuf_write(w, start, len);
127 static int is_command(const char *cmd_str, const char *this_str, int this_len)
129 int cmd_len = strlen(cmd_str);
130 if (cmd_len != this_len)
132 if (memcmp(cmd_str, this_str, cmd_len))
137 static int cmd_set(struct zoom_sh *sh, const char **args)
143 if (!(key = next_token_new_wrbuf(args)))
145 printf("missing argument for set\n");
148 val_len = next_token_chars(args, &val_buf, "");
150 ZOOM_options_setl(sh->options, wrbuf_cstr(key), val_buf, val_len);
152 ZOOM_options_set(sh->options, wrbuf_cstr(key), 0);
157 static int cmd_get(struct zoom_sh *sh, const char **args)
160 if (!(key = next_token_new_wrbuf(args)))
162 printf("missing argument for get\n");
167 const char *val = ZOOM_options_get(sh->options, wrbuf_cstr(key));
168 printf("%s = %s\n", wrbuf_cstr(key), val ? val : "<null>");
174 static int cmd_shell(struct zoom_sh *sh, const char **args)
176 int ret = system(*args);
178 printf("system command returned %d\n", ret);
182 static int cmd_rget(struct zoom_sh *sh, const char **args)
185 if (!(key = next_token_new_wrbuf(args)))
187 printf("missing argument for get\n");
192 struct zoom_db *db = sh->list;
193 for (; db; db = db->next)
198 ZOOM_resultset_option_get(db->res, wrbuf_cstr(key));
199 printf("%s = %s\n", wrbuf_cstr(key), val ? val : "<null>");
207 static int cmd_close(struct zoom_sh *sh, const char **args)
209 struct zoom_db **dbp;
211 host = next_token_new_wrbuf(args);
213 for (dbp = &sh->list; *dbp; )
216 struct zoom_db *db = *dbp;
217 if (!db->con || !host ||
218 ((h = ZOOM_connection_option_get(db->con, "host"))
219 && !strcmp(h, wrbuf_cstr(host))))
222 ZOOM_connection_destroy(db->con);
223 ZOOM_resultset_destroy(db->res);
234 static void display_records(ZOOM_connection c,
236 size_t start, size_t count, const char *type)
239 for (i = 0; i < count; i++)
241 size_t pos = i + start;
242 ZOOM_record rec = ZOOM_resultset_record(r, pos);
243 const char *db = ZOOM_record_get(rec, "database", 0);
245 if (ZOOM_record_error(rec, 0, 0, 0))
250 int error = ZOOM_record_error(rec, &msg, &addinfo, &diagset);
252 printf("%lld %s: %s (%s:%d) %s\n", (long long) pos,
253 (db ? db : "unknown"),
254 msg, diagset, error, addinfo ? addinfo : "none");
259 const char *render = ZOOM_record_get(rec, type, &len);
260 const char *syntax = ZOOM_record_get(rec, "syntax", 0);
261 const char *schema = ZOOM_record_get(rec, "schema", 0);
262 /* if rec is non-null, we got a record for display */
265 printf("%lld database=%s syntax=%s schema=%s\n",
266 (long long) pos, (db ? db : "unknown"), syntax,
267 schema ? schema : "unknown");
270 if (fwrite(render, 1, len, stdout) != (size_t) len)
272 printf("write to stdout failed\n");
281 static int cmd_show(struct zoom_sh *sh, const char **args)
283 size_t start = 0, count = 1;
284 const char *type = "render";
285 WRBUF render_str = 0;
292 if ((tmp = next_token_new_wrbuf(args)))
294 start = atoi(wrbuf_cstr(tmp));
298 if ((tmp = next_token_new_wrbuf(args)))
300 count = atoi(wrbuf_cstr(tmp));
303 render_str = next_token_new_wrbuf(args);
306 type = wrbuf_cstr(render_str);
308 for (db = sh->list; db; db = db->next)
310 ZOOM_resultset_records(db->res, 0, start, count);
313 for (db = sh->list; db; db = db->next)
316 const char *errmsg, *addinfo, *dset;
317 /* display errors if any */
320 if ((error = ZOOM_connection_error_x(db->con, &errmsg, &addinfo, &dset)))
322 printf("%s error: %s (%s:%d) %s\n",
323 ZOOM_connection_option_get(db->con, "host"), errmsg,
324 dset, error, addinfo);
329 /* OK, no major errors. Display records... */
330 display_records(db->con, db->res, start, count, type);
334 wrbuf_destroy(render_str);
338 static void display_facets(ZOOM_facet_field *facets, int count)
341 printf("Facets: \n");
342 for (i = 0; i < count; i++)
345 const char *facet_name = ZOOM_facet_field_name(facets[i]);
346 printf(" %s: \n", facet_name);
347 for (j = 0; j < ZOOM_facet_field_term_count(facets[i]); j++)
350 const char *term = ZOOM_facet_field_get_term(facets[i], j, &freq);
351 printf(" %s(%d) \n", term, freq);
356 static int cmd_facets(struct zoom_sh *sh, const char **args)
363 for (db = sh->list; db; db = db->next)
366 const char *errmsg, *addinfo, *dset;
367 /* display errors if any */
370 if ((error = ZOOM_connection_error_x(db->con, &errmsg, &addinfo,
373 printf("%s error: %s (%s:%d) %s\n",
374 ZOOM_connection_option_get(db->con, "host"), errmsg,
375 dset, error, addinfo);
380 int num_facets = ZOOM_resultset_facets_size(db->res);
382 ZOOM_facet_field *facets = ZOOM_resultset_facets(db->res);
383 display_facets(facets, num_facets);
390 static int cmd_suggestions(struct zoom_sh *sh, const char **args)
397 for (db = sh->list; db; db = db->next)
400 const char *errmsg, *addinfo, *dset;
401 /* display errors if any */
404 if ((error = ZOOM_connection_error_x(db->con, &errmsg, &addinfo,
407 printf("%s error: %s (%s:%d) %s\n",
408 ZOOM_connection_option_get(db->con, "host"), errmsg,
409 dset, error, addinfo);
414 const char *suggestions =
415 ZOOM_resultset_option_get(db->res, "suggestions");
417 printf("Suggestions: \n%s\n", suggestions);
423 static int cmd_ext(struct zoom_sh *sh, const char **args)
429 WRBUF ext_type_str = next_token_new_wrbuf(args);
433 printf("es: missing type "
434 "(itemorder, create, drop, commit, update, xmlupdate)\n");
437 for (number = 0, db = sh->list; db; db = db->next)
441 p = xmalloc(sizeof(*p) * number);
443 for (i = 0, db = sh->list; db; db = db->next)
446 p[i] = ZOOM_connection_package(db->con, 0);
447 ZOOM_package_send(p[i], ext_type_str ? wrbuf_cstr(ext_type_str):0);
453 for (i = 0, db = sh->list; db; db = db->next)
456 const char *errmsg, *addinfo, *dset;
457 /* display errors if any */
460 if ((error = ZOOM_connection_error_x(db->con, &errmsg, &addinfo,
463 printf("%s error: %s (%s:%d) %s\n",
464 ZOOM_connection_option_get(db->con, "host"), errmsg,
465 dset, error, addinfo);
472 v = ZOOM_package_option_get(p[i], "targetReference");
474 printf("targetReference: %s\n", v);
475 v = ZOOM_package_option_get(p[i], "xmlUpdateDoc");
477 printf("xmlUpdateDoc: %s\n", v);
479 ZOOM_package_destroy(p[i]);
483 wrbuf_destroy(ext_type_str);
488 static int cmd_debug(struct zoom_sh *sh, const char **args)
490 yaz_log_init_level(YLOG_ALL);
494 static int cmd_search(struct zoom_sh *sh, const char **args)
497 const char *query_str = *args;
501 s = ZOOM_query_create();
502 while (*query_str == ' ')
504 if (memcmp(query_str, "cql:", 4) == 0)
506 ZOOM_query_cql(s, query_str + 4);
508 else if (ZOOM_query_prefix(s, query_str))
510 printf("Bad PQF: %s\n", query_str);
511 ZOOM_query_destroy(s);
514 for (db = sh->list; db; db = db->next)
518 ZOOM_resultset_destroy(db->res);
519 db->res = ZOOM_connection_search(db->con, s);
522 ZOOM_query_destroy(s);
526 for (db = sh->list; db; db = db->next)
529 const char *errmsg, *addinfo, *dset;
530 /* display errors if any */
533 if ((error = ZOOM_connection_error_x(db->con, &errmsg, &addinfo,
536 printf("%s error: %s (%s:%d) %s\n",
537 ZOOM_connection_option_get(db->con, "host"), errmsg,
538 dset, error, addinfo);
543 /* OK, no major errors. Look at the result count */
544 int start = ZOOM_options_get_int(sh->options, "start", 0);
545 int count = ZOOM_options_get_int(sh->options, "count", 0);
548 printf("%s: %lld hits\n", ZOOM_connection_option_get(db->con,
550 (long long int) ZOOM_resultset_size(db->res));
552 facet_num = ZOOM_resultset_facets_size(db->res);
555 ZOOM_facet_field *facets = ZOOM_resultset_facets(db->res);
557 for (facet_idx = 0; facet_idx < facet_num; facet_idx++)
559 const char *name = ZOOM_facet_field_name(facets[facet_idx]);
561 size_t term_num = ZOOM_facet_field_term_count(facets[facet_idx]);
562 printf("facet: %s\n", name);
563 for (term_idx = 0; term_idx < term_num; term_idx++ )
567 ZOOM_facet_field_get_term(facets[facet_idx], term_idx, &freq);
568 printf("term: %s %d\n", term, freq);
573 display_records(db->con, db->res, start, count, "render");
579 static int cmd_scan(struct zoom_sh *sh, const char **args)
581 const char *query_str = *args;
582 ZOOM_query query = ZOOM_query_create();
588 while (*query_str == ' ')
591 if (memcmp(query_str, "cql:", 4) == 0)
593 ZOOM_query_cql(query, query_str + 4);
595 else if (ZOOM_query_prefix(query, query_str))
597 printf("Bad PQF: %s\n", query_str);
598 ZOOM_query_destroy(query);
602 for (number = 0, db = sh->list; db; db = db->next)
606 s = xmalloc(sizeof(*s) * number);
608 for (i = 0, db = sh->list; db; db = db->next)
610 s[i++] = ZOOM_connection_scan1(db->con, query);
612 ZOOM_query_destroy(query);
616 for (i = 0, db = sh->list; db; db = db->next)
619 const char *errmsg, *addinfo, *dset;
620 /* display errors if any */
623 if ((error = ZOOM_connection_error_x(db->con, &errmsg, &addinfo,
626 printf("%s error: %s (%s:%d) %s\n",
627 ZOOM_connection_option_get(db->con, "host"), errmsg,
628 dset, error, addinfo);
633 size_t p, sz = ZOOM_scanset_size(s[i]);
634 for (p = 0; p < sz; p++)
638 const char *term = ZOOM_scanset_display_term(s[i], p,
640 printf("%.*s %lld\n", (int) len, term, (long long int) occ);
642 ZOOM_scanset_destroy(s[i]);
650 static int cmd_sort(struct zoom_sh *sh, const char **args)
652 const char *sort_spec = *args;
656 while (*sort_spec == ' ')
659 for (db = sh->list; db; db = db->next)
661 ZOOM_resultset_sort(db->res, "yaz", sort_spec);
666 static int cmd_help(struct zoom_sh *sh, const char **args)
668 printf("connect <zurl>\n");
669 printf("search <pqf>\n");
670 printf("show [<start> [<count> [<type]]]\n");
672 printf("scan <term>\n");
674 printf("close <zurl>\n");
675 printf("ext <type>\n");
676 printf("set <option> [<value>]\n");
677 printf("get <option>\n");
678 printf("shell cmdline\n");
680 printf("options:\n");
683 printf(" databaseName\n");
684 printf(" preferredRecordSyntax\n");
686 printf(" elementSetName\n");
687 printf(" maximumRecordSize\n");
688 printf(" preferredRecordSize\n");
690 printf(" piggyback\n");
693 printf(" password\n");
694 printf(" implementationName\n");
695 printf(" charset\n");
697 printf(" timeout\n");
699 printf(" extraArgs\n");
700 printf(" suggestions\n");
704 static int cmd_connect(struct zoom_sh *sh, const char **args)
708 const char *errmsg, *addinfo, *dset;
710 WRBUF host = next_token_new_wrbuf(args);
713 printf("missing host after connect\n");
716 for (db = sh->list; db; db = db->next)
719 if (db->con && (h = ZOOM_connection_option_get(db->con, "host")) &&
720 !strcmp(h, wrbuf_cstr(host)))
722 ZOOM_connection_destroy(db->con);
726 if (!db) /* no match .. */
728 db = xmalloc(sizeof(*db));
733 db->con = ZOOM_connection_create(sh->options);
735 ZOOM_connection_connect(db->con, wrbuf_cstr(host), 0);
739 if ((error = ZOOM_connection_error_x(db->con, &errmsg, &addinfo, &dset)))
741 printf("%s error: %s (%s:%d) %s\n",
742 ZOOM_connection_option_get(db->con, "host"), errmsg,
743 dset, error, addinfo);
750 /** \brief parse and execute zoomsh command
752 \param buf command string and arguments
754 \retval 1 failure to execute
755 \retval -1 EOF (no more commands or quit seen)
757 static int cmd_parse(struct zoom_sh *sh, const char **buf)
763 cmd_len = next_token(buf, &cmd_str);
766 if (is_command("quit", cmd_str, cmd_len))
768 else if (is_command("set", cmd_str, cmd_len))
769 ret = cmd_set(sh, buf);
770 else if (is_command("get", cmd_str, cmd_len))
771 ret = cmd_get(sh, buf);
772 else if (is_command("rget", cmd_str, cmd_len))
773 ret = cmd_rget(sh, buf);
774 else if (is_command("connect", cmd_str, cmd_len))
775 ret = cmd_connect(sh, buf);
776 else if (is_command("open", cmd_str, cmd_len))
777 ret = cmd_connect(sh, buf);
778 else if (is_command("search", cmd_str, cmd_len))
779 ret = cmd_search(sh, buf);
780 else if (is_command("facets", cmd_str, cmd_len))
781 ret = cmd_facets(sh, buf);
782 else if (is_command("find", cmd_str, cmd_len))
783 ret = cmd_search(sh, buf);
784 else if (is_command("show", cmd_str, cmd_len))
785 ret = cmd_show(sh, buf);
786 else if (is_command("suggestions", cmd_str, cmd_len))
787 ret = cmd_suggestions(sh, buf);
788 else if (is_command("close", cmd_str, cmd_len))
789 ret = cmd_close(sh, buf);
790 else if (is_command("help", cmd_str, cmd_len))
791 ret = cmd_help(sh, buf);
792 else if (is_command("ext", cmd_str, cmd_len))
793 ret = cmd_ext(sh, buf);
794 else if (is_command("debug", cmd_str, cmd_len))
795 ret = cmd_debug(sh, buf);
796 else if (is_command("scan", cmd_str, cmd_len))
797 ret = cmd_scan(sh, buf);
798 else if (is_command("sort", cmd_str, cmd_len))
799 ret = cmd_sort(sh, buf);
800 else if (is_command("shell", cmd_str, cmd_len))
801 ret = cmd_shell(sh, buf);
804 printf("unknown command %.*s\n", cmd_len, cmd_str);
810 static int shell(struct zoom_sh *sh, int exit_on_error)
817 const char *bp = buf;
819 #if HAVE_READLINE_READLINE_H
822 line_in = readline("ZOOM>");
829 #if HAVE_READLINE_HISTORY_H
831 add_history(line_in);
833 if (strlen(line_in) > sizeof(buf)-1)
835 printf("Input line too long\n");
843 if (!line_in) /* no line buffer via readline or not enabled at all */
845 printf("ZOOM>"); fflush(stdout);
846 if (!fgets(buf, sizeof(buf)-1, stdin))
852 if ((cp = strchr(buf, '\n')))
854 res = cmd_parse(sh, &bp);
857 if (!exit_on_error && res > 0)
863 static int zoomsh(int argc, char **argv)
865 int res = 0; /* -1: EOF; 0 = OK, > 0 ERROR */
866 int exit_on_error = 0;
871 sh.options = ZOOM_options_create();
877 int option_ret = options("ev:", argv, argc, &arg);
878 const char *bp = arg;
882 res = cmd_parse(&sh, &bp);
883 /* returns res == -1 on quit */
884 if (!exit_on_error && res > 0)
885 res = 0; /* hide error */
887 case YAZ_OPTIONS_EOF:
888 res = shell(&sh, exit_on_error);
894 mask = yaz_log_mask_str(arg);
895 yaz_log_init_level(mask);
898 fprintf(stderr, "zoomsh: [-e] [-v] [commands]\n");
903 for (db = sh.list; db; )
905 struct zoom_db *n = db->next;
906 ZOOM_connection_destroy(db->con);
907 ZOOM_resultset_destroy(db->res);
911 ZOOM_options_destroy(sh.options);
912 if (res == -1) /* quit .. which is not an error */
917 int main(int argc, char **argv)
919 int ret = zoomsh(argc, argv);
925 * c-file-style: "Stroustrup"
926 * indent-tabs-mode: nil
928 * vim: shiftwidth=4 tabstop=8 expandtab