928bf957cd1705ae439789e6b774bae0a6c3e4fc
[idzebra-moved-to-github.git] / index / zebrash.c
1 /* $Id: zebrash.c,v 1.33 2005-03-09 12:14:42 adam Exp $
2    Copyright (C) 1995-2005
3    Index Data ApS
4
5 This file is part of the Zebra server.
6
7 Zebra is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
10 version.
11
12 Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Zebra; see the file LICENSE.zebra.  If not, write to the
19 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
20 02111-1307, USA.
21 */
22
23 /* 
24    zebrash.c - command-line interface to zebra API
25 */
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h> 
30 #include <ctype.h>
31 #include <unistd.h>  /* for isatty */
32
33 #if HAVE_READLINE_READLINE_H
34 #include <readline/readline.h> 
35 #endif
36 #if HAVE_READLINE_HISTORY_H
37 #include <readline/history.h>
38 #endif
39
40 #include <idzebra/api.h>
41 #include <yaz/log.h>
42 #include <yaz/proto.h>
43 #include <yaz/sortspec.h>
44 #include <yaz/options.h>
45 #include <yaz/wrbuf.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);
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, 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     SYSNO sysno=0;
353     int rc;
354     char *rec=restargs(args,1);
355     
356     rc = zebra_insert_record(zh,
357                              0,  /* record type */
358                              &sysno,
359                              0,  /* match */
360                              0,  /* fname */
361                              rec,
362                              strlen(rec),
363                              0);
364     if (0==rc)
365     {
366         wrbuf_printf(outbuff,"ok sysno=%d\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     rc=zebra_admin_exchange_record(zh, rec, strlen(rec),
385         id, strlen(id), atoi(action));
386     return rc;
387 }
388
389 /**********************************
390  * Searching and retrieving
391  */
392
393 static int cmd_search_pqf(char *args[], WRBUF outbuff)
394 {
395     zint hits = 0;
396     char *set = args[1];
397     char *qry = restargs(args,2);
398     int rc;
399     rc = zebra_search_PQF(zh, qry, set, &hits);
400     if (0==rc)
401         wrbuf_printf(outbuff, ZINT_FORMAT " hits found\n", hits);
402     return rc;
403 }
404
405 static int cmd_find( char *args[], WRBUF outbuff)
406 {
407     char *setname=DEFAULTRESULTSET;
408     int rc;
409     zint hits = 0;
410     WRBUF qry = wrbuf_alloc();
411     if (0==strstr(args[0],"@attr"))
412         wrbuf_puts(qry, "@attr 1=/ ");
413     wrbuf_puts(qry,restargs(args,1));
414     if (!zh)
415         onecommand("quickstart", outbuff, "");
416     wrbuf_printf(outbuff, "find %s\n",wrbuf_buf(qry));
417     rc = zebra_search_PQF(zh, wrbuf_buf(qry), setname, &hits);
418     if (0==rc)
419     {
420         wrbuf_printf(outbuff, ZINT_FORMAT " hits found\n", hits);
421         nextrecno = 1;
422     }
423     wrbuf_free(qry, 1);
424     return rc;
425 }
426
427 static int cmd_show( char *args[], WRBUF outbuff)
428 {
429     int start=defargint(args[1], nextrecno);
430     int nrecs=defargint(args[2],1);
431     char *setname=defarg(args[3],DEFAULTRESULTSET);
432     int rc=0;
433     ZebraRetrievalRecord *recs;
434     ODR odr;
435     Z_RecordComposition *pcomp=0;
436     int i;
437     oid_value format;
438
439     odr=odr_createmem(ODR_ENCODE);
440     recs= odr_malloc(odr,sizeof(ZebraRetrievalRecord)*nrecs);
441     rc =z_RecordComposition(odr, &pcomp, 0,"recordComposition");
442     format=oid_getvalbyname ("xml"); /*FIXME - let the user specify*/
443     for (i=0;i<nrecs;i++)
444         recs[i].position=start+i;
445
446     rc = zebra_records_retrieve (zh, odr, setname,
447                                  pcomp, format, nrecs,recs);
448     if (0==rc)
449     {
450         for (i=0;i<nrecs;i++)
451         {
452             printf("Err %d: %d\n",i,recs[i].errCode);
453             if (recs[i].buf)
454             {
455                 wrbuf_printf(outbuff,"Record %d\n", recs[i].position);
456                 wrbuf_write(outbuff, recs[i].buf, recs[i].len);
457                 wrbuf_puts(outbuff, "\n");
458             } else
459                 wrbuf_printf(outbuff,"NO Record %d\n", recs[i].position);
460         }
461         nextrecno=start+nrecs;
462     }
463     odr_destroy(odr);
464     return rc;
465 } /* cmd_show */
466
467 static int cmd_sort( char *args[], WRBUF outbuff)
468 {
469     int rc=0;
470     ODR odr;
471     int sortstatus=0;
472     Z_SortKeySpecList *spec=0;
473     const char * inpsets[]={ DEFAULTRESULTSET, 0};
474     /* FIXME - allow the user to specify result sets in/out */
475
476     odr=odr_createmem(ODR_ENCODE);
477     spec=yaz_sort_spec (odr, restargs(args,1));
478     if (!spec)
479         rc=1;
480     if (!rc)
481         rc=zebra_sort(zh, odr,
482                         1, inpsets,
483                         DEFAULTRESULTSET,
484                         spec,
485                         &sortstatus);
486     if (!rc)
487         wrbuf_printf(outbuff, "sort returned status %d\n",sortstatus);
488
489     odr_destroy(odr);
490     return rc;
491 } /* cmd_sort */
492 /*
493  *
494  * int bend_sort (void *handle, bend_sort_rr *rr)
495  * {
496  *     ZebraHandle zh = (ZebraHandle) handle;
497  *
498  *     zebra_sort (zh, rr->stream,
499  *                     rr->num_input_setnames, (const char **)
500  *                     rr->input_setnames,
501  *                     rr->output_setname,
502  *                     rr->sort_sequence,
503  *                     &rr->sort_status);
504  *     zebra_result (zh, &rr->errcode,
505  *                  &rr->errstring);
506  *     return 0;
507  *  }
508  *
509  */
510
511 /**************************************)
512  * Command table, parser, and help 
513  */
514
515 struct cmdstruct
516 {
517     char *cmd;
518     char *args;
519     char *explanation;
520     int (*testfunc)(char *args[], WRBUF outbuff);
521 } ;
522
523  
524 struct cmdstruct cmds[] = {
525     /* special cases:
526      *   if text is 0, does not list the command
527      *   if cmd is "", adds the args (and newline) in command listing
528      */
529     { "", "Starting and stopping:", "", 0 },
530     { "zebra_start", 
531       "[configfile]", 
532       "starts the zebra service. You need to call this first\n"
533       "if no configfile is given, assumes " DEFAULTCONFIG, 
534       cmd_zebra_start },
535     { "zebra_stop",   "", 
536       "stops the zebra service", 
537       cmd_zebra_stop },
538     { "zebra_open", "",  
539       "starts a zebra session. Once you have called zebra_start\n"
540       "you can call zebra_open to start working", 
541       cmd_zebra_open },
542     { "zebra_close", "", 
543       "closes a zebra session", 
544       cmd_zebra_close }, 
545     { "quickstart", "[configfile]", 
546       "Does a zebra_start, zebra_open, and sets up the log", 
547       cmd_quickstart }, 
548   
549     { "", "Log file:","", 0},  
550     { "yaz_log_file", 
551       "[filename]",
552       "Directs the log to filename (or stderr)",
553       cmd_yaz_log_file },
554     { "yaz_log_level", 
555       "[level]",
556       "Sets the logging level (or returns to default)",
557       cmd_yaz_log_level },
558     { "yaz_log_prefix", 
559       "[prefix]",
560       "Sets the log prefix",
561       cmd_yaz_log_prefix},    
562     { "yaz_log", 
563       "[level] text...",
564       "writes an entry in the log",
565       cmd_logf},    
566
567     { "", "Error handling:","", 0},
568     { "err",  "",
569       "Displays zebra's error status (code, str, add)",
570       cmd_err},    
571     { "errcode",  "",
572       "Displays zebra's error code",
573       cmd_errcode},    
574     { "errstr",  "",
575       "Displays zebra's error string",
576       cmd_errstr},    
577     { "erradd",  "",
578       "Displays zebra's additional error message",
579       cmd_erradd},    
580   
581     { "", "Admin:","", 0}, 
582     { "init",  "",
583       "Initializes the zebra database, destroying all data in it",
584       cmd_init},    
585     { "select_database",  "basename",
586       "Selects a database",
587       cmd_select_database},    
588     { "create_database", "basename",
589       "Create database",
590       cmd_create_database},
591     { "drop_database", "basename",
592       "Drop database",
593       cmd_drop_database},
594     { "begin_trans", "[rw]",
595       "Begins a transaction. rw=1 means write, otherwise read-only",
596       cmd_begin_trans},
597     { "end_trans","",
598       "Ends a transaction",
599       cmd_end_trans},
600
601     { "","Updating:","",0},
602     { "record_insert","record",
603       "inserts an sgml record into Default",
604       cmd_record_insert},
605     { "exchange_record","database record-id action record",
606       "inserts (1), updates (2), or deletes (3) a record \n"
607       "record-id must be a unique identifier for the record",
608       cmd_exchange_record},
609
610     { "","Searching and retrieving:","",0},
611     { "search_pqf","setname query",
612       "search ",
613       cmd_search_pqf},
614     { "find","query",
615       "simplified search",
616       cmd_find},
617     { "f","query",
618       "simplified search",
619       cmd_find},
620     { "show","[start] [numrecs] [resultset]",
621       "shows a result",
622       cmd_show},
623     { "s","[start] [numrecs] [resultset]",
624       "shows a result",
625       cmd_show},
626     { "sort","sortspec",
627       "sorts a result set. (example spec: 1=4 >)",
628       cmd_sort},
629       
630     { "", "Misc:","", 0}, 
631     { "echo", "string", 
632       "ouputs the string", 
633       cmd_echo },
634     { "q", "", 
635       "exits the program", 
636       cmd_quit },
637     { "quit", "", 
638       "exits the program", 
639       cmd_quit },
640     { "help", "[command]", 
641       "Gives help on command, or lists them all", 
642       cmd_help },
643     { "", "help [command] gives more info on command", "",0 },   
644   
645     {0,0,0,0} /* end marker */
646 };
647  
648 int onecommand( 
649                 char *line,     /* input line */
650                 WRBUF outbuff,  /* output goes here */
651                 const char *prevout) /* prev output, for 'expect' */
652 {
653     int i;
654     char *args[MAX_NO_ARGS];
655     int nargs;
656     char argbuf[MAX_ARG_LEN];
657     yaz_log(log_level,"%s",line);
658     strncpy(argbuf,line, MAX_ARG_LEN-1);
659     argbuf[MAX_ARG_LEN-1]='\0'; /* just to be sure */
660     /*memset(args,'\0',MAX_NO_ARGS*sizeof(char *));*/
661     nargs=split_args(argbuf, args);
662     
663 #if 0
664     for (i = 0; i <= n; i++)
665     {
666         const char *cp = args[i];
667         printf ("args %d :%s:\n", i, cp ? cp : "<null>");
668     }
669 #endif
670     if (0==nargs)
671             return -90; /* no command on line, too bad */
672
673     if (0==strcmp(args[0],"expect")) 
674     {
675         char *rest;
676         if (nargs>1) /* args[0] is not yet set, can't use restargs */
677             rest= line + (args[1]-argbuf); /* rest of the line */
678         else
679             return -1; /* need something to expect */
680         if (0==strstr(prevout,rest))
681         {
682             printf( "Failed expectation, '%s' not found\n", rest);
683             exit(9); 
684         }
685         return 0;
686     }
687     for (i=0;cmds[i].cmd;i++)
688         if (0==strcmp(cmds[i].cmd, args[0])) 
689         {
690             if (nargs>1)
691                 args[0]= line + (args[1]-argbuf); /* rest of the line */
692             else
693                 args[0]=""; 
694             return ((cmds[i].testfunc)(args,outbuff));
695         }
696     wrbuf_printf(outbuff, "Unknown command '%s'. Try help\n",args[0]);
697     yaz_log(log_level,"Unknown command");
698     return -90; 
699 }
700  
701 static int cmd_help( char *args[], WRBUF outbuff)
702
703     int i;
704     int linelen;
705     if (args[1]) 
706     { /* help for a single command */ 
707         for (i=0;cmds[i].cmd;i++)
708             if (0==strcmp(cmds[i].cmd, args[1])) 
709             {
710                 wrbuf_printf(outbuff,"%s  %s\n%s\n",
711                              cmds[i].cmd, cmds[i].args, 
712                              cmds[i].explanation);
713                 return 0;
714             }
715         wrbuf_printf(outbuff, "Unknown command '%s'", args[1]);
716     }
717     else 
718     { /* list all commands */
719         linelen=9999;
720         for (i=0;cmds[i].cmd;i++)
721         {
722             if (*cmds[i].cmd)
723             { /* ordinary command */
724                 if (linelen>50)
725                 {
726                     wrbuf_puts(outbuff,"\n   ");
727                     linelen=0;
728                 }
729                 linelen += strlen(cmds[i].cmd) + 2;
730                 wrbuf_printf(outbuff,"%s ", cmds[i].cmd);
731             } else
732             { /* section head */
733                 wrbuf_printf(outbuff,"\n%s\n   ",cmds[i].args);
734                 linelen=0;
735             }
736             } /* for */
737         wrbuf_puts(outbuff,"\n");
738     }
739     return 0;
740 }
741  
742 /* If Zebra reports an error after an operation,
743  * append it to the outbuff and log it */
744 static void Zerrors ( WRBUF outbuff)
745 {
746     int ec;
747     if (!zh)
748         return ;
749     ec=zebra_errCode (zh);
750     if (ec)
751     {
752         yaz_log(log_level, "   Zebra error %d: %s, (%s)",
753              ec, zebra_errString (zh),
754              zebra_errAdd (zh) );
755         wrbuf_printf(outbuff, "   Zebra error %d: %s, (%s)\n",
756                      ec, zebra_errString (zh),
757                      zebra_errAdd (zh) );
758         zebra_clearError(zh);
759     }
760 }
761
762 /************************************** 
763  * The shell
764  */
765  
766 void shell()
767 {
768     int rc=0;
769     WRBUF outbuff=wrbuf_alloc();
770     char prevout[MAX_OUT_BUFF]=""; /* previous output for 'expect' */
771     wrbuf_puts(outbuff,"Zebrash at your service");
772     while (rc!=-99)
773     {
774         char *nl_cp;
775         char buf[MAX_ARG_LEN];
776         char* line_in = 0;
777 #if HAVE_READLINE_READLINE_H
778         if (isatty(0)) {
779             line_in=readline(PROMPT);
780             if (!line_in)
781                 break;
782 #if HAVE_READLINE_HISTORY_H
783             if (*line_in)
784                 add_history(line_in);
785 #endif
786         }
787 #endif
788         /* line_in != NULL if readine is present and input is a tty */
789         
790         printf (PROMPT); 
791         fflush (stdout);
792         if (line_in)
793         {
794             if(strlen(line_in) > MAX_ARG_LEN-1) {
795                 fprintf(stderr,"Input line too long\n");
796                 break;
797             }
798             strcpy(buf,line_in);
799             free (line_in);
800         }
801         else 
802         {
803             if (!fgets (buf, MAX_ARG_LEN-1, stdin))
804                 break; 
805         }
806         
807         /* get rid of \n in line */
808         if ((nl_cp = strchr(buf, '\n')))
809             *nl_cp = '\0';
810         strncpy(prevout, wrbuf_buf(outbuff), MAX_OUT_BUFF);
811         wrbuf_rewind(outbuff);
812         rc=onecommand(buf, outbuff, prevout);
813         if (rc==0)
814         {
815             wrbuf_puts(outbuff, "   OK\n");
816             yaz_log(log_level, "OK");
817         }
818         else if (rc>-90)
819         {
820             wrbuf_printf(outbuff, "   command returned %d\n",rc);
821         } 
822         Zerrors(outbuff);
823         printf("%s\n", wrbuf_buf(outbuff));
824     } /* while */
825     wrbuf_free(outbuff,1);
826 } /* shell() */
827
828
829 static void usage()
830 {
831     printf ("usage:\n");
832     printf ("zebrash [-c config]\n");
833     exit(1);
834 }
835 /**************************************
836  * Main 
837  */
838
839 int main (int argc, char ** argv)
840 {
841     int ret;
842     char *arg = 0;
843     while ((ret = options ("c:h", argv, argc, &arg)) != -2)
844     {
845         switch(ret)
846         {
847         case 'c':
848             default_config = arg;
849             break;
850         case 'h':
851             usage();
852         /* FIXME - handle -v */
853         default:
854             fprintf(stderr, "bad option %s\n", arg);
855             usage();
856         }
857     }
858     log_level=yaz_log_module_level("zebrash");
859
860     shell();
861     return 0;
862 } /* main */