+int cmd_wait_response(const char *arg)
+{
+ int wait_for = atoi(arg);
+ int i=0;
+ if( wait_for < 1 ) {
+ wait_for = 1;
+ };
+
+ for( i=0 ; i < wait_for ; ++i ) {
+ wait_and_handle_response(1);
+ };
+ return 0;
+}
+
+static int cmd_help(const char *line);
+
+typedef char *(*completerFunctionType)(const char *text, int state);
+
+static struct {
+ char *cmd;
+ int (*fun)(const char *arg);
+ char *ad;
+ completerFunctionType rl_completerfunction;
+ int complete_filenames;
+ const char **local_tabcompletes;
+} cmd_array[] = {
+ {"open", cmd_open, "('tcp'|'ssl')':<host>[':'<port>][/<db>]",NULL,0,NULL},
+ {"quit", cmd_quit, "",NULL,0,NULL},
+ {"find", cmd_find, "<query>",NULL,0,NULL},
+ {"delete", cmd_delete, "<setname>",NULL,0,NULL},
+ {"base", cmd_base, "<base-name>",NULL,0,NULL},
+ {"show", cmd_show, "<rec#>['+'<#recs>['+'<setname>]]",NULL,0,NULL},
+ {"setscan", cmd_setscan, "<term>",NULL,0,NULL},
+ {"scan", cmd_scan, "<term>",NULL,0,NULL},
+ {"scanstep", cmd_scanstep, "<size>",NULL,0,NULL},
+ {"scanpos", cmd_scanpos, "<size>",NULL,0,NULL},
+ {"scansize", cmd_scansize, "<size>",NULL,0,NULL},
+ {"sort", cmd_sort, "<sortkey> <flag> <sortkey> <flag> ...",NULL,0,NULL},
+ {"sort+", cmd_sort_newset, "<sortkey> <flag> <sortkey> <flag> ...",NULL,0,NULL},
+ {"authentication", cmd_authentication, "<acctstring>",NULL,0,NULL},
+ {"lslb", cmd_lslb, "<largeSetLowerBound>",NULL,0,NULL},
+ {"ssub", cmd_ssub, "<smallSetUpperBound>",NULL,0,NULL},
+ {"mspn", cmd_mspn, "<mediumSetPresentNumber>",NULL,0,NULL},
+ {"status", cmd_status, "",NULL,0,NULL},
+ {"setnames", cmd_setnames, "",NULL,0,NULL},
+ {"cancel", cmd_cancel, "",NULL,0,NULL},
+ {"cancel_find", cmd_cancel_find, "<query>",NULL,0,NULL},
+ {"format", cmd_format, "<recordsyntax>",complete_format,0,NULL},
+ {"schema", cmd_schema, "<schema>",complete_schema,0,NULL},
+ {"elements", cmd_elements, "<elementSetName>",NULL,0,NULL},
+ {"close", cmd_close, "",NULL,0,NULL},
+ {"querytype", cmd_querytype, "<type>",complete_querytype,0,NULL},
+ {"refid", cmd_refid, "<id>",NULL,0,NULL},
+ {"itemorder", cmd_itemorder, "ill|item|xml <itemno>",NULL,0,NULL},
+ {"update", cmd_update, "<action> <recid> [<doc>]",NULL,0,NULL},
+ {"update0", cmd_update0, "<action> <recid> [<doc>]",NULL,0,NULL},
+ {"xmles", cmd_xmles, "<OID> <doc>",NULL,0,NULL},
+ {"packagename", cmd_packagename, "<packagename>",NULL,0,NULL},
+ {"proxy", cmd_proxy, "[('tcp'|'ssl')]<host>[':'<port>]",NULL,0,NULL},
+ {"charset", cmd_charset, "<nego_charset> <output_charset>",NULL,0,NULL},
+ {"negcharset", cmd_negcharset, "<nego_charset>",NULL,0,NULL},
+ {"displaycharset", cmd_displaycharset, "<output_charset>",NULL,0,NULL},
+ {"marccharset", cmd_marccharset, "<charset_name>",NULL,0,NULL},
+ {"querycharset", cmd_querycharset, "<charset_name>",NULL,0,NULL},
+ {"lang", cmd_lang, "<language_code>",NULL,0,NULL},
+ {"source", cmd_source_echo, "<filename>",NULL,1,NULL},
+ {".", cmd_source_echo, "<filename>",NULL,1,NULL},
+ {"!", cmd_subshell, "Subshell command",NULL,1,NULL},
+ {"set_apdufile", cmd_set_apdufile, "<filename>",NULL,1,NULL},
+ {"set_berfile", cmd_set_berfile, "<filename>",NULL,1,NULL},
+ {"set_marcdump", cmd_set_marcdump," <filename>",NULL,1,NULL},
+ {"set_cclfile", cmd_set_cclfile," <filename>",NULL,1,NULL},
+ {"set_cqlfile", cmd_set_cqlfile," <filename>",NULL,1,NULL},
+ {"set_auto_reconnect", cmd_set_auto_reconnect," on|off",complete_auto_reconnect,1,NULL},
+ {"set_auto_wait", cmd_set_auto_wait," on|off",complete_auto_reconnect,1,NULL},
+ {"set_otherinfo", cmd_set_otherinfo,"<otherinfoinddex> <oid> <string>",NULL,0,NULL},
+ {"sleep", cmd_sleep,"<seconds>",NULL,0,NULL},
+ {"register_oid", cmd_register_oid,"<name> <class> <oid>",NULL,0,NULL},
+ {"push_command", cmd_push_command,"<command>",command_generator,0,NULL},
+ {"register_tab", cmd_register_tab,"<commandname> <tab>",command_generator,0,NULL},
+ {"cclparse", cmd_cclparse,"<ccl find command>",NULL,0,NULL},
+ {"list_otherinfo",cmd_list_otherinfo,"[otherinfoinddex]",NULL,0,NULL},
+ {"list_all",cmd_list_all,"",NULL,0,NULL},
+ {"clear_otherinfo",cmd_clear_otherinfo,"",NULL,0,NULL},
+ {"wait_response",cmd_wait_response,"<number>",NULL,0,NULL},
+ /* Server Admin Functions */
+ {"adm-reindex", cmd_adm_reindex, "<database-name>",NULL,0,NULL},
+ {"adm-truncate", cmd_adm_truncate, "('database'|'index')<object-name>",NULL,0,NULL},
+ {"adm-create", cmd_adm_create, "",NULL,0,NULL},
+ {"adm-drop", cmd_adm_drop, "('database'|'index')<object-name>",NULL,0,NULL},
+ {"adm-import", cmd_adm_import, "<record-type> <dir> <pattern>",NULL,0,NULL},
+ {"adm-refresh", cmd_adm_refresh, "",NULL,0,NULL},
+ {"adm-commit", cmd_adm_commit, "",NULL,0,NULL},
+ {"adm-shutdown", cmd_adm_shutdown, "",NULL,0,NULL},
+ {"adm-startup", cmd_adm_startup, "",NULL,0,NULL},
+ {"explain", cmd_explain, "", NULL, 0, NULL},
+ {"options", cmd_options, "", NULL, 0, NULL},
+ {"zversion", cmd_zversion, "", NULL, 0, NULL},
+ {"help", cmd_help, "", NULL,0,NULL},
+ {"init", cmd_init, "", NULL,0,NULL},
+ {"sru", cmd_sru, "<method> <version>", NULL,0,NULL},
+ {"exit", cmd_quit, "",NULL,0,NULL},
+ {0,0,0,0,0,0}
+};
+
+static int cmd_help(const char *line)
+{
+ int i;
+ char topic[21];
+
+ *topic = 0;
+ sscanf(line, "%20s", topic);
+
+ if (*topic == 0)
+ printf("Commands:\n");
+ for (i = 0; cmd_array[i].cmd; i++)
+ if (*topic == 0 || strcmp(topic, cmd_array[i].cmd) == 0)
+ printf(" %s %s\n", cmd_array[i].cmd, cmd_array[i].ad);
+ if (!strcmp(topic, "find"))
+ {
+ printf("RPN:\n");
+ printf(" \"term\" Simple Term\n");
+ printf(" @attr [attset] type=value op Attribute\n");
+ printf(" @and opl opr And\n");
+ printf(" @or opl opr Or\n");
+ printf(" @not opl opr And-Not\n");
+ printf(" @set set Result set\n");
+ printf(" @prox exl dist ord rel uc ut Proximity. Use help prox\n");
+ printf("\n");
+ printf("Bib-1 attribute types\n");
+ printf("1=Use: ");
+ printf("4=Title 7=ISBN 8=ISSN 30=Date 62=Abstract 1003=Author 1016=Any\n");
+ printf("2=Relation: ");
+ printf("1< 2<= 3= 4>= 5> 6!= 102=Relevance\n");
+ printf("3=Position: ");
+ printf("1=First in Field 2=First in subfield 3=Any position\n");
+ printf("4=Structure: ");
+ printf("1=Phrase 2=Word 3=Key 4=Year 5=Date 6=WordList\n");
+ printf("5=Truncation: ");
+ printf("1=Right 2=Left 3=L&R 100=No 101=# 102=Re-1 103=Re-2\n");
+ printf("6=Completeness:");
+ printf("1=Incomplete subfield 2=Complete subfield 3=Complete field\n");
+ }
+ if (!strcmp(topic, "prox"))
+ {
+ printf("Proximity:\n");
+ printf(" @prox exl dist ord rel uc ut\n");
+ printf(" exl: exclude flag . 0=include, 1=exclude.\n");
+ printf(" dist: distance integer.\n");
+ printf(" ord: order flag. 0=unordered, 1=ordered.\n");
+ printf(" rel: relation integer. 1< 2<= 3= 4>= 5> 6!= .\n");
+ printf(" uc: unit class. k=known, p=private.\n");
+ printf(" ut: unit type. 1=character, 2=word, 3=sentence,\n");
+ printf(" 4=paragraph, 5=section, 6=chapter, 7=document,\n");
+ printf(" 8=element, 9=subelement, 10=elementType, 11=byte.\n");
+ printf("\nExamples:\n");
+ printf(" Search for a and b in-order at most 3 words apart:\n");
+ printf(" @prox 0 3 1 2 k 2 a b\n");
+ printf(" Search for any order of a and b next to each other:\n");
+ printf(" @prox 0 1 0 3 k 2 a b\n");
+ }
+ return 1;
+}
+
+int cmd_register_tab(const char* arg)
+{
+#if HAVE_READLINE_READLINE_H
+ char command[101], tabargument[101];
+ int i;
+ int num_of_tabs;
+ const char** tabslist;
+
+ if (sscanf(arg, "%100s %100s", command, tabargument) < 1) {
+ return 0;
+ }
+
+ /* locate the amdn in the list */
+ for (i = 0; cmd_array[i].cmd; i++) {
+ if (!strncmp(cmd_array[i].cmd, command, strlen(command))) {
+ break;
+ }
+ }
+
+ if (!cmd_array[i].cmd) {
+ fprintf(stderr,"Unknown command %s\n",command);
+ return 1;
+ }
+
+
+ if (!cmd_array[i].local_tabcompletes)
+ cmd_array[i].local_tabcompletes = (const char **) calloc(1,sizeof(char**));
+
+ num_of_tabs=0;
+
+ tabslist = cmd_array[i].local_tabcompletes;
+ for(; tabslist && *tabslist; tabslist++) {
+ num_of_tabs++;
+ }
+
+ cmd_array[i].local_tabcompletes = (const char **)
+ realloc(cmd_array[i].local_tabcompletes,
+ (num_of_tabs+2)*sizeof(char**));
+ tabslist = cmd_array[i].local_tabcompletes;
+ tabslist[num_of_tabs] = strdup(tabargument);
+ tabslist[num_of_tabs+1] = NULL;
+#endif
+ return 1;
+}
+
+
+void process_cmd_line(char* line)
+{
+ int i, res;
+ char word[32], arg[10240];
+
+#if HAVE_GETTIMEOFDAY
+ gettimeofday(&tv_start, 0);
+#endif
+
+ if ((res = sscanf(line, "%31s %10239[^;]", word, arg)) <= 0)
+ {
+ strcpy(word, last_cmd);
+ *arg = '\0';
+ }
+ else if (res == 1)
+ *arg = 0;
+ strcpy(last_cmd, word);
+
+ /* removed tailing spaces from the arg command */
+ {
+ char* p = arg;
+ char* lastnonspace=NULL;
+
+ for(;*p; ++p) {
+ if(!isspace(*(unsigned char *) p)) {
+ lastnonspace = p;
+ }
+ }
+ if(lastnonspace)
+ *(++lastnonspace) = 0;
+ }
+
+ for (i = 0; cmd_array[i].cmd; i++)
+ if (!strncmp(cmd_array[i].cmd, word, strlen(word)))
+ {
+ res = (*cmd_array[i].fun)(arg);
+ break;
+ }
+
+ if (!cmd_array[i].cmd) /* dump our help-screen */
+ {
+ printf("Unknown command: %s.\n", word);
+ printf("Type 'help' for list of commands\n");
+ res = 1;
+ }
+
+ if(apdu_file) fflush(apdu_file);
+
+ if (res >= 2 && auto_wait)
+ wait_and_handle_response(0);
+
+ if(apdu_file)
+ fflush(apdu_file);
+ if(marc_file)
+ fflush(marc_file);
+}
+
+static char *command_generator(const char *text, int state)
+{
+#if HAVE_READLINE_READLINE_H
+ static int idx;
+ if (state==0) {
+ idx = 0;
+ }
+ for( ; cmd_array[idx].cmd; ++idx) {
+ if (!strncmp(cmd_array[idx].cmd, text, strlen(text))) {
+ ++idx; /* skip this entry on the next run */
+ return strdup(cmd_array[idx-1].cmd);
+ }
+ }
+#endif
+ return NULL;
+}
+
+#if HAVE_READLINE_READLINE_H
+static const char** default_completer_list = NULL;
+
+static char* default_completer(const char* text, int state)
+{
+ return complete_from_list(default_completer_list, text, state);
+}
+#endif
+
+#if HAVE_READLINE_READLINE_H
+
+/*
+ This function only known how to complete on the first word
+*/
+char **readline_completer(char *text, int start, int end)
+{
+ completerFunctionType completerToUse;
+
+ if(start == 0) {
+#if HAVE_READLINE_RL_COMPLETION_MATCHES
+ char** res = rl_completion_matches(text, command_generator);
+#else
+ char** res = completion_matches(text,
+ (CPFunction*)command_generator);
+#endif
+ rl_attempted_completion_over = 1;
+ return res;
+ } else {
+ char arg[10240],word[32];
+ int i=0 ,res;
+ if ((res = sscanf(rl_line_buffer, "%31s %10239[^;]", word, arg)) <= 0) {
+ rl_attempted_completion_over = 1;
+ return NULL;
+ }
+
+ for (i = 0; cmd_array[i].cmd; i++)
+ if (!strncmp(cmd_array[i].cmd, word, strlen(word)))
+ break;
+
+ if(!cmd_array[i].cmd)
+ return NULL;
+
+ default_completer_list = cmd_array[i].local_tabcompletes;
+
+ completerToUse = cmd_array[i].rl_completerfunction;
+ if (!completerToUse)
+ { /* if command completer is not defined use the default completer */
+ completerToUse = default_completer;
+ }
+ if (completerToUse) {
+#ifdef HAVE_READLINE_RL_COMPLETION_MATCHES
+ char** res=
+ rl_completion_matches(text, completerToUse);
+#else
+ char** res=
+ completion_matches(text, (CPFunction*)completerToUse);
+#endif
+ if (!cmd_array[i].complete_filenames)
+ rl_attempted_completion_over = 1;
+ return res;
+ } else {
+ if (!cmd_array[i].complete_filenames)
+ rl_attempted_completion_over = 1;
+ return 0;
+ }
+ }
+}
+#endif
+
+#ifndef WIN32
+void ctrl_c_handler(int x)
+{
+ exit_client(0);
+}
+#endif
+
+static void client(void)
+{
+ char line[10240];
+
+ line[10239] = '\0';
+
+#ifndef WIN32
+ signal(SIGINT, ctrl_c_handler);
+#endif
+
+#if HAVE_GETTIMEOFDAY
+ gettimeofday(&tv_start, 0);
+#endif
+
+ while (1)
+ {
+ char *line_in = NULL;
+#if HAVE_READLINE_READLINE_H
+ if (isatty(0))
+ {
+ line_in=readline(C_PROMPT);
+ if (!line_in)
+ break;
+#if HAVE_READLINE_HISTORY_H
+ if (*line_in)
+ add_history(line_in);
+#endif
+ strncpy(line, line_in, sizeof(line)-1);
+ free(line_in);
+ }
+#endif
+ if (!line_in)
+ {
+ char *end_p;
+ printf(C_PROMPT);
+ fflush(stdout);
+ if (!fgets(line, sizeof(line)-1, stdin))
+ break;
+ if ((end_p = strchr(line, '\n')))
+ *end_p = '\0';
+ }
+ if (isatty(0))
+ file_history_add_line(file_history, line);
+ process_cmd_line(line);
+ }
+}
+
+static void show_version(void)
+{
+ char vstr[20], sha1_str[41];
+
+ yaz_version(vstr, sha1_str);
+ printf("YAZ version: %s %s\n", YAZ_VERSION, YAZ_VERSION_SHA1);
+ if (strcmp(sha1_str, YAZ_VERSION_SHA1))
+ printf("YAZ DLL/SO: %s %s\n", vstr, sha1_str);
+ exit(0);
+}
+