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