2 * Copyright (C) 1995-2007, Index Data ApS
3 * See the file LICENSE for details.
5 * $Id: zoomsh.c,v 1.48 2007-08-16 10:09:37 adam Exp $
9 \brief ZOOM C command line tool (shell)
17 #include <yaz/comstack.h>
19 #if HAVE_READLINE_READLINE_H
20 #include <readline/readline.h>
22 #if HAVE_READLINE_HISTORY_H
23 #include <readline/history.h>
26 #include <yaz/xmalloc.h>
34 static int next_token(const char **cpp, const char **t_start)
37 const char *cp = *cpp;
44 while (*cp && *cp != '"')
55 while (*cp && *cp != ' ' && *cp != '\r' && *cp != '\n')
64 return len; /* return -1 if no token was read .. */
67 static int next_token_copy(const char **cpp, char *buf_out, int buf_max)
70 int len = next_token(cpp, &start);
78 memcpy(buf_out, start, len);
83 static int is_command(const char *cmd_str, const char *this_str, int this_len)
85 int cmd_len = strlen(cmd_str);
86 if (cmd_len != this_len)
88 if (memcmp(cmd_str, this_str, cmd_len))
93 static void cmd_set(ZOOM_connection *c, ZOOM_resultset *r,
97 char key[40], val[80];
99 if (next_token_copy(args, key, sizeof(key)) < 0)
101 printf("missing argument for set\n");
104 if (next_token_copy(args, val, sizeof(val)) < 0)
105 ZOOM_options_set(options, key, 0);
107 ZOOM_options_set(options, key, val);
110 static void cmd_get(ZOOM_connection *c, ZOOM_resultset *r,
111 ZOOM_options options,
115 if (next_token_copy(args, key, sizeof(key)) < 0)
117 printf("missing argument for get\n");
121 const char *val = ZOOM_options_get(options, key);
122 printf("%s = %s\n", key, val ? val : "<null>");
126 static void cmd_rget(ZOOM_connection *c, ZOOM_resultset *r,
127 ZOOM_options options,
131 if (next_token_copy(args, key, sizeof(key)) < 0)
133 printf("missing argument for get\n");
138 for (i = 0; i<MAX_CON; i++)
144 val = ZOOM_resultset_option_get(r[i], key);
145 printf("%s = %s\n", key, val ? val : "<null>");
150 static void cmd_close(ZOOM_connection *c, ZOOM_resultset *r,
151 ZOOM_options options,
156 next_token_copy(args, host, sizeof(host));
157 for (i = 0; i<MAX_CON; i++)
162 if ((h = ZOOM_connection_option_get(c[i], "host"))
165 ZOOM_connection_destroy(c[i]);
168 else if (*host == '\0')
170 ZOOM_connection_destroy(c[i]);
176 static void display_records(ZOOM_connection c,
178 int start, int count)
181 for (i = 0; i<count; i++)
184 ZOOM_record rec = ZOOM_resultset_record(r, pos);
185 const char *db = ZOOM_record_get(rec, "database", 0);
187 if (ZOOM_record_error(rec, 0, 0, 0))
192 int error = ZOOM_record_error(rec, &msg, &addinfo, &diagset);
194 printf("%d %s: %s (%s:%d) %s\n", pos, (db ? db : "unknown"),
195 msg, diagset, error, addinfo);
200 const char *render = ZOOM_record_get(rec, "render", &len);
201 const char *opac_render = ZOOM_record_get(rec, "opac", &opac_len);
202 const char *syntax = ZOOM_record_get(rec, "syntax", 0);
203 /* if rec is non-null, we got a record for display */
207 pos, (db ? db : "unknown"), syntax);
209 fwrite(render, 1, len, stdout);
212 fwrite(opac_render, 1, opac_len, stdout);
219 static void cmd_show(ZOOM_connection *c, ZOOM_resultset *r,
220 ZOOM_options options,
224 char start_str[10], count_str[10];
226 if (next_token_copy(args, start_str, sizeof(start_str)) >= 0)
227 ZOOM_options_set(options, "start", start_str);
229 if (next_token_copy(args, count_str, sizeof(count_str)) >= 0)
230 ZOOM_options_set(options, "count", count_str);
232 for (i = 0; i<MAX_CON; i++)
233 ZOOM_resultset_records(r[i], 0, atoi(start_str), atoi(count_str));
234 while (ZOOM_event(MAX_CON, c))
237 for (i = 0; i<MAX_CON; i++)
240 const char *errmsg, *addinfo, *dset;
241 /* display errors if any */
244 if ((error = ZOOM_connection_error_x(c[i], &errmsg, &addinfo, &dset)))
245 printf("%s error: %s (%s:%d) %s\n",
246 ZOOM_connection_option_get(c[i], "host"), errmsg,
247 dset, error, addinfo);
250 /* OK, no major errors. Display records... */
251 int start = ZOOM_options_get_int(options, "start", 0);
252 int count = ZOOM_options_get_int(options, "count", 0);
253 display_records(c[i], r[i], start, count);
256 ZOOM_options_set(options, "count", "0");
257 ZOOM_options_set(options, "start", "0");
260 static void cmd_ext(ZOOM_connection *c, ZOOM_resultset *r,
261 ZOOM_options options,
264 ZOOM_package p[MAX_CON];
265 char ext_type_str[10];
269 if (next_token_copy(args, ext_type_str, sizeof(ext_type_str)) < 0)
272 for (i = 0; i<MAX_CON; i++)
276 p[i] = ZOOM_connection_package(c[i], 0);
277 ZOOM_package_send(p[i], ext_type_str);
283 while (ZOOM_event(MAX_CON, c))
286 for (i = 0; i<MAX_CON; i++)
289 const char *errmsg, *addinfo, *dset;
290 /* display errors if any */
293 if ((error = ZOOM_connection_error_x(c[i], &errmsg, &addinfo, &dset)))
294 printf("%s error: %s (%s:%d) %s\n",
295 ZOOM_connection_option_get(c[i], "host"), errmsg,
296 dset, error, addinfo);
301 v = ZOOM_package_option_get(p[i], "targetReference");
303 printf("targetReference: %s\n", v);
304 v = ZOOM_package_option_get(p[i], "xmlUpdateDoc");
306 printf("xmlUpdateDoc: %s\n", v);
308 ZOOM_package_destroy(p[i]);
312 static void cmd_debug(ZOOM_connection *c, ZOOM_resultset *r,
313 ZOOM_options options,
316 yaz_log_init_level(YLOG_ALL);
319 static void cmd_search(ZOOM_connection *c, ZOOM_resultset *r,
320 ZOOM_options options,
324 const char *query_str = *args;
327 s = ZOOM_query_create();
328 while (*query_str == ' ')
330 if (memcmp(query_str, "cql:", 4) == 0)
332 ZOOM_query_cql(s, query_str + 4);
334 else if (ZOOM_query_prefix(s, query_str))
336 printf("Bad PQF: %s\n", query_str);
339 for (i = 0; i<MAX_CON; i++)
344 ZOOM_resultset_destroy(r[i]);
348 r[i] = ZOOM_connection_search(c[i], s);
350 ZOOM_query_destroy(s);
352 while (ZOOM_event(MAX_CON, c))
355 for (i = 0; i<MAX_CON; i++)
358 const char *errmsg, *addinfo, *dset;
359 /* display errors if any */
362 if ((error = ZOOM_connection_error_x(c[i], &errmsg, &addinfo, &dset)))
363 printf("%s error: %s (%s:%d) %s\n",
364 ZOOM_connection_option_get(c[i], "host"), errmsg,
365 dset, error, addinfo);
368 /* OK, no major errors. Look at the result count */
369 int start = ZOOM_options_get_int(options, "start", 0);
370 int count = ZOOM_options_get_int(options, "count", 0);
372 printf("%s: %ld hits\n", ZOOM_connection_option_get(c[i], "host"),
373 (long) ZOOM_resultset_size(r[i]));
375 display_records(c[i], r[i], start, count);
380 static void cmd_scan(ZOOM_connection *c, ZOOM_resultset *r,
381 ZOOM_options options,
384 const char *query_str = *args;
385 ZOOM_query query = ZOOM_query_create();
387 ZOOM_scanset s[MAX_CON];
389 while (*query_str == ' ')
392 if (memcmp(query_str, "cql:", 4) == 0)
394 ZOOM_query_cql(query, query_str + 4);
396 else if (ZOOM_query_prefix(query, query_str))
398 printf("Bad PQF: %s\n", query_str);
402 for (i = 0; i<MAX_CON; i++)
405 s[i] = ZOOM_connection_scan1(c[i], query);
409 ZOOM_query_destroy(query);
411 while (ZOOM_event(MAX_CON, c))
413 for (i = 0; i<MAX_CON; i++)
416 const char *errmsg, *addinfo, *dset;
417 /* display errors if any */
420 if ((error = ZOOM_connection_error_x(c[i], &errmsg, &addinfo, &dset)))
421 printf("%s error: %s (%s:%d) %s\n",
422 ZOOM_connection_option_get(c[i], "host"), errmsg,
423 dset, error, addinfo);
426 size_t p, sz = ZOOM_scanset_size(s[i]);
427 for (p = 0; p < sz; p++)
431 const char *term = ZOOM_scanset_display_term(s[i], p,
433 fwrite(term, 1, len, stdout);
434 printf(" %d\n", occ);
436 ZOOM_scanset_destroy(s[i]);
441 static void cmd_sort(ZOOM_connection *c, ZOOM_resultset *r,
442 ZOOM_options options,
445 const char *sort_spec = *args;
448 while (*sort_spec == ' ')
451 for (i = 0; i<MAX_CON; i++)
454 ZOOM_resultset_sort(r[i], "yaz", sort_spec);
456 while (ZOOM_event(MAX_CON, c))
460 static void cmd_help(ZOOM_connection *c, ZOOM_resultset *r,
461 ZOOM_options options,
464 printf("connect <zurl>\n");
465 printf("search <pqf>\n");
466 printf("show [<start> [<count>]\n");
467 printf("scan <term>\n");
469 printf("close <zurl>\n");
470 printf("ext <type>\n");
471 printf("set <option> [<value>]\n");
472 printf("get <option>\n");
474 printf("options:\n");
477 printf(" databaseName\n");
478 printf(" preferredRecordSyntax\n");
480 printf(" elementSetName\n");
481 printf(" maximumRecordSize\n");
482 printf(" preferredRecordSize\n");
484 printf(" piggyback\n");
487 printf(" password\n");
488 printf(" implementationName\n");
489 printf(" charset\n");
493 static void cmd_connect(ZOOM_connection *c, ZOOM_resultset *r,
494 ZOOM_options options,
498 const char *errmsg, *addinfo, *dset;
501 if (next_token_copy(args, host, sizeof(host)) < 0)
503 printf("missing host after connect\n");
506 for (j = -1, i = 0; i<MAX_CON; i++)
509 if (c[i] && (h = ZOOM_connection_option_get(c[i], "host")) &&
512 ZOOM_connection_destroy(c[i]);
515 else if (c[i] == 0 && j == -1)
518 if (i == MAX_CON) /* no match .. */
522 printf("no more connection available\n");
525 i = j; /* OK, use this one is available */
527 c[i] = ZOOM_connection_create(options);
528 ZOOM_connection_connect(c[i], host, 0);
530 if ((error = ZOOM_connection_error_x(c[i], &errmsg, &addinfo, &dset)))
531 printf("%s error: %s (%s:%d) %s\n",
532 ZOOM_connection_option_get(c[i], "host"), errmsg,
533 dset, error, addinfo);
536 static int cmd_parse(ZOOM_connection *c, ZOOM_resultset *r,
537 ZOOM_options options,
543 cmd_len = next_token(buf, &cmd_str);
546 if (is_command("quit", cmd_str, cmd_len))
548 else if (is_command("set", cmd_str, cmd_len))
549 cmd_set(c, r, options, buf);
550 else if (is_command("get", cmd_str, cmd_len))
551 cmd_get(c, r, options, buf);
552 else if (is_command("rget", cmd_str, cmd_len))
553 cmd_rget(c, r, options, buf);
554 else if (is_command("connect", cmd_str, cmd_len))
555 cmd_connect(c, r, options, buf);
556 else if (is_command("open", cmd_str, cmd_len))
557 cmd_connect(c, r, options, buf);
558 else if (is_command("search", cmd_str, cmd_len))
559 cmd_search(c, r, options, buf);
560 else if (is_command("find", cmd_str, cmd_len))
561 cmd_search(c, r, options, buf);
562 else if (is_command("show", cmd_str, cmd_len))
563 cmd_show(c, r, options, buf);
564 else if (is_command("close", cmd_str, cmd_len))
565 cmd_close(c, r, options, buf);
566 else if (is_command("help", cmd_str, cmd_len))
567 cmd_help(c, r, options, buf);
568 else if (is_command("ext", cmd_str, cmd_len))
569 cmd_ext(c, r, options, buf);
570 else if (is_command("debug", cmd_str, cmd_len))
571 cmd_debug(c, r, options, buf);
572 else if (is_command("scan", cmd_str, cmd_len))
573 cmd_scan(c, r, options, buf);
574 else if (is_command("sort", cmd_str, cmd_len))
575 cmd_sort(c, r, options, buf);
577 printf("unknown command %.*s\n", cmd_len, cmd_str);
581 void shell(ZOOM_connection *c, ZOOM_resultset *r,
582 ZOOM_options options)
588 const char *bp = buf;
589 #if HAVE_READLINE_READLINE_H
591 line_in=readline("ZOOM>");
594 #if HAVE_READLINE_HISTORY_H
596 add_history(line_in);
598 if(strlen(line_in) > 999) {
599 printf("Input line too long\n");
605 printf("ZOOM>"); fflush(stdout);
606 if (!fgets(buf, 999, stdin))
609 if ((cp = strchr(buf, '\n')))
611 if (!cmd_parse(c, r, options, &bp))
616 static void zoomsh(int argc, char **argv)
618 ZOOM_options options = ZOOM_options_create();
620 ZOOM_connection z39_con[MAX_CON];
621 ZOOM_resultset z39_res[MAX_CON];
623 for (i = 0; i<MAX_CON; i++)
629 for (i = 0; i<MAX_CON; i++)
633 for (i = 1; i<argc; i++)
635 const char *bp = argv[i];
636 res = cmd_parse(z39_con, z39_res, options, &bp);
637 if (res == 0) /* received quit */
640 if (res) /* do cmdline shell only if not quitting */
641 shell(z39_con, z39_res, options);
642 ZOOM_options_destroy(options);
644 for (i = 0; i<MAX_CON; i++)
646 ZOOM_connection_destroy(z39_con[i]);
647 ZOOM_resultset_destroy(z39_res[i]);
651 int main(int argc, char **argv)
653 const char *maskstr = 0;
654 if (argc > 2 && !strcmp(argv[1], "-v"))
660 else if (argc > 1 && !strncmp(argv[1], "-v", 2))
668 int mask = yaz_log_mask_str(maskstr);
669 yaz_log_init_level(mask);
677 * indent-tabs-mode: nil
679 * vim: shiftwidth=4 tabstop=8 expandtab