1 /* This file is part of the YAZ toolkit.
2 * Copyright (C) 1995-2009 Index Data
3 * See the file LICENSE for details.
7 \brief ZOOM C command line tool (shell)
15 #include <yaz/comstack.h>
17 #if HAVE_READLINE_READLINE_H
18 #include <readline/readline.h>
20 #if HAVE_READLINE_HISTORY_H
21 #include <readline/history.h>
24 #include <yaz/xmalloc.h>
32 static int next_token(const char **cpp, const char **t_start)
35 const char *cp = *cpp;
42 while (*cp && *cp != '"')
53 while (*cp && *cp != ' ' && *cp != '\r' && *cp != '\n')
62 return len; /* return -1 if no token was read .. */
65 static int next_token_copy(const char **cpp, char *buf_out, int buf_max)
68 int len = next_token(cpp, &start);
76 memcpy(buf_out, start, len);
81 static int is_command(const char *cmd_str, const char *this_str, int this_len)
83 int cmd_len = strlen(cmd_str);
84 if (cmd_len != this_len)
86 if (memcmp(cmd_str, this_str, cmd_len))
91 static void cmd_set(ZOOM_connection *c, ZOOM_resultset *r,
95 char key[40], val[80];
97 if (next_token_copy(args, key, sizeof(key)) < 0)
99 printf("missing argument for set\n");
102 if (next_token_copy(args, val, sizeof(val)) < 0)
103 ZOOM_options_set(options, key, 0);
105 ZOOM_options_set(options, key, val);
108 static void cmd_get(ZOOM_connection *c, ZOOM_resultset *r,
109 ZOOM_options options,
113 if (next_token_copy(args, key, sizeof(key)) < 0)
115 printf("missing argument for get\n");
119 const char *val = ZOOM_options_get(options, key);
120 printf("%s = %s\n", key, val ? val : "<null>");
124 static void cmd_rget(ZOOM_connection *c, ZOOM_resultset *r,
125 ZOOM_options options,
129 if (next_token_copy(args, key, sizeof(key)) < 0)
131 printf("missing argument for get\n");
136 for (i = 0; i<MAX_CON; i++)
142 val = ZOOM_resultset_option_get(r[i], key);
143 printf("%s = %s\n", key, val ? val : "<null>");
148 static void cmd_close(ZOOM_connection *c, ZOOM_resultset *r,
149 ZOOM_options options,
154 next_token_copy(args, host, sizeof(host));
155 for (i = 0; i<MAX_CON; i++)
160 if ((h = ZOOM_connection_option_get(c[i], "host"))
163 ZOOM_connection_destroy(c[i]);
166 else if (*host == '\0')
168 ZOOM_connection_destroy(c[i]);
174 static void display_records(ZOOM_connection c,
176 int start, int count, const char *type)
179 for (i = 0; i<count; i++)
182 ZOOM_record rec = ZOOM_resultset_record(r, pos);
183 const char *db = ZOOM_record_get(rec, "database", 0);
185 if (ZOOM_record_error(rec, 0, 0, 0))
190 int error = ZOOM_record_error(rec, &msg, &addinfo, &diagset);
192 printf("%d %s: %s (%s:%d) %s\n", pos, (db ? db : "unknown"),
193 msg, diagset, error, addinfo ? addinfo : "none");
198 const char *render = ZOOM_record_get(rec, type, &len);
199 const char *opac_render = ZOOM_record_get(rec, "opac", &opac_len);
200 const char *syntax = ZOOM_record_get(rec, "syntax", 0);
201 const char *schema = ZOOM_record_get(rec, "schema", 0);
202 /* if rec is non-null, we got a record for display */
205 printf("%d database=%s syntax=%s schema=%s\n",
206 pos, (db ? db : "unknown"), syntax,
207 schema ? schema : "unknown");
210 if (fwrite(render, 1, len, stdout) != (size_t) len)
212 printf("write to stdout failed\n");
218 if (fwrite(opac_render, 1, opac_len, stdout) != (size_t)
220 printf("write to stdout failed\n");
227 static void cmd_show(ZOOM_connection *c, ZOOM_resultset *r,
228 ZOOM_options options,
232 char start_str[10], count_str[10], render_str[60];
233 const char *type = "render";
235 if (next_token_copy(args, start_str, sizeof(start_str)) >= 0)
236 ZOOM_options_set(options, "start", start_str);
238 if (next_token_copy(args, count_str, sizeof(count_str)) <= 0)
239 strcpy(count_str, "1");
240 ZOOM_options_set(options, "count", count_str);
242 if (next_token_copy(args, render_str, sizeof(render_str)) >= 0)
245 for (i = 0; i<MAX_CON; i++)
246 ZOOM_resultset_records(r[i], 0, atoi(start_str), atoi(count_str));
247 while (ZOOM_event(MAX_CON, c))
250 for (i = 0; i<MAX_CON; i++)
253 const char *errmsg, *addinfo, *dset;
254 /* display errors if any */
257 if ((error = ZOOM_connection_error_x(c[i], &errmsg, &addinfo, &dset)))
258 printf("%s error: %s (%s:%d) %s\n",
259 ZOOM_connection_option_get(c[i], "host"), errmsg,
260 dset, error, addinfo);
263 /* OK, no major errors. Display records... */
264 int start = ZOOM_options_get_int(options, "start", 0);
265 int count = ZOOM_options_get_int(options, "count", 0);
266 display_records(c[i], r[i], start, count, type);
269 ZOOM_options_set(options, "count", "0");
270 ZOOM_options_set(options, "start", "0");
273 static void cmd_ext(ZOOM_connection *c, ZOOM_resultset *r,
274 ZOOM_options options,
277 ZOOM_package p[MAX_CON];
278 char ext_type_str[10];
282 if (next_token_copy(args, ext_type_str, sizeof(ext_type_str)) < 0)
285 for (i = 0; i<MAX_CON; i++)
289 p[i] = ZOOM_connection_package(c[i], 0);
290 ZOOM_package_send(p[i], ext_type_str);
296 while (ZOOM_event(MAX_CON, c))
299 for (i = 0; i<MAX_CON; i++)
302 const char *errmsg, *addinfo, *dset;
303 /* display errors if any */
306 if ((error = ZOOM_connection_error_x(c[i], &errmsg, &addinfo, &dset)))
307 printf("%s error: %s (%s:%d) %s\n",
308 ZOOM_connection_option_get(c[i], "host"), errmsg,
309 dset, error, addinfo);
314 v = ZOOM_package_option_get(p[i], "targetReference");
316 printf("targetReference: %s\n", v);
317 v = ZOOM_package_option_get(p[i], "xmlUpdateDoc");
319 printf("xmlUpdateDoc: %s\n", v);
321 ZOOM_package_destroy(p[i]);
325 static void cmd_debug(ZOOM_connection *c, ZOOM_resultset *r,
326 ZOOM_options options,
329 yaz_log_init_level(YLOG_ALL);
332 static void cmd_search(ZOOM_connection *c, ZOOM_resultset *r,
333 ZOOM_options options,
337 const char *query_str = *args;
340 s = ZOOM_query_create();
341 while (*query_str == ' ')
343 if (memcmp(query_str, "cql:", 4) == 0)
345 ZOOM_query_cql(s, query_str + 4);
347 else if (ZOOM_query_prefix(s, query_str))
349 printf("Bad PQF: %s\n", query_str);
352 for (i = 0; i<MAX_CON; i++)
357 ZOOM_resultset_destroy(r[i]);
361 r[i] = ZOOM_connection_search(c[i], s);
363 ZOOM_query_destroy(s);
365 while (ZOOM_event(MAX_CON, c))
368 for (i = 0; i<MAX_CON; i++)
371 const char *errmsg, *addinfo, *dset;
372 /* display errors if any */
375 if ((error = ZOOM_connection_error_x(c[i], &errmsg, &addinfo, &dset)))
376 printf("%s error: %s (%s:%d) %s\n",
377 ZOOM_connection_option_get(c[i], "host"), errmsg,
378 dset, error, addinfo);
381 /* OK, no major errors. Look at the result count */
382 int start = ZOOM_options_get_int(options, "start", 0);
383 int count = ZOOM_options_get_int(options, "count", 0);
385 printf("%s: %ld hits\n", ZOOM_connection_option_get(c[i], "host"),
386 (long) ZOOM_resultset_size(r[i]));
388 display_records(c[i], r[i], start, count, "render");
393 static void cmd_scan(ZOOM_connection *c, ZOOM_resultset *r,
394 ZOOM_options options,
397 const char *query_str = *args;
398 ZOOM_query query = ZOOM_query_create();
400 ZOOM_scanset s[MAX_CON];
402 while (*query_str == ' ')
405 if (memcmp(query_str, "cql:", 4) == 0)
407 ZOOM_query_cql(query, query_str + 4);
409 else if (ZOOM_query_prefix(query, query_str))
411 printf("Bad PQF: %s\n", query_str);
415 for (i = 0; i<MAX_CON; i++)
418 s[i] = ZOOM_connection_scan1(c[i], query);
422 ZOOM_query_destroy(query);
424 while (ZOOM_event(MAX_CON, c))
426 for (i = 0; i<MAX_CON; i++)
429 const char *errmsg, *addinfo, *dset;
430 /* display errors if any */
433 if ((error = ZOOM_connection_error_x(c[i], &errmsg, &addinfo, &dset)))
434 printf("%s error: %s (%s:%d) %s\n",
435 ZOOM_connection_option_get(c[i], "host"), errmsg,
436 dset, error, addinfo);
439 size_t p, sz = ZOOM_scanset_size(s[i]);
440 for (p = 0; p < sz; p++)
444 const char *term = ZOOM_scanset_display_term(s[i], p,
447 printf("%.*s %d\n", len, term, occ);
449 ZOOM_scanset_destroy(s[i]);
454 static void cmd_sort(ZOOM_connection *c, ZOOM_resultset *r,
455 ZOOM_options options,
458 const char *sort_spec = *args;
461 while (*sort_spec == ' ')
464 for (i = 0; i<MAX_CON; i++)
467 ZOOM_resultset_sort(r[i], "yaz", sort_spec);
469 while (ZOOM_event(MAX_CON, c))
473 static void cmd_help(ZOOM_connection *c, ZOOM_resultset *r,
474 ZOOM_options options,
477 printf("connect <zurl>\n");
478 printf("search <pqf>\n");
479 printf("show [<start> [<count> [<type]]]\n");
480 printf("scan <term>\n");
482 printf("close <zurl>\n");
483 printf("ext <type>\n");
484 printf("set <option> [<value>]\n");
485 printf("get <option>\n");
487 printf("options:\n");
490 printf(" databaseName\n");
491 printf(" preferredRecordSyntax\n");
493 printf(" elementSetName\n");
494 printf(" maximumRecordSize\n");
495 printf(" preferredRecordSize\n");
497 printf(" piggyback\n");
500 printf(" password\n");
501 printf(" implementationName\n");
502 printf(" charset\n");
506 static void cmd_connect(ZOOM_connection *c, ZOOM_resultset *r,
507 ZOOM_options options,
511 const char *errmsg, *addinfo, *dset;
514 if (next_token_copy(args, host, sizeof(host)) < 0)
516 printf("missing host after connect\n");
519 for (j = -1, i = 0; i<MAX_CON; i++)
522 if (c[i] && (h = ZOOM_connection_option_get(c[i], "host")) &&
525 ZOOM_connection_destroy(c[i]);
528 else if (c[i] == 0 && j == -1)
531 if (i == MAX_CON) /* no match .. */
535 printf("no more connection available\n");
538 i = j; /* OK, use this one is available */
540 c[i] = ZOOM_connection_create(options);
541 ZOOM_connection_connect(c[i], host, 0);
543 if ((error = ZOOM_connection_error_x(c[i], &errmsg, &addinfo, &dset)))
544 printf("%s error: %s (%s:%d) %s\n",
545 ZOOM_connection_option_get(c[i], "host"), errmsg,
546 dset, error, addinfo);
549 static int cmd_parse(ZOOM_connection *c, ZOOM_resultset *r,
550 ZOOM_options options,
556 cmd_len = next_token(buf, &cmd_str);
559 if (is_command("quit", cmd_str, cmd_len))
561 else if (is_command("set", cmd_str, cmd_len))
562 cmd_set(c, r, options, buf);
563 else if (is_command("get", cmd_str, cmd_len))
564 cmd_get(c, r, options, buf);
565 else if (is_command("rget", cmd_str, cmd_len))
566 cmd_rget(c, r, options, buf);
567 else if (is_command("connect", cmd_str, cmd_len))
568 cmd_connect(c, r, options, buf);
569 else if (is_command("open", cmd_str, cmd_len))
570 cmd_connect(c, r, options, buf);
571 else if (is_command("search", cmd_str, cmd_len))
572 cmd_search(c, r, options, buf);
573 else if (is_command("find", cmd_str, cmd_len))
574 cmd_search(c, r, options, buf);
575 else if (is_command("show", cmd_str, cmd_len))
576 cmd_show(c, r, options, buf);
577 else if (is_command("close", cmd_str, cmd_len))
578 cmd_close(c, r, options, buf);
579 else if (is_command("help", cmd_str, cmd_len))
580 cmd_help(c, r, options, buf);
581 else if (is_command("ext", cmd_str, cmd_len))
582 cmd_ext(c, r, options, buf);
583 else if (is_command("debug", cmd_str, cmd_len))
584 cmd_debug(c, r, options, buf);
585 else if (is_command("scan", cmd_str, cmd_len))
586 cmd_scan(c, r, options, buf);
587 else if (is_command("sort", cmd_str, cmd_len))
588 cmd_sort(c, r, options, buf);
590 printf("unknown command %.*s\n", cmd_len, cmd_str);
594 void shell(ZOOM_connection *c, ZOOM_resultset *r,
595 ZOOM_options options)
601 const char *bp = buf;
602 #if HAVE_READLINE_READLINE_H
604 line_in=readline("ZOOM>");
607 #if HAVE_READLINE_HISTORY_H
609 add_history(line_in);
611 if(strlen(line_in) > 999) {
612 printf("Input line too long\n");
618 printf("ZOOM>"); fflush(stdout);
619 if (!fgets(buf, 999, stdin))
622 if ((cp = strchr(buf, '\n')))
624 if (!cmd_parse(c, r, options, &bp))
629 static void zoomsh(int argc, char **argv)
631 ZOOM_options options = ZOOM_options_create();
633 ZOOM_connection z39_con[MAX_CON];
634 ZOOM_resultset z39_res[MAX_CON];
636 for (i = 0; i<MAX_CON; i++)
642 for (i = 0; i<MAX_CON; i++)
646 for (i = 1; i<argc; i++)
648 const char *bp = argv[i];
649 res = cmd_parse(z39_con, z39_res, options, &bp);
650 if (res == 0) /* received quit */
653 if (res) /* do cmdline shell only if not quitting */
654 shell(z39_con, z39_res, options);
655 ZOOM_options_destroy(options);
657 for (i = 0; i<MAX_CON; i++)
659 ZOOM_connection_destroy(z39_con[i]);
660 ZOOM_resultset_destroy(z39_res[i]);
664 int main(int argc, char **argv)
666 const char *maskstr = 0;
667 if (argc > 2 && !strcmp(argv[1], "-v"))
673 else if (argc > 1 && !strncmp(argv[1], "-v", 2))
681 int mask = yaz_log_mask_str(maskstr);
682 yaz_log_init_level(mask);
690 * c-file-style: "Stroustrup"
691 * indent-tabs-mode: nil
693 * vim: shiftwidth=4 tabstop=8 expandtab