From 2984a4a74dbbe7aaf4f07788ae4785041cf6004a Mon Sep 17 00:00:00 2001 From: ja7 Date: Tue, 29 Jan 2002 20:17:41 +0000 Subject: [PATCH] Changed to flush apdu and marc log files a apdu is recived. Changed to remove blanks at end of commandline. Added source of $HOME/.yazclientrc and ./yazclientrc on startup added the folowing commands push_command - adds the rest of the line to set_apdufile - change apdu logfile from commandline set_marcdump - change marcdump file form commandline set_cclfields - change Ccl2rpn config file register_oid - regristrate a private oid Cleandup the tabcompletion and when it compleates on filenames. added completions for the follwing commands push_command format schema attributeset querytype new pr. command completion is placed in tabcomplete.[ch] Current problems: - the tabcompleation code is leaking - not mutch bot leaking. Added emacs local versiables comment for tabs config to client.c --- client/Makefile.am | 4 +- client/client.c | 436 +++++++++++++++++++++++++++++++++++++++++++------- client/tabcomplete.c | 116 ++++++++++++++ client/tabcomplete.h | 16 ++ 4 files changed, 516 insertions(+), 56 deletions(-) create mode 100644 client/tabcomplete.c create mode 100644 client/tabcomplete.h diff --git a/client/Makefile.am b/client/Makefile.am index b9efc62..f7a50c8 100644 --- a/client/Makefile.am +++ b/client/Makefile.am @@ -1,12 +1,12 @@ ## Copyright (C) 1995-2000, Index Data ## All rights reserved. -## $Id: Makefile.am,v 1.11 2001-04-06 12:26:46 adam Exp $ +## $Id: Makefile.am,v 1.12 2002-01-29 20:17:41 ja7 Exp $ bin_PROGRAMS=yaz-client EXTRA_DIST = default.bib -yaz_client_SOURCES=client.c admin.c admin.h +yaz_client_SOURCES=client.c admin.c admin.h tabcomplete.c yaz_client_LDADD = ../lib/libyaz.la $(READLINE_LIBS) diff --git a/client/client.c b/client/client.c index 9980c11..2ee4efd 100644 --- a/client/client.c +++ b/client/client.c @@ -2,7 +2,7 @@ * Copyright (c) 1995-2002, Index Data * See the file LICENSE for details. * - * $Id: client.c,v 1.137 2002-01-28 09:25:38 adam Exp $ + * $Id: client.c,v 1.138 2002-01-29 20:17:41 ja7 Exp $ */ #include @@ -39,7 +39,11 @@ #include #endif +#include + + #include "admin.h" +#include "tabcomplete.h" #define C_PROMPT "Z> " @@ -89,7 +93,17 @@ static CCL_bibset bibset; /* CCL bibset handle */ /* set this one to 1, to avoid decode of unknown MARCs */ #define AVOID_MARC_DECODE 1 +/* nice helper macro as extensive tabbing gives spaces at the en of the args lines */ +#define REMOVE_TAILING_BLANKS(a) {\ + char* args_end=(a)+strlen(a)-1; \ + while(isspace(*args_end)) {*args_end=0;--args_end;}; \ + } + + void process_cmd_line(char* line); +char ** readline_completer(char *text, int start, int end); +char *command_generator(char *text, int state); + ODR getODROutputStream() { @@ -1983,12 +1997,22 @@ int cmd_proxy(char* arg) { int cmd_source(char* arg) { + /* first should open the file and read one line at a time.. */ FILE* includeFile; char line[1024], *cp; + + { + char* args_end=(arg)+strlen(arg)-1; + while(isspace(*args_end)) + {*args_end=0; + --args_end;}; + } + + REMOVE_TAILING_BLANKS(arg); if(strlen(arg)<1) { - fprintf(stderr,"Error in source command use a filename"); + fprintf(stderr,"Error in source command use a filename\n"); return -1; }; @@ -2022,10 +2046,203 @@ int cmd_source(char* arg) } int cmd_subshell(char* args) { - system(args); + if(strlen(args)) + system(args); + else + system(getenv("SHELL")); + + printf("\n"); return 1; } + + +int cmd_set_apdufile(char* arg) { + REMOVE_TAILING_BLANKS(arg); + + if(apdu_file && apdu_file != stderr) { /* don't close stdout*/ + perror("unable to close apdu log file"); + }; + apdu_file=NULL; + + if(strlen(arg)<1) { + return 1; + } + + if(!strcmp(arg,"-")) + apdu_file=stderr; + else + apdu_file=fopen(arg, "a"); + + if(!apdu_file) { + perror("unable to open apdu log file no apdu log loaded"); + } else { + odr_setprint(print, apdu_file); + }; + + return 1; +}; + + +int cmd_set_cclfields(char* arg) { +#if YAZ_MODULE_ccl + FILE *inf; + + REMOVE_TAILING_BLANKS(arg); + + bibset = ccl_qual_mk (); + inf = fopen (arg, "r"); + if (inf) + { + ccl_qual_file (bibset, inf); + fclose (inf); + } +#else + fprintf(stderr,"Not compiled with the yaz ccl module\n"); +#endif + + return 1; +}; + +int cmd_set_marcdump(char* arg) { + if(marcdump && marcdump != stderr) { /* don't close stdout*/ + perror("unable to close apdu log file"); + }; + marcdump=NULL; + + if(strlen(arg)<1) { + return 1; + } + + if(!strcmp(arg,"-")) + marcdump=stderr; + else + marcdump=fopen(arg, "a"); + + if(!marcdump) { + perror("unable to open apdu marcdump file no marcdump done\n"); + }; + + return 1; +}; + +int cmd_set_proxy(char* arg) { + if(yazProxy) free(yazProxy); + yazProxy=NULL; + + if(strlen(arg) > 1) { + yazProxy=strdup(arg); + }; + return 1; +}; + +/* + this command takes 3 arge {name class oid} + */ +int cmd_register_oid(char* args) { + static struct { + char* className; + oid_class oclass; + } oid_classes[] = { + {"appctx",CLASS_APPCTX}, + {"absyn",CLASS_ABSYN}, + {"attset",CLASS_ATTSET}, + {"transyn",CLASS_TRANSYN}, + {"diagset",CLASS_DIAGSET}, + {"recsyn",CLASS_RECSYN}, + {"resform",CLASS_RESFORM}, + {"accform",CLASS_ACCFORM}, + {"extserv",CLASS_EXTSERV}, + {"userinfo",CLASS_USERINFO}, + {"elemspec",CLASS_ELEMSPEC}, + {"varset",CLASS_VARSET}, + {"schema",CLASS_SCHEMA}, + {"tagset",CLASS_TAGSET}, + {"general",CLASS_GENERAL}, + {0,0} + }; + char oname_str[101], oclass_str[101], oid_str[101]; + char* name; + int i; + oid_class oidclass = CLASS_GENERAL; + int val = 0, oid[OID_SIZE]; + struct oident * new_oident=NULL; + + if (sscanf (args, "%100[^ ] %100[^ ] %100s", oname_str,oclass_str, oid_str) < 1) { + printf("Error in regristrate command \n"); + return 0; + }; + + for (i = 0; oid_classes[i].className; i++) { + if (!strcmp(oid_classes[i].className, oclass_str)) + { + oidclass=oid_classes[i].oclass; + break; + } + } + + if(!(oid_classes[i].className)) { + printf("Unknonwn oid class %s\n",oclass_str); + return 0; + }; + + + + i = 0; + name = oid_str; + val = 0; + + while (isdigit (*name)) + { + val = val*10 + (*name - '0'); + name++; + if (*name == '.') + { + if (i < OID_SIZE-1) + oid[i++] = val; + val = 0; + name++; + } + } + oid[i] = val; + oid[i+1] = -1; + + new_oident=oid_addent (oid,PROTO_GENERAL,oidclass,oname_str,VAL_DYNAMIC); + if(strcmp(new_oident->desc,oname_str)) { + fprintf(stderr,"oid is already named as %s, regristration faild\n",new_oident->desc); + }; + return 1; +}; + +int cmd_push_command(char* arg) { +#if HAVE_READLINE_HISTORY_H + if(strlen(arg)>1) + add_history(arg); +#else + fprintf(stderr,"Not compiled with the readline/history module\n"); +#endif + return 1; +}; + +void source_rcfile() { + /* Look for a $HOME/.yazclientrc and source it if it exists */ + struct stat statbuf; + char buffer[1000]; + char* homedir=getenv("HOME"); + if(!homedir) return; + + sprintf(buffer,"%s/.yazclientrc",homedir); + + if(stat(buffer,&statbuf)==0) { + cmd_source(buffer); + }; + + if(stat(".yazclientrc",&statbuf)==0) { + cmd_source(".yazclientrc"); + }; +}; + + static void initialize(void) { #if YAZ_MODULE_ccl @@ -2038,6 +2255,8 @@ static void initialize(void) fprintf(stderr, "failed to allocate ODR streams\n"); exit(1); } + oid_init(); + setvbuf(stdout, 0, _IONBF, 0); if (apdu_file) odr_setprint(print, apdu_file); @@ -2052,6 +2271,12 @@ static void initialize(void) } #endif cmd_base("Default"); + +#if HAVE_READLINE_READLINE_H + rl_attempted_completion_function = (CPPFunction*)readline_completer; +#endif + + source_rcfile(); } @@ -2170,58 +2395,66 @@ void wait_and_handle_responce() } } + +static struct { + char *cmd; + int (*fun)(char *arg); + char *ad; + char *(*rl_completerfunction)(char *text, int state); + int complete_filenames; +} cmd[] = { + {"open", cmd_open, "('tcp'|'ssl')':[':'][/]",NULL,0}, + {"quit", cmd_quit, "",NULL,0}, + {"find", cmd_find, "",NULL,0}, + {"delete", cmd_delete, "",NULL,0}, + {"base", cmd_base, "",NULL,0}, + {"show", cmd_show, "['+'<#recs>['+']]",NULL,0}, + {"scan", cmd_scan, "",NULL,0}, + {"sort", cmd_sort, " ...",NULL,0}, + {"sort+", cmd_sort_newset, " ...",NULL,0}, + {"authentication", cmd_authentication, "",NULL,0}, + {"lslb", cmd_lslb, "",NULL,0}, + {"ssub", cmd_ssub, "",NULL,0}, + {"mspn", cmd_mspn, "",NULL,0}, + {"status", cmd_status, "",NULL,0}, + {"setnames", cmd_setnames, "",NULL,0}, + {"cancel", cmd_cancel, "",NULL,0}, + {"format", cmd_format, "",complete_format,0}, + {"schema", cmd_schema, "",complete_schema,0}, + {"elements", cmd_elements, "",NULL,0}, + {"close", cmd_close, "",NULL,0}, + {"attributeset", cmd_attributeset, "",complete_attributeset,0}, + {"querytype", cmd_querytype, "",complete_querytype,0}, + {"refid", cmd_refid, "",NULL,0}, + {"itemorder", cmd_itemorder, "ill|item ",NULL,0}, + {"update", cmd_update, "",NULL,0}, + {"packagename", cmd_packagename, "",NULL,0}, + {"proxy", cmd_proxy, "('tcp'|'osi')':'['/'][':']",NULL,0}, + {".", cmd_source, "",NULL,1}, + {"!", cmd_subshell, "Subshell command",NULL,0}, + {"set_apdufile", cmd_set_apdufile, "",NULL,0}, + {"set_marcdump", cmd_set_marcdump," ",NULL,0}, + {"set_cclfields", cmd_set_cclfields,"",NULL,1}, + {"register_oid",cmd_register_oid," ",NULL,0}, + {"push_command",cmd_push_command,"",command_generator,0}, + /* Server Admin Functions */ + {"adm-reindex", cmd_adm_reindex, "",NULL,0}, + {"adm-truncate", cmd_adm_truncate, "('database'|'index')",NULL,0}, + {"adm-create", cmd_adm_create, "",NULL,0}, + {"adm-drop", cmd_adm_drop, "('database'|'index')",NULL,0}, + {"adm-import", cmd_adm_import, " ",NULL,0}, + {"adm-refresh", cmd_adm_refresh, "",NULL,0}, + {"adm-commit", cmd_adm_commit, "",NULL,0}, + {"adm-shutdown", cmd_adm_shutdown, "",NULL,0}, + {"adm-startup", cmd_adm_startup, "",NULL,0}, + {0,0,0,0,0} +}; + void process_cmd_line(char* line) -{ - static struct { - char *cmd; - int (*fun)(char *arg); - char *ad; - } cmd[] = { - {"open", cmd_open, "('tcp'|'ssl')':[':'][/]"}, - {"quit", cmd_quit, ""}, - {"find", cmd_find, ""}, - {"delete", cmd_delete, ""}, - {"base", cmd_base, ""}, - {"show", cmd_show, "['+'<#recs>['+']]"}, - {"scan", cmd_scan, ""}, - {"sort", cmd_sort, " ..."}, - {"sort+", cmd_sort_newset, " ..."}, - {"authentication", cmd_authentication, ""}, - {"lslb", cmd_lslb, ""}, - {"ssub", cmd_ssub, ""}, - {"mspn", cmd_mspn, ""}, - {"status", cmd_status, ""}, - {"setnames", cmd_setnames, ""}, - {"cancel", cmd_cancel, ""}, - {"format", cmd_format, ""}, - {"schema", cmd_schema, ""}, - {"elements", cmd_elements, ""}, - {"close", cmd_close, ""}, - {"attributeset", cmd_attributeset, ""}, - {"querytype", cmd_querytype, ""}, - {"refid", cmd_refid, ""}, - {"itemorder", cmd_itemorder, "ill|item "}, - {"update", cmd_update, ""}, - {"packagename", cmd_packagename, ""}, - {"proxy", cmd_proxy, "('tcp'|'osi')':'['/'][':']"}, - {".", cmd_source, ""}, - {"!", cmd_subshell, "Subshell command"}, - /* Server Admin Functions */ - {"adm-reindex", cmd_adm_reindex, ""}, - {"adm-truncate", cmd_adm_truncate, "('database'|'index')"}, - {"adm-create", cmd_adm_create, ""}, - {"adm-drop", cmd_adm_drop, "('database'|'index')"}, - {"adm-import", cmd_adm_import, " "}, - {"adm-refresh", cmd_adm_refresh, ""}, - {"adm-commit", cmd_adm_commit, ""}, - {"adm-shutdown", cmd_adm_shutdown, ""}, - {"adm-startup", cmd_adm_startup, ""}, - {0,0} - }; +{ int i,res; char word[32], arg[1024]; - #if HAVE_GETTIMEOFDAY gettimeofday (&tv_start, 0); #endif @@ -2234,6 +2467,23 @@ void process_cmd_line(char* line) else if (res == 1) *arg = 0; strcpy(last_cmd, word); + + /* removed tailing spaces from the arg command */ + { + char* p; + char* lastnonspace=NULL; + p = arg; + + for(;*p; ++p) { + if(!isspace(*p)) { + lastnonspace = p; + }; + }; + if(lastnonspace) + *(++lastnonspace) = 0; + }; + + for (i = 0; cmd[i].cmd; i++) if (!strncmp(cmd[i].cmd, word, strlen(word))) { @@ -2248,11 +2498,79 @@ void process_cmd_line(char* line) printf(" %s %s\n", cmd[i].cmd, cmd[i].ad); return; } + + if(apdu_file) fflush(apdu_file); + if (res >= 2) wait_and_handle_responce(); + + if(apdu_file) fflush(apdu_file); + if(marcdump) fflush(marcdump); } +char *command_generator(char *text, int state) +{ + static idx; // index is the last used the last time command_generator was called + char *command; + if (state==0) { + idx = 0; + } + for( ; cmd[idx].cmd; ++idx) { + if (!strncmp(cmd[idx].cmd,text,strlen(text))) { + ++idx; /* skip this entry on the next run */ + return strdup(cmd[idx-1].cmd); + }; + } + return NULL; +} + + +/* + This function only known how to complete on the first word +*/ +char ** readline_completer(char *text, int start, int end) { +#if HAVE_READLINE_READLINE_H + + if(start == 0) { + char** res=completion_matches(text, (CPFunction*)command_generator); + rl_attempted_completion_over = 1; + return res; + } else { + char arg[1024],word[32]; + int i=0 ,res; + if ((res = sscanf(rl_line_buffer, "%31s %1023[^;]", word, arg)) <= 0) { + rl_attempted_completion_over = 1; + return NULL; + }; + + if(start != strlen(word) +1 ) { + rl_attempted_completion_over = 1; + return 0; + } + for (i = 0; cmd[i].cmd; i++) { + if (!strncmp(cmd[i].cmd, word, strlen(word))) { + break; + } + } + + + if(!cmd[i].complete_filenames) + rl_attempted_completion_over = 1; + if(cmd[i].rl_completerfunction) { + char** res=completion_matches(text, (CPFunction*)cmd[i].rl_completerfunction); + rl_attempted_completion_over = 1; + return res; + } else { + rl_attempted_completion_over = 1; + return 0; + }; + }; +#else + return 0; +#endif +}; + static void client(void) { @@ -2270,7 +2588,7 @@ static void client(void) { #if HAVE_READLINE_READLINE_H - char* line_in; + char* line_in=NULL; line_in=readline(C_PROMPT); if (!line_in) break; @@ -2301,7 +2619,7 @@ int main(int argc, char **argv) char *auth_command = 0; char *arg; int ret; - + while ((ret = options("k:c:a:m:v:p:u:", argv, argc, &arg)) != -2) { switch (ret) @@ -2354,7 +2672,7 @@ int main(int argc, char **argv) "[-k size] []\n", prog); exit (1); - } + } } initialize(); if (auth_command) @@ -2382,3 +2700,13 @@ int main(int argc, char **argv) client (); exit (0); } + + + + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ diff --git a/client/tabcomplete.c b/client/tabcomplete.c new file mode 100644 index 0000000..9513965 --- /dev/null +++ b/client/tabcomplete.c @@ -0,0 +1,116 @@ +#include "tabcomplete.h" +#include +#include +#include + + +/* ***************************************************************************** + * + * generic compleater + * + * *****************************************************************************/ + +char* complete_from_list(char* completions[], char *text, int state) { + static idx; + if(state==0) { + idx = 0; + } + for(; completions[idx]; ++ idx) { + if(!strncmp(completions[idx],text,strlen(text))) { + ++idx; /* skip this entry on the next run */ + return (char*)strdup(completions[idx-1]); + }; + }; + return NULL; +}; + + +/* ***************************************************************************** + * + * code for getting a list of valid strings from the oid subsystem + * + * *****************************************************************************/ + + +typedef struct { + oid_class oclass; + char** values; + size_t index; + size_t max; +} oid_callback_t; + +/*! + This is the call back function given to oid_trav... it updates the list of pointers into the oid + owned data +*/ + +void oid_loader(struct oident* oid, void* data_) { + oid_callback_t* data=(oid_callback_t*) data_; + + //fprintf(stderr,"ja7: called with %d: %s\n",oid->oclass,oid->desc); + if((oid->oclass == CLASS_GENERAL) || (oid->oclass == data->oclass)) { + if(data->index==data->max) { + data->values=(char**)realloc(data->values,((data->max+1)*2)*sizeof(char*)); + data->max=(data->max+1)*2 - 1; + }; + data->values[data->index]=oid->desc; + ++data->index; + } +}; + +char** build_list_for_oclass(oid_class oclass) { + oid_callback_t data; + data.values = calloc(10,sizeof(char*)); + data.index = 0; + data.max = 9; + data.oclass = oclass; + + oid_trav(oid_loader, &data); + + data.values[data.index]=0; + return data.values; +}; + +/* ***************************************************************************** + * + * the compleater functions + * + * *****************************************************************************/ + +char* complete_querytype(char *text, int state) { + char* querytypes[] = {"ccl2rpn","prefix","cclrpn","ccl",0}; + return complete_from_list(querytypes,text,state); +}; + + +char* complete_format(char* text, int state) { + char** list=build_list_for_oclass(CLASS_RECSYN); + char* res=complete_from_list(list,text,state); + + free(list); + return res; +}; + +char* complete_schema(char* text, int state) { + char** list=build_list_for_oclass(CLASS_SCHEMA); + char* res=complete_from_list(list,text,state); + + free(list); + return res; +}; + + +char* complete_attributeset(char* text, int state) { + char** list=build_list_for_oclass(CLASS_ATTSET); + char* res=complete_from_list(list,text,state); + + free(list); + return res; +}; + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ diff --git a/client/tabcomplete.h b/client/tabcomplete.h new file mode 100644 index 0000000..04d1497 --- /dev/null +++ b/client/tabcomplete.h @@ -0,0 +1,16 @@ +/* + This file contains the compleaters for the different commands. +*/ + + +char* complete_querytype(char* text, int state); +char* complete_format(char* text, int state); +char* complete_schema(char* text, int state); +char* complete_attributeset(char* text, int state); + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ -- 1.7.10.4