eda24ba90141fba8ea832aba3e40a94cbe4e3dae
[idzebra-moved-to-github.git] / index / zebrash.c
1 /* This file is part of the Zebra server.
2    Copyright (C) 1994-2009 Index Data
3
4 Zebra is free software; you can redistribute it and/or modify it under
5 the terms of the GNU General Public License as published by the Free
6 Software Foundation; either version 2, or (at your option) any later
7 version.
8
9 Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
10 WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17
18 */
19
20 /* 
21    zebrash.c - command-line interface to zebra API
22 */
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h> 
27 #include <ctype.h>
28 #if HAVE_UNISTD_H
29 #include <unistd.h>
30 #endif
31
32 #if HAVE_READLINE_READLINE_H
33 #include <readline/readline.h> 
34 #endif
35 #if HAVE_READLINE_HISTORY_H
36 #include <readline/history.h>
37 #endif
38
39 #include <idzebra/api.h>
40 #include <yaz/log.h>
41 #include <yaz/proto.h>
42 #include <yaz/sortspec.h>
43 #include <yaz/options.h>
44 #include <yaz/wrbuf.h>
45 #include <yaz/oid_db.h>
46
47 #define MAX_NO_ARGS 32
48 #define MAX_OUT_BUFF 4096
49 #define MAX_ARG_LEN 1024
50 #define PROMPT "ZebraSh>"
51 #define DEFAULTCONFIG "./zebra.cfg"
52 #define DEFAULTDATABASE "Default"
53 #define DEFAULTRESULTSET "MyResultSet"
54
55
56 /**************************************
57  * Global variables (yuck!)
58  */
59
60 ZebraService zs=0;  /* our global handle to zebra */
61 ZebraHandle  zh=0;  /* the current session */
62 /* time being, only one session works */
63 int nextrecno=1;  /* record number to show next */
64 static char *default_config = DEFAULTCONFIG;
65 static int log_level=0;
66
67
68 /**************************************
69  * Help functions
70  */
71
72  
73 static int split_args( char *line, char** args )
74 { /* splits line into individual null-terminated strings, 
75    * returns pointers to them in args */
76   /* FIXME - do we need to handle quoted args ?? */
77     char *p=line;
78     int i=0;
79     int n=0;
80     args[0]=0; /* by default */
81     while (*p==' ' || *p=='\t' || *p=='\n')
82             p++;
83     while (*p)
84     {
85         while (*p==' ' || *p=='\t' || *p=='\n')
86             p++;
87         if (*p=='#')  /* skip comments */
88             break;  
89         args[i++]=p;
90         args[i]=0;
91         while (*p && *p!=' ' && *p!='\t' && *p!='\n' && *p!='#')
92             p++;
93         *p++='\0';
94     }
95     n=i;
96     while (n<MAX_NO_ARGS)
97         args[n++]=0;
98     return i;
99 }
100
101 static char *defarg( char *arg, char *def )
102 {
103     if (!arg)
104         return def;
105     if (!*arg)
106         return def;
107     return arg;
108 }
109 static int defargint( char *arg, int def )
110 {
111     int v=def;
112     char *a=defarg(arg,0);
113     if (a)
114         sscanf(a," %i", &v);
115     return v;
116 }
117
118 static char *restargs( char *args[], int n)
119 { /* Returns the rest of the arguments, starting at the nth, */
120   /* to the end of the command line. Assumes args[0] contains */
121   /* the original line, minus the command itself */
122     int skiplen= args[n]-args[1];
123     if (skiplen > strlen(args[0]))
124         return "";
125     return args[0]+skiplen;
126 }
127
128 int onecommand( char *line, WRBUF outbuff, const char *prevout); 
129
130 /**************************************
131  * Simple support commands
132  */
133
134 int cmd_echo( char *args[], WRBUF outbuff)
135 {
136     wrbuf_printf(outbuff,"%s\n",restargs(args,1));
137     return 0;
138 }
139  
140 int cmd_quit( char *args[], WRBUF outbuff)
141 {
142     if (zs)
143     {
144         onecommand("zebra_close",outbuff,"");
145         zs=0;
146     }
147     if (zh)
148     {
149         onecommand("zebra_stop",outbuff,"");
150         zh=0;
151     }
152     wrbuf_puts(outbuff, "bye");
153     return -99; /* special stop signal */
154 }
155
156 /**************************************
157  * Tests for starting and stopping zebra, etc
158  */
159  
160 static int cmd_help( char *args[], WRBUF outbuff); 
161  
162 static int cmd_zebra_start( char *args[], WRBUF outbuff)
163 {
164     char *conf=args[1];
165     if (!conf || !*conf) {
166         wrbuf_puts(outbuff,"no config file specified, using ");
167         wrbuf_puts(outbuff, default_config);
168         wrbuf_puts(outbuff, "\n");
169         conf=default_config;
170     }
171     zs=zebra_start(conf);
172     if (!zs) {
173         wrbuf_puts(outbuff, "zebra_start failed" );
174         return 2;
175     }
176     return 0; /* ok */
177 }
178  
179 static int cmd_zebra_stop( char *args[], WRBUF outbuff)
180 {
181     if (!zs)
182         wrbuf_puts(outbuff,"zebra seems not to have been started, "
183                    "stopping anyway\n");
184     zebra_stop(zs);
185     zs=0;
186     return 0; /* ok */
187 }
188
189 static int cmd_zebra_open( char *args[], WRBUF outbuff)
190 {
191     if (!zs)
192         wrbuf_puts(outbuff,"zebra seems not to have been started, "
193                    "trying anyway\n");
194     zh = zebra_open(zs, 0);
195     return 0; /* ok */
196 }
197
198 static int cmd_zebra_close( char *args[], WRBUF outbuff)
199 {
200     if (!zh)
201         wrbuf_puts(outbuff,"Seems like you have not called zebra_open,"
202                    "trying anyway\n");
203     zebra_close(zh);
204     return 0; /* ok */
205 }
206
207 static int cmd_quickstart( char *args[], WRBUF outbuff)
208 {
209     char tmp[128];
210     int rc=0;
211     if (!rc)
212         rc=onecommand("yaz_log_file zebrash.log",outbuff,"");
213     if (!rc)
214         rc=onecommand("yaz_log_prefix ZebraSh", outbuff,"");
215     sprintf(tmp, "yaz_log_level 0x%x", YLOG_DEFAULT_LEVEL | log_level );
216     if (!rc)
217         rc=onecommand(tmp,outbuff,"");
218     yaz_log(log_level,"quickstart");
219     if (!zs)
220         if (!rc)
221             rc=onecommand("zebra_start",outbuff,"");
222     if (!zh)
223         if (!rc)
224             rc=onecommand("zebra_open",outbuff,"");
225     if (!rc)
226         rc=onecommand("select_database Default",outbuff,"");
227     return rc;
228 }
229
230 /**************************************
231  * Log file handling
232  */
233
234 static int cmd_yaz_log_file( char *args[], WRBUF outbuff)
235 {
236     char *fn = defarg(args[1],0);
237     wrbuf_printf(outbuff, "sending yaz-log to %s\n",fn);
238     yaz_log_init_file(fn);
239     return 0; /* ok */
240 }
241
242 static int cmd_yaz_log_level( char *args[], WRBUF outbuff)
243 {
244     int  lev = defargint(args[1],YLOG_DEFAULT_LEVEL);
245     wrbuf_printf(outbuff, "setting yaz-log to level %d (ox%x)\n",lev,lev);
246     yaz_log_init_level(lev);
247     return 0; /* ok */
248 }
249
250 static int cmd_yaz_log_prefix( char *args[], WRBUF outbuff)
251 {
252     char *pref = defarg(args[1],"ZebraSh");
253     wrbuf_printf(outbuff, "setting yaz-log prefix to %s\n",pref);
254     yaz_log_init_prefix(pref);
255     return 0; /* ok */
256 }
257
258 static int cmd_logf( char *args[], WRBUF outbuff)
259 {
260     int lev = defargint(args[1],0);
261     int i=1;  
262     if (lev)
263         i=2;
264     else
265         lev=YLOG_LOG; /* this is in the default set!*/
266     yaz_log( lev, "%s", restargs(args,i));
267     return 0; /* ok */
268 }
269  
270 /****************
271  * Error handling 
272  */
273 static int cmd_err ( char *args[], WRBUF outbuff)
274 {
275     wrbuf_printf(outbuff, "errCode: %d \nerrStr:  %s\nerrAdd:  %s \n",
276                  zebra_errCode (zh),
277                  zebra_errString (zh),  
278                  zebra_errAdd (zh) );
279     return 0; /* ok */
280 }
281 static int cmd_errcode ( char *args[], WRBUF outbuff)
282 {
283     wrbuf_printf(outbuff, "errCode: %d \n",
284                  zebra_errCode (zh));
285     return 0; /* ok */
286 }
287 static int cmd_errstr ( char *args[], WRBUF outbuff)
288 {
289     wrbuf_printf(outbuff, "errStr:  %s\n",
290                  zebra_errString (zh));
291     return 0; /* ok */
292 }
293 static int cmd_erradd ( char *args[], WRBUF outbuff)
294 {
295     wrbuf_printf(outbuff, "errAdd:  %s \n",
296                  zebra_errAdd (zh) ); 
297     return 0; /* ok */
298 }
299
300 /**************************************
301  * Admin commands
302  */
303
304 static int cmd_init ( char *args[], WRBUF outbuff)
305 {
306     zebra_init(zh);
307     return 0; /* ok */
308 }
309
310 static int cmd_select_database ( char *args[], WRBUF outbuff)
311 {
312     char *db=defarg(args[1],DEFAULTDATABASE);
313         wrbuf_printf(outbuff,"Selecting database '%s'\n",db);
314     return zebra_select_database(zh, db);
315 }
316  
317 static int cmd_create_database( char *args[], WRBUF outbuff)
318 {
319     char *db=defarg(args[1],DEFAULTDATABASE);
320     wrbuf_printf(outbuff,"Creating database '%s'\n",db);
321     
322     return zebra_create_database(zh, db);
323 }
324
325 static int cmd_drop_database( char *args[], WRBUF outbuff)
326 {
327     char *db=args[1];
328     if (!db)
329         db="Default";
330     wrbuf_printf(outbuff,"Dropping database '%s'\n",db);
331     return zebra_drop_database(zh, db);
332 }
333
334 static int cmd_begin_trans( char *args[], WRBUF outbuff)
335 {
336     int rw=0;
337     if (args[1] && ( (args[1][0]=='1') || (args[1][0]=='w') ))
338         rw=1;
339     return zebra_begin_trans(zh,rw);
340 }
341
342 static int cmd_end_trans( char *args[], WRBUF outbuff)
343 {
344     return zebra_end_trans(zh);
345 }
346 /*************************************
347  * Inserting and deleting
348  */
349
350 static int cmd_record_insert( char *args[], WRBUF outbuff)
351 {
352     zint sysno = 0;
353     int rc;
354     char *rec=restargs(args,1);
355     
356     rc = zebra_update_record(zh,
357                              action_insert,
358                              0,  /* record type */
359                              &sysno,
360                              0,  /* match */
361                              0,  /* fname */
362                              rec,
363                              strlen(rec));
364     if (0==rc)
365     {
366         wrbuf_printf(outbuff,"ok sysno=" ZINT_FORMAT "\n",sysno);
367     }
368     return rc;
369 }
370
371
372 static int cmd_exchange_record( char *args[], WRBUF outbuff)
373 {
374     char *id = args[1];
375     char *action = args[2];
376     int rc;
377     char *rec=restargs(args,3);
378     if (!(id && action && args[4] ))
379     {
380         wrbuf_puts(outbuff,"Missing arguments!\n");
381         onecommand("help exchange_record", outbuff, "");
382         return -90;
383     }
384
385     rc = zebra_update_record(zh, action_update, 0 /* record_type */,
386                              0 /* sysno */,
387                              id /* match */,
388                              0 /* fname */,
389                              rec, strlen(rec));
390     return rc;
391 }
392
393 /**********************************
394  * Searching and retrieving
395  */
396
397 static int cmd_search_pqf(char *args[], WRBUF outbuff)
398 {
399     zint hits = 0;
400     char *set = args[1];
401     char *qry = restargs(args,2);
402     int rc;
403     rc = zebra_search_PQF(zh, qry, set, &hits);
404     if (0==rc)
405         wrbuf_printf(outbuff, ZINT_FORMAT " hits found\n", hits);
406     return rc;
407 }
408
409 static int cmd_find( char *args[], WRBUF outbuff)
410 {
411     char *setname=DEFAULTRESULTSET;
412     int rc;
413     zint hits = 0;
414     WRBUF qry = wrbuf_alloc();
415     if (0==strstr(args[0],"@attr"))
416         wrbuf_puts(qry, "@attr 1=/ ");
417     wrbuf_puts(qry,restargs(args,1));
418     if (!zh)
419         onecommand("quickstart", outbuff, "");
420     wrbuf_printf(outbuff, "find %s\n",wrbuf_cstr(qry));
421     rc = zebra_search_PQF(zh, wrbuf_cstr(qry), setname, &hits);
422     if (0==rc)
423     {
424         wrbuf_printf(outbuff, ZINT_FORMAT " hits found\n", hits);
425         nextrecno = 1;
426     }
427     wrbuf_destroy(qry);
428     return rc;
429 }
430
431 static int cmd_show( char *args[], WRBUF outbuff)
432 {
433     int start=defargint(args[1], nextrecno);
434     int nrecs=defargint(args[2],1);
435     char *setname=defarg(args[3],DEFAULTRESULTSET);
436     int rc=0;
437     ZebraRetrievalRecord *recs;
438     ODR odr;
439     Z_RecordComposition *pcomp=0;
440     int i;
441
442     odr = odr_createmem(ODR_ENCODE);
443     recs= odr_malloc(odr,sizeof(ZebraRetrievalRecord)*nrecs);
444     rc =z_RecordComposition(odr, &pcomp, 0,"recordComposition");
445
446     for (i=0;i<nrecs;i++)
447         recs[i].position=start+i;
448
449     rc = zebra_records_retrieve(zh, odr, setname,
450                                 pcomp, yaz_oid_recsyn_xml, nrecs,recs);
451     if (0==rc)
452     {
453         for (i=0;i<nrecs;i++)
454         {
455             printf("Err %d: %d\n",i,recs[i].errCode);
456             if (recs[i].buf)
457             {
458                 wrbuf_printf(outbuff,"Record %d\n", recs[i].position);
459                 wrbuf_write(outbuff, recs[i].buf, recs[i].len);
460                 wrbuf_puts(outbuff, "\n");
461             } else
462                 wrbuf_printf(outbuff,"NO Record %d\n", recs[i].position);
463         }
464         nextrecno=start+nrecs;
465     }
466     odr_destroy(odr);
467     return rc;
468 } /* cmd_show */
469
470 static int cmd_sort( char *args[], WRBUF outbuff)
471 {
472     int rc=0;
473     ODR odr;
474     int sortstatus=0;
475     Z_SortKeySpecList *spec=0;
476     const char * inpsets[]={ DEFAULTRESULTSET, 0};
477     /* FIXME - allow the user to specify result sets in/out */
478
479     odr=odr_createmem(ODR_ENCODE);
480     spec=yaz_sort_spec (odr, restargs(args,1));
481     if (!spec)
482         rc=1;
483     if (!rc)
484         rc=zebra_sort(zh, odr,
485                         1, inpsets,
486                         DEFAULTRESULTSET,
487                         spec,
488                         &sortstatus);
489     if (!rc)
490         wrbuf_printf(outbuff, "sort returned status %d\n",sortstatus);
491
492     odr_destroy(odr);
493     return rc;
494 } /* cmd_sort */
495 /*
496  *
497  * int bend_sort (void *handle, bend_sort_rr *rr)
498  * {
499  *     ZebraHandle zh = (ZebraHandle) handle;
500  *
501  *     zebra_sort (zh, rr->stream,
502  *                     rr->num_input_setnames, (const char **)
503  *                     rr->input_setnames,
504  *                     rr->output_setname,
505  *                     rr->sort_sequence,
506  *                     &rr->sort_status);
507  *     zebra_result (zh, &rr->errcode,
508  *                  &rr->errstring);
509  *     return 0;
510  *  }
511  *
512  */
513
514 /**************************************)
515  * Command table, parser, and help 
516  */
517
518 struct cmdstruct
519 {
520     char *cmd;
521     char *args;
522     char *explanation;
523     int (*testfunc)(char *args[], WRBUF outbuff);
524 } ;
525
526  
527 struct cmdstruct cmds[] = {
528     /* special cases:
529      *   if text is 0, does not list the command
530      *   if cmd is "", adds the args (and newline) in command listing
531      */
532     { "", "Starting and stopping:", "", 0 },
533     { "zebra_start", 
534       "[configfile]", 
535       "starts the zebra service. You need to call this first\n"
536       "if no configfile is given, assumes " DEFAULTCONFIG, 
537       cmd_zebra_start },
538     { "zebra_stop",   "", 
539       "stops the zebra service", 
540       cmd_zebra_stop },
541     { "zebra_open", "",  
542       "starts a zebra session. Once you have called zebra_start\n"
543       "you can call zebra_open to start working", 
544       cmd_zebra_open },
545     { "zebra_close", "", 
546       "closes a zebra session", 
547       cmd_zebra_close }, 
548     { "quickstart", "[configfile]", 
549       "Does a zebra_start, zebra_open, and sets up the log", 
550       cmd_quickstart }, 
551   
552     { "", "Log file:","", 0},  
553     { "yaz_log_file", 
554       "[filename]",
555       "Directs the log to filename (or stderr)",
556       cmd_yaz_log_file },
557     { "yaz_log_level", 
558       "[level]",
559       "Sets the logging level (or returns to default)",
560       cmd_yaz_log_level },
561     { "yaz_log_prefix", 
562       "[prefix]",
563       "Sets the log prefix",
564       cmd_yaz_log_prefix},    
565     { "yaz_log", 
566       "[level] text...",
567       "writes an entry in the log",
568       cmd_logf},    
569
570     { "", "Error handling:","", 0},
571     { "err",  "",
572       "Displays zebra's error status (code, str, add)",
573       cmd_err},    
574     { "errcode",  "",
575       "Displays zebra's error code",
576       cmd_errcode},    
577     { "errstr",  "",
578       "Displays zebra's error string",
579       cmd_errstr},    
580     { "erradd",  "",
581       "Displays zebra's additional error message",
582       cmd_erradd},    
583   
584     { "", "Admin:","", 0}, 
585     { "init",  "",
586       "Initializes the zebra database, destroying all data in it",
587       cmd_init},    
588     { "select_database",  "basename",
589       "Selects a database",
590       cmd_select_database},    
591     { "create_database", "basename",
592       "Create database",
593       cmd_create_database},
594     { "drop_database", "basename",
595       "Drop database",
596       cmd_drop_database},
597     { "begin_trans", "[rw]",
598       "Begins a transaction. rw=1 means write, otherwise read-only",
599       cmd_begin_trans},
600     { "end_trans","",
601       "Ends a transaction",
602       cmd_end_trans},
603
604     { "","Updating:","",0},
605     { "record_insert","record",
606       "inserts an sgml record into Default",
607       cmd_record_insert},
608     { "exchange_record","database record-id action record",
609       "inserts (1), updates (2), or deletes (3) a record \n"
610       "record-id must be a unique identifier for the record",
611       cmd_exchange_record},
612
613     { "","Searching and retrieving:","",0},
614     { "search_pqf","setname query",
615       "search ",
616       cmd_search_pqf},
617     { "find","query",
618       "simplified search",
619       cmd_find},
620     { "f","query",
621       "simplified search",
622       cmd_find},
623     { "show","[start] [numrecs] [resultset]",
624       "shows a result",
625       cmd_show},
626     { "s","[start] [numrecs] [resultset]",
627       "shows a result",
628       cmd_show},
629     { "sort","sortspec",
630       "sorts a result set. (example spec: 1=4 >)",
631       cmd_sort},
632       
633     { "", "Misc:","", 0}, 
634     { "echo", "string", 
635       "ouputs the string", 
636       cmd_echo },
637     { "q", "", 
638       "exits the program", 
639       cmd_quit },
640     { "quit", "", 
641       "exits the program", 
642       cmd_quit },
643     { "help", "[command]", 
644       "Gives help on command, or lists them all", 
645       cmd_help },
646     { "", "help [command] gives more info on command", "",0 },   
647   
648     {0,0,0,0} /* end marker */
649 };
650  
651 int onecommand( 
652                 char *line,     /* input line */
653                 WRBUF outbuff,  /* output goes here */
654                 const char *prevout) /* prev output, for 'expect' */
655 {
656     int i;
657     char *args[MAX_NO_ARGS];
658     int nargs;
659     char argbuf[MAX_ARG_LEN];
660     yaz_log(log_level,"%s",line);
661     strncpy(argbuf,line, MAX_ARG_LEN-1);
662     argbuf[MAX_ARG_LEN-1]='\0'; /* just to be sure */
663     /*memset(args,'\0',MAX_NO_ARGS*sizeof(char *));*/
664     nargs=split_args(argbuf, args);
665     
666 #if 0
667     for (i = 0; i <= n; i++)
668     {
669         const char *cp = args[i];
670         printf ("args %d :%s:\n", i, cp ? cp : "<null>");
671     }
672 #endif
673     if (0==nargs)
674             return -90; /* no command on line, too bad */
675
676     if (0==strcmp(args[0],"expect")) 
677     {
678         char *rest;
679         if (nargs>1) /* args[0] is not yet set, can't use restargs */
680             rest= line + (args[1]-argbuf); /* rest of the line */
681         else
682             return -1; /* need something to expect */
683         if (0==strstr(prevout,rest))
684         {
685             printf( "Failed expectation, '%s' not found\n", rest);
686             exit(9); 
687         }
688         return 0;
689     }
690     for (i=0;cmds[i].cmd;i++)
691         if (0==strcmp(cmds[i].cmd, args[0])) 
692         {
693             if (nargs>1)
694                 args[0]= line + (args[1]-argbuf); /* rest of the line */
695             else
696                 args[0]=""; 
697             return ((cmds[i].testfunc)(args,outbuff));
698         }
699     wrbuf_printf(outbuff, "Unknown command '%s'. Try help\n",args[0]);
700     yaz_log(log_level,"Unknown command");
701     return -90; 
702 }
703  
704 static int cmd_help( char *args[], WRBUF outbuff)
705
706     int i;
707     int linelen;
708     if (args[1]) 
709     { /* help for a single command */ 
710         for (i=0;cmds[i].cmd;i++)
711             if (0==strcmp(cmds[i].cmd, args[1])) 
712             {
713                 wrbuf_printf(outbuff,"%s  %s\n%s\n",
714                              cmds[i].cmd, cmds[i].args, 
715                              cmds[i].explanation);
716                 return 0;
717             }
718         wrbuf_printf(outbuff, "Unknown command '%s'", args[1]);
719     }
720     else 
721     { /* list all commands */
722         linelen=9999;
723         for (i=0;cmds[i].cmd;i++)
724         {
725             if (*cmds[i].cmd)
726             { /* ordinary command */
727                 if (linelen>50)
728                 {
729                     wrbuf_puts(outbuff,"\n   ");
730                     linelen=0;
731                 }
732                 linelen += strlen(cmds[i].cmd) + 2;
733                 wrbuf_printf(outbuff,"%s ", cmds[i].cmd);
734             } else
735             { /* section head */
736                 wrbuf_printf(outbuff,"\n%s\n   ",cmds[i].args);
737                 linelen=0;
738             }
739             } /* for */
740         wrbuf_puts(outbuff,"\n");
741     }
742     return 0;
743 }
744  
745 /* If Zebra reports an error after an operation,
746  * append it to the outbuff and log it */
747 static void Zerrors (WRBUF outbuff)
748 {
749     int ec;
750     if (!zh)
751         return ;
752     ec=zebra_errCode (zh);
753     if (ec)
754     {
755         yaz_log(log_level, "   Zebra error %d: %s, (%s)",
756              ec, zebra_errString (zh),
757              zebra_errAdd (zh) );
758         wrbuf_printf(outbuff, "   Zebra error %d: %s, (%s)\n",
759                      ec, zebra_errString (zh),
760                      zebra_errAdd (zh) );
761     }
762 }
763
764 /************************************** 
765  * The shell
766  */
767  
768 void shell(void)
769 {
770     int rc=0;
771     WRBUF outbuff=wrbuf_alloc();
772     char prevout[MAX_OUT_BUFF]=""; /* previous output for 'expect' */
773     wrbuf_puts(outbuff,"Zebrash at your service");
774     while (rc!=-99)
775     {
776         char *nl_cp;
777         char buf[MAX_ARG_LEN];
778         char* line_in = 0;
779 #if HAVE_READLINE_READLINE_H
780         if (isatty(0)) {
781             line_in=readline(PROMPT);
782             if (!line_in)
783                 break;
784 #if HAVE_READLINE_HISTORY_H
785             if (*line_in)
786                 add_history(line_in);
787 #endif
788         }
789 #endif
790         /* line_in != NULL if readine is present and input is a tty */
791         
792         printf (PROMPT); 
793         fflush (stdout);
794         if (line_in)
795         {
796             if(strlen(line_in) > MAX_ARG_LEN-1) {
797                 fprintf(stderr,"Input line too long\n");
798                 break;
799             }
800             strcpy(buf,line_in);
801             free (line_in);
802         }
803         else 
804         {
805             if (!fgets (buf, MAX_ARG_LEN-1, stdin))
806                 break; 
807         }
808         
809         /* get rid of \n in line */
810         if ((nl_cp = strchr(buf, '\n')))
811             *nl_cp = '\0';
812         strncpy(prevout, wrbuf_cstr(outbuff), MAX_OUT_BUFF);
813         wrbuf_rewind(outbuff);
814         rc=onecommand(buf, outbuff, prevout);
815         if (rc==0)
816         {
817             wrbuf_puts(outbuff, "   OK\n");
818             yaz_log(log_level, "OK");
819         }
820         else if (rc>-90)
821         {
822             wrbuf_printf(outbuff, "   command returned %d\n",rc);
823         } 
824         Zerrors(outbuff);
825         printf("%s\n", wrbuf_cstr(outbuff));
826     } /* while */
827     wrbuf_destroy(outbuff);
828 } /* shell() */
829
830
831 static void usage(void)
832 {
833     printf ("usage:\n");
834     printf ("zebrash [-c config]\n");
835     exit(1);
836 }
837 /**************************************
838  * Main 
839  */
840
841 int main (int argc, char ** argv)
842 {
843     int ret;
844     char *arg = 0;
845     while ((ret = options ("c:h", argv, argc, &arg)) != -2)
846     {
847         switch(ret)
848         {
849         case 'c':
850             default_config = arg;
851             break;
852         case 'h':
853             usage();
854         /* FIXME - handle -v */
855         default:
856             fprintf(stderr, "bad option %s\n", arg);
857             usage();
858         }
859     }
860     log_level=yaz_log_module_level("zebrash");
861
862     shell();
863     return 0;
864 } /* main */
865 /*
866  * Local variables:
867  * c-basic-offset: 4
868  * indent-tabs-mode: nil
869  * End:
870  * vim: shiftwidth=4 tabstop=8 expandtab
871  */
872