1 /* This file is part of the YAZ toolkit.
2 * Copyright (C) 1995-2010 Index Data
3 * See the file LICENSE for details.
7 \brief ZOOM C command line tool (shell)
15 #if HAVE_READLINE_READLINE_H
16 #include <readline/readline.h>
18 #if HAVE_READLINE_HISTORY_H
19 #include <readline/history.h>
27 static int next_token(const char **cpp, const char **t_start)
30 const char *cp = *cpp;
37 while (*cp && *cp != '"')
48 while (*cp && *cp != ' ' && *cp != '\r' && *cp != '\n')
57 return len; /* return -1 if no token was read .. */
60 static int next_token_copy(const char **cpp, char *buf_out, int buf_max)
63 int len = next_token(cpp, &start);
71 memcpy(buf_out, start, len);
76 static int is_command(const char *cmd_str, const char *this_str, int this_len)
78 int cmd_len = strlen(cmd_str);
79 if (cmd_len != this_len)
81 if (memcmp(cmd_str, this_str, cmd_len))
86 static void cmd_set(ZOOM_connection *c, ZOOM_resultset *r,
90 char key[40], val[80];
92 if (next_token_copy(args, key, sizeof(key)) < 0)
94 printf("missing argument for set\n");
97 if (next_token_copy(args, val, sizeof(val)) < 0)
98 ZOOM_options_set(options, key, 0);
100 ZOOM_options_set(options, key, val);
103 static void cmd_get(ZOOM_connection *c, ZOOM_resultset *r,
104 ZOOM_options options,
108 if (next_token_copy(args, key, sizeof(key)) < 0)
110 printf("missing argument for get\n");
114 const char *val = ZOOM_options_get(options, key);
115 printf("%s = %s\n", key, val ? val : "<null>");
119 static void cmd_rget(ZOOM_connection *c, ZOOM_resultset *r,
120 ZOOM_options options,
124 if (next_token_copy(args, key, sizeof(key)) < 0)
126 printf("missing argument for get\n");
131 for (i = 0; i<MAX_CON; i++)
137 val = ZOOM_resultset_option_get(r[i], key);
138 printf("%s = %s\n", key, val ? val : "<null>");
143 static void cmd_close(ZOOM_connection *c, ZOOM_resultset *r,
144 ZOOM_options options,
149 next_token_copy(args, host, sizeof(host));
150 for (i = 0; i<MAX_CON; i++)
155 if ((h = ZOOM_connection_option_get(c[i], "host"))
158 ZOOM_connection_destroy(c[i]);
161 else if (*host == '\0')
163 ZOOM_connection_destroy(c[i]);
169 static void display_records(ZOOM_connection c,
171 size_t start, size_t count, const char *type)
174 for (i = 0; i < count; i++)
176 size_t pos = i + start;
177 ZOOM_record rec = ZOOM_resultset_record(r, pos);
178 const char *db = ZOOM_record_get(rec, "database", 0);
180 if (ZOOM_record_error(rec, 0, 0, 0))
185 int error = ZOOM_record_error(rec, &msg, &addinfo, &diagset);
187 printf("%lld %s: %s (%s:%d) %s\n", (long long) pos,
188 (db ? db : "unknown"),
189 msg, diagset, error, addinfo ? addinfo : "none");
194 const char *render = ZOOM_record_get(rec, type, &len);
195 const char *opac_render = ZOOM_record_get(rec, "opac", &opac_len);
196 const char *syntax = ZOOM_record_get(rec, "syntax", 0);
197 const char *schema = ZOOM_record_get(rec, "schema", 0);
198 /* if rec is non-null, we got a record for display */
201 printf("%lld database=%s syntax=%s schema=%s\n",
202 (long long) pos, (db ? db : "unknown"), syntax,
203 schema ? schema : "unknown");
206 if (fwrite(render, 1, len, stdout) != (size_t) len)
208 printf("write to stdout failed\n");
214 if (fwrite(opac_render, 1, opac_len, stdout) != (size_t)
216 printf("write to stdout failed\n");
223 static void cmd_show(ZOOM_connection *c, ZOOM_resultset *r,
224 ZOOM_options options,
228 size_t start = 0, count = 1;
229 const char *type = "render";
233 char start_str[30], count_str[30];
234 if (next_token_copy(args, start_str, sizeof(start_str)) > 0)
235 start = atoi(start_str);
237 if (next_token_copy(args, count_str, sizeof(count_str)) > 0)
238 count = atoi(count_str);
240 if (next_token_copy(args, render_str, sizeof(render_str)) > 0)
244 for (i = 0; i < MAX_CON; i++)
245 ZOOM_resultset_records(r[i], 0, start, count);
246 while (ZOOM_event(MAX_CON, c))
249 for (i = 0; i < MAX_CON; i++)
252 const char *errmsg, *addinfo, *dset;
253 /* display errors if any */
256 if ((error = ZOOM_connection_error_x(c[i], &errmsg, &addinfo, &dset)))
257 printf("%s error: %s (%s:%d) %s\n",
258 ZOOM_connection_option_get(c[i], "host"), errmsg,
259 dset, error, addinfo);
262 /* OK, no major errors. Display records... */
263 display_records(c[i], r[i], start, count, type);
268 static void cmd_ext(ZOOM_connection *c, ZOOM_resultset *r,
269 ZOOM_options options,
272 ZOOM_package p[MAX_CON];
273 char ext_type_str[10];
277 if (next_token_copy(args, ext_type_str, sizeof(ext_type_str)) < 0)
280 for (i = 0; i<MAX_CON; i++)
284 p[i] = ZOOM_connection_package(c[i], 0);
285 ZOOM_package_send(p[i], ext_type_str);
291 while (ZOOM_event(MAX_CON, c))
294 for (i = 0; i<MAX_CON; i++)
297 const char *errmsg, *addinfo, *dset;
298 /* display errors if any */
301 if ((error = ZOOM_connection_error_x(c[i], &errmsg, &addinfo, &dset)))
302 printf("%s error: %s (%s:%d) %s\n",
303 ZOOM_connection_option_get(c[i], "host"), errmsg,
304 dset, error, addinfo);
309 v = ZOOM_package_option_get(p[i], "targetReference");
311 printf("targetReference: %s\n", v);
312 v = ZOOM_package_option_get(p[i], "xmlUpdateDoc");
314 printf("xmlUpdateDoc: %s\n", v);
316 ZOOM_package_destroy(p[i]);
320 static void cmd_debug(ZOOM_connection *c, ZOOM_resultset *r,
321 ZOOM_options options,
324 yaz_log_init_level(YLOG_ALL);
327 static void cmd_search(ZOOM_connection *c, ZOOM_resultset *r,
328 ZOOM_options options,
332 const char *query_str = *args;
335 s = ZOOM_query_create();
336 while (*query_str == ' ')
338 if (memcmp(query_str, "cql:", 4) == 0)
340 ZOOM_query_cql(s, query_str + 4);
342 else if (ZOOM_query_prefix(s, query_str))
344 printf("Bad PQF: %s\n", query_str);
347 for (i = 0; i<MAX_CON; i++)
352 ZOOM_resultset_destroy(r[i]);
356 r[i] = ZOOM_connection_search(c[i], s);
358 ZOOM_query_destroy(s);
360 while (ZOOM_event(MAX_CON, c))
363 for (i = 0; i<MAX_CON; i++)
366 const char *errmsg, *addinfo, *dset;
367 /* display errors if any */
370 if ((error = ZOOM_connection_error_x(c[i], &errmsg, &addinfo, &dset)))
371 printf("%s error: %s (%s:%d) %s\n",
372 ZOOM_connection_option_get(c[i], "host"), errmsg,
373 dset, error, addinfo);
376 /* OK, no major errors. Look at the result count */
377 int start = ZOOM_options_get_int(options, "start", 0);
378 int count = ZOOM_options_get_int(options, "count", 0);
380 printf("%s: %lld hits\n", ZOOM_connection_option_get(c[i], "host"),
381 (long long int) ZOOM_resultset_size(r[i]));
383 display_records(c[i], r[i], start, count, "render");
388 static void cmd_scan(ZOOM_connection *c, ZOOM_resultset *r,
389 ZOOM_options options,
392 const char *query_str = *args;
393 ZOOM_query query = ZOOM_query_create();
395 ZOOM_scanset s[MAX_CON];
397 while (*query_str == ' ')
400 if (memcmp(query_str, "cql:", 4) == 0)
402 ZOOM_query_cql(query, query_str + 4);
404 else if (ZOOM_query_prefix(query, query_str))
406 printf("Bad PQF: %s\n", query_str);
410 for (i = 0; i<MAX_CON; i++)
413 s[i] = ZOOM_connection_scan1(c[i], query);
417 ZOOM_query_destroy(query);
419 while (ZOOM_event(MAX_CON, c))
421 for (i = 0; i<MAX_CON; i++)
424 const char *errmsg, *addinfo, *dset;
425 /* display errors if any */
428 if ((error = ZOOM_connection_error_x(c[i], &errmsg, &addinfo, &dset)))
429 printf("%s error: %s (%s:%d) %s\n",
430 ZOOM_connection_option_get(c[i], "host"), errmsg,
431 dset, error, addinfo);
434 size_t p, sz = ZOOM_scanset_size(s[i]);
435 for (p = 0; p < sz; p++)
439 const char *term = ZOOM_scanset_display_term(s[i], p,
441 printf("%.*s %lld\n", (int) len, term, (long long int) occ);
443 ZOOM_scanset_destroy(s[i]);
448 static void cmd_sort(ZOOM_connection *c, ZOOM_resultset *r,
449 ZOOM_options options,
452 const char *sort_spec = *args;
455 while (*sort_spec == ' ')
458 for (i = 0; i<MAX_CON; i++)
461 ZOOM_resultset_sort(r[i], "yaz", sort_spec);
463 while (ZOOM_event(MAX_CON, c))
467 static void cmd_help(ZOOM_connection *c, ZOOM_resultset *r,
468 ZOOM_options options,
471 printf("connect <zurl>\n");
472 printf("search <pqf>\n");
473 printf("show [<start> [<count> [<type]]]\n");
474 printf("scan <term>\n");
476 printf("close <zurl>\n");
477 printf("ext <type>\n");
478 printf("set <option> [<value>]\n");
479 printf("get <option>\n");
481 printf("options:\n");
484 printf(" databaseName\n");
485 printf(" preferredRecordSyntax\n");
487 printf(" elementSetName\n");
488 printf(" maximumRecordSize\n");
489 printf(" preferredRecordSize\n");
491 printf(" piggyback\n");
494 printf(" password\n");
495 printf(" implementationName\n");
496 printf(" charset\n");
498 printf(" timeout\n");
501 static void cmd_connect(ZOOM_connection *c, ZOOM_resultset *r,
502 ZOOM_options options,
506 const char *errmsg, *addinfo, *dset;
509 if (next_token_copy(args, host, sizeof(host)) < 0)
511 printf("missing host after connect\n");
514 for (j = -1, i = 0; i<MAX_CON; i++)
517 if (c[i] && (h = ZOOM_connection_option_get(c[i], "host")) &&
520 ZOOM_connection_destroy(c[i]);
523 else if (c[i] == 0 && j == -1)
526 if (i == MAX_CON) /* no match .. */
530 printf("no more connection available\n");
533 i = j; /* OK, use this one is available */
535 c[i] = ZOOM_connection_create(options);
536 ZOOM_connection_connect(c[i], host, 0);
538 if ((error = ZOOM_connection_error_x(c[i], &errmsg, &addinfo, &dset)))
539 printf("%s error: %s (%s:%d) %s\n",
540 ZOOM_connection_option_get(c[i], "host"), errmsg,
541 dset, error, addinfo);
544 static int cmd_parse(ZOOM_connection *c, ZOOM_resultset *r,
545 ZOOM_options options,
551 cmd_len = next_token(buf, &cmd_str);
554 if (is_command("quit", cmd_str, cmd_len))
556 else if (is_command("set", cmd_str, cmd_len))
557 cmd_set(c, r, options, buf);
558 else if (is_command("get", cmd_str, cmd_len))
559 cmd_get(c, r, options, buf);
560 else if (is_command("rget", cmd_str, cmd_len))
561 cmd_rget(c, r, options, buf);
562 else if (is_command("connect", cmd_str, cmd_len))
563 cmd_connect(c, r, options, buf);
564 else if (is_command("open", cmd_str, cmd_len))
565 cmd_connect(c, r, options, buf);
566 else if (is_command("search", cmd_str, cmd_len))
567 cmd_search(c, r, options, buf);
568 else if (is_command("find", cmd_str, cmd_len))
569 cmd_search(c, r, options, buf);
570 else if (is_command("show", cmd_str, cmd_len))
571 cmd_show(c, r, options, buf);
572 else if (is_command("close", cmd_str, cmd_len))
573 cmd_close(c, r, options, buf);
574 else if (is_command("help", cmd_str, cmd_len))
575 cmd_help(c, r, options, buf);
576 else if (is_command("ext", cmd_str, cmd_len))
577 cmd_ext(c, r, options, buf);
578 else if (is_command("debug", cmd_str, cmd_len))
579 cmd_debug(c, r, options, buf);
580 else if (is_command("scan", cmd_str, cmd_len))
581 cmd_scan(c, r, options, buf);
582 else if (is_command("sort", cmd_str, cmd_len))
583 cmd_sort(c, r, options, buf);
585 printf("unknown command %.*s\n", cmd_len, cmd_str);
589 void shell(ZOOM_connection *c, ZOOM_resultset *r,
590 ZOOM_options options)
596 const char *bp = buf;
597 #if HAVE_READLINE_READLINE_H
599 line_in=readline("ZOOM>");
602 #if HAVE_READLINE_HISTORY_H
604 add_history(line_in);
606 if(strlen(line_in) > 999) {
607 printf("Input line too long\n");
613 printf("ZOOM>"); fflush(stdout);
614 if (!fgets(buf, 999, stdin))
617 if ((cp = strchr(buf, '\n')))
619 if (!cmd_parse(c, r, options, &bp))
624 static void zoomsh(int argc, char **argv)
626 ZOOM_options options = ZOOM_options_create();
628 ZOOM_connection z39_con[MAX_CON];
629 ZOOM_resultset z39_res[MAX_CON];
631 for (i = 0; i<MAX_CON; i++)
637 for (i = 0; i<MAX_CON; i++)
641 for (i = 1; i<argc; i++)
643 const char *bp = argv[i];
644 res = cmd_parse(z39_con, z39_res, options, &bp);
645 if (res == 0) /* received quit */
648 if (res) /* do cmdline shell only if not quitting */
649 shell(z39_con, z39_res, options);
650 ZOOM_options_destroy(options);
652 for (i = 0; i<MAX_CON; i++)
654 ZOOM_connection_destroy(z39_con[i]);
655 ZOOM_resultset_destroy(z39_res[i]);
659 int main(int argc, char **argv)
661 const char *maskstr = 0;
662 if (argc > 2 && !strcmp(argv[1], "-v"))
668 else if (argc > 1 && !strncmp(argv[1], "-v", 2))
676 int mask = yaz_log_mask_str(maskstr);
677 yaz_log_init_level(mask);
685 * c-file-style: "Stroustrup"
686 * indent-tabs-mode: nil
688 * vim: shiftwidth=4 tabstop=8 expandtab