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