%{
static char rcsid[] = "$Id: query.y,v 2.2 1997/11/21 17:42:54 sxw Exp $";
/* 
 *  query.y -- Broker query manager interface grammer (yacc/bison).
 *
 *
 *  DEBUG: none
 *  AUTHOR: Harvest derived
 *
 *  Harvest Indexer http://www.tardis.ed.ac.uk/harvest/
 *  ---------------------------------------------------
 *
 *  The Harvest Indexer is a continued development of code developed by
 *  the Harvest Project. Development is carried out by numerous individuals
 *  in the Internet community, and is not officially connected with the
 *  original Harvest Project or its funding sources.
 * 
 *  Please mail harvest@tardis.ed.ac.uk if you are interested in participating
 *  in the development effort.
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *  
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *  
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
/*  ----------------------------------------------------------------------
 *  Copyright (c) 1994, 1995.  All rights reserved.
 *  
 *    The Harvest software was developed by the Internet Research Task
 *    Force Research Group on Resource Discovery (IRTF-RD):
 *  
 *          Mic Bowman of Transarc Corporation.
 *          Peter Danzig of the University of Southern California.
 *          Darren R. Hardy of the University of Colorado at Boulder.
 *          Udi Manber of the University of Arizona.
 *          Michael F. Schwartz of the University of Colorado at Boulder.
 *          Duane Wessels of the University of Colorado at Boulder.
 *  
 *    This copyright notice applies to software in the Harvest
 *    ``src/'' directory only.  Users should consult the individual
 *    copyright notices in the ``components/'' subdirectories for
 *    copyright information about other software bundled with the
 *    Harvest source code distribution.
 *  
 *  TERMS OF USE
 *    
 *    The Harvest software may be used and re-distributed without
 *    charge, provided that the software origin and research team are
 *    cited in any use of the system.  Most commonly this is
 *    accomplished by including a link to the Harvest Home Page
 *    (http://harvest.cs.colorado.edu/) from the query page of any
 *    Broker you deploy, as well as in the query result pages.  These
 *    links are generated automatically by the standard Broker
 *    software distribution.
 *    
 *    The Harvest software is provided ``as is'', without express or
 *    implied warranty, and with no support nor obligation to assist
 *    in its use, correction, modification or enhancement.  We assume
 *    no liability with respect to the infringement of copyrights,
 *    trade secrets, or any patents, and are not responsible for
 *    consequential damages.  Proper use of the Harvest software is
 *    entirely the responsibility of the user.
 *  
 *  DERIVATIVE WORKS
 *  
 *    Users may make derivative works from the Harvest software, subject 
 *    to the following constraints:
 *  
 *      - You must include the above copyright notice and these 
 *        accompanying paragraphs in all forms of derivative works, 
 *        and any documentation and other materials related to such 
 *        distribution and use acknowledge that the software was 
 *        developed at the above institutions.
 *  
 *      - You must notify IRTF-RD regarding your distribution of 
 *        the derivative work.
 *  
 *      - You must clearly notify users that your are distributing 
 *        a modified version and not the original Harvest software.
 *  
 *      - Any derivative product is also subject to these copyright 
 *        and use restrictions.
 *  
 *    Note that the Harvest software is NOT in the public domain.  We
 *    retain copyright, as specified above.
 *  
 *  HISTORY OF FREE SOFTWARE STATUS
 *  
 *    Originally we required sites to license the software in cases
 *    where they were going to build commercial products/services
 *    around Harvest.  In June 1995 we changed this policy.  We now
 *    allow people to use the core Harvest software (the code found in
 *    the Harvest ``src/'' directory) for free.  We made this change
 *    in the interest of encouraging the widest possible deployment of
 *    the technology.  The Harvest software is really a reference
 *    implementation of a set of protocols and formats, some of which
 *    we intend to standardize.  We encourage commercial
 *    re-implementations of code complying to this set of standards.  
 *  
 */
#include "broker.h"

/* Global variables */
extern qlist_t *query_list;
extern int yydebug;
extern int t_flag;
extern long sincetime;
extern char *errstr;	/* parser error for Query manager */
extern char *id_buf;	/* this is strdup'ed in query.l; always free */
extern char *passwd;	/* The Admin-Password */

/* Query manager flags */
extern int QM_descflag;
extern int QM_opaqueflag;
extern int QM_echoflag;
extern char *QM_op;

/* Local functions */
static int checkpasswd _PARAMS((char *));
static qlist_t *make_node _PARAMS((char *, int , char *, int ));
static qlist_t *make_not_node _PARAMS((qlist_t *));
static qlist_t *arrange_select_node _PARAMS((char *, qlist_t *));
static qlist_t *arrange_logical_node _PARAMS((qlist_t *, qlist_t *));

static arg_t   *new_arg _PARAMS((void *, int));
static arg_t   *add_arg _PARAMS((arg_t *, arg_t *));

%}

%union{
  char *ChPtr;
  qlist_t *QL;
  arg_t *A;
  int  INTT;
}

