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>
48 static void process_events(struct zoom_sh *sh)
54 for (number = 0, db = sh->list; db; db = db->next)
57 c = xmalloc(sizeof(*c) * number);
59 for (i = 0, db = sh->list; db; db = db->next)
63 yaz_log(YLOG_DEBUG, "process_events");
64 while ((i = ZOOM_event(number, c)) != 0)
66 int peek = ZOOM_connection_peek_event(c[i-1]);
67 int event = ZOOM_connection_last_event(c[i-1]);
68 yaz_log(YLOG_DEBUG, "no = %d peek = %d event = %d %s", i-1,
71 ZOOM_get_event_str(event));
76 static int next_token_chars(const char **cpp, const char **t_start,
77 const char *tok_chars)
80 const char *cp = *cpp;
87 while (*cp && *cp != '"')
98 while (*cp && !strchr(tok_chars, *cp))
107 return len; /* return -1 if no token was read .. */
110 static int next_token(const char **cpp, const char **t_start)
112 return next_token_chars(cpp, t_start, "\r\n ");
116 static WRBUF next_token_new_wrbuf(const char **cpp)
120 int len = next_token(cpp, &start);
125 wrbuf_write(w, start, len);
129 static int is_command(const char *cmd_str, const char *this_str, int this_len)
131 int cmd_len = strlen(cmd_str);
132 if (cmd_len != this_len)
134 if (memcmp(cmd_str, this_str, cmd_len))
139 static int cmd_set(struct zoom_sh *sh, const char **args)
145 if (!(key = next_token_new_wrbuf(args)))
147 printf("missing argument for set\n");
150 val_len = next_token_chars(args, &val_buf, "");
152 ZOOM_options_setl(sh->options, wrbuf_cstr(key), val_buf, val_len);
154 ZOOM_options_set(sh->options, wrbuf_cstr(key), 0);
159 static int cmd_get(struct zoom_sh *sh, const char **args)
162 if (!(key = next_token_new_wrbuf(args)))
164 printf("missing argument for get\n");
169 const char *val = ZOOM_options_get(sh->options, wrbuf_cstr(key));
170 printf("%s = %s\n", wrbuf_cstr(key), val ? val : "<null>");
176 static int cmd_shell(struct zoom_sh *sh, const char **args)
178 int ret = system(*args);
180 printf("system command returned %d\n", ret);
184 static int cmd_rget(struct zoom_sh *sh, const char **args)
187 if (!(key = next_token_new_wrbuf(args)))
189 printf("missing argument for get\n");
194 struct zoom_db *db = sh->list;
195 for (; db; db = db->next)
200 ZOOM_resultset_option_get(db->res, wrbuf_cstr(key));
201 printf("%s = %s\n", wrbuf_cstr(key), val ? val : "<null>");
209 static int cmd_close(struct zoom_sh *sh, const char **args)
211 struct zoom_db **dbp;
213 host = next_token_new_wrbuf(args);
215 for (dbp = &sh->list; *dbp; )
218 struct zoom_db *db = *dbp;
219 if (!db->con || !host ||
220 ((h = ZOOM_connection_option_get(db->con, "host"))
221 && !strcmp(h, wrbuf_cstr(host))))
224 ZOOM_connection_destroy(db->con);
225 ZOOM_resultset_destroy(db->res);
236 static void display_records(ZOOM_connection c,
238 size_t start, size_t count, const char *type)
241 for (i = 0; i < count; i++)
243 size_t pos = i + start;
244 ZOOM_record rec = ZOOM_resultset_record(r, pos);
245 const char *db = ZOOM_record_get(rec, "database", 0);
247 if (ZOOM_record_error(rec, 0, 0, 0))
252 int error = ZOOM_record_error(rec, &msg, &addinfo, &diagset);
254 printf("%lld %s: %s (%s:%d) %s\n", (long long) pos,
255 (db ? db : "unknown"),
256 msg, diagset, error, addinfo ? addinfo : "none");
261 const char *render = ZOOM_record_get(rec, type, &len);
262 const char *syntax = ZOOM_record_get(rec, "syntax", 0);
263 const char *schema = ZOOM_record_get(rec, "schema", 0);
264 /* if rec is non-null, we got a record for display */
267 printf("%lld database=%s syntax=%s schema=%s\n",
268 (long long) pos, (db ? db : "unknown"), syntax,
269 schema ? schema : "unknown");
272 if (fwrite(render, 1, len, stdout) != (size_t) len)
274 printf("write to stdout failed\n");
283 static int cmd_show(struct zoom_sh *sh, const char **args)
285 size_t start = 0, count = 1;
286 const char *type = "render";
287 WRBUF render_str = 0;
294 if ((tmp = next_token_new_wrbuf(args)))
296 start = atoi(wrbuf_cstr(tmp));
300 if ((tmp = next_token_new_wrbuf(args)))
302 count = atoi(wrbuf_cstr(tmp));
305 render_str = next_token_new_wrbuf(args);
308 type = wrbuf_cstr(render_str);
310 for (db = sh->list; db; db = db->next)
312 ZOOM_resultset_records(db->res, 0, start, count);
315 for (db = sh->list; db; db = db->next)
318 const char *errmsg, *addinfo, *dset;
319 /* display errors if any */
322 if ((error = ZOOM_connection_error_x(db->con, &errmsg, &addinfo, &dset)))
324 printf("%s error: %s (%s:%d) %s\n",
325 ZOOM_connection_option_get(db->con, "host"), errmsg,
326 dset, error, addinfo);
331 /* OK, no major errors. Display records... */
332 display_records(db->con, db->res, start, count, type);
336 wrbuf_destroy(render_str);
340 static void display_facets(ZOOM_facet_field *facets, int count)
343 printf("Facets: \n");
344 for (i = 0; i < count; i++)
347 const char *facet_name = ZOOM_facet_field_name(facets[i]);
348 printf(" %s: \n", facet_name);
349 for (j = 0; j < ZOOM_facet_field_term_count(facets[i]); j++)
352 const char *term = ZOOM_facet_field_get_term(facets[i], j, &freq);
353 printf(" %s(%d) \n", term, freq);
358 static int cmd_facets(struct zoom_sh *sh, const char **args)
365 for (db = sh->list; db; db = db->next)
368 const char *errmsg, *addinfo, *dset;
369 /* display errors if any */
372 if ((error = ZOOM_connection_error_x(db->con, &errmsg, &addinfo,
375 printf("%s error: %s (%s:%d) %s\n",
376 ZOOM_connection_option_get(db->con, "host"), errmsg,
377 dset, error, addinfo);
382 int num_facets = ZOOM_resultset_facets_size(db->res);
384 ZOOM_facet_field *facets = ZOOM_resultset_facets(db->res);
385 display_facets(facets, num_facets);
392 static int cmd_suggestions(struct zoom_sh *sh, const char **args)
399 for (db = sh->list; db; db = db->next)
402 const char *errmsg, *addinfo, *dset;
403 /* display errors if any */
406 if ((error = ZOOM_connection_error_x(db->con, &errmsg, &addinfo,
409 printf("%s error: %s (%s:%d) %s\n",
410 ZOOM_connection_option_get(db->con, "host"), errmsg,
411 dset, error, addinfo);
416 const char *suggestions =
417 ZOOM_resultset_option_get(db->res, "suggestions");
419 printf("Suggestions: \n%s\n", suggestions);
425 static int cmd_ext(struct zoom_sh *sh, const char **args)
431 WRBUF ext_type_str = next_token_new_wrbuf(args);
435 printf("es: missing type "
436 "(itemorder, create, drop, commit, update, xmlupdate)\n");
439 for (number = 0, db = sh->list; db; db = db->next)
443 p = xmalloc(sizeof(*p) * number);
445 for (i = 0, db = sh->list; db; db = db->next)
448 p[i] = ZOOM_connection_package(db->con, 0);
449 ZOOM_package_send(p[i], ext_type_str ? wrbuf_cstr(ext_type_str):0);
455 for (i = 0, db = sh->list; db; db = db->next)
458 const char *errmsg, *addinfo, *dset;
459 /* display errors if any */
462 if ((error = ZOOM_connection_error_x(db->con, &errmsg, &addinfo,
465 printf("%s error: %s (%s:%d) %s\n",
466 ZOOM_connection_option_get(db->con, "host"), errmsg,
467 dset, error, addinfo);
474 v = ZOOM_package_option_get(p[i], "targetReference");
476 printf("targetReference: %s\n", v);
477 v = ZOOM_package_option_get(p[i], "xmlUpdateDoc");
479 printf("xmlUpdateDoc: %s\n", v);
481 ZOOM_package_destroy(p[i]);
485 wrbuf_destroy(ext_type_str);
490 static int cmd_debug(struct zoom_sh *sh, const char **args)
492 yaz_log_init_level(YLOG_ALL);
496 static int cmd_search(struct zoom_sh *sh, const char **args)
499 const char *query_str = *args;
503 s = ZOOM_query_create();
504 while (*query_str == ' ')
506 if (memcmp(query_str, "cql:", 4) == 0)
508 ZOOM_query_cql(s, query_str + 4);
510 else if (ZOOM_query_prefix(s, query_str))
512 printf("Bad PQF: %s\n", query_str);
513 ZOOM_query_destroy(s);
516 if (sh->strategy && wrbuf_len(sh->strategy) && wrbuf_len(sh->criteria))
518 int r = ZOOM_query_sortby2(s, wrbuf_cstr(sh->strategy),
519 wrbuf_cstr(sh->criteria));
523 printf("Bad sortby strategy: %s\n", wrbuf_cstr(sh->strategy));
525 printf("Bad sortby criteria: %s\n", wrbuf_cstr(sh->criteria));
526 ZOOM_query_destroy(s);
529 printf("sortby added\n");
531 for (db = sh->list; db; db = db->next)
535 ZOOM_resultset_destroy(db->res);
536 db->res = ZOOM_connection_search(db->con, s);
539 ZOOM_query_destroy(s);
543 for (db = sh->list; db; db = db->next)
546 const char *errmsg, *addinfo, *dset;
547 /* display errors if any */
550 if ((error = ZOOM_connection_error_x(db->con, &errmsg, &addinfo,
553 printf("%s error: %s (%s:%d) %s\n",
554 ZOOM_connection_option_get(db->con, "host"), errmsg,
555 dset, error, addinfo);
560 /* OK, no major errors. Look at the result count */
561 int start = ZOOM_options_get_int(sh->options, "start", 0);
562 int count = ZOOM_options_get_int(sh->options, "count", 0);
565 printf("%s: %lld hits\n", ZOOM_connection_option_get(db->con,
567 (long long int) ZOOM_resultset_size(db->res));
569 facet_num = ZOOM_resultset_facets_size(db->res);
572 ZOOM_facet_field *facets = ZOOM_resultset_facets(db->res);
574 for (facet_idx = 0; facet_idx < facet_num; facet_idx++)
576 const char *name = ZOOM_facet_field_name(facets[facet_idx]);
578 size_t term_num = ZOOM_facet_field_term_count(facets[facet_idx]);
579 printf("facet: %s\n", name);
580 for (term_idx = 0; term_idx < term_num; term_idx++ )
584 ZOOM_facet_field_get_term(facets[facet_idx], term_idx, &freq);
585 printf("term: %s %d\n", term, freq);
590 display_records(db->con, db->res, start, count, "render");
596 static int cmd_scan(struct zoom_sh *sh, const char **args)
598 const char *query_str = *args;
599 ZOOM_query query = ZOOM_query_create();
605 while (*query_str == ' ')
608 if (memcmp(query_str, "cql:", 4) == 0)
610 ZOOM_query_cql(query, query_str + 4);
612 else if (ZOOM_query_prefix(query, query_str))
614 printf("Bad PQF: %s\n", query_str);
615 ZOOM_query_destroy(query);
619 for (number = 0, db = sh->list; db; db = db->next)
623 s = xmalloc(sizeof(*s) * number);
625 for (i = 0, db = sh->list; db; db = db->next)
627 s[i++] = ZOOM_connection_scan1(db->con, query);
629 ZOOM_query_destroy(query);
633 for (i = 0, db = sh->list; db; db = db->next)
636 const char *errmsg, *addinfo, *dset;
637 /* display errors if any */
640 if ((error = ZOOM_connection_error_x(db->con, &errmsg, &addinfo,
643 printf("%s error: %s (%s:%d) %s\n",
644 ZOOM_connection_option_get(db->con, "host"), errmsg,
645 dset, error, addinfo);
650 size_t p, sz = ZOOM_scanset_size(s[i]);
651 for (p = 0; p < sz; p++)
655 const char *term = ZOOM_scanset_display_term(s[i], p,
657 printf("%.*s %lld\n", (int) len, term, (long long int) occ);
659 ZOOM_scanset_destroy(s[i]);
667 static int cmd_sortby(struct zoom_sh *sh, const char **args)
670 const char *criteria;
671 if (!(strategy = next_token_new_wrbuf(args)))
673 printf("missing argument argument: strategy and criteria\n");
677 while (*criteria == ' ')
679 wrbuf_destroy(sh->strategy);
680 sh->strategy = strategy;
682 wrbuf_rewind(sh->criteria);
683 wrbuf_puts(sh->criteria, criteria);
687 static int cmd_sort(struct zoom_sh *sh, const char **args)
689 const char *sort_spec = *args;
693 while (*sort_spec == ' ')
696 for (db = sh->list; db; db = db->next)
698 ZOOM_resultset_sort(db->res, "yaz", sort_spec);
703 static int cmd_help(struct zoom_sh *sh, const char **args)
705 printf("connect <zurl>\n");
706 printf("search <pqf>\n");
707 printf("sortby <strategy> <criteria>\n");
708 printf("show [<start> [<count> [<type]]]\n");
710 printf("scan <term>\n");
712 printf("close <zurl>\n");
713 printf("ext <type>\n");
714 printf("set <option> [<value>]\n");
715 printf("get <option>\n");
716 printf("shell cmdline\n");
718 printf("options:\n");
721 printf(" databaseName\n");
722 printf(" preferredRecordSyntax\n");
724 printf(" elementSetName\n");
725 printf(" maximumRecordSize\n");
726 printf(" preferredRecordSize\n");
728 printf(" piggyback\n");
731 printf(" password\n");
732 printf(" implementationName\n");
733 printf(" charset\n");
735 printf(" timeout\n");
737 printf(" extraArgs\n");
738 printf(" suggestions\n");
742 static int cmd_connect(struct zoom_sh *sh, const char **args)
746 const char *errmsg, *addinfo, *dset;
748 WRBUF host = next_token_new_wrbuf(args);
751 printf("missing host after connect\n");
754 for (db = sh->list; db; db = db->next)
757 if (db->con && (h = ZOOM_connection_option_get(db->con, "host")) &&
758 !strcmp(h, wrbuf_cstr(host)))
760 ZOOM_connection_destroy(db->con);
764 if (!db) /* no match .. */
766 db = xmalloc(sizeof(*db));
771 db->con = ZOOM_connection_create(sh->options);
773 ZOOM_connection_connect(db->con, wrbuf_cstr(host), 0);
777 if ((error = ZOOM_connection_error_x(db->con, &errmsg, &addinfo, &dset)))
779 printf("%s error: %s (%s:%d) %s\n",
780 ZOOM_connection_option_get(db->con, "host"), errmsg,
781 dset, error, addinfo);
788 /** \brief parse and execute zoomsh command
790 \param buf command string and arguments
792 \retval 1 failure to execute
793 \retval -1 EOF (no more commands or quit seen)
795 static int cmd_parse(struct zoom_sh *sh, const char **buf)
801 cmd_len = next_token(buf, &cmd_str);
804 if (is_command("quit", cmd_str, cmd_len))
806 else if (is_command("set", cmd_str, cmd_len))
807 ret = cmd_set(sh, buf);
808 else if (is_command("get", cmd_str, cmd_len))
809 ret = cmd_get(sh, buf);
810 else if (is_command("rget", cmd_str, cmd_len))
811 ret = cmd_rget(sh, buf);
812 else if (is_command("connect", cmd_str, cmd_len))
813 ret = cmd_connect(sh, buf);
814 else if (is_command("open", cmd_str, cmd_len))
815 ret = cmd_connect(sh, buf);
816 else if (is_command("search", cmd_str, cmd_len))
817 ret = cmd_search(sh, buf);
818 else if (is_command("sortby", cmd_str, cmd_len))
819 ret = cmd_sortby(sh, buf);
820 else if (is_command("facets", cmd_str, cmd_len))
821 ret = cmd_facets(sh, buf);
822 else if (is_command("find", cmd_str, cmd_len))
823 ret = cmd_search(sh, buf);
824 else if (is_command("show", cmd_str, cmd_len))
825 ret = cmd_show(sh, buf);
826 else if (is_command("suggestions", cmd_str, cmd_len))
827 ret = cmd_suggestions(sh, buf);
828 else if (is_command("close", cmd_str, cmd_len))
829 ret = cmd_close(sh, buf);
830 else if (is_command("help", cmd_str, cmd_len))
831 ret = cmd_help(sh, buf);
832 else if (is_command("ext", cmd_str, cmd_len))
833 ret = cmd_ext(sh, buf);
834 else if (is_command("debug", cmd_str, cmd_len))
835 ret = cmd_debug(sh, buf);
836 else if (is_command("scan", cmd_str, cmd_len))
837 ret = cmd_scan(sh, buf);
838 else if (is_command("sort", cmd_str, cmd_len))
839 ret = cmd_sort(sh, buf);
840 else if (is_command("shell", cmd_str, cmd_len))
841 ret = cmd_shell(sh, buf);
844 printf("unknown command %.*s\n", cmd_len, cmd_str);
850 static int shell(struct zoom_sh *sh, int exit_on_error)
857 const char *bp = buf;
859 #if HAVE_READLINE_READLINE_H
862 line_in = readline("ZOOM>");
869 #if HAVE_READLINE_HISTORY_H
871 add_history(line_in);
873 if (strlen(line_in) > sizeof(buf)-1)
875 printf("Input line too long\n");
883 if (!line_in) /* no line buffer via readline or not enabled at all */
885 printf("ZOOM>"); fflush(stdout);
886 if (!fgets(buf, sizeof(buf)-1, stdin))
892 if ((cp = strchr(buf, '\n')))
894 res = cmd_parse(sh, &bp);
897 if (!exit_on_error && res > 0)
903 static int zoomsh(int argc, char **argv)
905 int res = 0; /* -1: EOF; 0 = OK, > 0 ERROR */
906 int exit_on_error = 0;
911 sh.options = ZOOM_options_create();
913 sh.criteria = wrbuf_alloc();
919 int option_ret = options("ev:", argv, argc, &arg);
920 const char *bp = arg;
924 res = cmd_parse(&sh, &bp);
925 /* returns res == -1 on quit */
926 if (!exit_on_error && res > 0)
927 res = 0; /* hide error */
929 case YAZ_OPTIONS_EOF:
930 res = shell(&sh, exit_on_error);
936 mask = yaz_log_mask_str(arg);
937 yaz_log_init_level(mask);
940 fprintf(stderr, "zoomsh: [-e] [-v] [commands]\n");
945 for (db = sh.list; db; )
947 struct zoom_db *n = db->next;
948 ZOOM_connection_destroy(db->con);
949 ZOOM_resultset_destroy(db->res);
953 ZOOM_options_destroy(sh.options);
954 wrbuf_destroy(sh.strategy);
955 wrbuf_destroy(sh.criteria);
956 if (res == -1) /* quit .. which is not an error */
961 int main(int argc, char **argv)
963 int ret = zoomsh(argc, argv);
969 * c-file-style: "Stroustrup"
970 * indent-tabs-mode: nil
972 * vim: shiftwidth=4 tabstop=8 expandtab