Implemented drop database
[idzebra-moved-to-github.git] / index / zebrash.c
1 /* $Id: zebrash.c,v 1.14 2003-06-30 19:37:12 adam Exp $
2    Copyright (C) 2002,2003
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
32 #if HAVE_READLINE_READLINE_H
33 #include <readline/readline.h> 
34 #endif
35 #if HAVE_READLINE_HISTORY_H
36 #include <readline/history.h>
37 #endif
38
39 #include "zebraapi.h"
40 #include <yaz/log.h>
41
42 #define MAX_NO_ARGS 32
43 #define MAX_OUT_BUFF 4096
44 #define MAX_ARG_LEN 1024
45 #define PROMPT "ZebraSh>"
46 #define DEFAULTCONFIG "./zebra.cfg"
47
48 /**************************************
49  * Global variables (yuck!)
50  */
51
52 ZebraService zs=0;  /* our global handle to zebra */
53 ZebraHandle  zh=0;  /* the current session */
54 /* time being, only one session works */
55
56 /**************************************
57  * Help functions
58  */
59
60  
61 static int split_args( char *line, char** args )
62 { /* splits line into individual null-terminated strings, 
63    * returns pointers to them in args */
64   /* FIXME - do we need to handle quoted args ?? */
65     char *p=line;
66     int i=0;
67     int n=0;
68     args[0]=0; /* by default */
69     while (*p==' ' || *p=='\t' || *p=='\n')
70         p++;
71     while (*p)
72     {
73         while (*p==' ' || *p=='\t' || *p=='\n')
74             p++;
75         if (*p=='#')  /* skip comments */
76             break;  
77         args[i++]=p;
78         args[i]=0;
79         while (*p && *p!=' ' && *p!='\t' && *p!='\n' && *p!='#')
80             p++;
81         *p++='\0';
82     }
83     n=i;
84     while (n<MAX_NO_ARGS)
85         args[n++]=0;
86     return i;
87 }
88
89 static char *defarg( char *arg, char *def )
90 {
91     if (!arg)
92         return def;
93     if (!*arg)
94         return def;
95     return arg;
96 }
97 static int defargint( char *arg, int def )
98 {
99     int v=def;
100     char *a=defarg(arg,0);
101     if (a)
102         sscanf(a," %i", &v);
103     return v;
104 }
105
106 int onecommand( char *line, char *outbuff, const char *prevout); 
107  
108 /**************************************
109  * Simple support commands
110  */
111
112 int cmd_echo( char *args[], char *outbuff)
113 {
114     strcpy(outbuff, args[0]);
115     return 0;
116 }
117  
118 int cmd_quit( char *args[], char *outbuff)
119 {
120     strcpy(outbuff, "bye");
121     return -99; /* special stop signal */
122 }
123
124 /**************************************
125  * Tests for starting and stopping zebra, etc
126  */
127  
128 static int cmd_help( char *args[], char *outbuff); 
129  
130 static int cmd_zebra_start( char *args[], char *outbuff)
131 {
132     char *conf=args[1];
133     if (!conf || !*conf) {
134         strcat(outbuff,"no config file specified, using "
135                DEFAULTCONFIG "\n" );
136         conf=DEFAULTCONFIG;
137     }
138     zs=zebra_start(conf);
139     if (!zs) {
140         strcpy(outbuff, "zebra_start failed" );
141         return 2;
142     }
143     return 0; /* ok */
144 }
145  
146 static int cmd_zebra_stop( char *args[], char *outbuff)
147 {
148     if (!zs)
149         strcat(outbuff,"zebra seems not to have been started, "
150                "stopping anyway\n");
151     zebra_stop(zs);
152     zs=0;
153     return 0; /* ok */
154 }
155
156 static int cmd_zebra_open( char *args[], char *outbuff)
157 {
158     if (!zs)
159         strcat(outbuff,"zebra seems not to have been started, "
160                "trying anyway\n");
161     zh=zebra_open(zs);
162     return 0; /* ok */
163 }
164
165 static int cmd_zebra_close( char *args[], char *outbuff)
166 {
167     if (!zh)
168         strcat(outbuff,"Seems like you have not called zebra_open,"
169                "trying anyway\n");
170     zebra_close(zh);
171     return 0; /* ok */
172 }
173
174 static int cmd_quickstart( char *args[], char *outbuff)
175 {
176     char tmp[128];
177     int rc=0;
178     if (!rc)
179         rc=onecommand("yaz_log_file zebrash.log",outbuff,"");
180     if (!rc)
181         rc=onecommand("yaz_log_prefix ZebraSh", outbuff,"");
182     sprintf(tmp, "yaz_log_level 0x%x", LOG_DEFAULT_LEVEL | LOG_APP);
183     if (!rc)
184         rc=onecommand(tmp,outbuff,"");
185     logf(LOG_APP,"quickstart");
186     if (!rc)
187         rc=onecommand("zebra_start",outbuff,"");
188     if (!rc)
189         rc=onecommand("zebra_open",outbuff,"");
190     if (!rc)
191         rc=onecommand("select_database Default",outbuff,"");
192     return rc;
193 }
194
195 /**************************************
196  * Log file handling
197  */
198
199 static int cmd_yaz_log_file( char *args[], char *outbuff)
200 {
201     char *fn = defarg(args[1],0);
202     char tmp[255];
203     sprintf(tmp, "sending yaz-log to %s\n",fn);
204     strcat(outbuff, tmp);
205     yaz_log_init_file(fn);
206     return 0; /* ok */
207 }
208
209 static int cmd_yaz_log_level( char *args[], char *outbuff)
210 {
211     int  lev = defargint(args[1],LOG_DEFAULT_LEVEL);
212     char tmp[255];
213     sprintf(tmp, "setting yaz-log to level %d (ox%x)\n",lev,lev);
214     strcat(outbuff, tmp);
215     yaz_log_init_level(lev);
216     return 0; /* ok */
217 }
218
219 static int cmd_yaz_log_prefix( char *args[], char *outbuff)
220 {
221     char *pref = defarg(args[1],"ZebraSh");
222     char tmp[255];
223     sprintf(tmp, "setting yaz-log prefix to %s\n",pref);
224     strcat(outbuff, tmp);
225     yaz_log_init_prefix(pref);
226     return 0; /* ok */
227 }
228
229 static int cmd_logf( char *args[], char *outbuff)
230 {
231     int lev = defargint(args[1],0);
232     char tmp[MAX_OUT_BUFF]="";
233     int i=1;
234     if (lev)
235         i=2;
236     else
237         lev=LOG_LOG; /* this is in the default set!*/
238     while (args[i])
239     {
240         strcat(tmp, args[i++]);
241         strcat(tmp, " ");
242     }
243     logf(lev,tmp);
244     return 0; /* ok */
245 }
246  
247 /****************
248  * Error handling 
249  */
250 static int cmd_err ( char *args[], char *outbuff)
251 {
252     char tmp[MAX_OUT_BUFF];
253     sprintf(tmp, "errCode: %d \nerrStr:  %s\nerrAdd:  %s \n",
254             zebra_errCode (zh),
255             zebra_errString (zh),  
256             zebra_errAdd (zh) );
257     strcat(outbuff, tmp);
258     return 0; /* ok */
259 }
260 static int cmd_errcode ( char *args[], char *outbuff)
261 {
262     char tmp[MAX_OUT_BUFF];
263     sprintf(tmp, "errCode: %d \n",
264             zebra_errCode (zh));
265     strcat(outbuff, tmp);
266     return 0; /* ok */
267 }
268 static int cmd_errstr ( char *args[], char *outbuff)
269 {
270     char tmp[MAX_OUT_BUFF];
271     sprintf(tmp, "errStr:  %s\n",
272             zebra_errString (zh));
273     strcat(outbuff, tmp);
274     return 0; /* ok */
275 }
276 static int cmd_erradd ( char *args[], char *outbuff)
277 {
278     char tmp[MAX_OUT_BUFF];
279     sprintf(tmp, "errAdd:  %s \n",
280             zebra_errAdd (zh) ); 
281     strcat(outbuff, tmp);
282     return 0; /* ok */
283 }
284
285 /**************************************
286  * Admin commands
287  */
288
289 static int cmd_init ( char *args[], char *outbuff)
290 {
291     zebra_init(zh);
292     return 0; /* ok */
293 }
294
295 static int cmd_select_database ( char *args[], char *outbuff)
296 {
297     char *db=args[1];
298     if (!db) {
299         db="Default";
300         strcat(outbuff,"Selecting database 'Default'\n");
301     }
302     return zebra_select_database(zh, db);
303 }
304  
305 static int cmd_create_database( char *args[], char *outbuff)
306 {
307     char *db=args[1];
308     if (!db)
309         db="Default";
310     strcat(outbuff,"Creating database ");
311     strcat(outbuff,db);
312     strcat(outbuff,"\n");
313         
314     return zebra_create_database(zh, db);
315 }
316
317 static int cmd_drop_database( char *args[], char *outbuff)
318 {
319     char *db=args[1];
320     if (!db)
321         db="Default";
322     strcat(outbuff,"Dropping database ");
323     strcat(outbuff,db);
324     strcat(outbuff,"\n");
325         
326     return zebra_drop_database(zh, db);
327 }
328
329 static int cmd_begin_trans( char *args[], char *outbuff)
330 {
331     int rw=0;
332     if (args[1] && ( (args[1][0]=='1') || (args[1][0]=='w') ))
333         rw=1;
334     return zebra_begin_trans(zh,rw);
335 }
336 static int cmd_end_trans( char *args[], char *outbuff)
337 {
338     return zebra_end_trans(zh);
339 }
340 /*************************************
341  * Inserting and deleting
342  */
343
344 static int cmd_record_insert( char *args[], char *outbuff)
345 {
346     int sysno=0;
347     char buf[MAX_ARG_LEN];
348     int i;
349     int rc;
350     
351     i=1;
352     buf[0]='\0';
353     while (args[i])
354     {
355         strcat(buf, args[i++]);
356         strcat(buf, " ");
357     }
358     rc=zebra_record_insert(zh,buf, strlen(buf), &sysno);
359     if (0==rc)
360     {
361         sprintf(buf,"ok sysno=%d\n",sysno);
362         strcat(outbuff,buf);
363     }
364     return rc;
365 }
366
367
368 static int cmd_exchange_record( char *args[], char *outbuff)
369 {
370     char *base=args[1];
371     char *id = args[2];
372     char *action = args[3];
373     int i=4;
374     int rc;
375     char buf[MAX_ARG_LEN];
376     if (!(base && id && action && args[4] ))
377     {
378         strcat(outbuff,"Missing arguments!\n");
379         onecommand("help exchange_record", outbuff, "");
380         return -90;
381     }
382     while (args[i])
383     {
384         strcat(buf, args[i++]);
385         strcat(buf, " ");
386     }
387     rc=zebra_admin_exchange_record(zh, base, buf, strlen(buf),
388         id, strlen(id), atoi(action));
389     return rc;
390 }
391
392
393 /**************************************)
394  * Command table, parser, and help 
395  */
396
397 struct cmdstruct
398 {
399     char * cmd;
400     char * args;
401     char * explanation;
402     int (*testfunc)(char *args[], char *outbuff);
403 } ;
404
405  
406 struct cmdstruct cmds[] = {
407     /* special cases:
408      *   if text is 0, does not list the command
409      *   if cmd is "", adds the args (and newline) in command listing
410      */
411     { "", "Starting and stopping:", "", 0 },
412     { "zebra_start", 
413       "[configfile]", 
414       "starts the zebra service. You need to call this first\n"
415       "if no configfile is given, assumes " DEFAULTCONFIG, 
416       cmd_zebra_start },
417     { "zebra_stop",   "", 
418       "stops the zebra service", 
419       cmd_zebra_stop },
420     { "zebra_open", "",  
421       "starts a zebra session. Once you have called zebra_start\n"
422       "you can call zebra_open to start working", 
423       cmd_zebra_open },
424     { "zebra_close", "", 
425       "closes a zebra session", 
426       cmd_zebra_close }, 
427     { "quickstart", "[configfile]", 
428       "Does a zebra_start, zebra_open, and sets up the log", 
429       cmd_quickstart }, 
430   
431     { "", "Log file:","", 0},  
432     { "yaz_log_file", 
433       "[filename]",
434       "Directs the log to filename (or stderr)",
435       cmd_yaz_log_file },
436     { "yaz_log_level", 
437       "[level]",
438       "Sets the logging level (or returns to default)",
439       cmd_yaz_log_level },
440     { "yaz_log_prefix", 
441       "[prefix]",
442       "Sets the log prefix",
443       cmd_yaz_log_prefix},    
444     { "logf", 
445       "[level] text...",
446       "writes an entry in the log",
447       cmd_logf},    
448
449     { "", "Error handling:","", 0},
450     { "err",  "",
451       "Displays zebra's error status (code, str, add)",
452       cmd_err},    
453     { "errcode",  "",
454       "Displays zebra's error code",
455       cmd_errcode},    
456     { "errstr",  "",
457       "Displays zebra's error string",
458       cmd_errstr},    
459     { "erradd",  "",
460       "Displays zebra's additional error message",
461       cmd_erradd},    
462   
463     { "", "Admin:","", 0}, 
464     { "init",  "",
465       "Initializes the zebra database, destroying all data in it",
466       cmd_init},    
467     { "select_database",  "basename",
468       "Selects a database",
469       cmd_select_database},    
470     { "create_database", "basename",
471       "Create database",
472       cmd_create_database},
473     { "drop_database", "basename",
474       "Drop database",
475       cmd_drop_database},
476     { "begin_trans", "[rw]",
477       "Begins a transaction. rw=1 means write, otherwise read-only",
478       cmd_begin_trans},
479     { "end_trans","",
480       "Ends a transaction",
481       cmd_end_trans},
482
483     { "","Updating:","",0},
484     { "record_insert","record",
485       "inserts an sgml record into Default",
486       cmd_record_insert},
487     { "exchange_record","database record-id action record",
488       "inserts (1), updates (2), or deletes (3) a record \n"
489       "record-id must be a unique identifier for the record",
490       cmd_exchange_record},
491     { "", "Misc:","", 0}, 
492     { "echo", "string", 
493       "ouputs the string", 
494       cmd_echo },
495     { "quit", "", 
496       "exits the program", 
497       cmd_quit },
498     { "help", "[command]", 
499       "Gives help on command, or lists them all", 
500       cmd_help },
501     { "", "help [command] gives more info on command", "",0 },   
502   
503     {0,0,0,0} /* end marker */
504 };
505  
506 int onecommand( 
507                 char *line,     /* input line */
508                 char *outbuff,  /* output goes here */
509                 const char *prevout) /* prev output, for 'expect' */
510 {
511     int i;
512     char *args[MAX_NO_ARGS];
513     int n;
514     char argbuf[MAX_ARG_LEN];
515     logf(LOG_APP,"%s",line);
516     strncpy(argbuf,line, MAX_ARG_LEN-1);
517     argbuf[MAX_ARG_LEN-1]='\0'; /* just to be sure */
518     n=split_args(argbuf, args);
519
520 #if 0
521     for (i = 0; i <= n; i++)
522     {
523         const char *cp = args[i];
524         printf ("args %d :%s:\n", i, cp ? cp : "<null>");
525     }
526 #endif
527     if (0==n)
528         return -90; /* no command on line, too bad */
529
530     if (0==strcmp(args[0],"expect")) 
531     {
532         char *rest;
533         if (n>1)
534             rest= line + (args[1]-argbuf); /* rest of the line */
535         else
536             return -1; /* need something to expect */
537         printf("expecting '%s'\n",rest); /*!*/
538         if (0==strstr(prevout,rest))
539         {
540             printf( "Failed expectation, '%s' not found\n", rest);
541             exit(9); 
542         }
543         return 0;
544     }
545     for (i=0;cmds[i].cmd;i++)
546         if (0==strcmp(cmds[i].cmd, args[0])) 
547         {
548             if (n>1)
549                 args[0]= line + (args[1]-argbuf); /* rest of the line */
550             else
551                 args[0]=""; 
552             return ((cmds[i].testfunc)(args,outbuff));
553         }
554     strcat(outbuff, "Unknown command '");
555     strcat(outbuff,args[0] );
556     strcat(outbuff,"'. Try help");
557     logf(LOG_APP,"Unknown command");
558     return -90; 
559 }
560  
561 static int cmd_help( char *args[], char *outbuff)
562
563     int i;
564     char tmp[MAX_ARG_LEN];
565     if (args[1]) 
566     { /* help for a single command */ 
567         for (i=0;cmds[i].cmd;i++)
568             if (0==strcmp(cmds[i].cmd, args[1])) 
569             {
570                 strcat(outbuff,cmds[i].cmd);
571                 strcat(outbuff,"  ");
572                 strcat(outbuff,cmds[i].args);
573                 strcat(outbuff,"\n");
574                 strcat(outbuff,cmds[i].explanation);
575                 strcat(outbuff,"\n");
576                 return 0;
577             }
578         strcat(outbuff, "Unknown command ");
579         strcat(outbuff, args[1] );
580     }
581     else 
582     { /* list all commands */
583         strcpy(tmp,"    ");
584         for (i=0;cmds[i].cmd;i++)
585             if (cmds[i].explanation)
586             {
587                 /* sprintf(tmp, "%s %s %s\n",
588                    cmds[i].cmd, cmds[i].args, cmds[i].explanation);
589                 */
590                 strcat(tmp, cmds[i].cmd);
591                 strcat(tmp,"  ");
592                 if (!*cmds[i].cmd)
593                 {
594                     strcat(outbuff, tmp);
595                     strcat(outbuff,"\n");
596                     strcpy(tmp,"    ");
597                     if (*cmds[i].args)
598                     {
599                         strcat(outbuff, cmds[i].args);
600                         strcat(outbuff,"\n");
601                     }
602                 }
603                 if (strlen(tmp)>50)
604                 {
605                     strcat(outbuff,tmp);
606                     strcat(outbuff,"\n");
607                     strcpy(tmp,"    ");
608                 }
609             }
610         strcat(outbuff,tmp);
611     }
612     return 0;
613 }
614  
615 /* If Zebra reports an error after an operation,
616  * append it to the outbuff and log it */
617 static void Zerrors ( char *outbuff)
618 {
619     int ec;
620     char tmp[MAX_OUT_BUFF];
621     if (!zh)
622         return ;
623     ec=zebra_errCode (zh);
624     if (ec)
625     {
626         sprintf(tmp, "   Zebra error %d: %s, (%s)",
627                 ec, zebra_errString (zh),
628                 zebra_errAdd (zh) );
629         strcat(outbuff, tmp);
630         strcat(outbuff, "\n");
631         logf(LOG_APP, tmp);
632         zebra_clearError(zh);
633     }
634 }
635   
636 /************************************** 
637  * The shell
638  */
639  
640 void shell()
641 {
642     int rc=0;
643     char tmp[MAX_ARG_LEN];
644     char outbuff[MAX_OUT_BUFF]="";
645     char prevout[MAX_OUT_BUFF]=""; /* previous output for 'expect' */
646     while (rc!=-99)
647     {
648         char buf[MAX_ARG_LEN];
649 #if HAVE_READLINE_READLINE_H
650         char* line_in;
651         line_in=readline(PROMPT);
652         if (!line_in)
653             break;
654 #if HAVE_READLINE_HISTORY_H
655         if (*line_in)
656             add_history(line_in);
657 #endif
658         if(strlen(line_in) > MAX_ARG_LEN-1) {
659             fprintf(stderr,"Input line too long\n");
660             break;
661         };
662         strcpy(buf,line_in);
663         free (line_in);
664 #else    
665         printf (PROMPT); 
666         fflush (stdout);
667         if (!fgets (buf, MAX_ARG_LEN-1, stdin))
668             break; 
669 #endif 
670         
671         strncpy(prevout, outbuff, MAX_OUT_BUFF);
672         outbuff[0]='\0';
673         rc=onecommand(buf, outbuff, prevout);
674         if (rc==0)
675         {
676             strcat(outbuff, "   OK\n");
677             logf(LOG_APP, "OK");
678         }
679         else if (rc>-90)
680         {
681             sprintf(tmp, "   command returned %d\n",rc);
682             strcat(outbuff,tmp);
683         } 
684         Zerrors(outbuff);
685         printf("%s\n", outbuff);
686     } /* while */
687 } /* shell() */
688   
689  
690 /**************************************
691  * Main 
692  */
693  
694 int main (int argc, char ** args)
695 {
696     shell();
697     return 0;
698 } /* main */