/* RUN-TIME CONFIGURATION FILE PARSER */
/**********************************************************************
 *
 * zparse.y --
 * Copyright (C) 2000  The New Zealand Digital Library Project
 *
 * A component of the Greenstone digital library software
 * from the New Zealand Digital Library Project at the
 * University of Waikato, New Zealand.
 *
 * 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.
 *
 *********************************************************************/

%{
  /* verbatim C code - functions, etc */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "z3950cfg.h" /* structure types, and #define of yyin/yyparse */

#define YYDEBUG 1
#define YYERROR_VERBOSE 1
char defLanguage=0;

/* defined in parse.fl */
extern int lineno;

#ifndef YYRECOVERING
int YYRECOVERING=0; /* this is supposed to already be defined as a macro */
#endif

/* defined in z3950proto.cpp */
struct z3950cfg *zserver_list=NULL;

/* this is set in z3950proto.cpp */
FILE *errfile;

int yylex(void);

int yyerror(char *string);

void errormsg(char *str);

%}


%union {
  char *string;
  struct z3950cfg *cfg;
  struct z3950aboutlist *about;
  int number;
}


/* keywords */
/***** NOTE: can explicitly give values for each token, AND
give a string for the token name eg 
%token GSDLVERSION 257  "Version"
*******/
%token GSDLVERSION 257
%token GENERAL_SECTION 258 SEARCH_SECTION 259 
%token BROWSE_SECTION 260 MACROS_SECTION 261
%token MAINTAINER 262
%token PUBLIC 263
%token TRUE 264 FALSE 265
%token LANGUAGES 266 EN 267 FR 268 MI 269 ZH 270 DE 271
%token NAME 272
%token <string> STRING 273
%token ICON 274 SMALLICON 275
%token ABOUT 276
%token SEARCHTEXT 277
%token DOCUMENT 278 SECTION 279
%token BROWSE 280 TYPE 281 FORMAT 282
/* classifiers */
%token  LIST 283 SORTEDLIST 284 SECTIONLIST 285 SORTEDSECTIONLIST 286 
%token DATELIST 287
/* formats */
%token  ICONLINK 288 TEXTLINK 289
/* layouts */
%token  DOCUMENTIMAGES 290 DOCUMENTHEADER 291 DOCUMENTTEXT 292
%token  DOCUMENTBUTTONS 293 DOCUMENTARROWSBOTTOM 294

/* all other text */
%token <string> DATA 295

%type <cfg>      zserver zserverlist
%type <number>  port
%type <string>   icon smallicon lang name
%type <about>    about aboutLang aboutList
%%
/* grammar */
z3950         : version zserverlist {zserver_list=$2;}
              | version {zserver_list=NULL;} /* if all commented out or none... */


version       : GSDLVERSION {;}
              | {fprintf(errfile,"No version - not GSDL config file?\n");return(1);}

zserverlist   : zserverlist zserver {if ($2!=NULL) {$2->next=$1;$$=$2;}}
              | zserver ;

zserver       : DATA DATA port DATA name icon smallicon about 
                   {
		     if (YYRECOVERING)
		       {$$=NULL;YYRECOVERING=0;} 
		     else {
		       if(($$=malloc(sizeof(struct z3950cfg)))==NULL)
			 {
			   fprintf(errfile,"malloc failed\n");
			   return(1);
			 }
		       $$->shortname=$1;
		       $$->hostname=$2;
		       $$->port=$3;
		       $$->dbname=$4;
		       $$->longname=$5;
		       $$->icon=$6;
		       $$->smallicon=$7;
		       $$->about=$8;
		       $$->next=NULL;
		     }
		   }
              | error {$$=NULL;
	      fprintf(errfile,"discarding zserver (line %d)\n",lineno);}
              ;

name          : STRING {;}
              | {errormsg("Database name needs to be followed by a short "
			  "descriptive name (enclosed in \" marks)");
	         $$=NULL;
	         YYRECOVERING=1;} /* we should scrap this server */

port          : ':' DATA {$$=atoi($2);}
              | {$$=210;} /* default z39.50 server port */
              ;

icon          : ICON STRING {$$=$2;}
              | ICON DATA {$$=$2;
                  errormsg("Icon must be enclosed in quotes");
	      yylex();yylex();}
              | {$$=NULL;}
smallicon     : SMALLICON STRING {$$=$2;}
              | SMALLICON DATA {$$=$2;
	      /* this is because of the ':' */
              errormsg("Smallicon must be enclosed in quotes.\n");
	      yylex();yylex();
	      }
              | {$$=NULL;}

about         : aboutList {defLanguage=0;}
              | {$$=NULL;}

aboutList     : aboutLang {;}
                      /* note this action reverses the order of the list */
              | aboutList aboutLang {$$=$2;$2->next=$1;} 


aboutLang     : ABOUT lang STRING 
                             {
			       if(($$=malloc(sizeof(struct z3950aboutlist)))
				  ==NULL) {
				 fprintf(errfile,"Malloc failed\n");
				 return(1);
			       }
			       $$->lang=$2;
			       $$->text=$3;
			       $$->next=NULL;
			     }
              | ABOUT STRING 
                             {
			       if (defLanguage)
		                 {
				   fprintf(errfile,"warning: (line %d): already have a default language in config file\n",lineno);
				 }
			       else defLanguage=1;
			       
			       if(($$=malloc(sizeof(struct z3950aboutlist)))
				  ==NULL) {
				 fprintf(errfile,"Malloc failed\n");
				 return(1);
			       }
			       $$->lang=NULL; /* default lang... */
			       $$->text=$2;
			       $$->next=NULL;
			     }
/* this can only happen once (default lang) */


/* languages should be done using a lookup, rather than hard-coding 
   them as tokens. Also '_' token for en_BR */
lang          : DATA '_' DATA 
                             {
			       $$=malloc(strlen($1)+strlen($3)+1);
			       strncpy($$,$1,strlen($1));
			       $$[strlen($1)]='_';
			       strncpy($$+strlen($1)+1,$3,strlen($3));
			       free($1);free($3);
			     }
              | DATA {;}
/*lang '_' DATA {;} */
/*              | EN {;}
		| FR {;}
		| MI {;}
		| ZH {;}
		| DE {;}
		| DATA {errormsg("unknown language");}*/
              | error {errormsg("missing language");}

/*documentHeader : DOCUMENTHEADER STRING {;}
              | {;}

documentText  : DOCUMENTTEXT STRING {;}
              | {;}
*/

%%
/*int strncasecmp (const char *, const char *,size_t);*/
int yyerror(char *string) {
  fprintf(errfile,"Parse error (line %d) near \n\"%s\"<---:%s\n",lineno,
	  yylval.string,string);
  return(1);
}

void errormsg(char *str) {
  fprintf(errfile,"Err (line %d, near \"%s\"): %s.\n",lineno,
	  yylval.string,str);
}

/* *
int main (int argc, char *argv[]) {
  if (argc==2)
    if (argv[1][0]=='-'&&argv[1][1]=='d')
      yydebug=1;

  yyparse();
  return(0);
}
* */
