Added quick find command 'find' (or 'f'). Quickstarts
[idzebra-moved-to-github.git] / index / zebrash.c
1 /* $Id: zebrash.c,v 1.15 2003-07-03 14:45:02 heikki 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 (!zs)
187         if (!rc)
188             rc=onecommand("zebra_start",outbuff,"");
189     if (!zh)
190         if (!rc)
191             rc=onecommand("zebra_open",outbuff,"");
192     if (!rc)
193         rc=onecommand("select_database Default",outbuff,"");
194     return rc;
195 }
196
197 /**************************************
198  * Log file handling
199  */
200
201 static int cmd_yaz_log_file( char *args[], char *outbuff)
202 {
203     char *fn = defarg(args[1],0);
204     char tmp[255];
205     sprintf(tmp, "sending yaz-log to %s\n",fn);
206     strcat(outbuff, tmp);
207     yaz_log_init_file(fn);
208     return 0; /* ok */
209 }
210
211 static int cmd_yaz_log_level( char *args[], char *outbuff)
212 {
213     int  lev = defargint(args[1],LOG_DEFAULT_LEVEL);
214     char tmp[255];
215     sprintf(tmp, "setting yaz-log to level %d (ox%x)\n",lev,lev);
216     strcat(outbuff, tmp);
217     yaz_log_init_level(lev);
218     return 0; /* ok */
219 }
220
221 static int cmd_yaz_log_prefix( char *args[], char *outbuff)
222 {
223     char *pref = defarg(args[1],"ZebraSh");
224     char tmp[255];
225     sprintf(tmp, "setting yaz-log prefix to %s\n",pref);
226     strcat(outbuff, tmp);
227     yaz_log_init_prefix(pref);
228     return 0; /* ok */
229 }
230
231 static int cmd_logf( char *args[], char *outbuff)
232 {
233     int lev = defargint(args[1],0);
234     char tmp[MAX_OUT_BUFF]="";
235     int i=1;
236     if (lev)
237         i=2;
238     else
239         lev=LOG_LOG; /* this is in the default set!*/
240     while (args[i])
241     {
242         strcat(tmp, args[i++]);
243         strcat(tmp, " ");
244     }
245     logf(lev,tmp);
246     return 0; /* ok */
247 }
248  
249 /****************
250  * Error handling 
251  */
252 static int cmd_err ( char *args[], char *outbuff)
253 {
254     char tmp[MAX_OUT_BUFF];
255     sprintf(tmp, "errCode: %d \nerrStr:  %s\nerrAdd:  %s \n",
256             zebra_errCode (zh),
257             zebra_errString (zh),  
258             zebra_errAdd (zh) );
259     strcat(outbuff, tmp);
260     return 0; /* ok */
261 }
262 static int cmd_errcode ( char *args[], char *outbuff)
263 {
264     char tmp[MAX_OUT_BUFF];
265     sprintf(tmp, "errCode: %d \n",
266             zebra_errCode (zh));
267     strcat(outbuff, tmp);
268     return 0; /* ok */
269 }
270 static int cmd_errstr ( char *args[], char *outbuff)
271 {
272     char tmp[MAX_OUT_BUFF];
273     sprintf(tmp, "errStr:  %s\n",
274             zebra_errString (zh));
275     strcat(outbuff, tmp);
276     return 0; /* ok */
277 }
278 static int cmd_erradd ( char *args[], char *outbuff)
279 {
280     char tmp[MAX_OUT_BUFF];
281     sprintf(tmp, "errAdd:  %s \n",
282             zebra_errAdd (zh) ); 
283     strcat(outbuff, tmp);
284     return 0; /* ok */
285 }
286
287 /**************************************
288  * Admin commands
289  */
290
291 static int cmd_init ( char *args[], char *outbuff)
292 {
293     zebra_init(zh);
294     return 0; /* ok */
295 }
296
297 static int cmd_select_database ( char *args[], char *outbuff)
298 {
299     char *db=args[1];
300     if (!db) {
301         db="Default";
302         strcat(outbuff,"Selecting database 'Default'\n");
303     }
304     return zebra_select_database(zh, db);
305 }
306  
307 static int cmd_create_database( char *args[], char *outbuff)
308 {
309     char *db=args[1];
310     if (!db)
311         db="Default";
312     strcat(outbuff,"Creating database ");
313     strcat(outbuff,db);
314     strcat(outbuff,"\n");
315         
316     return zebra_create_database(zh, db);
317 }
318
319 static int cmd_drop_database( char *args[], char *outbuff)
320 {
321     char *db=args[1];
322     if (!db)
323         db="Default";
324     strcat(outbuff,"Dropping database ");
325     strcat(outbuff,db);
326     strcat(outbuff,"\n");
327         
328     return zebra_drop_database(zh, db);
329 }
330
331 static int cmd_begin_trans( char *args[], char *outbuff)
332 {
333     int rw=0;
334     if (args[1] && ( (args[1][0]=='1') || (args[1][0]=='w') ))
335         rw=1;
336     return zebra_begin_trans(zh,rw);
337 }
338 static int cmd_end_trans( char *args[], char *outbuff)
339 {
340     return zebra_end_trans(zh);
341 }
342 /*************************************
343  * Inserting and deleting
344  */
345
346 static int cmd_record_insert( char *args[], char *outbuff)
347 {
348     int sysno=0;
349     char buf[MAX_ARG_LEN];
350     int i;
351     int rc;
352     
353     i=1;
354     buf[0]='\0';
355     while (args[i])
356     {
357         strcat(buf, args[i++]);
358         strcat(buf, " ");
359     }
360     rc=zebra_record_insert(zh,buf, strlen(buf), &sysno);
361     if (0==rc)
362     {
363         sprintf(buf,"ok sysno=%d\n",sysno);
364         strcat(outbuff,buf);
365     }
366     return rc;
367 }
368
369
370 static int cmd_exchange_record( char *args[], char *outbuff)
371 {
372     char *base=args[1];
373     char *id = args[2];
374     char *action = args[3];
375     int i=4;
376     int rc;
377     char buf[MAX_ARG_LEN];
378     if (!(base && id && action && args[4] ))
379     {
380         strcat(outbuff,"Missing arguments!\n");
381         onecommand("help exchange_record", outbuff, "");
382         return -90;
383     }
384     while (args[i])
385     {
386         strcat(buf, args[i++]);
387         strcat(buf, " ");
388     }
389     rc=zebra_admin_exchange_record(zh, base, buf, strlen(buf),
390         id, strlen(id), atoi(action));
391     return rc;
392 }
393
394 /**********************************
395  * Searching and retrieving
396  */
397
398 static int cmd_search_pqf( char *args[], char *outbuff)
399 {
400     int hits=0;
401     char *set=args[1];
402     char qry[MAX_ARG_LEN]="";
403     int i=2;
404     int rc;
405     while (args[i])
406     {
407             strcat(qry, args[i++]);
408             strcat(qry, " ");
409     }
410     rc=zebra_search_PQF(zh, qry, set, &hits);
411     if (0==rc)
412     {
413         sprintf(qry,"%d hits found\n",hits);
414         strcat(outbuff,qry);
415     }
416     return rc;
417 }
418
419 static int cmd_find( char *args[], char *outbuff)
420 {
421     char *setname="MyResultSet";
422     char qry[MAX_ARG_LEN]="";
423     int i=1;
424     int rc;
425     int hits=0;
426     if (0==strstr(args[0],"@attr"))
427         strcat(qry, "@attr 1=/ ");
428     while (args[i])
429     {
430             strcat(qry, args[i++]);
431             strcat(qry, " ");
432     }
433     if (!zh)
434             onecommand("quickstart", outbuff, "");
435     strcat(outbuff, "find ");
436     strcat(outbuff, qry);
437     strcat(outbuff, "\n");
438     rc=zebra_search_PQF(zh, qry, setname, &hits);
439     if (0==rc)
440     {
441         sprintf(qry,"%d hits found\n",hits);
442         strcat(outbuff,qry);
443     }
444     return rc;
445 }
446
447 /**************************************)
448  * Command table, parser, and help 
449  */
450
451 struct cmdstruct
452 {
453     char * cmd;
454     char * args;
455     char * explanation;
456     int (*testfunc)(char *args[], char *outbuff);
457 } ;
458
459  
460 struct cmdstruct cmds[] = {
461     /* special cases:
462      *   if text is 0, does not list the command
463      *   if cmd is "", adds the args (and newline) in command listing
464      */
465     { "", "Starting and stopping:", "", 0 },
466     { "zebra_start", 
467       "[configfile]", 
468       "starts the zebra service. You need to call this first\n"
469       "if no configfile is given, assumes " DEFAULTCONFIG, 
470       cmd_zebra_start },
471     { "zebra_stop",   "", 
472       "stops the zebra service", 
473       cmd_zebra_stop },
474     { "zebra_open", "",  
475       "starts a zebra session. Once you have called zebra_start\n"
476       "you can call zebra_open to start working", 
477       cmd_zebra_open },
478     { "zebra_close", "", 
479       "closes a zebra session", 
480       cmd_zebra_close }, 
481     { "quickstart", "[configfile]", 
482       "Does a zebra_start, zebra_open, and sets up the log", 
483       cmd_quickstart }, 
484   
485     { "", "Log file:","", 0},  
486     { "yaz_log_file", 
487       "[filename]",
488       "Directs the log to filename (or stderr)",
489       cmd_yaz_log_file },
490     { "yaz_log_level", 
491       "[level]",
492       "Sets the logging level (or returns to default)",
493       cmd_yaz_log_level },
494     { "yaz_log_prefix", 
495       "[prefix]",
496       "Sets the log prefix",
497       cmd_yaz_log_prefix},    
498     { "logf", 
499       "[level] text...",
500       "writes an entry in the log",
501       cmd_logf},    
502
503     { "", "Error handling:","", 0},
504     { "err",  "",
505       "Displays zebra's error status (code, str, add)",
506       cmd_err},    
507     { "errcode",  "",
508       "Displays zebra's error code",
509       cmd_errcode},    
510     { "errstr",  "",
511       "Displays zebra's error string",
512       cmd_errstr},    
513     { "erradd",  "",
514       "Displays zebra's additional error message",
515       cmd_erradd},    
516   
517     { "", "Admin:","", 0}, 
518     { "init",  "",
519       "Initializes the zebra database, destroying all data in it",
520       cmd_init},    
521     { "select_database",  "basename",
522       "Selects a database",
523       cmd_select_database},    
524     { "create_database", "basename",
525       "Create database",
526       cmd_create_database},
527     { "drop_database", "basename",
528       "Drop database",
529       cmd_drop_database},
530     { "begin_trans", "[rw]",
531       "Begins a transaction. rw=1 means write, otherwise read-only",
532       cmd_begin_trans},
533     { "end_trans","",
534       "Ends a transaction",
535       cmd_end_trans},
536
537     { "","Updating:","",0},
538     { "record_insert","record",
539       "inserts an sgml record into Default",
540       cmd_record_insert},
541     { "exchange_record","database record-id action record",
542       "inserts (1), updates (2), or deletes (3) a record \n"
543       "record-id must be a unique identifier for the record",
544       cmd_exchange_record},
545     { "","Searching and retrieving:","",0},
546     { "search_pqf","setname query",
547       "search ",
548       cmd_search_pqf},
549     { "find","query",
550       "simplified search",
551       cmd_find},
552     { "f","query",
553       "simplified search",
554       cmd_find},
555     { "", "Misc:","", 0}, 
556     { "echo", "string", 
557       "ouputs the string", 
558       cmd_echo },
559     { "q", "", 
560       "exits the program", 
561       cmd_quit },
562     { "quit", "", 
563       "exits the program", 
564       cmd_quit },
565     { "help", "[command]", 
566       "Gives help on command, or lists them all", 
567       cmd_help },
568     { "", "help [command] gives more info on command", "",0 },   
569   
570     {0,0,0,0} /* end marker */
571 };
572  
573 int onecommand( 
574                 char *line,     /* input line */
575                 char *outbuff,  /* output goes here */
576                 const char *prevout) /* prev output, for 'expect' */
577 {
578     int i;
579     char *args[MAX_NO_ARGS];
580     int n;
581     char argbuf[MAX_ARG_LEN];
582     logf(LOG_APP,"%s",line);
583     strncpy(argbuf,line, MAX_ARG_LEN-1);
584     argbuf[MAX_ARG_LEN-1]='\0'; /* just to be sure */
585     n=split_args(argbuf, args);
586
587 #if 0
588     for (i = 0; i <= n; i++)
589     {
590         const char *cp = args[i];
591         printf ("args %d :%s:\n", i, cp ? cp : "<null>");
592     }
593 #endif
594     if (0==n)
595         return -90; /* no command on line, too bad */
596
597     if (0==strcmp(args[0],"expect")) 
598     {
599         char *rest;
600         if (n>1)
601             rest= line + (args[1]-argbuf); /* rest of the line */
602         else
603             return -1; /* need something to expect */
604         printf("expecting '%s'\n",rest); /*!*/
605         if (0==strstr(prevout,rest))
606         {
607             printf( "Failed expectation, '%s' not found\n", rest);
608             exit(9); 
609         }
610         return 0;
611     }
612     for (i=0;cmds[i].cmd;i++)
613         if (0==strcmp(cmds[i].cmd, args[0])) 
614         {
615             if (n>1)
616                 args[0]= line + (args[1]-argbuf); /* rest of the line */
617             else
618                 args[0]=""; 
619             return ((cmds[i].testfunc)(args,outbuff));
620         }
621     strcat(outbuff, "Unknown command '");
622     strcat(outbuff,args[0] );
623     strcat(outbuff,"'. Try help");
624     logf(LOG_APP,"Unknown command");
625     return -90; 
626 }
627  
628 static int cmd_help( char *args[], char *outbuff)
629
630     int i;
631     char tmp[MAX_ARG_LEN];
632     if (args[1]) 
633     { /* help for a single command */ 
634         for (i=0;cmds[i].cmd;i++)
635             if (0==strcmp(cmds[i].cmd, args[1])) 
636             {
637                 strcat(outbuff,cmds[i].cmd);
638                 strcat(outbuff,"  ");
639                 strcat(outbuff,cmds[i].args);
640                 strcat(outbuff,"\n");
641                 strcat(outbuff,cmds[i].explanation);
642                 strcat(outbuff,"\n");
643                 return 0;
644             }
645         strcat(outbuff, "Unknown command ");
646         strcat(outbuff, args[1] );
647     }
648     else 
649     { /* list all commands */
650         strcpy(tmp,"    ");
651         for (i=0;cmds[i].cmd;i++)
652             if (cmds[i].explanation)
653             {
654                 /* sprintf(tmp, "%s %s %s\n",
655                    cmds[i].cmd, cmds[i].args, cmds[i].explanation);
656                 */
657                 strcat(tmp, cmds[i].cmd);
658                 strcat(tmp,"  ");
659                 if (!*cmds[i].cmd)
660                 {
661                     strcat(outbuff, tmp);
662                     strcat(outbuff,"\n");
663                     strcpy(tmp,"    ");
664                     if (*cmds[i].args)
665                     {
666                         strcat(outbuff, cmds[i].args);
667                         strcat(outbuff,"\n");
668                     }
669                 }
670                 if (strlen(tmp)>50)
671                 {
672                     strcat(outbuff,tmp);
673                     strcat(outbuff,"\n");
674                     strcpy(tmp,"    ");
675                 }
676             }
677         strcat(outbuff,tmp);
678     }
679     return 0;
680 }
681  
682 /* If Zebra reports an error after an operation,
683  * append it to the outbuff and log it */
684 static void Zerrors ( char *outbuff)
685 {
686     int ec;
687     char tmp[MAX_OUT_BUFF];
688     if (!zh)
689         return ;
690     ec=zebra_errCode (zh);
691     if (ec)
692     {
693         sprintf(tmp, "   Zebra error %d: %s, (%s)",
694                 ec, zebra_errString (zh),
695                 zebra_errAdd (zh) );
696         strcat(outbuff, tmp);
697         strcat(outbuff, "\n");
698         logf(LOG_APP, tmp);
699         zebra_clearError(zh);
700     }
701 }
702   
703 /************************************** 
704  * The shell
705  */
706  
707 void shell()
708 {
709     int rc=0;
710     char tmp[MAX_ARG_LEN];
711     char outbuff[MAX_OUT_BUFF]="";
712     char prevout[MAX_OUT_BUFF]=""; /* previous output for 'expect' */
713     while (rc!=-99)
714     {
715         char buf[MAX_ARG_LEN];
716 #if HAVE_READLINE_READLINE_H
717         char* line_in;
718         line_in=readline(PROMPT);
719         if (!line_in)
720             break;
721 #if HAVE_READLINE_HISTORY_H
722         if (*line_in)
723             add_history(line_in);
724 #endif
725         if(strlen(line_in) > MAX_ARG_LEN-1) {
726             fprintf(stderr,"Input line too long\n");
727             break;
728         };
729         strcpy(buf,line_in);
730         free (line_in);
731 #else    
732         printf (PROMPT); 
733         fflush (stdout);
734         if (!fgets (buf, MAX_ARG_LEN-1, stdin))
735             break; 
736 #endif 
737         
738         strncpy(prevout, outbuff, MAX_OUT_BUFF);
739         outbuff[0]='\0';
740         rc=onecommand(buf, outbuff, prevout);
741         if (rc==0)
742         {
743             strcat(outbuff, "   OK\n");
744             logf(LOG_APP, "OK");
745         }
746         else if (rc>-90)
747         {
748             sprintf(tmp, "   command returned %d\n",rc);
749             strcat(outbuff,tmp);
750         } 
751         Zerrors(outbuff);
752         printf("%s\n", outbuff);
753     } /* while */
754 } /* shell() */
755   
756  
757 /**************************************
758  * Main 
759  */
760  
761 int main (int argc, char ** args)
762 {
763     shell();
764     return 0;
765 } /* main */