%token AND_ OR_ NOT_ EXCEPT_ ID_ LPAREN_ RPAREN_ EXACT_
%token LCBRACK_ RCBRACK_ COMMA_ 
%token REGEXP_ LSST_ GTRT_ BULK_ BESTTOK_ ADMIN_ USERQ_ ALLB_ END_ DO_
%token SET_ COLLECT_ CLEAN_ FINDEX_ START_ COMPRESS_ ATTRIBUTE_ OPERATION_
%token LFLUSH_ LCLOSE_ LOPEN_ LROTATE_ IINDEX_ SINCETOK_
%token LOGA_ LOGR_ ADDO_ REMOQ_ REMON_ SHUTDN_ PASSWD_ DOSTATS_ PARSTF_
%token INFO_ PING_
%token DESCFLAG_ INDEXFLAG_ OPAQUEFLAG_ 
%token UNIQIFY_ RESTIDXSVR_

%type <ChPtr> id indexflag adminflags logical_c
%type <INTT>  selectop logical doadmin commands addlist remlist safecommand parstflist
%type <QL>    clauselist clause restspec query command relation 
%type <QL>    primary logoprel func
%type <A>     arg arglist


%start command
%% /* Start of rules */
command        : {t_flag = UQUERY;} USERQ_ query {$$ = $3;}
               | {t_flag = QBULK;} BULK_ query {$$ = $3;}
               | {t_flag = ADMIN;} ADMIN_ doadmin {if($3 == ERROR) YYERROR; $$ = NULL;}
               ;

query          : flags END_ clauselist  {$$ = $3; query_list = $3;}
               ;

flags	       : flags userflags
               | 
               ;

userflags      : SINCETOK_ id   { sincetime = atol($2); xfree($2); }
	       | DESCFLAG_ 	{ QM_descflag = 1; }
	       | OPAQUEFLAG_ 	{ QM_opaqueflag = 1; }
               | ATTRIBUTE_ id  { QM_add_attribute($2); xfree($2); }
               | OPERATION_ id  { QM_op = xstrdup($2); xfree($2); }
               | INDEXFLAG_ id indexflag { do_IND_Set_Flags($2,$3); xfree($2); xfree($3); }
               ;

indexflag      : id { $$ = $1; }
               | { $$ = NULL; }
               ;

clauselist     : relation           {$$ = $1;}
               | relation logoprel  {$$ = arrange_logical_node($1, $2);}
               | ALLB_              {if(t_flag != QBULK) YYERROR; t_flag = ABULK; $$ = NULL;}
               ;

logoprel      : logical relation {$$ = make_node(NULL, $1, (char *)$2, LOGICAL);}
              | logoprel logical relation 
		{$1->rlist = (char *) make_node((char *) $1->rlist, $2, (char *) $3, LOGICAL); $$ = $1;}
              ;

relation       : primary        {$$ = $1;}
               | NOT_ primary   {$$ = make_not_node($2);}
               | func		{ $$ = $1; }
               ;

primary        : clause         {$$ = $1;}
               | LPAREN_ clauselist RPAREN_ {$$ = $2;}
               ;

clause         : id restspec { $$ = arrange_select_node($1, $2);}
               ;

restspec       : selectop id {$$ = make_node(NULL, $1, $2, SELECT);} 
               |             {$$ = make_node(NULL, REGEX, NULL, SELECT);} 
	       ;

func           : id        LCBRACK_ arglist RCBRACK_	{ $$ = make_node ($1, FUNCTION, (char *) $3, FUNCTION); }
               | logical_c LCBRACK_ arglist RCBRACK_	{ $$ = make_node ($1, FUNCTION, (char *) $3, FUNCTION); }
               ;

arglist        : arg				{ $$ = $1; }
               | arg COMMA_ arglist		{ $$ = add_arg ($3, $1); }
               ;

arg            : id				{ $$ = new_arg ($1, STRING); }
               | func				{ $$ = new_arg ((void *) $1, FUNCTION); }
               ;

selectop       : EXACT_   {$$ = EXACT;}
               | REGEXP_  {$$ = REGEX;}
               | LSST_    {$$ = LST;}
               | GTRT_    {$$ = GTT;}
               ;

logical_c      : AND_     {$$ = xstrdup ("AND");}
               | OR_      {$$ = xstrdup ("OR");}
               | EXCEPT_  {$$ = xstrdup ("EXCEPT");}
               ;

logical        : AND_     {$$ = AND;}
               | OR_      {$$ = OR;}
               | EXCEPT_  {$$ = EXCEPT;}
               ;

id             : ID_ {$$ = id_buf; /* id_buf was strdup'ed */ } 
               ;

doadmin        : adminflags {if (checkpasswd($1) == ERROR) YYERROR; xfree($1);} commands {$$ = $3;}
               | adminflags safecommand {$$ = $2;}
               ;

adminflags     : PASSWD_ id   { $$ = $2; }
               |              { $$ = NULL; }
               ;

