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