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