addlist	       : addlist id 
                 { if (AD_add_object($2) != SUCCESS) $$ = ERROR; else $$ = $1; xfree($2); }
               | { $$ = SUCCESS; }
               ;

remlist	       : remlist id 
                 { if (AD_remove_name($2) != SUCCESS) $$ = ERROR; else $$ = $1; xfree($2); }
               | { $$ = SUCCESS; }
               ;

parstflist     : parstflist id 
                 { if (AD_parse_templatefile($2) != SUCCESS) $$ = ERROR; else $$ = $1; xfree($2); }
               | { $$ = SUCCESS; }
               ;

commands       : COLLECT_ 		{$$ = COL_Do_Collection();}
               | CLEAN_   		{$$ = RG_Cleaner(); }
               | COMPRESS_   		{$$ = Do_Compression(); }
               | FINDEX_  		{$$ = do_IND_Index_Full();}
               | IINDEX_  		{$$ = do_IND_Index_Incremental();}
               | LFLUSH_  		{$$ = LOG_flush_log();}
               | LCLOSE_  		{$$ = LOG_close_log();}
               | LOPEN_   		{$$ = LOG_Init();}
               | LROTATE_ 		{$$ = LOG_rotate();}
               | SHUTDN_           	{$$ = Broker_Shutdown();}
               | START_            	{$$ = AD_restart();}
               | UNIQIFY_    		{$$ = Do_Uniqify(); }
               | RESTIDXSVR_   		{$$ = Do_Restart_Index_Server(); }
               | DOSTATS_   	   	{$$ = AD_do_stats();}
               | LOGA_  id         	{$$ = AD_log_on($2); xfree($2);}
               | LOGR_  id         	{$$ = AD_log_off($2); xfree($2);}
               | SET_ id id        
			{$$ = set_str($2, $3); xfree($2); xfree($3);}
               | REMOQ_ clauselist 
			{query_list = $2; t_flag = QDELETE; $$ = 0;}
               | ADDO_ { do_IND_Index_Start(); } addlist 
                 {if (do_IND_Index_Flush()!=SUCCESS) $$ = ERROR; else $$ = $3;}
               | REMON_ { do_IND_Index_Start(); } remlist 
                 {if (do_IND_Index_Flush()!=SUCCESS) $$ = ERROR; else $$ = $3;}
               | PARSTF_ { do_IND_Index_Start(); } parstflist 
                 {if (do_IND_Index_Flush()!=SUCCESS) $$ = ERROR; else $$ = $3;}
               ;

safecommand    : INFO_    		{$$ = AD_do_info(); }
               | PING_ id  	   	{$$ = AD_do_ping($2); xfree($2); }
               | PING_   	   	{$$ = AD_do_ping(NULL); }
	       ;
%%

int yyerror(s)
char *s;
{
  errstr = xstrdup(s);
  return 0;
}

/* make a list/tree node */
static qlist_t *make_node(left, op, right, type)
char *left;
int op;
char *right;
int type;
{
  qlist_t *tmp;

  tmp = (qlist_t *) xmalloc(sizeof(qlist_t));
  memset (tmp, '\0', sizeof (qlist_t));
  tmp->type = type;
  tmp->op = op;
  tmp->rlist = right;
  tmp->llist = left;
  
  return(tmp);
}

/* arrange node as needed */
static qlist_t *arrange_select_node(str, qptr)
char *str;
qlist_t *qptr;
{

  if(qptr->rlist){
    COL_Normalize_Name(str);
    qptr->llist = str;
  }
  else{
    qptr->rlist = str;
  }

  return(qptr);
}

static qlist_t *arrange_logical_node(qptr1, qptr2)
qlist_t *qptr1, *qptr2;
{

  qptr2->llist = (char *) qptr1;

  return(qptr2);
}

static qlist_t *make_not_node(qptr)
qlist_t *qptr;
{

  return(make_node(NULL, NOT, (char *) qptr, LOGICAL));
}

static int checkpasswd(str)
char *str;
{
  if (passwd != NULL) {
    if (str != NULL) 
      if (strcmp(str, passwd) == 0)
	return SUCCESS;

    errorlog ("Incorrect password.\n");
    return ERROR;
  }

  return SUCCESS;
}


arg_t	*new_arg (ptr, type)
	void	*ptr;
	int	type;
{
	arg_t	*t;

	t		= (arg_t *) xmalloc (sizeof (arg_t));
	memset (t, '\0', sizeof (arg_t));
	t->type		= type;
	switch (type) {
	case STRING:
		t->ptr = (void *) xstrdup ((char *) ptr);
		break;
	case FUNCTION:
		t->ptr = ptr;
		break;
	}
	return t;
}

/* Add Arg 'a' to linked list 'b'; return 'b' */
arg_t	*add_arg (a, b)
	arg_t *a, *b;
{
	arg_t *t;
	for (t = b; t->next; t=t->next);
	t->next = a;
	return b;
}
