Index: /trunk/gsdl/src/recpt/Makefile.in
===================================================================
--- /trunk/gsdl/src/recpt/Makefile.in	(revision 1346)
+++ /trunk/gsdl/src/recpt/Makefile.in	(revision 1347)
@@ -30,4 +30,7 @@
 CCFLAGS = @CFLAGS@
 
+# YAZ kit for z39.50
+YAZDIR=../../packages/yaz
+
 USE_FASTCGI = @USE_FASTCGI@
 ifneq ($(USE_FASTCGI), 1)
@@ -37,5 +40,5 @@
 INCLUDES = -I../../lib -I. -I../colservr -I../../packages/mg \
 	   -I../../packages/mg/lib -I../../packages/mg/src/text \
-	   -I../mgpp/lib -I../mgpp/text
+	   -I../mgpp/lib -I../mgpp/text -I$(YAZDIR)/include
 else 
 DEFS = -DNZDL -DQUIET -DSHORT_SUFFIX -DPARADOCNUM -DGSDLSERVER \
@@ -79,5 +82,5 @@
 RECEPTHEADERS = 
 
-LIBRARYHEADERS = nullproto.h
+LIBRARYHEADERS = nullproto.h z3950proto.h z3950server.h
 
 HEADERS = $(COMMONHEADERS) $(RECPTHEADERS) $(LIBRARYHEADERS)
@@ -97,5 +100,6 @@
 RECPTSOURCES = recptmain.cpp
 
-LIBRARYSOURCES = nullproto.cpp librarymain.cpp
+LIBRARYSOURCES = nullproto.cpp z3950proto.cpp z3950server.cpp librarymain.cpp \
+		zparse.tab.c parse.yy.c $(YAZDIR)/client/yaz_zclient.c
 
 SOURCES = $(COMMONSOURCES) $(RECPTSOURCES) $(LIBRARYSOURCES)
@@ -111,9 +115,10 @@
 		hlistbrowserclass.o datelistbrowserclass.o invbrowserclass.o \
 		pagedbrowserclass.o htmlbrowserclass.o delhistoryaction.o \
-		historydb.o
+		historydb.o parse.yy.o
 
 RECPTOBJECTS = recptmain.o
 
-LIBRARYOBJECTS = nullproto.o librarymain.o
+LIBRARYOBJECTS = nullproto.o z3950proto.o z3950server.o librarymain.o \
+		zparse.tab.o $(YAZDIR)/client/yaz_zclient.o
 
 OBJECTS = $(COMMONOBJECTS) $(RECPTOBJECTS) $(LIBRARYOBJECTS)
@@ -139,14 +144,31 @@
 		  ../colservr/mgppqueryfilter.o
 
-
-EXEC = recpt library
+#EXEC = recpt library
+EXEC = library
 
 all: $(EXEC)
 
+## z39.50 stuff
+$(YAZDIR)/client/yaz_zclient.o: $(YAZDIR)/client/yaz_zclient.h $(YAZDIR)/client/yaz_zclient.c $(YAZDIR)/lib/libyaz.a
+	cd $(YAZDIR)/client && 	make yaz_zclient.o
+
+$(YAZDIR)/lib/libyaz.a:
+	cd $(YAZDIR) && ./configure && make all
+
+z3950server.o: $(YAZDIR)/client/yaz_zclient.h
+
+zparse.tab.c: zparse.y
+	@YACC@ -d zparse.y
+
+parse.yy.c: parse.fl
+	flex -oparse.yy.c parse.fl
+
+PARSE_TMPFILES= zparse.tab.o zparse.tab.c zparse.tab.h parse.yy.o parse.yy.c
+
 distclean:
-	rm -f $(OBJECTS) $(EXEC) Makefile
+	rm -f $(OBJECTS) $(EXEC) $(PARSE_TMPFILES) Makefile
 
 clean:
-	rm -f $(OBJECTS) $(EXEC)
+	rm -f $(OBJECTS) $(EXEC) $(PARSE_TMPFILES)
 
 install:
@@ -185,4 +207,5 @@
     ../../packages/mg/src/text/libtextin.a \
     ../../packages/mg/lib/libmg.a \
+    $(YAZDIR)/lib/libyaz.a \
     ../mgpp/text/libtextin.a \
     ../mgpp/lib/libmg.a 
Index: /trunk/gsdl/src/recpt/OIDtools.cpp
===================================================================
--- /trunk/gsdl/src/recpt/OIDtools.cpp	(revision 1346)
+++ /trunk/gsdl/src/recpt/OIDtools.cpp	(revision 1347)
@@ -104,4 +104,36 @@
 }
 
+// overloaded, to allow "custom" filter options.
+bool get_info (const text_t &OID, const text_t &collection,
+	       const text_tset &metadata, const OptionValue_tarray &options,
+	       bool getParents,
+	       recptproto *collectproto, FilterResponse_t &response, 
+	       ostream &logout) {
+
+  response.clear();
+
+  comerror_t err;
+  FilterRequest_t request;
+
+  request.filterName = "NullFilter";
+  request.filterResultOptions = FRmetadata;
+  request.getParents = getParents;
+  request.filterOptions = options;
+  request.fields = metadata;
+  request.docSet.push_back (OID);
+  
+  collectproto->filter (collection, request, response, err, logout);
+  if (err != noError) {
+    outconvertclass text_t2ascii;
+    logout << text_t2ascii
+	   << "Error: call to filter failed for " << OID
+	   << " in OIDtools::get_info (" 
+	   << get_comerror_string (err) << ")\n";
+    return false;
+  }
+  
+  return true;
+}
+
 bool get_info (const text_tarray &OIDs, const text_t &collection,
 	       const text_tset &metadata, bool getParents,
@@ -133,4 +165,6 @@
   return true;
 }
+
+
 
 // has_children returns true if OID has children
Index: /trunk/gsdl/src/recpt/OIDtools.h
===================================================================
--- /trunk/gsdl/src/recpt/OIDtools.h	(revision 1346)
+++ /trunk/gsdl/src/recpt/OIDtools.h	(revision 1347)
@@ -49,4 +49,9 @@
 	       recptproto *collectproto, FilterResponse_t &response, 
 	       ostream &logout);
+bool get_info (const text_t &OID, const text_t &collection,
+	       const text_tset &metadata, const OptionValue_tarray &options,
+	       bool getParents,
+	       recptproto *collectproto, FilterResponse_t &response, 
+	       ostream &logout);
 bool get_info (const text_tarray &OIDs, const text_t &collection,
 	       const text_tset &metadata, bool getParents,
Index: /trunk/gsdl/src/recpt/TODO
===================================================================
--- /trunk/gsdl/src/recpt/TODO	(revision 1347)
+++ /trunk/gsdl/src/recpt/TODO	(revision 1347)
@@ -0,0 +1,57 @@
+For Z 39.50 Stuff
+
+pageaction.cpp
+--------------
+Macros:
+ * for "about" page, use a custom _textbrowseoptions_ macro (ie
+   create a new macro, maybe create a z3950.dm macro file ??)
+   (also maybe _numbrowseoptions_
+
+(Irrelevant?) (c. line 332)
+    disp.setmacro ("numdocs", "Global", cinfo.numDocs);
+    disp.setmacro ("builddate", "Global", builddate);
+
+That message "This collection contains..." is in the _collectionextra_
+macro.
+could get numdocs from the z39.50 server, as well as any other status
+information.
+
+win32.mak
+---------
+Needs updating for all added files (z*, parse.fl)
+
+yaz
+---
+Maybe put libyaz.a in $GSDLHOME/lib ?
+
+
+DESIGN ISSUES
+for z39.50 (and eventually nullproto when corba allows recept. and
+coll server to be physically separate), if the server is unavailable,
+should this be determined at:
+  * "home page" creation time, in which case the recept. must ping and
+test each collection it knows about, which may cause unacceptable delay, or
+  * "about page" creation time (ie individual collection), in which case
+the collection can not customise the page layout by modifying macros.
+
+Eg currently, the z39.50 collection will not create a TCP connection to the
+"target" (ie z39.50 server somewhere around the world) until it tries to
+get the "About this collection" information for that collection. 
+If the connection fails, the protocol can not change _queryform_ part of
+the page.
+
+
+MULTI-LINGUAL SUPPORT
+Multi-lingual - eg macros - want to set _collectionextra_ using
+metadata["collectionextra"] based on the chosen interface language.
+Should be done by OIDtools.cpp:get_info() and any action that calls
+proto->filter().
+queryaction.cpp (c. line 1097):
+  // add the requested language as an option to the query
+  if (!args["l"].empty()) {
+    OptionValue_t option;
+    option.name="Language";
+    option.value=args["l"];
+    request.filterOptions.push_back(option);
+  }
+
Index: /trunk/gsdl/src/recpt/cgiwrapper.cpp
===================================================================
--- /trunk/gsdl/src/recpt/cgiwrapper.cpp	(revision 1346)
+++ /trunk/gsdl/src/recpt/cgiwrapper.cpp	(revision 1347)
@@ -376,17 +376,42 @@
   recptprotolistclass::iterator rprotolist_here = protos->begin();
   recptprotolistclass::iterator rprotolist_end = protos->end();
+
+  bool is_z3950 = false;
   bool found_valid_col = false;
+
   while (rprotolist_here != rprotolist_end) {
-    if ((*rprotolist_here).p != NULL) {
-
-      text_tarray collist;
-      comerror_t err;
-      (*rprotolist_here).p->get_collection_list (collist, err, cerr);
-      if (err == noError) {
-	text_tarray::iterator collist_here = collist.begin();
-	text_tarray::iterator collist_end = collist.end();
-
-	while (collist_here != collist_end) {
+    if ((*rprotolist_here).p == NULL) continue;
+    else if (is_z3950==false &&
+	     (*rprotolist_here).p->get_protocol_name() == "z3950proto") {
+      cout << "\nZ39.50 Servers:   (always public)\n"
+	   << "---------------\n";
+      is_z3950=true;
+    }
+
+    text_tarray collist;
+    comerror_t err;
+    (*rprotolist_here).p->get_collection_list (collist, err, cerr);
+    if (err == noError) {
+      text_tarray::iterator collist_here = collist.begin();
+      text_tarray::iterator collist_end = collist.end();
+      
+      while (collist_here != collist_end) {
+	
+	cout << text_t2ascii << *collist_here;
+	
+	int spaces = (22 - (*collist_here).size());
+	if (spaces < 2) spaces = 2;
+	text_t outspaces;
+	for (int i = 0; i < spaces; i++) outspaces.push_back (' ');
+	cout << text_t2ascii << outspaces;
+	
+	ColInfoResponse_t cinfo;
+	(*rprotolist_here).p->get_collectinfo (*collist_here, cinfo, err, cerr);
+	if (err == noError && is_z3950 == false) {
+	  if (cinfo.isPublic) cout << "public ";
+	  else cout << "private";
 	  
+	  if (cinfo.buildDate > 0) cout << "   running    ";
+	  else cout << "   not running";
 	  cout << text_t2ascii << *collist_here;
 
@@ -414,8 +439,13 @@
 	  collist_here ++;
 	}
+	
+	cout << "\n";
+	
+	collist_here ++;
       }
     }
+    is_z3950=false;
     rprotolist_here ++;
-  }
+  } // end of while loop
   
   if (!found_valid_col) {
Index: /trunk/gsdl/src/recpt/documentaction.cpp
===================================================================
--- /trunk/gsdl/src/recpt/documentaction.cpp	(revision 1346)
+++ /trunk/gsdl/src/recpt/documentaction.cpp	(revision 1347)
@@ -365,10 +365,19 @@
   text_tset metadata;
 
-  ColInfoResponse_t *cinfo = recpt->get_collectinfo_ptr (collectproto, collection, logout);
-  if (cinfo == NULL) {
-    logout << "ERROR (documentaction::define_external_macros): get_collectinfo_ptr returned NULL\n";
-    return;
-  }
-  load_formatinfo (cinfo->format, args.getintarg("gt"));
+  // get info on current collection and load up formatinfo
+  // I'd prefer not to do this here as we're getting 
+  // collection info every time (and probably also getting
+  // it in other places some of the time) - One day I'll
+  // fix it ... maybe - Stefan.
+  ColInfoResponse_t cinfo;
+
+  collectproto->get_collectinfo (collection, cinfo, err, logout);
+  load_formatinfo (cinfo.format, args.getintarg("gt"));
+  //  ColInfoResponse_t *cinfo = recpt->get_collectinfo_ptr (collectproto, collection, logout);
+  //  if (cinfo == NULL) {
+  //    logout << "ERROR (documentaction::define_external_macros): get_collectinfo_ptr returned NULL\n";
+  //    return;
+  //  }
+  //load_formatinfo (cinfo->format, args.getintarg("gt"));
 
   if (formatinfo.DocumentUseHTML) {
@@ -594,7 +603,17 @@
 
     metadata.insert ("archivedir");
-    
+
+    OptionValue_tarray options;
+    // we need to know what the query was for the z3950proto
+    if (collectproto->get_protocol_name()=="z3950proto") {
+      OptionValue_t opt;
+      opt.name="Query";
+      opt.value=args["q"];
+      options.push_back(opt);
+    }
+
     // get metadata for this document and it's parents
-    if (get_info (arg_d, collection, metadata, true, collectproto, response, logout)) {
+    if (get_info (arg_d, collection, metadata, options, 
+		  true, collectproto, response, logout)) {
       disp.setmacro ("header", "document", "_textheader_");
 
Index: /trunk/gsdl/src/recpt/librarymain.cpp
===================================================================
--- /trunk/gsdl/src/recpt/librarymain.cpp	(revision 1346)
+++ /trunk/gsdl/src/recpt/librarymain.cpp	(revision 1347)
@@ -27,4 +27,6 @@
 #include "cgiwrapper.h"
 #include "nullproto.h"
+// z39.50 stuff - johnmcp
+#include "z3950proto.h"
 #include "collectserver.h"
 #include "filter.h"
@@ -64,4 +66,5 @@
   receptionist recpt;
   nullproto nproto;
+  z3950proto zproto;
 
   text_tarray collections;
@@ -120,4 +123,5 @@
     browsefilterclass *browsefilter = new browsefilterclass();
     browsefilter->set_gdbmptr (gdbmhandler);
+
     cserver->add_filter (browsefilter);  
  
@@ -136,5 +140,4 @@
        mggdbmsource->set_mgsearchptr (mgsearch);
        cserver->add_source (mggdbmsource);
-   
     }
     else if (buildtype == "mgpp") {
@@ -166,5 +169,5 @@
     colinfo.push_back (gsdlhome);
     recpt.configure ("collectinfo", colinfo);
-  
+    
     nproto.add_collectserver (cserver);
     thiscol ++;
@@ -174,4 +177,21 @@
   recpt.add_protocol (&nproto);
   
+
+
+  // z39.50 stuff - johnmcp
+
+  // add the z39.50 server information. Read in the file
+  // etc/recpt/z3950.cfg for list of servers and their databases.
+  text_t z3950cfg = filename_cat (gsdlhome, "etc");
+  z3950cfg = filename_cat (z3950cfg, "recpt");
+  z3950cfg = filename_cat (z3950cfg, "z3950.cfg");
+  if (file_exists(z3950cfg)) {
+    zproto.read_config_file(z3950cfg);
+    // only add this protocol if we have any servers configured.
+    if (zproto.getServerCount()>0)
+      recpt.add_protocol (&zproto);
+  }
+
+
   // add other converters
   utf8inconvertclass utf8inconvert;
Index: /trunk/gsdl/src/recpt/pageaction.cpp
===================================================================
--- /trunk/gsdl/src/recpt/pageaction.cpp	(revision 1346)
+++ /trunk/gsdl/src/recpt/pageaction.cpp	(revision 1347)
@@ -148,9 +148,15 @@
 	  collist_here ++;
 	}
+
+	// disp.setmacro ("homeextra", "home", homeextra); 
 	for (; count%3 != 0; count ++) homeextra += "<td></td>\n";
       }
     }
+    homeextra += "</td></tr>\n<tr>\n";
     rprotolist_here ++;
   }
+
+  homeextra += "</tr></table></center>\n";
+  disp.setmacro ("homeextra", "home", homeextra); 
 
   if (!found_valid_col) {
Index: /trunk/gsdl/src/recpt/parse.fl
===================================================================
--- /trunk/gsdl/src/recpt/parse.fl	(revision 1347)
+++ /trunk/gsdl/src/recpt/parse.fl	(revision 1347)
@@ -0,0 +1,112 @@
+/* This is the lexical analyser - it returns tokens to the parsers.
+   This is used by both parsers - one for the build-time config files
+   and one for the run-time config files. Note the included file "parse.h"
+   is a symlink to the relevant header file. */
+
+%{
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+/*#define YYSTYPE char * - YYSTYPE is defined in zparse.tab.h */
+#include "zparse.tab.h"
+
+/* forward declarations for std functions not picked up. */
+/*int fileno(FILE *);*/
+/*char *strdup(char *);*/
+
+int lineno=1;
+%}
+
+%option noyywrap
+
+COMMENT  \#.*(\n|\r)
+
+%x  STRINGCOND
+%%
+	char *string;
+	int string_len;
+
+{COMMENT}		lineno++;/*yylval.string=yytext;*/yyleng=0;
+,			return (',');
+:			return (':');
+\_			return ('_');
+\[GSDL[0-9]+\.[0-9]+\] yylval.string=yytext;return(GSDLVERSION);
+\[General\]		return (GENERAL_SECTION);
+\[Search\ [fF]ields\]	return (SEARCH_SECTION);
+\[Browse\ [fF]ields\]	return (BROWSE_SECTION);
+\[Macros\]		return (MACROS_SECTION);
+maintainer		return (MAINTAINER);
+Languages		return(LANGUAGES);
+About			return(ABOUT);
+Browse			return(BROWSE);
+Date[lL]ist		return(DATELIST);
+Document[aA]rrows[bB]ottom return(DOCUMENTARROWSBOTTOM);
+Document[bB]uttons	return(DOCUMENTBUTTONS);
+Document[hH]eader	return(DOCUMENTHEADER);
+Document[iI]mages	return(DOCUMENTIMAGES);
+Document[tT]ext		return(DOCUMENTTEXT);
+Icon[lL]ink		return(ICONLINK);
+List			return(LIST);
+Format			return(FORMAT);
+Name			return(NAME);
+Search[tT]ext		return(SEARCHTEXT);
+Section[lL]ist		return(SECTIONLIST);
+Sorted[lL]ist		return(SORTEDLIST);
+Sorted[sS]ection[lL]ist	return(SORTEDSECTIONLIST);
+Text[lL]ink		return(TEXTLINK);
+Type			return(TYPE);
+public			return (PUBLIC);
+true			return (TRUE);
+false			return (FALSE);
+^document		return (DOCUMENT);
+^section		return (SECTION);
+[iI]con			return (ICON);
+[sS]mall[iI]con		return (SMALLICON);
+\"			{string=NULL;BEGIN(STRINGCOND);}
+<STRINGCOND>{
+  ([^\"\\\n])*		{/* append this to our current string EXC NEWLINE */
+			if (string==NULL) string_len=0; else
+			string_len=strlen(string);
+			string=realloc(string,string_len+strlen(yytext)+1);
+			/* +1 is for trailing \0 */
+			strcpy(string+string_len,yytext);
+			}
+  ([^\"\\])*\n		{/* append this to our current string - INC NEWLINE */
+			lineno++;
+			if (string==NULL) string_len=0; else
+			string_len=strlen(string);
+			string=realloc(string,string_len+strlen(yytext)+1);
+			/* +1 is for trailing \0 */
+			strcpy(string+string_len,yytext);
+			}
+  "\\"\"		|
+  \"\"		{       /*replace quoted quote with one quote*/
+			string_len=strlen(string);
+			string=realloc(string,string_len+2);
+			string[string_len]='\"';
+			string[string_len+1]='\0';
+			}
+  \"		{
+			BEGIN(INITIAL);
+			yylval.string=string;
+			return(STRING);
+			  /* note that the string may have long bits of 
+			     whitespace in it that we could remove. */
+			}
+}
+[[:alnum:]@\.-]+	yylval.string=strdup(yytext);return (DATA);
+(" "|\t)		;
+(\n|\r)			lineno++;
+%%
+/******** deleted rules: *******
+en			return(EN);
+fr			return(FR);
+mi			return(MI);
+zh			return(ZH);
+de			return(DE);
+***************/
+
+
+
+
Index: /trunk/gsdl/src/recpt/parse.yy.c
===================================================================
--- /trunk/gsdl/src/recpt/parse.yy.c	(revision 1347)
+++ /trunk/gsdl/src/recpt/parse.yy.c	(revision 1347)
@@ -0,0 +1,1955 @@
+#line 2 "parse.yy.c"
+/* A lexical scanner generated by flex */
+
+/* Scanner skeleton version:
+ * $Header$
+ */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+
+#include <stdio.h>
+
+
+/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */
+#ifdef c_plusplus
+#ifndef __cplusplus
+#define __cplusplus
+#endif
+#endif
+
+
+#ifdef __cplusplus
+
+#include <stdlib.h>
+#include <unistd.h>
+
+/* Use prototypes in function declarations. */
+#define YY_USE_PROTOS
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else	/* ! __cplusplus */
+
+#if __STDC__
+
+#define YY_USE_PROTOS
+#define YY_USE_CONST
+
+#endif	/* __STDC__ */
+#endif	/* ! __cplusplus */
+
+#ifdef __TURBOC__
+ #pragma warn -rch
+ #pragma warn -use
+#include <io.h>
+#include <stdlib.h>
+#define YY_USE_CONST
+#define YY_USE_PROTOS
+#endif
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+
+#ifdef YY_USE_PROTOS
+#define YY_PROTO(proto) proto
+#else
+#define YY_PROTO(proto) ()
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index.  If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition.  This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN yy_start = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state.  The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START ((yy_start - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE yyrestart( yyin )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#define YY_BUF_SIZE 16384
+
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+
+extern int yyleng;
+extern FILE *yyin, *yyout;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+/* The funky do-while in the following #define is used to turn the definition
+ * int a single C statement (which needs a semi-colon terminator).  This
+ * avoids problems with code like:
+ *
+ * 	if ( condition_holds )
+ *		yyless( 5 );
+ *	else
+ *		do_something_else();
+ *
+ * Prior to using the do-while the compiler would get upset at the
+ * "else" because it interpreted the "if" statement as being all
+ * done when it reached the ';' after the yyless() call.
+ */
+
+/* Return all but the first 'n' matched characters back to the input stream. */
+
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up yytext. */ \
+		*yy_cp = yy_hold_char; \
+		YY_RESTORE_YY_MORE_OFFSET \
+		yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \
+		YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+		} \
+	while ( 0 )
+
+#define unput(c) yyunput( c, yytext_ptr )
+
+/* The following is because we cannot portably get our hands on size_t
+ * (without autoconf's help, which isn't available because we want
+ * flex-generated scanners to compile on their own).
+ */
+typedef unsigned int yy_size_t;
+
+
+struct yy_buffer_state
+	{
+	FILE *yy_input_file;
+
+	char *yy_ch_buf;		/* input buffer */
+	char *yy_buf_pos;		/* current position in input buffer */
+
+	/* Size of input buffer in bytes, not including room for EOB
+	 * characters.
+	 */
+	yy_size_t yy_buf_size;
+
+	/* Number of characters read into yy_ch_buf, not including EOB
+	 * characters.
+	 */
+	int yy_n_chars;
+
+	/* Whether we "own" the buffer - i.e., we know we created it,
+	 * and can realloc() it to grow it, and should free() it to
+	 * delete it.
+	 */
+	int yy_is_our_buffer;
+
+	/* Whether this is an "interactive" input source; if so, and
+	 * if we're using stdio for input, then we want to use getc()
+	 * instead of fread(), to make sure we stop fetching input after
+	 * each newline.
+	 */
+	int yy_is_interactive;
+
+	/* Whether we're considered to be at the beginning of a line.
+	 * If so, '^' rules will be active on the next match, otherwise
+	 * not.
+	 */
+	int yy_at_bol;
+
+	/* Whether to try to fill the input buffer when we reach the
+	 * end of it.
+	 */
+	int yy_fill_buffer;
+
+	int yy_buffer_status;
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+	/* When an EOF's been seen but there's still some text to process
+	 * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+	 * shouldn't try reading from the input source any more.  We might
+	 * still have a bunch of tokens to match, though, because of
+	 * possible backing-up.
+	 *
+	 * When we actually see the EOF, we change the status to "new"
+	 * (via yyrestart()), so that the user can continue scanning by
+	 * just pointing yyin at a new input file.
+	 */
+#define YY_BUFFER_EOF_PENDING 2
+	};
+
+static YY_BUFFER_STATE yy_current_buffer = 0;
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ */
+#define YY_CURRENT_BUFFER yy_current_buffer
+
+
+/* yy_hold_char holds the character lost when yytext is formed. */
+static char yy_hold_char;
+
+static int yy_n_chars;		/* number of characters read into yy_ch_buf */
+
+
+int yyleng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 1;		/* whether we need to initialize */
+static int yy_start = 0;	/* start state number */
+
+/* Flag which is used to allow yywrap()'s to do buffer switches
+ * instead of setting up a fresh yyin.  A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void yyrestart YY_PROTO(( FILE *input_file ));
+
+void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer ));
+void yy_load_buffer_state YY_PROTO(( void ));
+YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size ));
+void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b ));
+void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file ));
+void yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b ));
+#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer )
+
+YY_BUFFER_STATE yy_scan_buffer YY_PROTO(( char *base, yy_size_t size ));
+YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str ));
+YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len ));
+
+static void *yy_flex_alloc YY_PROTO(( yy_size_t ));
+static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t ));
+static void yy_flex_free YY_PROTO(( void * ));
+
+#define yy_new_buffer yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+	{ \
+	if ( ! yy_current_buffer ) \
+		yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+	yy_current_buffer->yy_is_interactive = is_interactive; \
+	}
+
+#define yy_set_bol(at_bol) \
+	{ \
+	if ( ! yy_current_buffer ) \
+		yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+	yy_current_buffer->yy_at_bol = at_bol; \
+	}
+
+#define YY_AT_BOL() (yy_current_buffer->yy_at_bol)
+
+
+#define yywrap() 1
+#define YY_SKIP_YYWRAP
+typedef unsigned char YY_CHAR;
+FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
+typedef int yy_state_type;
+extern char *yytext;
+#define yytext_ptr yytext
+
+static yy_state_type yy_get_previous_state YY_PROTO(( void ));
+static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state ));
+static int yy_get_next_buffer YY_PROTO(( void ));
+static void yy_fatal_error YY_PROTO(( yyconst char msg[] ));
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+	yytext_ptr = yy_bp; \
+	yyleng = (int) (yy_cp - yy_bp); \
+	yy_hold_char = *yy_cp; \
+	*yy_cp = '\0'; \
+	yy_c_buf_p = yy_cp;
+
+#define YY_NUM_RULES 46
+#define YY_END_OF_BUFFER 47
+static yyconst short int yy_accept[274] =
+    {   0,
+        0,    0,   38,   38,   47,   46,   44,   45,   37,   46,
+        2,   43,    3,   43,   43,   43,   43,   43,   43,   43,
+       43,   43,   46,    4,   43,   43,   43,   43,   43,   43,
+       43,   43,   38,   39,   42,   46,    0,    1,    1,   43,
+       43,   43,   43,   43,   43,   43,   43,   43,   43,   43,
+       43,   43,   43,   43,    0,    0,    0,    0,   43,   43,
+       43,   43,   43,   43,   43,   38,   39,    0,   41,   40,
+       43,   43,   43,   43,   43,   43,   43,   43,   43,   43,
+       43,   43,   43,   43,   43,    0,    0,    0,    0,    0,
+       43,   43,   43,   43,   43,   43,   43,   43,   43,   43,
+
+       43,   43,   35,   43,   21,   23,   43,   43,   43,   43,
+       43,   29,    0,    0,    0,    0,    0,   43,   35,   43,
+       43,   31,   43,   43,   12,   43,   43,   43,   43,   43,
+       43,   43,   43,   43,   43,   43,    0,    0,    0,    0,
+        0,   32,   43,   43,   43,   43,   13,   43,   43,   22,
+       43,   43,   43,   43,   43,   43,   43,    0,    0,    0,
+        0,    0,   43,   30,   43,   43,   43,   43,   43,   43,
+       43,   43,   43,   43,   43,   43,    0,    0,    0,    0,
+        0,   43,   43,   34,   14,   43,   20,   43,   43,   43,
+       43,   43,   43,   28,    0,    0,    0,    9,    0,   43,
+
+       33,   43,   43,   43,   43,   43,   11,   43,   43,   36,
+       43,   43,    0,    5,    6,    0,   43,   43,   43,   43,
+       43,   43,   24,   43,   26,   43,    0,    0,   10,   43,
+       43,   43,   43,   43,   25,   43,    0,    0,   43,   43,
+       43,   43,   19,   43,    0,    0,   43,   43,   43,   43,
+       43,    0,    0,   43,   43,   17,   18,   43,    0,    0,
+       43,   16,   43,    8,    7,   43,   43,   43,   27,   43,
+       43,   15,    0
+    } ;
+
+static yyconst int yy_ec[256] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
+        1,    1,    4,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    5,    1,    6,    7,    1,    1,    1,    1,    1,
+        1,    1,    1,    8,    9,   10,    1,   11,   11,   11,
+       11,   11,   11,   11,   11,   11,   11,   12,    1,    1,
+        1,    1,    1,    9,   13,   14,    9,   15,    9,   16,
+       17,   18,   19,    9,    9,   20,   21,   22,    9,    9,
+        9,    9,   23,   24,    9,    9,    9,    9,    9,    9,
+       25,   26,   27,    1,   28,    1,   29,   30,   31,   32,
+
+       33,   34,   35,   36,   37,    9,   38,   39,   40,   41,
+       42,   43,    9,   44,   45,   46,   47,    9,   48,   49,
+       50,    9,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1
+    } ;
+
+static yyconst int yy_meta[51] =
+    {   0,
+        1,    1,    1,    1,    1,    2,    1,    1,    3,    3,
+        3,    1,    3,    3,    3,    3,    3,    3,    3,    3,
+        3,    3,    3,    3,    1,    2,    1,    1,    3,    3,
+        3,    3,    3,    3,    3,    3,    3,    3,    3,    3,
+        3,    3,    3,    3,    3,    3,    3,    3,    3,    3
+    } ;
+
+static yyconst short int yy_base[279] =
+    {   0,
+        0,   19,   49,   50,  331,  332,  332,  332,  332,   54,
+      332,    0,  332,  300,  285,   25,  286,  296,   31,  297,
+       29,   28,   49,  332,  296,  293,  294,  275,  281,  276,
+      277,   40,  315,  314,  310,  309,   78,  332,   80,    0,
+      272,  271,  266,  280,  266,  267,  267,  262,  266,   48,
+      276,  260,  254,  259,  257,   62,  271,  266,  259,  255,
+      259,  265,  247,  262,  261,  288,  287,  286,  332,  332,
+      241,  239,  253,  238,  244,  242,  247,  235,  247,  235,
+      232,  238,  230,  229,  241,  231,  257,  230,  239,  240,
+      223,  226,  225,  226,  231,  216,  216,  215,  215,   54,
+
+      219,  229,   66,  210,    0,    0,  225,  218,  215,  220,
+       67,    0,  204,  231,  217,  205,  204,  214,    0,  200,
+      208,    0,  204,  206,    0,  209,  204,  207,  193,  201,
+      208,  200,  193,   70,  202,  196,  187,  220,  186,  187,
+      197,    0,  198,  195,  192,  182,    0,  178,  181,    0,
+      180,  185,   64,  178,  187,   74,  176,  183,   80,  186,
+      169,  177,  175,    0,  170,  169,  163,  162,  169,  173,
+      172,   72,  162,  166,  169,  163,  195,  188,  159,  170,
+      191,  154,  148,    0,    0,  107,    0,  148,  143,  154,
+      149,  144,  157,    0,   80,   88,  160,  332,   82,  153,
+
+        0,  141,  137,  150,  142,  148,    0,  134,  134,    0,
+      132,  131,  139,  332,  332,  138,  130,  129,  126,  142,
+      141,  120,    0,  122,    0,  130,  133,  131,    0,  119,
+      106,  119,  115,  103,    0,  106,  108,  107,   97,  100,
+      108,  107,    0,   98,  106,  103,   89,   92,   88,   85,
+       83,   84,   83,   87,   82,    0,    0,   87,   96,   91,
+       70,    0,   64,  332,  332,   62,   58,   56,    0,   58,
+       25,    0,  332,  153,  156,   56,  159,  162
+    } ;
+
+static yyconst short int yy_def[279] =
+    {   0,
+      273,    1,  274,  274,  273,  273,  273,  273,  273,  275,
+      273,  276,  273,  276,  276,  276,  276,  276,  276,  276,
+      276,  276,  273,  273,  276,  276,  276,  276,  276,  276,
+      276,  276,  277,  278,  273,  273,  275,  273,  275,  276,
+      276,  276,  276,  276,  276,  276,  276,  276,  276,  276,
+      276,  276,  276,  276,  273,  273,  273,  273,  276,  276,
+      276,  276,  276,  276,  276,  277,  278,  278,  273,  273,
+      276,  276,  276,  276,  276,  276,  276,  276,  276,  276,
+      276,  276,  276,  276,  276,  273,  273,  273,  273,  273,
+      276,  276,  276,  276,  276,  276,  276,  276,  276,  276,
+
+      276,  276,  276,  276,  276,  276,  276,  276,  276,  276,
+      276,  276,  273,  273,  273,  273,  273,  276,  276,  276,
+      276,  276,  276,  276,  276,  276,  276,  276,  276,  276,
+      276,  276,  276,  276,  276,  276,  273,  273,  273,  273,
+      273,  276,  276,  276,  276,  276,  276,  276,  276,  276,
+      276,  276,  276,  276,  276,  276,  276,  273,  273,  273,
+      273,  273,  276,  276,  276,  276,  276,  276,  276,  276,
+      276,  276,  276,  276,  276,  276,  273,  273,  273,  273,
+      273,  276,  276,  276,  276,  276,  276,  276,  276,  276,
+      276,  276,  276,  276,  273,  273,  273,  273,  273,  276,
+
+      276,  276,  276,  276,  276,  276,  276,  276,  276,  276,
+      276,  276,  273,  273,  273,  273,  276,  276,  276,  276,
+      276,  276,  276,  276,  276,  276,  273,  273,  276,  276,
+      276,  276,  276,  276,  276,  276,  273,  273,  276,  276,
+      276,  276,  276,  276,  273,  273,  276,  276,  276,  276,
+      276,  273,  273,  276,  276,  276,  276,  276,  273,  273,
+      276,  276,  276,  273,  273,  276,  276,  276,  276,  276,
+      276,  276,    0,  273,  273,  273,  273,  273
+    } ;
+
+static yyconst short int yy_nxt[383] =
+    {   0,
+        6,    7,    8,    8,    7,    9,   10,   11,   12,   12,
+       12,   13,   14,   15,   16,   17,   12,   12,   18,   19,
+       12,   20,   21,   22,   23,    6,    6,   24,   12,   12,
+       12,   12,   12,   25,   12,   12,   26,   12,   12,   27,
+       12,   12,   28,   12,   29,   30,   12,   12,   12,   12,
+       31,   34,   34,   43,   35,   35,   38,   39,   40,   47,
+       53,   50,   55,   32,  272,   56,   44,   48,   51,   57,
+       52,   58,   65,  127,   36,   36,   80,   54,   81,   51,
+       38,   39,   38,   39,   87,  130,  136,  171,  155,  178,
+      159,  190,  127,  174,   88,  213,  175,  216,  196,  271,
+
+      261,  270,  258,  269,  130,  136,  155,  268,  267,  171,
+      190,  266,  174,  213,  214,  216,  261,  265,  175,  202,
+      203,  258,  264,  263,  204,  205,  262,  260,  259,  257,
+      206,  256,  255,  254,  253,  202,  203,  252,  251,  250,
+      249,  248,  204,  205,  247,  246,  245,  244,  243,  242,
+      241,  240,  206,   33,   33,   33,   37,   37,   37,   66,
+      239,   66,   68,  238,   68,  237,  236,  235,  234,  233,
+      232,  231,  230,  229,  228,  227,  226,  225,  224,  223,
+      222,  221,  220,  219,  218,  217,  215,  212,  211,  210,
+      209,  208,  207,  201,  200,  199,  198,  197,  196,  195,
+
+      194,  193,  192,  191,  189,  188,  187,  186,  185,  184,
+      183,  182,  181,  180,  179,  177,  176,  173,  172,  170,
+      169,  168,  167,  166,  165,  164,  163,  162,  161,  160,
+      159,  158,  157,  156,  154,  153,  152,  151,  150,  149,
+      148,  147,  146,  145,  144,  143,  142,  141,  140,  139,
+      138,  137,  135,  134,  133,  132,  131,  129,  128,  126,
+      125,  124,  123,  122,  121,  120,  119,  118,  117,  116,
+      115,  114,  113,  112,  111,  110,  109,  108,  107,  106,
+      105,  104,  103,  102,  101,  100,   99,   98,   67,   67,
+       67,   97,   96,   95,   94,   93,   92,   91,   90,   89,
+
+       86,   85,   84,   83,   82,   79,   78,   77,   76,   75,
+       74,   73,   72,   71,   70,   69,   67,   67,   64,   63,
+       51,   62,   61,   60,   59,   49,   46,   45,   42,   41,
+      273,    5,  273,  273,  273,  273,  273,  273,  273,  273,
+      273,  273,  273,  273,  273,  273,  273,  273,  273,  273,
+      273,  273,  273,  273,  273,  273,  273,  273,  273,  273,
+      273,  273,  273,  273,  273,  273,  273,  273,  273,  273,
+      273,  273,  273,  273,  273,  273,  273,  273,  273,  273,
+      273,  273
+    } ;
+
+static yyconst short int yy_chk[383] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        2,    3,    4,   16,    3,    4,   10,   10,  276,   19,
+       22,   21,   23,    2,  271,   23,   16,   19,   21,   23,
+       21,   23,   32,  100,    3,    4,   50,   22,   50,   32,
+       37,   37,   39,   39,   56,  103,  111,  153,  134,  159,
+      159,  172,  100,  156,   56,  195,  156,  199,  196,  270,
+
+      254,  268,  251,  267,  103,  111,  134,  266,  263,  153,
+      172,  261,  156,  195,  196,  199,  254,  260,  156,  186,
+      186,  251,  259,  258,  186,  186,  255,  253,  252,  250,
+      186,  249,  248,  247,  246,  186,  186,  245,  244,  242,
+      241,  240,  186,  186,  239,  238,  237,  236,  234,  233,
+      232,  231,  186,  274,  274,  274,  275,  275,  275,  277,
+      230,  277,  278,  228,  278,  227,  226,  224,  222,  221,
+      220,  219,  218,  217,  216,  213,  212,  211,  209,  208,
+      206,  205,  204,  203,  202,  200,  197,  193,  192,  191,
+      190,  189,  188,  183,  182,  181,  180,  179,  178,  177,
+
+      176,  175,  174,  173,  171,  170,  169,  168,  167,  166,
+      165,  163,  162,  161,  160,  158,  157,  155,  154,  152,
+      151,  149,  148,  146,  145,  144,  143,  141,  140,  139,
+      138,  137,  136,  135,  133,  132,  131,  130,  129,  128,
+      127,  126,  124,  123,  121,  120,  118,  117,  116,  115,
+      114,  113,  110,  109,  108,  107,  104,  102,  101,   99,
+       98,   97,   96,   95,   94,   93,   92,   91,   90,   89,
+       88,   87,   86,   85,   84,   83,   82,   81,   80,   79,
+       78,   77,   76,   75,   74,   73,   72,   71,   68,   67,
+       66,   65,   64,   63,   62,   61,   60,   59,   58,   57,
+
+       55,   54,   53,   52,   51,   49,   48,   47,   46,   45,
+       44,   43,   42,   41,   36,   35,   34,   33,   31,   30,
+       29,   28,   27,   26,   25,   20,   18,   17,   15,   14,
+        5,  273,  273,  273,  273,  273,  273,  273,  273,  273,
+      273,  273,  273,  273,  273,  273,  273,  273,  273,  273,
+      273,  273,  273,  273,  273,  273,  273,  273,  273,  273,
+      273,  273,  273,  273,  273,  273,  273,  273,  273,  273,
+      273,  273,  273,  273,  273,  273,  273,  273,  273,  273,
+      273,  273
+    } ;
+
+static yy_state_type yy_last_accepting_state;
+static char *yy_last_accepting_cpos;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+char *yytext;
+#line 1 "parse.fl"
+#define INITIAL 0
+/* This is the lexical analyser - it returns tokens to the parsers.
+   This is used by both parsers - one for the build-time config files
+   and one for the run-time config files. Note the included file "parse.h"
+   is a symlink to the relevant header file. */
+#line 7 "parse.fl"
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+/*#define YYSTYPE char * - YYSTYPE is defined in zparse.tab.h */
+#include "zparse.tab.h"
+
+/* forward declarations for std functions not picked up. */
+/*int fileno(FILE *);*/
+/*char *strdup(char *);*/
+
+int lineno=1;
+#define STRINGCOND 1
+
+#line 559 "parse.yy.c"
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap YY_PROTO(( void ));
+#else
+extern int yywrap YY_PROTO(( void ));
+#endif
+#endif
+
+#ifndef YY_NO_UNPUT
+static void yyunput YY_PROTO(( int c, char *buf_ptr ));
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int ));
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen YY_PROTO(( yyconst char * ));
+#endif
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+static int yyinput YY_PROTO(( void ));
+#else
+static int input YY_PROTO(( void ));
+#endif
+#endif
+
+#if YY_STACK_USED
+static int yy_start_stack_ptr = 0;
+static int yy_start_stack_depth = 0;
+static int *yy_start_stack = 0;
+#ifndef YY_NO_PUSH_STATE
+static void yy_push_state YY_PROTO(( int new_state ));
+#endif
+#ifndef YY_NO_POP_STATE
+static void yy_pop_state YY_PROTO(( void ));
+#endif
+#ifndef YY_NO_TOP_STATE
+static int yy_top_state YY_PROTO(( void ));
+#endif
+
+#else
+#define YY_NO_PUSH_STATE 1
+#define YY_NO_POP_STATE 1
+#define YY_NO_TOP_STATE 1
+#endif
+
+#ifdef YY_MALLOC_DECL
+YY_MALLOC_DECL
+#else
+#if __STDC__
+#ifndef __cplusplus
+#include <stdlib.h>
+#endif
+#else
+/* Just try to get by without declaring the routines.  This will fail
+ * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int)
+ * or sizeof(void*) != sizeof(int).
+ */
+#endif
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO (void) fwrite( yytext, yyleng, 1, yyout )
+#endif
+
+/* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+	if ( yy_current_buffer->yy_is_interactive ) \
+		{ \
+		int c = '*', n; \
+		for ( n = 0; n < max_size && \
+			     (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+			buf[n] = (char) c; \
+		if ( c == '\n' ) \
+			buf[n++] = (char) c; \
+		if ( c == EOF && ferror( yyin ) ) \
+			YY_FATAL_ERROR( "input in flex scanner failed" ); \
+		result = n; \
+		} \
+	else if ( ((result = fread( buf, 1, max_size, yyin )) == 0) \
+		  && ferror( yyin ) ) \
+		YY_FATAL_ERROR( "input in flex scanner failed" );
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+#endif
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL int yylex YY_PROTO(( void ))
+#endif
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+	if ( yyleng > 0 ) \
+		yy_current_buffer->yy_at_bol = \
+				(yytext[yyleng - 1] == '\n'); \
+	YY_USER_ACTION
+
+YY_DECL
+	{
+	register yy_state_type yy_current_state;
+	register char *yy_cp, *yy_bp;
+	register int yy_act;
+
+#line 26 "parse.fl"
+
+	char *string;
+	int string_len;
+
+#line 718 "parse.yy.c"
+
+	if ( yy_init )
+		{
+		yy_init = 0;
+
+#ifdef YY_USER_INIT
+		YY_USER_INIT;
+#endif
+
+		if ( ! yy_start )
+			yy_start = 1;	/* first start state */
+
+		if ( ! yyin )
+			yyin = stdin;
+
+		if ( ! yyout )
+			yyout = stdout;
+
+		if ( ! yy_current_buffer )
+			yy_current_buffer =
+				yy_create_buffer( yyin, YY_BUF_SIZE );
+
+		yy_load_buffer_state();
+		}
+
+	while ( 1 )		/* loops until end-of-file is reached */
+		{
+		yy_cp = yy_c_buf_p;
+
+		/* Support of yytext. */
+		*yy_cp = yy_hold_char;
+
+		/* yy_bp points to the position in yy_ch_buf of the start of
+		 * the current run.
+		 */
+		yy_bp = yy_cp;
+
+		yy_current_state = yy_start;
+		yy_current_state += YY_AT_BOL();
+yy_match:
+		do
+			{
+			register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+			if ( yy_accept[yy_current_state] )
+				{
+				yy_last_accepting_state = yy_current_state;
+				yy_last_accepting_cpos = yy_cp;
+				}
+			while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+				{
+				yy_current_state = (int) yy_def[yy_current_state];
+				if ( yy_current_state >= 274 )
+					yy_c = yy_meta[(unsigned int) yy_c];
+				}
+			yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+			++yy_cp;
+			}
+		while ( yy_base[yy_current_state] != 332 );
+
+yy_find_action:
+		yy_act = yy_accept[yy_current_state];
+		if ( yy_act == 0 )
+			{ /* have to back up */
+			yy_cp = yy_last_accepting_cpos;
+			yy_current_state = yy_last_accepting_state;
+			yy_act = yy_accept[yy_current_state];
+			}
+
+		YY_DO_BEFORE_ACTION;
+
+
+do_action:	/* This label is used only to access EOF actions. */
+
+
+		switch ( yy_act )
+	{ /* beginning of action switch */
+			case 0: /* must back up */
+			/* undo the effects of YY_DO_BEFORE_ACTION */
+			*yy_cp = yy_hold_char;
+			yy_cp = yy_last_accepting_cpos;
+			yy_current_state = yy_last_accepting_state;
+			goto yy_find_action;
+
+case 1:
+YY_RULE_SETUP
+#line 30 "parse.fl"
+lineno++;/*yylval.string=yytext;*/yyleng=0;
+	YY_BREAK
+case 2:
+YY_RULE_SETUP
+#line 31 "parse.fl"
+return (',');
+	YY_BREAK
+case 3:
+YY_RULE_SETUP
+#line 32 "parse.fl"
+return (':');
+	YY_BREAK
+case 4:
+YY_RULE_SETUP
+#line 33 "parse.fl"
+return ('_');
+	YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 34 "parse.fl"
+yylval.string=yytext;return(GSDLVERSION);
+	YY_BREAK
+case 6:
+YY_RULE_SETUP
+#line 35 "parse.fl"
+return (GENERAL_SECTION);
+	YY_BREAK
+case 7:
+YY_RULE_SETUP
+#line 36 "parse.fl"
+return (SEARCH_SECTION);
+	YY_BREAK
+case 8:
+YY_RULE_SETUP
+#line 37 "parse.fl"
+return (BROWSE_SECTION);
+	YY_BREAK
+case 9:
+YY_RULE_SETUP
+#line 38 "parse.fl"
+return (MACROS_SECTION);
+	YY_BREAK
+case 10:
+YY_RULE_SETUP
+#line 39 "parse.fl"
+return (MAINTAINER);
+	YY_BREAK
+case 11:
+YY_RULE_SETUP
+#line 40 "parse.fl"
+return(LANGUAGES);
+	YY_BREAK
+case 12:
+YY_RULE_SETUP
+#line 41 "parse.fl"
+return(ABOUT);
+	YY_BREAK
+case 13:
+YY_RULE_SETUP
+#line 42 "parse.fl"
+return(BROWSE);
+	YY_BREAK
+case 14:
+YY_RULE_SETUP
+#line 43 "parse.fl"
+return(DATELIST);
+	YY_BREAK
+case 15:
+YY_RULE_SETUP
+#line 44 "parse.fl"
+return(DOCUMENTARROWSBOTTOM);
+	YY_BREAK
+case 16:
+YY_RULE_SETUP
+#line 45 "parse.fl"
+return(DOCUMENTBUTTONS);
+	YY_BREAK
+case 17:
+YY_RULE_SETUP
+#line 46 "parse.fl"
+return(DOCUMENTHEADER);
+	YY_BREAK
+case 18:
+YY_RULE_SETUP
+#line 47 "parse.fl"
+return(DOCUMENTIMAGES);
+	YY_BREAK
+case 19:
+YY_RULE_SETUP
+#line 48 "parse.fl"
+return(DOCUMENTTEXT);
+	YY_BREAK
+case 20:
+YY_RULE_SETUP
+#line 49 "parse.fl"
+return(ICONLINK);
+	YY_BREAK
+case 21:
+YY_RULE_SETUP
+#line 50 "parse.fl"
+return(LIST);
+	YY_BREAK
+case 22:
+YY_RULE_SETUP
+#line 51 "parse.fl"
+return(FORMAT);
+	YY_BREAK
+case 23:
+YY_RULE_SETUP
+#line 52 "parse.fl"
+return(NAME);
+	YY_BREAK
+case 24:
+YY_RULE_SETUP
+#line 53 "parse.fl"
+return(SEARCHTEXT);
+	YY_BREAK
+case 25:
+YY_RULE_SETUP
+#line 54 "parse.fl"
+return(SECTIONLIST);
+	YY_BREAK
+case 26:
+YY_RULE_SETUP
+#line 55 "parse.fl"
+return(SORTEDLIST);
+	YY_BREAK
+case 27:
+YY_RULE_SETUP
+#line 56 "parse.fl"
+return(SORTEDSECTIONLIST);
+	YY_BREAK
+case 28:
+YY_RULE_SETUP
+#line 57 "parse.fl"
+return(TEXTLINK);
+	YY_BREAK
+case 29:
+YY_RULE_SETUP
+#line 58 "parse.fl"
+return(TYPE);
+	YY_BREAK
+case 30:
+YY_RULE_SETUP
+#line 59 "parse.fl"
+return (PUBLIC);
+	YY_BREAK
+case 31:
+YY_RULE_SETUP
+#line 60 "parse.fl"
+return (TRUE);
+	YY_BREAK
+case 32:
+YY_RULE_SETUP
+#line 61 "parse.fl"
+return (FALSE);
+	YY_BREAK
+case 33:
+YY_RULE_SETUP
+#line 62 "parse.fl"
+return (DOCUMENT);
+	YY_BREAK
+case 34:
+YY_RULE_SETUP
+#line 63 "parse.fl"
+return (SECTION);
+	YY_BREAK
+case 35:
+YY_RULE_SETUP
+#line 64 "parse.fl"
+return (ICON);
+	YY_BREAK
+case 36:
+YY_RULE_SETUP
+#line 65 "parse.fl"
+return (SMALLICON);
+	YY_BREAK
+case 37:
+YY_RULE_SETUP
+#line 66 "parse.fl"
+{string=NULL;BEGIN(STRINGCOND);}
+	YY_BREAK
+
+case 38:
+YY_RULE_SETUP
+#line 68 "parse.fl"
+{/* append this to our current string EXC NEWLINE */
+			if (string==NULL) string_len=0; else
+			string_len=strlen(string);
+			string=realloc(string,string_len+strlen(yytext)+1);
+			/* +1 is for trailing \0 */
+			strcpy(string+string_len,yytext);
+			}
+	YY_BREAK
+case 39:
+YY_RULE_SETUP
+#line 75 "parse.fl"
+{/* append this to our current string - INC NEWLINE */
+			lineno++;
+			if (string==NULL) string_len=0; else
+			string_len=strlen(string);
+			string=realloc(string,string_len+strlen(yytext)+1);
+			/* +1 is for trailing \0 */
+			strcpy(string+string_len,yytext);
+			}
+	YY_BREAK
+case 40:
+#line 84 "parse.fl"
+case 41:
+YY_RULE_SETUP
+#line 84 "parse.fl"
+{       /*replace quoted quote with one quote*/
+			string_len=strlen(string);
+			string=realloc(string,string_len+2);
+			string[string_len]='\"';
+			string[string_len+1]='\0';
+			}
+	YY_BREAK
+case 42:
+YY_RULE_SETUP
+#line 90 "parse.fl"
+{
+			BEGIN(INITIAL);
+			yylval.string=string;
+			return(STRING);
+			  /* note that the string may have long bits of 
+			     whitespace in it that we could remove. */
+			}
+	YY_BREAK
+
+case 43:
+YY_RULE_SETUP
+#line 98 "parse.fl"
+yylval.string=strdup(yytext);return (DATA);
+	YY_BREAK
+case 44:
+YY_RULE_SETUP
+#line 99 "parse.fl"
+;
+	YY_BREAK
+case 45:
+YY_RULE_SETUP
+#line 100 "parse.fl"
+lineno++;
+	YY_BREAK
+case 46:
+YY_RULE_SETUP
+#line 101 "parse.fl"
+ECHO;
+	YY_BREAK
+#line 1055 "parse.yy.c"
+case YY_STATE_EOF(INITIAL):
+case YY_STATE_EOF(STRINGCOND):
+	yyterminate();
+
+	case YY_END_OF_BUFFER:
+		{
+		/* Amount of text matched not including the EOB char. */
+		int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1;
+
+		/* Undo the effects of YY_DO_BEFORE_ACTION. */
+		*yy_cp = yy_hold_char;
+		YY_RESTORE_YY_MORE_OFFSET
+
+		if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW )
+			{
+			/* We're scanning a new file or input source.  It's
+			 * possible that this happened because the user
+			 * just pointed yyin at a new source and called
+			 * yylex().  If so, then we have to assure
+			 * consistency between yy_current_buffer and our
+			 * globals.  Here is the right place to do so, because
+			 * this is the first action (other than possibly a
+			 * back-up) that will match for the new input source.
+			 */
+			yy_n_chars = yy_current_buffer->yy_n_chars;
+			yy_current_buffer->yy_input_file = yyin;
+			yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL;
+			}
+
+		/* Note that here we test for yy_c_buf_p "<=" to the position
+		 * of the first EOB in the buffer, since yy_c_buf_p will
+		 * already have been incremented past the NUL character
+		 * (since all states make transitions on EOB to the
+		 * end-of-buffer state).  Contrast this with the test
+		 * in input().
+		 */
+		if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] )
+			{ /* This was really a NUL. */
+			yy_state_type yy_next_state;
+
+			yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text;
+
+			yy_current_state = yy_get_previous_state();
+
+			/* Okay, we're now positioned to make the NUL
+			 * transition.  We couldn't have
+			 * yy_get_previous_state() go ahead and do it
+			 * for us because it doesn't know how to deal
+			 * with the possibility of jamming (and we don't
+			 * want to build jamming into it because then it
+			 * will run more slowly).
+			 */
+
+			yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+			yy_bp = yytext_ptr + YY_MORE_ADJ;
+
+			if ( yy_next_state )
+				{
+				/* Consume the NUL. */
+				yy_cp = ++yy_c_buf_p;
+				yy_current_state = yy_next_state;
+				goto yy_match;
+				}
+
+			else
+				{
+				yy_cp = yy_c_buf_p;
+				goto yy_find_action;
+				}
+			}
+
+		else switch ( yy_get_next_buffer() )
+			{
+			case EOB_ACT_END_OF_FILE:
+				{
+				yy_did_buffer_switch_on_eof = 0;
+
+				if ( yywrap() )
+					{
+					/* Note: because we've taken care in
+					 * yy_get_next_buffer() to have set up
+					 * yytext, we can now set up
+					 * yy_c_buf_p so that if some total
+					 * hoser (like flex itself) wants to
+					 * call the scanner after we return the
+					 * YY_NULL, it'll still work - another
+					 * YY_NULL will get returned.
+					 */
+					yy_c_buf_p = yytext_ptr + YY_MORE_ADJ;
+
+					yy_act = YY_STATE_EOF(YY_START);
+					goto do_action;
+					}
+
+				else
+					{
+					if ( ! yy_did_buffer_switch_on_eof )
+						YY_NEW_FILE;
+					}
+				break;
+				}
+
+			case EOB_ACT_CONTINUE_SCAN:
+				yy_c_buf_p =
+					yytext_ptr + yy_amount_of_matched_text;
+
+				yy_current_state = yy_get_previous_state();
+
+				yy_cp = yy_c_buf_p;
+				yy_bp = yytext_ptr + YY_MORE_ADJ;
+				goto yy_match;
+
+			case EOB_ACT_LAST_MATCH:
+				yy_c_buf_p =
+				&yy_current_buffer->yy_ch_buf[yy_n_chars];
+
+				yy_current_state = yy_get_previous_state();
+
+				yy_cp = yy_c_buf_p;
+				yy_bp = yytext_ptr + YY_MORE_ADJ;
+				goto yy_find_action;
+			}
+		break;
+		}
+
+	default:
+		YY_FATAL_ERROR(
+			"fatal flex scanner internal error--no action found" );
+	} /* end of action switch */
+		} /* end of scanning one token */
+	} /* end of yylex */
+
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ *	EOB_ACT_LAST_MATCH -
+ *	EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ *	EOB_ACT_END_OF_FILE - end of file
+ */
+
+static int yy_get_next_buffer()
+	{
+	register char *dest = yy_current_buffer->yy_ch_buf;
+	register char *source = yytext_ptr;
+	register int number_to_move, i;
+	int ret_val;
+
+	if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] )
+		YY_FATAL_ERROR(
+		"fatal flex scanner internal error--end of buffer missed" );
+
+	if ( yy_current_buffer->yy_fill_buffer == 0 )
+		{ /* Don't try to fill the buffer, so this is an EOF. */
+		if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 )
+			{
+			/* We matched a single character, the EOB, so
+			 * treat this as a final EOF.
+			 */
+			return EOB_ACT_END_OF_FILE;
+			}
+
+		else
+			{
+			/* We matched some text prior to the EOB, first
+			 * process it.
+			 */
+			return EOB_ACT_LAST_MATCH;
+			}
+		}
+
+	/* Try to read more data. */
+
+	/* First move last chars to start of buffer. */
+	number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1;
+
+	for ( i = 0; i < number_to_move; ++i )
+		*(dest++) = *(source++);
+
+	if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+		/* don't do the read, it's not guaranteed to return an EOF,
+		 * just force an EOF
+		 */
+		yy_current_buffer->yy_n_chars = yy_n_chars = 0;
+
+	else
+		{
+		int num_to_read =
+			yy_current_buffer->yy_buf_size - number_to_move - 1;
+
+		while ( num_to_read <= 0 )
+			{ /* Not enough room in the buffer - grow it. */
+#ifdef YY_USES_REJECT
+			YY_FATAL_ERROR(
+"input buffer overflow, can't enlarge buffer because scanner uses REJECT" );
+#else
+
+			/* just a shorter name for the current buffer */
+			YY_BUFFER_STATE b = yy_current_buffer;
+
+			int yy_c_buf_p_offset =
+				(int) (yy_c_buf_p - b->yy_ch_buf);
+
+			if ( b->yy_is_our_buffer )
+				{
+				int new_size = b->yy_buf_size * 2;
+
+				if ( new_size <= 0 )
+					b->yy_buf_size += b->yy_buf_size / 8;
+				else
+					b->yy_buf_size *= 2;
+
+				b->yy_ch_buf = (char *)
+					/* Include room in for 2 EOB chars. */
+					yy_flex_realloc( (void *) b->yy_ch_buf,
+							 b->yy_buf_size + 2 );
+				}
+			else
+				/* Can't grow it, we don't own it. */
+				b->yy_ch_buf = 0;
+
+			if ( ! b->yy_ch_buf )
+				YY_FATAL_ERROR(
+				"fatal error - scanner input buffer overflow" );
+
+			yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+			num_to_read = yy_current_buffer->yy_buf_size -
+						number_to_move - 1;
+#endif
+			}
+
+		if ( num_to_read > YY_READ_BUF_SIZE )
+			num_to_read = YY_READ_BUF_SIZE;
+
+		/* Read in more data. */
+		YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]),
+			yy_n_chars, num_to_read );
+
+		yy_current_buffer->yy_n_chars = yy_n_chars;
+		}
+
+	if ( yy_n_chars == 0 )
+		{
+		if ( number_to_move == YY_MORE_ADJ )
+			{
+			ret_val = EOB_ACT_END_OF_FILE;
+			yyrestart( yyin );
+			}
+
+		else
+			{
+			ret_val = EOB_ACT_LAST_MATCH;
+			yy_current_buffer->yy_buffer_status =
+				YY_BUFFER_EOF_PENDING;
+			}
+		}
+
+	else
+		ret_val = EOB_ACT_CONTINUE_SCAN;
+
+	yy_n_chars += number_to_move;
+	yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+	yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+	yytext_ptr = &yy_current_buffer->yy_ch_buf[0];
+
+	return ret_val;
+	}
+
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+static yy_state_type yy_get_previous_state()
+	{
+	register yy_state_type yy_current_state;
+	register char *yy_cp;
+
+	yy_current_state = yy_start;
+	yy_current_state += YY_AT_BOL();
+
+	for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp )
+		{
+		register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+		if ( yy_accept[yy_current_state] )
+			{
+			yy_last_accepting_state = yy_current_state;
+			yy_last_accepting_cpos = yy_cp;
+			}
+		while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+			{
+			yy_current_state = (int) yy_def[yy_current_state];
+			if ( yy_current_state >= 274 )
+				yy_c = yy_meta[(unsigned int) yy_c];
+			}
+		yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+		}
+
+	return yy_current_state;
+	}
+
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ *	next_state = yy_try_NUL_trans( current_state );
+ */
+
+#ifdef YY_USE_PROTOS
+static yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state )
+#else
+static yy_state_type yy_try_NUL_trans( yy_current_state )
+yy_state_type yy_current_state;
+#endif
+	{
+	register int yy_is_jam;
+	register char *yy_cp = yy_c_buf_p;
+
+	register YY_CHAR yy_c = 1;
+	if ( yy_accept[yy_current_state] )
+		{
+		yy_last_accepting_state = yy_current_state;
+		yy_last_accepting_cpos = yy_cp;
+		}
+	while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+		{
+		yy_current_state = (int) yy_def[yy_current_state];
+		if ( yy_current_state >= 274 )
+			yy_c = yy_meta[(unsigned int) yy_c];
+		}
+	yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+	yy_is_jam = (yy_current_state == 273);
+
+	return yy_is_jam ? 0 : yy_current_state;
+	}
+
+
+#ifndef YY_NO_UNPUT
+#ifdef YY_USE_PROTOS
+static void yyunput( int c, register char *yy_bp )
+#else
+static void yyunput( c, yy_bp )
+int c;
+register char *yy_bp;
+#endif
+	{
+	register char *yy_cp = yy_c_buf_p;
+
+	/* undo effects of setting up yytext */
+	*yy_cp = yy_hold_char;
+
+	if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
+		{ /* need to shift things up to make room */
+		/* +2 for EOB chars. */
+		register int number_to_move = yy_n_chars + 2;
+		register char *dest = &yy_current_buffer->yy_ch_buf[
+					yy_current_buffer->yy_buf_size + 2];
+		register char *source =
+				&yy_current_buffer->yy_ch_buf[number_to_move];
+
+		while ( source > yy_current_buffer->yy_ch_buf )
+			*--dest = *--source;
+
+		yy_cp += (int) (dest - source);
+		yy_bp += (int) (dest - source);
+		yy_current_buffer->yy_n_chars =
+			yy_n_chars = yy_current_buffer->yy_buf_size;
+
+		if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
+			YY_FATAL_ERROR( "flex scanner push-back overflow" );
+		}
+
+	*--yy_cp = (char) c;
+
+
+	yytext_ptr = yy_bp;
+	yy_hold_char = *yy_cp;
+	yy_c_buf_p = yy_cp;
+	}
+#endif	/* ifndef YY_NO_UNPUT */
+
+
+#ifdef __cplusplus
+static int yyinput()
+#else
+static int input()
+#endif
+	{
+	int c;
+
+	*yy_c_buf_p = yy_hold_char;
+
+	if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
+		{
+		/* yy_c_buf_p now points to the character we want to return.
+		 * If this occurs *before* the EOB characters, then it's a
+		 * valid NUL; if not, then we've hit the end of the buffer.
+		 */
+		if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] )
+			/* This was really a NUL. */
+			*yy_c_buf_p = '\0';
+
+		else
+			{ /* need more input */
+			int offset = yy_c_buf_p - yytext_ptr;
+			++yy_c_buf_p;
+
+			switch ( yy_get_next_buffer() )
+				{
+				case EOB_ACT_LAST_MATCH:
+					/* This happens because yy_g_n_b()
+					 * sees that we've accumulated a
+					 * token and flags that we need to
+					 * try matching the token before
+					 * proceeding.  But for input(),
+					 * there's no matching to consider.
+					 * So convert the EOB_ACT_LAST_MATCH
+					 * to EOB_ACT_END_OF_FILE.
+					 */
+
+					/* Reset buffer status. */
+					yyrestart( yyin );
+
+					/* fall through */
+
+				case EOB_ACT_END_OF_FILE:
+					{
+					if ( yywrap() )
+						return EOF;
+
+					if ( ! yy_did_buffer_switch_on_eof )
+						YY_NEW_FILE;
+#ifdef __cplusplus
+					return yyinput();
+#else
+					return input();
+#endif
+					}
+
+				case EOB_ACT_CONTINUE_SCAN:
+					yy_c_buf_p = yytext_ptr + offset;
+					break;
+				}
+			}
+		}
+
+	c = *(unsigned char *) yy_c_buf_p;	/* cast for 8-bit char's */
+	*yy_c_buf_p = '\0';	/* preserve yytext */
+	yy_hold_char = *++yy_c_buf_p;
+
+	yy_current_buffer->yy_at_bol = (c == '\n');
+
+	return c;
+	}
+
+
+#ifdef YY_USE_PROTOS
+void yyrestart( FILE *input_file )
+#else
+void yyrestart( input_file )
+FILE *input_file;
+#endif
+	{
+	if ( ! yy_current_buffer )
+		yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE );
+
+	yy_init_buffer( yy_current_buffer, input_file );
+	yy_load_buffer_state();
+	}
+
+
+#ifdef YY_USE_PROTOS
+void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer )
+#else
+void yy_switch_to_buffer( new_buffer )
+YY_BUFFER_STATE new_buffer;
+#endif
+	{
+	if ( yy_current_buffer == new_buffer )
+		return;
+
+	if ( yy_current_buffer )
+		{
+		/* Flush out information for old buffer. */
+		*yy_c_buf_p = yy_hold_char;
+		yy_current_buffer->yy_buf_pos = yy_c_buf_p;
+		yy_current_buffer->yy_n_chars = yy_n_chars;
+		}
+
+	yy_current_buffer = new_buffer;
+	yy_load_buffer_state();
+
+	/* We don't actually know whether we did this switch during
+	 * EOF (yywrap()) processing, but the only time this flag
+	 * is looked at is after yywrap() is called, so it's safe
+	 * to go ahead and always set it.
+	 */
+	yy_did_buffer_switch_on_eof = 1;
+	}
+
+
+#ifdef YY_USE_PROTOS
+void yy_load_buffer_state( void )
+#else
+void yy_load_buffer_state()
+#endif
+	{
+	yy_n_chars = yy_current_buffer->yy_n_chars;
+	yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos;
+	yyin = yy_current_buffer->yy_input_file;
+	yy_hold_char = *yy_c_buf_p;
+	}
+
+
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_create_buffer( FILE *file, int size )
+#else
+YY_BUFFER_STATE yy_create_buffer( file, size )
+FILE *file;
+int size;
+#endif
+	{
+	YY_BUFFER_STATE b;
+
+	b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+	b->yy_buf_size = size;
+
+	/* yy_ch_buf has to be 2 characters longer than the size given because
+	 * we need to put in 2 end-of-buffer characters.
+	 */
+	b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 );
+	if ( ! b->yy_ch_buf )
+		YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+	b->yy_is_our_buffer = 1;
+
+	yy_init_buffer( b, file );
+
+	return b;
+	}
+
+
+#ifdef YY_USE_PROTOS
+void yy_delete_buffer( YY_BUFFER_STATE b )
+#else
+void yy_delete_buffer( b )
+YY_BUFFER_STATE b;
+#endif
+	{
+	if ( ! b )
+		return;
+
+	if ( b == yy_current_buffer )
+		yy_current_buffer = (YY_BUFFER_STATE) 0;
+
+	if ( b->yy_is_our_buffer )
+		yy_flex_free( (void *) b->yy_ch_buf );
+
+	yy_flex_free( (void *) b );
+	}
+
+
+#ifndef YY_ALWAYS_INTERACTIVE
+#ifndef YY_NEVER_INTERACTIVE
+extern int isatty YY_PROTO(( int ));
+#endif
+#endif
+
+#ifdef YY_USE_PROTOS
+void yy_init_buffer( YY_BUFFER_STATE b, FILE *file )
+#else
+void yy_init_buffer( b, file )
+YY_BUFFER_STATE b;
+FILE *file;
+#endif
+
+
+	{
+	yy_flush_buffer( b );
+
+	b->yy_input_file = file;
+	b->yy_fill_buffer = 1;
+
+#if YY_ALWAYS_INTERACTIVE
+	b->yy_is_interactive = 1;
+#else
+#if YY_NEVER_INTERACTIVE
+	b->yy_is_interactive = 0;
+#else
+	b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+#endif
+#endif
+	}
+
+
+#ifdef YY_USE_PROTOS
+void yy_flush_buffer( YY_BUFFER_STATE b )
+#else
+void yy_flush_buffer( b )
+YY_BUFFER_STATE b;
+#endif
+
+	{
+	if ( ! b )
+		return;
+
+	b->yy_n_chars = 0;
+
+	/* We always need two end-of-buffer characters.  The first causes
+	 * a transition to the end-of-buffer state.  The second causes
+	 * a jam in that state.
+	 */
+	b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+	b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+	b->yy_buf_pos = &b->yy_ch_buf[0];
+
+	b->yy_at_bol = 1;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	if ( b == yy_current_buffer )
+		yy_load_buffer_state();
+	}
+
+
+#ifndef YY_NO_SCAN_BUFFER
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size )
+#else
+YY_BUFFER_STATE yy_scan_buffer( base, size )
+char *base;
+yy_size_t size;
+#endif
+	{
+	YY_BUFFER_STATE b;
+
+	if ( size < 2 ||
+	     base[size-2] != YY_END_OF_BUFFER_CHAR ||
+	     base[size-1] != YY_END_OF_BUFFER_CHAR )
+		/* They forgot to leave room for the EOB's. */
+		return 0;
+
+	b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
+
+	b->yy_buf_size = size - 2;	/* "- 2" to take care of EOB's */
+	b->yy_buf_pos = b->yy_ch_buf = base;
+	b->yy_is_our_buffer = 0;
+	b->yy_input_file = 0;
+	b->yy_n_chars = b->yy_buf_size;
+	b->yy_is_interactive = 0;
+	b->yy_at_bol = 1;
+	b->yy_fill_buffer = 0;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	yy_switch_to_buffer( b );
+
+	return b;
+	}
+#endif
+
+
+#ifndef YY_NO_SCAN_STRING
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_string( yyconst char *yy_str )
+#else
+YY_BUFFER_STATE yy_scan_string( yy_str )
+yyconst char *yy_str;
+#endif
+	{
+	int len;
+	for ( len = 0; yy_str[len]; ++len )
+		;
+
+	return yy_scan_bytes( yy_str, len );
+	}
+#endif
+
+
+#ifndef YY_NO_SCAN_BYTES
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_bytes( yyconst char *bytes, int len )
+#else
+YY_BUFFER_STATE yy_scan_bytes( bytes, len )
+yyconst char *bytes;
+int len;
+#endif
+	{
+	YY_BUFFER_STATE b;
+	char *buf;
+	yy_size_t n;
+	int i;
+
+	/* Get memory for full buffer, including space for trailing EOB's. */
+	n = len + 2;
+	buf = (char *) yy_flex_alloc( n );
+	if ( ! buf )
+		YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
+
+	for ( i = 0; i < len; ++i )
+		buf[i] = bytes[i];
+
+	buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR;
+
+	b = yy_scan_buffer( buf, n );
+	if ( ! b )
+		YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
+
+	/* It's okay to grow etc. this buffer, and we should throw it
+	 * away when we're done.
+	 */
+	b->yy_is_our_buffer = 1;
+
+	return b;
+	}
+#endif
+
+
+#ifndef YY_NO_PUSH_STATE
+#ifdef YY_USE_PROTOS
+static void yy_push_state( int new_state )
+#else
+static void yy_push_state( new_state )
+int new_state;
+#endif
+	{
+	if ( yy_start_stack_ptr >= yy_start_stack_depth )
+		{
+		yy_size_t new_size;
+
+		yy_start_stack_depth += YY_START_STACK_INCR;
+		new_size = yy_start_stack_depth * sizeof( int );
+
+		if ( ! yy_start_stack )
+			yy_start_stack = (int *) yy_flex_alloc( new_size );
+
+		else
+			yy_start_stack = (int *) yy_flex_realloc(
+					(void *) yy_start_stack, new_size );
+
+		if ( ! yy_start_stack )
+			YY_FATAL_ERROR(
+			"out of memory expanding start-condition stack" );
+		}
+
+	yy_start_stack[yy_start_stack_ptr++] = YY_START;
+
+	BEGIN(new_state);
+	}
+#endif
+
+
+#ifndef YY_NO_POP_STATE
+static void yy_pop_state()
+	{
+	if ( --yy_start_stack_ptr < 0 )
+		YY_FATAL_ERROR( "start-condition stack underflow" );
+
+	BEGIN(yy_start_stack[yy_start_stack_ptr]);
+	}
+#endif
+
+
+#ifndef YY_NO_TOP_STATE
+static int yy_top_state()
+	{
+	return yy_start_stack[yy_start_stack_ptr - 1];
+	}
+#endif
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+#ifdef YY_USE_PROTOS
+static void yy_fatal_error( yyconst char msg[] )
+#else
+static void yy_fatal_error( msg )
+char msg[];
+#endif
+	{
+	(void) fprintf( stderr, "%s\n", msg );
+	exit( YY_EXIT_FAILURE );
+	}
+
+
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up yytext. */ \
+		yytext[yyleng] = yy_hold_char; \
+		yy_c_buf_p = yytext + n; \
+		yy_hold_char = *yy_c_buf_p; \
+		*yy_c_buf_p = '\0'; \
+		yyleng = n; \
+		} \
+	while ( 0 )
+
+
+/* Internal utility routines. */
+
+#ifndef yytext_ptr
+#ifdef YY_USE_PROTOS
+static void yy_flex_strncpy( char *s1, yyconst char *s2, int n )
+#else
+static void yy_flex_strncpy( s1, s2, n )
+char *s1;
+yyconst char *s2;
+int n;
+#endif
+	{
+	register int i;
+	for ( i = 0; i < n; ++i )
+		s1[i] = s2[i];
+	}
+#endif
+
+#ifdef YY_NEED_STRLEN
+#ifdef YY_USE_PROTOS
+static int yy_flex_strlen( yyconst char *s )
+#else
+static int yy_flex_strlen( s )
+yyconst char *s;
+#endif
+	{
+	register int n;
+	for ( n = 0; s[n]; ++n )
+		;
+
+	return n;
+	}
+#endif
+
+
+#ifdef YY_USE_PROTOS
+static void *yy_flex_alloc( yy_size_t size )
+#else
+static void *yy_flex_alloc( size )
+yy_size_t size;
+#endif
+	{
+	return (void *) malloc( size );
+	}
+
+#ifdef YY_USE_PROTOS
+static void *yy_flex_realloc( void *ptr, yy_size_t size )
+#else
+static void *yy_flex_realloc( ptr, size )
+void *ptr;
+yy_size_t size;
+#endif
+	{
+	/* The cast to (char *) in the following accommodates both
+	 * implementations that use char* generic pointers, and those
+	 * that use void* generic pointers.  It works with the latter
+	 * because both ANSI C and C++ allow castless assignment from
+	 * any pointer type to void*, and deal with argument conversions
+	 * as though doing an assignment.
+	 */
+	return (void *) realloc( (char *) ptr, size );
+	}
+
+#ifdef YY_USE_PROTOS
+static void yy_flex_free( void *ptr )
+#else
+static void yy_flex_free( ptr )
+void *ptr;
+#endif
+	{
+	free( ptr );
+	}
+
+#if YY_MAIN
+int main()
+	{
+	yylex();
+	return 0;
+	}
+#endif
+#line 101 "parse.fl"
+
+/******** deleted rules: *******
+en			return(EN);
+fr			return(FR);
+mi			return(MI);
+zh			return(ZH);
+de			return(DE);
+***************/
+
+
+
+
Index: /trunk/gsdl/src/recpt/queryaction.cpp
===================================================================
--- /trunk/gsdl/src/recpt/queryaction.cpp	(revision 1346)
+++ /trunk/gsdl/src/recpt/queryaction.cpp	(revision 1347)
@@ -996,4 +996,5 @@
     args["q"]=formattedstring; 
   }
+
   format_querystring (formattedstring, args.getintarg("b"));
   set_queryfilter_options (request, formattedstring, args);
Index: /trunk/gsdl/src/recpt/z3950cfg.h
===================================================================
--- /trunk/gsdl/src/recpt/z3950cfg.h	(revision 1347)
+++ /trunk/gsdl/src/recpt/z3950cfg.h	(revision 1347)
@@ -0,0 +1,29 @@
+/*
+  This defines a data structure shared between:
+  * the C++ z3950proto class defined in z3950proto.cpp, and
+  * the C function yyparse() created by bison from the file zparse.fl
+  */
+
+#ifndef _Z3950CFG_H
+#define _Z3950CFG_H
+
+struct z3950aboutlist {
+  char *lang;
+  char *text;
+  struct z3950aboutlist *next;
+};
+struct z3950cfg {
+  char *shortname;
+  char *hostname;
+  int port;
+  char *dbname;
+  char *longname;
+  char *icon;
+  char *smallicon;
+  struct z3950aboutlist *about;
+  struct z3950cfg *next;
+};
+struct z3950cfg *zserver_list;
+#else
+extern struct z3950cfg *zserver_list;
+#endif
Index: /trunk/gsdl/src/recpt/z3950proto.cpp
===================================================================
--- /trunk/gsdl/src/recpt/z3950proto.cpp	(revision 1346)
+++ /trunk/gsdl/src/recpt/z3950proto.cpp	(revision 1347)
@@ -26,41 +26,123 @@
 #include "z3950proto.h"
 #include "comtypes.h"
-#include <stdio.h>
-
-/*** 
-    We will use the "collection" argument as the name of the database
-    to query on the z3950 server.
-***/
-
-
-z3950_server::z3950_server() {
-  count=0;
-  info=NULL;
-  meta["iconcollection"]="/~johnmcp/gsdl/images/zserver.png";
-}
-
-
-
-
-// z3950 Protocol functions
+#include "browsefilter.h"
+#include "queryfilter.h"
+#include "filter.h"
+// z39.50 yaz stuff
+#include <stdio.h> // for (FILE *) type for yyin and fopen.
+// config file parsing stuff
+#include "z3950cfg.h" // for reading in config files - 
+// defines "struct z3950cfg *zserver_list" as the head of the list.
+extern FILE *yyin;
+extern "C" {
+  extern int zconfigparse();
+}
+
+
+
+
 z3950proto::z3950proto() {
   zserver_count=0;
 }
 
-void z3950proto::add_server (const z3950_server& zserver) {
+z3950proto::~z3950proto() {
+}
+
+void z3950proto::add_server (z3950_server& zserver) {
 
   // append the new server
   zserver_count++;
-  zservers.push_back(zserver);
-}
-
-void z3950proto::configure (const text_t &/*key*/, 
-			    const text_tarray &/*cfgline*/) {
+  zservers.push_back(&zserver);
+}
+
+void z3950proto::read_config_file(const text_t &filename) {
+  struct z3950cfg *here;
+  struct z3950cfg *oldhere;
+  z3950_server *zserver;
+  ShortColInfo_t *tempinfo;
+
+  // zconfigparse() is defined in zparse.tab.c,
+  // which is the bison output of zparse.y
+
+  yyin=fopen(filename.getcstr(),"r");
+  if (yyin==NULL) {
+    cerr << "Could not open "<<filename.getcstr()<<" for reading.\n";
+  }
+  zconfigparse();
+  // we now have the config files in the ptr zserver_list
+  if (zserver_list==NULL)
+    return; // no valid servers found in the config file - note that
+  // the parser will have already spat out any errors.
+
+  // now create z3950servers for each structure in server_list
+  here=zserver_list;
+  while (here!=NULL) {
+    zserver=new z3950_server;
+    tempinfo=new ShortColInfo_t;
+
+    tempinfo->host.setcstr(here->hostname);
+    tempinfo->port=here->port;
+    tempinfo->name.setcstr(here->dbname);
+    zserver->setInfo(tempinfo);
+    zserver->setName(here->shortname);
+    // now collection metadata.
+    zserver->setMeta("collectionname",here->longname);
+    if (here->icon!=NULL)
+      zserver->setMeta("iconcollection",here->icon);
+    if (here->smallicon!=NULL)
+      zserver->setMeta("iconcollectionsmall",here->smallicon);
+    
+    /*    filterclass *filter = new filterclass ();
+	  zserver->add_filter (filter);
+	  browsefilterclass *browsefilter = new browsefilterclass();
+	  zserver->add_filter (browsefilter);
+	  queryfilterclass *queryfilter = new queryfilterclass();
+	  zserver->add_filter (queryfilter);
+    */
+
+    // About list
+    if (here->about!=NULL) {
+      struct z3950aboutlist *about_here=here->about;
+      struct z3950aboutlist *oldabout;
+
+      while (about_here!=NULL) {
+	// problem with default lang (null): can't add ("",..)
+	if (about_here->lang==NULL)
+	  zserver->addcfgAbout("en",about_here->text);
+	else
+	  zserver->addcfgAbout(about_here->lang, about_here->text);
+	oldabout=about_here;
+	about_here=about_here->next;
+	free(oldabout->lang);
+	free(oldabout->text);
+	free(oldabout);
+      }
+    }
+
+    oldhere=here;
+    here=here->next;
+    free(oldhere->shortname);
+    free(oldhere->hostname);
+    free(oldhere->dbname);
+    free(oldhere->longname);
+    free(oldhere->icon);
+    free(oldhere->smallicon);
+    free(oldhere);
+
+    add_server(*zserver);
+  } // end of while loop.
+
+}
+
+void z3950proto::configure (const text_t &key,
+			    const text_tarray &cfgline) {
 
   // this is called for each line in the gsdlsite.cfg file
-  /*  cerr << "z3950proto::configure called:"
-      << "key is " << key.getcstr()
-      << "\n1st line is " << cfgline[0].getcstr() << endl;
-  */
+
+  if (0)
+    cerr << "z3950proto::configure called:"
+	 << "key is " << key.getcstr()
+	 << "\n1st line is " << cfgline[0].getcstr() << endl;
+  
 }
 
@@ -96,5 +178,5 @@
   z3950_server_array::iterator end = zservers.end();
   while (here != end) {
-    collist.push_back(here->getName());
+    collist.push_back((*here)->getName());
     //const ShortColInfo_t *info=here->getInfo();
     //collist.push_back(info->name);
@@ -108,5 +190,5 @@
   z3950_server_array::iterator end = zservers.end();
   while (here != end) {
-    if(here->getName()==collection) {
+    if((*here)->getName()==collection) {
       hascollection=true;
       return;
@@ -133,5 +215,5 @@
   z3950_server_array::iterator end = zservers.end();
   while (here != end) {
-    if(here->getName()==collection) {
+    if((*here)->getName()==collection) {
       break;
     }
@@ -139,6 +221,4 @@
   }
 
-  // is this right? ie does end refer to the last element, or AFTER the
-  // last element?
   if (here==end) {
     err=protocolError;
@@ -149,8 +229,5 @@
   }
 
-  /*  collectinfo.shortInfo.name="sdfg";
-      collectinfo.shortInfo.host="localhost";
-      collectinfo.shortInfo.port=0; */
-  const ShortColInfo_t *colinfo=here->getInfo();
+  const ShortColInfo_t *colinfo=(*here)->getInfo();
   collectinfo.shortInfo.name=colinfo->name;
   collectinfo.shortInfo.host=colinfo->host;
@@ -163,6 +240,7 @@
   // leave ccsCols empty (no cross-coll. searching - for now)
   /*collectinfo.ccsCols=(text_tarray);*/ //not like this!!!
-  collectinfo.languages.push_back("en");
-  collectinfo.languages.push_back("fr");
+  // This info is available from the config file -- johnmcp
+  /*******collectinfo.languages.push_back("en");
+	  collectinfo.languages.push_back("fr");********/
   collectinfo.numDocs=0;
   collectinfo.numWords=0;
@@ -170,18 +248,40 @@
   // copy the text maps over.
   //  collectinfo.collectionmeta; // text_tmap
-  //  delete collectinfo.collectionmeta;
-  collectinfo.collectionmeta=*(here->getMeta());
-  /* collectinfo.format; //text_tmap
-    collectinfo.building; //text_tmap
+  collectinfo.collectionmeta=*((*here)->getMeta());
+  collectinfo.format=*((*here)->getFormat()); //text_tmap
+  /*    collectinfo.building; //text_tmap  */
+
+  ////collectinfo.receptionist="z3950"; 
+  /* for now... this is a url,  relative to .../cgi-bin.
+     NOTE: if this is empty, it defaults to _gwcgi_?a=p&p=about&c=<colname>
   */
-
-collectinfo.receptionist="z3950"; /* for now... this is a url,
-				    relative to .../cgi-bin   */
 }
 
 void z3950proto::get_filterinfo (const text_t &/*collection*/,
-				 InfoFiltersResponse_t &/*response*/,
+				 InfoFiltersResponse_t &response,
 				 comerror_t &/*err*/, ostream &/*logout*/) {
-
+  // we'll fake it here, and say we have set up some filters
+  response.filterNames.insert("BrowseFilter");
+  response.filterNames.insert("QueryFilter");
+  response.filterNames.insert("NullFilter");
+
+}
+
+void z3950proto::get_filteroptions (const text_t &/*collection*/,
+				    const InfoFilterOptionsRequest_t &/*req*/,
+				    InfoFilterOptionsResponse_t &response, 
+				    comerror_t &err, ostream &/*logout*/) {
+  // for now, assume all servers have the same characteristics
+  /*  if (request.filterName=="QueryFilter") { } 
+      else if (request.filterName=="BrowseFilter") { } 
+      else if (request.filterName=="NullFilter") {  } */
+  response.filterOptions["Index"].type=FilterOption_t::stringt;
+  response.filterOptions["Index"].repeatable=FilterOption_t::onePerQuery;
+  response.filterOptions["Index"].defaultValue="any";
+  response.filterOptions["Index"].validValues.push_back(".any");
+  response.filterOptions["Index"].validValues.push_back(".title");
+  response.filterOptions["Index"].validValues.push_back(".author");
+  // and maybe ["Language"] option as well?
+  err=noError;
 }
 
@@ -190,58 +290,287 @@
 			 FilterResponse_t &response,
 			 comerror_t &err, ostream &logout) {
-  // assume this function is only called when creating the title page,
-  // and looking for the metadata regarding icons.
-  response.numDocs=0;
-  response.isApprox=Approximate; // Exact | Approximate | MoreThan
+  // this function is called when:
+  //  *  creating the title page,(looking for iconcoll* & collectname metadata)
+  //  *  creating the about page (looking for "Title" metadata)
+  //  * doing the query - (note that a request for metadata comes first, then
+  // filterOptions = FRmetadata | FROID | FRtermFreq (64+4+1)
+
+  // metadata-only requests have filterName="NullFilter", else "QueryFilter".
+  // For the title page, we should not create a connection to the target
+  // (target means the actual z39.50 server, origin means us), but
+  // for the about page and query pages, we need to get information from the
+  // origin. (eg for the about page, we will print out some info such as ID,
+  // name and version.
+
+  // cerr now goes to errout.txt in etc directory
+  err=noError;
+
+  // get relevant "collection"
+  z3950_server_array::iterator zserver = zservers.begin();
+  z3950_server_array::iterator zend = zservers.end();
+  while (zserver != zend) {
+    if((*zserver)->getName()==collection) {
+      break;
+    }
+    zserver++;
+  }
+  // now have collection in zserver.
+  
+  ColInfoResponse_t info;
+  ResultDocInfo_t *docInfo;
+  
   // leave response.termInfo empty
-  // leave response.docInfo empty
-  /* got the following for first query:
-     request.filterResultOptions=FRmetadata;
-     request.getParents=getParents
-     request.fields=metadata
-     request.docSet (includes OID);
+  // response.termInfo.push_back(""); ??????? (should be empty if not req.)
+
+  // See if this is for a query action
+  if (request.filterName=="QueryFilter") {
+    /* Sample OptionValue pairs
+      `StartResults'=`1'
+      `EndResults'=`20'
+      `Term'=`firstword secondword' (term is just whatever the user typed in)
+      `QueryType'=`ranked' => 'OR' (cgiarg t=1)
+      `QueryType' = `boolean' => 'AND' (cgiarg t=0)
+      `Casefold'=`true'
+      `Stem'=`false'
+      `Maxdocs'=`50'
+     */
+    // go through options
+    text_t opt_term;            // the term(s) that the user entered 
+    text_t opt_fields;          // which fields to search on
+    int opt_start=1, opt_end=20; // default values
+    int nummatches=0, maxdocs=50; // default values
+    OptionValue_tarray::iterator ov_here=request.filterOptions.begin();
+    OptionValue_tarray::iterator ov_end=request.filterOptions.end();
+    while (ov_here != ov_end) {
+      //      cout << "OV pair: `" << ov_here->name.getcstr() << "'=`" 
+      //   << ov_here->value.getcstr() << "'\n";
+      if (ov_here->name=="Term") 
+	{
+	  opt_term=ov_here->value;
+	} else if (ov_here->name=="Index") 
+	  {
+	    opt_fields=ov_here->value;
+	  } else if (ov_here->name=="StartResults") 
+	    {
+	      opt_start=ov_here->value.getint();
+	    } else if (ov_here->name=="EndResults") 
+	      {
+		opt_end=ov_here->value.getint();
+	      } else if (ov_here->name=="Maxdocs") 
+		{
+		  maxdocs=ov_here->value.getint();
+		} 
+      ov_here++;
+    }
+    err=noError;
+    text_tarray *titles=(*zserver)->getrecordTitles(opt_term,
+						    opt_fields,
+						    opt_start, // first to get
+						    opt_end-opt_start, //count
+						    &nummatches,err);
+    if (err!=noError) {
+      // can we return an err msg in a response, or just use
+      // the more drastic Greenstone error mechanism?
+      docInfo=new ResultDocInfo_t;
+      response.docInfo.push_back(*docInfo);
+      docInfo->metadata["Title"].values.push_back("Error - query err?");
+      logout << "\nz3950 filter query: error connecting to server\n";
+      // for now, DON'T use GSDL protocol err.
+      err=noError;
+      return;
+    }
+    // check if (titles==NULL) - only happens on error?
+    if (nummatches>0) {
+      text_tarray::iterator titles_here=titles->begin();
+      text_tarray::iterator titles_end=titles->end();
+      int counter=1;
+      while (titles_here!=titles_end) {
+	docInfo=new ResultDocInfo_t; 
+	docInfo->metadata["Title"].values.push_back(*titles_here);
+	docInfo->result_num=counter;
+	// we need to give some OID, so we'll just use counter for now...
+	// make it the number into the whole possible retrieved set.
+	docInfo->OID=counter+opt_start-1;
+	response.docInfo.push_back(*docInfo);
+	counter++;
+	titles_here++;
+      }
+    }
+
+    if (request.filterResultOptions & FRtermFreq) {
+      if (nummatches>maxdocs) {
+      	response.numDocs=maxdocs; // eg "more than 50" (if Maxdocs==50)
+	response.isApprox=MoreThan;
+      } else {
+	response.numDocs=nummatches; // eg "36 documents"
+	response.isApprox=Exact; // Exact | Approximate | MoreThan
+      }
+    } // end of if (... & FRtermFreq)
+    
+  } // end of if (... & FROID)
+  else {
+    // this wasn't a query action
+
+    if (request.filterOptions.size()>0 &&
+	request.filterOptions[0].name=="ParentNode") {
+      // don't want to return anything
+      return;
+      /*    } else if (request.docSet.size() &&
+	    request.docSet[0]!="collection") {
+	    // documentaction
+	    // if docSet is not empty, it is either "collection", or an array
+	    // of OIDs 
+	    docInfo=new ResultDocInfo_t;
+	    response.docInfo.push_back(*docInfo);
+      */
+    } else {
+      // in case we need to return only metadata
+      docInfo=new ResultDocInfo_t;
+      response.docInfo.push_back(*docInfo); 
+    }
+  }
+
+  // Fill in metadata for each response.docInfo (if wanted)
+  if (request.filterResultOptions & FRmetadata) {
+    get_collectinfo (collection, info, err, logout);
+    // should check err returned here....
+
+    // get the Query out of the filterOptions.
+    text_t query="";
+    text_t field="";
+    OptionValue_tarray::iterator opt_here=request.filterOptions.begin();
+    OptionValue_tarray::iterator opt_end=request.filterOptions.end();
+    while (opt_here!=opt_end) {
+      if (opt_here->name=="Query") {
+	query=opt_here->value;
+	if (field!="") break; // break from loop if we've got both
+      } else if (opt_here->name=="Index") {
+	field=opt_here->value;
+	if (query!="") break; // break from loop if we've got both
+      }
+      opt_here++;
+    }
+
+    if (!request.fields.empty()) {
+      // loop on each document being returned
+      ResultDocInfo_tarray::iterator docs_here=response.docInfo.begin();
+      ResultDocInfo_tarray::iterator docs_end=response.docInfo.end();
+      while (docs_here!=docs_end) {
+	
+	// loop on all the metadata fields in request.fields (type text_tset)
+	text_tset::iterator fields_here=request.fields.begin();
+	text_tset::iterator fields_end=request.fields.end();
+	text_tmap::iterator it;
+	while (fields_here!=fields_end) {
+	  it=info.collectionmeta.find(*fields_here);
+	  ////////// cerr << "filter: getting " << (*fields_here).getcstr();
+	  if (it!=info.collectionmeta.end())
+	    docs_here->metadata[*fields_here].values.push_back((*it).second);
+	  else if (*fields_here=="Title" && !request.docSet.empty()) { 
+	    // We only do this for a document action.
+	    // (This comes through as a NullQuery).
+	    // hopefully docSet is only not empty for documentaction...
+	    text_t doctitle;
+	    int i;
+	    // check that docSet isn't empty first!!!!!!
+	    i=request.docSet[0].getint();
+	    text_t doctext="unneeded";
+	    (*zserver)->getfullrecord(query, field, i, doctitle, doctext, err);
+	    // check err value!
+	    docs_here->metadata["Title"].values.push_back(doctitle);	    
+	  } else {
+	    docs_here->metadata[*fields_here].values.push_back("");
+	    /////// cerr << " (not found)";
+	  }
+	  ////////cerr << "\n";
+	  fields_here++;
+	} // end of inner while loop
+	docs_here++;
+      } // end of outer while loop
+    } // end of if (!request.fields.empty())
+
+    else { // request.fields empty: return all metadata for about page or query
+      // we'll only put it in the first docInfo.
+      text_tmap::iterator colmeta_here=info.collectionmeta.begin();
+      text_tmap::iterator colmeta_end=info.collectionmeta.end();
+      while (colmeta_here!=colmeta_end) {
+	response.docInfo[0].metadata[(*colmeta_here).first].
+	  values.push_back((*colmeta_here).second);
+	/////cerr << "\t" << (*colmeta_here).first.getcstr() << "\n";
+	colmeta_here++;
+      }
+
+      // check if "collectionextra" metadata is set. If it isn't, we should
+      // create connection to target to get it.
+      if (info.collectionmeta.find("collectionextra")==colmeta_end) {
+	// it hasn't been set yet...
+	text_t abouttext="<B>Server Online</B><br>\n";
+	abouttext+=(*zserver)->getzAbout();
+	// add in the "About" text we read in from config file.
+	// how do we incorporate multi-lingual metadata?
+	abouttext+="<P>\n";
+	text_t tmpabout;
+
+	if ((*zserver)->getcfgAbout("en", tmpabout)==true)
+	  abouttext+=tmpabout;
+
+	(*zserver)->setMeta("collectionextra",abouttext);
+	response.docInfo[0].metadata["collectionextra"].values.push_back(abouttext);
+      }
+    } // end of else
+
+    // do indices' names, regardless of whether asked for or not...
+    if (!response.docInfo.empty()) {
+     response.docInfo[0].metadata[".author"].values.push_back("author fields");
+      response.docInfo[0].metadata[".title"].values.push_back("title fields");
+      response.docInfo[0].metadata[".any"].values.push_back("any fields");
+    }
+  } //end of  if (... & FRmetadata) ...
+}
+
+
+
+void z3950proto::get_document (const text_t &collection,
+			       const DocumentRequest_t &request,
+			       DocumentResponse_t &response,
+			       comerror_t &err, ostream &logout) {
+
+  err=noError;
+
+  // get relevant "collection"
+  z3950_server_array::iterator zserver = zservers.begin();
+  z3950_server_array::iterator zend = zservers.end();
+  while (zserver != zend) {
+    if((*zserver)->getName()==collection) {
+      break;
+    }
+    zserver++;
+  }
+  // now have collection in zserver.
+
+  /*  cout << "get document:\n\tOID: " << request.OID.getcstr()
+      << "\n\tdocType: " << request.docType.getcstr()
+      << "\n\tdocFormat: " << request.docFormat.getcstr() <<"\n";
   */
-  // fill in the metadata for each of the OIDs (if it is requested)
-  if (request.filterResultOptions & FRmetadata) {
-    // request.fields // type text_tset
-    // docInfo is type ResultDocInfo_tarray
-    ColInfoResponse_t *info = new ColInfoResponse_t;
-    get_collectinfo (collection, *info, err, logout);
-    // should check err returned here....
-
-    ResultDocInfo_t *docInfo=new ResultDocInfo_t;
-    
-    text_tmap::iterator it=info->collectionmeta.find("collectionname");
-    // cerr now goes to errout.txt in etc directory
-    // "(*it).first" is key, "(*it).second" is value(s).
-    if (it!=info->collectionmeta.end()) 
-      docInfo->metadata["collectionname"].values.push_back((*it).second);
-    else // needs to exist, but be empty
-      docInfo->metadata["collectionname"].values.push_back("");
-
-    it=info->collectionmeta.find("iconcollection");
-    if (it!=info->collectionmeta.end()) 
-      docInfo->metadata["iconcollection"].values.push_back((*it).second);
-    else // needs to exist, but be empty
-      docInfo->metadata["iconcollection"].values.push_back("");
-
-    it=info->collectionmeta.find("iconcollectionsmall");
-    if (it!=info->collectionmeta.end()) 
-      docInfo->metadata["iconcollectionsmall"].values.push_back((*it).second);
-    else // needs to exist, but be empty
-      docInfo->metadata["iconcollectionsmall"].values.push_back("");
-    
-
-    response.docInfo.push_back(*docInfo);
-  }
-
-  err=noError;
-}
-
-void z3950proto::get_document (const text_t &/*collection*/,
-			       const DocumentRequest_t &/*request*/,
-			       DocumentResponse_t &/*response*/,
-			       comerror_t &err, ostream &logout) {
-
+
+  /* docresponse consists of
+     text_t response.doc */
+  text_t title="unneeded";
+  text_t doctext;
+  text_t query; // this should not be needed, as we have already connected to 
+  // get the  title....
+  text_t field; // ditto...
+  (*zserver)->getfullrecord(query,field,request.OID.getint(),
+			    title,doctext,err);
+  // check return value of above? (false=>not connected) 
+  if (err==noError)
+    response.doc=doctext;
+  else {
+    // could print out different messages based on error type....
+    response.doc="<h2>Error</h2>There was an error while connecting to the ";
+    response.doc+="z39.50 server (ie target). Most likely this was a \n";
+    response.doc+="\"Connection Refused\" error.\n";
+
+  }
   if (0) {
     err=protocolError;
@@ -249,5 +578,2 @@
   }
 }
-
-
-#endif
Index: /trunk/gsdl/src/recpt/z3950proto.h
===================================================================
--- /trunk/gsdl/src/recpt/z3950proto.h	(revision 1346)
+++ /trunk/gsdl/src/recpt/z3950proto.h	(revision 1347)
@@ -28,62 +28,5 @@
 
 #include "recptproto.h"
-
-// each server can have one or more databases
-/*
-  class z3950_DB {
-  protected:
-  text_t name; // Descriptive name
-  text_t database; // name for server
-  
-  public:
-  z3950_DB();     // constructor
-  ~z3950_DB();    // deconstructor
-  const text_t getName() {return name;}                // this gets name
-  void setName(text_t newName) {name=newName;} // this sets name
-  // need to get next (for linked list)
-  };
-  
-
-  typedef  vector<z3950_DB>  z3950_DB_array;
-*/
-
-/*class z3950_DB_Array {
-  protected:
-  int count;
-  // some arraytype...
-  public:
-  z3950_DB first();
-  z3950_DB last();
-  void     add(z3950_DB *db);
-  void     remove(z3950_DB *db);
-  };
-*/
-
-
-class z3950_server {
- protected:
-  text_t title;    // Descriptive name
-  text_t hostname; // network name (IP or host+domain name)
-  text_tmap meta;  // metadata for this collection (ie server/database pair)
-  // this is currently only iconcollection (and iconcollectionsmall)
-  int count;
-  //  z3950_DB_array* db;
-  ShortColInfo_t *info; // has  (database) name, host and port
-
- public:
-  z3950_server();
-  // z3950_DB_array getDBs();
-  const text_t getName() {return title;}
-  void setName(const text_t &newname) {title=newname;}
-  //  void setHostname(const text_t &newname) {hostname=newname;}
-  void setInfo(ShortColInfo_t *newinfo) {info=newinfo;}
-  const ShortColInfo_t *getInfo() {return info;}
-  const text_tmap *getMeta() {return &meta;}
-};
-
-typedef  vector<z3950_server>  z3950_server_array;
-
-
-
+#include "z3950server.h"
 
 class z3950proto : public recptproto {
@@ -93,12 +36,15 @@
 public:
   z3950proto();
-  virtual ~z3950proto() {}
+  virtual ~z3950proto();
 
+  int getServerCount() { return zserver_count;}
   /*
   void add_collectserver (collectserver *thecserver) 
         {cservers.addcollectserver(thecserver);}
   */
+  
+  void add_server(z3950_server& zserver);
 
-  void add_server(const z3950_server& zserver);
+  void read_config_file(const text_t &filename);
 
   void configure (const text_t &key, const text_tarray &cfgline);
@@ -128,4 +74,9 @@
       FilterResponse_t &response, ostream &logout);
   */
+
+  void get_filteroptions (const text_t &collection,
+                          const InfoFilterOptionsRequest_t &request,
+                          InfoFilterOptionsResponse_t &response, 
+                          comerror_t &err, ostream &logout);
   
   void filter (const text_t &collection,
@@ -141,4 +92,3 @@
 };
 
-
 #endif
Index: /trunk/gsdl/src/recpt/z3950server.cpp
===================================================================
--- /trunk/gsdl/src/recpt/z3950server.cpp	(revision 1347)
+++ /trunk/gsdl/src/recpt/z3950server.cpp	(revision 1347)
@@ -0,0 +1,271 @@
+#include "z3950server.h"
+#include "comtypes.h"
+#include <stdio.h>
+// z39.50 yaz stuff
+
+extern "C" {
+#include "yaz/client/yaz_zclient.h"
+}
+
+/*** 
+     each z39.50 server+database pair is a GSDL collection.
+***/
+
+z3950_server::z3950_server() {
+  info=NULL;
+  connected=false;
+  titles=NULL;
+  // for now, assume that all records will have text associated with them.
+  meta["hastxt"]="1";
+  // for now, assume we don't want ANY DocumentButtons.
+  format["DocumentButtons"]="";
+}
+
+z3950_server::~z3950_server() {
+}
+
+void z3950_server::setMeta(const text_t &key, const text_t &value) {
+  meta[key]=value;
+}
+
+void z3950_server::setName(const text_t &newname) {
+  title=newname;
+  meta["collectionname"]=newname;
+}
+
+void z3950_server::addcfgAbout(const text_t &lang, const text_t &abouttext) {
+    about[lang]=abouttext;
+}
+
+bool z3950_server::getcfgAbout(const text_t &lang, text_t &abouttxt) {
+  text_tmap::iterator it;
+  it=about.find(lang);
+  if (it==about.end()) return (false);
+  abouttxt=((*it).second);
+  return (true);
+}
+
+
+// now functions that actually talk over the tcp connection.
+
+// create a tcp connection to the associated target. Currently, this will
+// re-initialise if we are already connected.
+bool z3950_server::connect() {
+  text_t server_and_port;
+  char *zserverinfo;
+
+  server_and_port=info->host+":"+info->port;
+  // remember that info.name is the database name
+
+  z_initialize();
+
+  if (z_cmd_open(server_and_port.getcstr(),info->name.getcstr())==1)
+    // we got a connection error
+    return false;
+
+  // get initialisation response.
+  z_getnextAPDU();
+  zserverinfo=z_get_initResponse();
+  if (zserverinfo!=NULL) {
+    z_initstr.appendcstr(zserverinfo);
+  }
+  free(zserverinfo);
+
+  connected=true;
+  return true;
+}
+
+void z3950_server::parseQuery(const text_t &query, 
+			      const text_t &fields,
+			      text_t &parsed_query) {
+  /****** FIXME *****/
+  // We need to format the query string into RPN - 
+  // by just passing it like this, it will only work for simple queries.
+  // This will require us to actually come up with a query syntax and 
+  // a parser. For now, we'll just do an "AND" query for all terms
+
+  // we need to count number of terms separated by a space
+  char *ptr=query.getcstr();
+  int strlength=strlen(ptr);
+  bool inword=false;
+  int num_terms=0;
+  for (int i=0;i<strlength;i++) {
+    if (*(ptr+i)!=' ') {
+      if (inword==false) {
+	inword=true;
+	num_terms++;
+      }
+    }
+    else { // ptr+i is a space
+      inword=false;
+      }
+  }
+  
+  // set the field(s) to search on - main ones (that I've found) include:
+  //  1016  => Any
+  //  1     => (Personal) Name
+  //  4     => Title
+  //  21    => Subject Heading
+  //  45    => Subject precis
+  // Note I have no idea how these actually work - I think some servers
+  // only have limited fields, and map all subject-type requests into that
+  // subject field, etc.
+
+  parsed_query="@attr 1=";
+  if (fields==".author")
+    parsed_query+="1 ";
+  else if (fields==".title")
+    parsed_query+="4 ";
+  else // fields==".any"
+    parsed_query+="1016 ";
+
+  // append "@and" for each term after the first
+  for (int i=1;i<num_terms;i++)
+    parsed_query+="@and ";
+  // append the actual query
+  parsed_query+=query;
+
+}
+
+text_tarray *z3950_server::getrecordTitles(const text_t &query, 
+					   const text_t &fields,
+					   int first, int count,
+					   int *nummatches, comerror_t &err) {
+  char **c_str_titles;
+  int i;
+  int last;
+  if (titles!=NULL) delete (titles);
+  titles=new text_tarray;
+
+  /* check if connected */
+  if (connected==false) 
+    if (connect()==false) {
+      // we could not connect.
+      err=protocolError;
+      return (NULL);
+    }
+  
+
+  text_t expanded_query="";
+  parseQuery(query,fields,expanded_query);
+
+  // following functions defined in yaz_zclient.c
+  *nummatches=z_cmd_dosearch(expanded_query.getcstr()); // returns # found, -1 on err.
+  if (*nummatches<=0) {
+    if (*nummatches==0) {
+      // no matches
+      return (NULL);
+    } else  if (*nummatches==-1) {
+      // prefix query error
+      err=protocolError;
+      return (NULL);
+    }  else if (*nummatches==-2) {
+      // sendsearchRequest not answered by searchResponse
+      err=protocolError;
+      return (NULL);
+    }
+  }
+  // could do a sort eventually, eg on date, title, etc.
+  // (non-existent function)    z_sort(field, asc|desc);
+  /* min of (count, first + (*nummatches) ) */
+  // z_getrecordTitles ( first, howmany )
+  c_str_titles=z_getrecordTitles(first,min(count,*nummatches-first+1));
+  if (c_str_titles==NULL) {
+    // an error occurred. we need a logout/err as an arg
+    return (NULL);
+  }
+  if (c_str_titles[0]==0) {
+    // no matches.
+    return (NULL);
+  }
+  last=(int)c_str_titles[0];
+  for (i=1;i<=last;i++) {
+    titles->push_back(c_str_titles[i]);
+    free(c_str_titles[i]);
+  }
+  free(c_str_titles);
+  return (titles);
+  
+}
+
+bool z3950_server::getfullrecord(const text_t &query, const text_t &fields,
+				 const int ID, 
+				 text_t &rettitle, 
+				 text_t &rettext, comerror_t &err) {
+  if (connected==false) {
+    if (connect()==false) {
+      // error connecting...
+      err=protocolError;
+      return (false);
+    }
+    // since we have just re-connected, we need to do the
+    // query again.
+
+    text_t expanded_query="";
+    parseQuery(query,fields,expanded_query);
+
+    int returned=z_cmd_dosearch(expanded_query.getcstr());
+    if (returned<=0) {
+      // 0 => none.
+      // <0 => error
+      err=protocolError;
+      return (false);
+    }
+  }
+
+  if (rettitle!="unneeded") {
+    char **c_str_titles;
+    //int dummy;
+    c_str_titles=z_getrecordTitles(ID,1); // check this return value.
+    if (c_str_titles!=NULL && (int)c_str_titles[0]==1) {
+      rettitle.setcstr(c_str_titles[1]); // and check this 
+      free (c_str_titles);
+      // rettitle="Dummy Title";
+    } else {
+      // we didn't get something....
+      rettitle="Nothing Returned...";
+    }
+  }
+
+  if (rettext!="unneeded") {
+    // get the text
+    rettext.setcstr(z_getfullRecord(ID));
+  }
+  return (true);
+  }
+
+text_t &z3950_server::getzAbout() {
+  text_t zserverresp;
+
+  // Assume we have not yet connected, so that must be done here.
+  if (connected==true)
+    return (z_initstr);
+  
+  // we need to create the tcp connection to the target (server)  
+  //  z_initstr=new text_t;
+  
+  if (connect()==false) {
+    z_initstr.setcstr("<H2>Server offline</H2>Error - could not connect to server <B>");
+    z_initstr += info->host.getcstr();
+    z_initstr += "</B> on port ";
+    z_initstr += info->port;
+    z_initstr += "\n";
+    return (z_initstr);
+  }
+  
+  // z_initstr currently contains the target's response. We want to
+  // PREPEND the following information.
+  zserverresp=z_initstr;
+  z_initstr="Internet server: <b>";
+  z_initstr+=info->host;
+  z_initstr+="</b> on port ";
+  z_initstr+=info->port;
+  z_initstr+=".<br>\n";
+  z_initstr+=zserverresp;
+
+  // should close /******* WHAT IF DOING A QUERY!??!?!? ********/
+  // z_cmd_close(0);
+  // connected=false;
+  return (z_initstr);
+}
+
Index: /trunk/gsdl/src/recpt/z3950server.h
===================================================================
--- /trunk/gsdl/src/recpt/z3950server.h	(revision 1347)
+++ /trunk/gsdl/src/recpt/z3950server.h	(revision 1347)
@@ -0,0 +1,49 @@
+#ifndef Z3950SERVER_H
+#define Z3050SERVER_H
+
+#include "comtypes.h"
+
+// each "server" (ie collection) consists of a {z39.50 server + database} pair.
+class z3950_server {
+ protected:
+  text_t title;    // Descriptive name
+  text_t z_initstr; // a string returned when the connection is initialised.
+  text_tmap meta;  // metadata for this collection (ie server/database pair)
+  text_tmap format;
+  text_tmap about; // langauge/abouttext pair for collection.
+  ShortColInfo_t *info; // has  (database) name, host and port
+  text_tarray *titles; 
+  bool connect();
+  bool connected; // tcp connection to the z39.50 server (target)
+
+ public:
+  z3950_server();
+  ~z3950_server();
+  void setName(const text_t &newname);
+  const text_t getName() {return title;}
+  void setMeta(const text_t &key, const text_t &value);
+  const text_tmap *getMeta() {return &meta;}
+  const text_tmap *getFormat() {return &format;}
+  void setInfo(ShortColInfo_t *newinfo) {info=newinfo;}
+  const ShortColInfo_t *getInfo() {return info;}
+  void addcfgAbout(const text_t &lang, const text_t &abouttext);
+  bool getcfgAbout(const text_t &lang, text_t &abouttext);
+  // now the functions that actually talk to the target (ie zserver) over tcp
+  text_t &getzAbout(); // gets any name, id, MOTD, etc from server.
+  text_tarray *getrecordTitles(const text_t &query,
+			       const text_t &fields,
+			       const int first, const int count,
+			       int *nummatches, comerror_t &err);
+  /* only get one record at a time? (Eventually we could buffer them, but
+     for now... */
+  bool getfullrecord(const text_t &query, const text_t &fields,
+		     const int ID, text_t &rettitle, 
+		     text_t &rettext,comerror_t &err);
+ private:
+  void parseQuery(const text_t &query, const text_t &fields, 
+		  text_t &parsed_query);
+};
+
+typedef  vector<z3950_server *>  z3950_server_array;
+
+#endif
Index: /trunk/gsdl/src/recpt/zparse.tab.c
===================================================================
--- /trunk/gsdl/src/recpt/zparse.tab.c	(revision 1347)
+++ /trunk/gsdl/src/recpt/zparse.tab.c	(revision 1347)
@@ -0,0 +1,1195 @@
+
+/*  A Bison parser, made from zparse.y
+ by  GNU Bison version 1.27
+  */
+
+#define YYBISON 1  /* Identify Bison output.  */
+
+#define	GSDLVERSION	257
+#define	GENERAL_SECTION	258
+#define	SEARCH_SECTION	259
+#define	BROWSE_SECTION	260
+#define	MACROS_SECTION	261
+#define	MAINTAINER	262
+#define	PUBLIC	263
+#define	TRUE	264
+#define	FALSE	265
+#define	LANGUAGES	266
+#define	EN	267
+#define	FR	268
+#define	MI	269
+#define	ZH	270
+#define	DE	271
+#define	NAME	272
+#define	STRING	273
+#define	ICON	274
+#define	SMALLICON	275
+#define	ABOUT	276
+#define	SEARCHTEXT	277
+#define	DOCUMENT	278
+#define	SECTION	279
+#define	BROWSE	280
+#define	TYPE	281
+#define	FORMAT	282
+#define	LIST	283
+#define	SORTEDLIST	284
+#define	SECTIONLIST	285
+#define	SORTEDSECTIONLIST	286
+#define	DATELIST	287
+#define	ICONLINK	288
+#define	TEXTLINK	289
+#define	DOCUMENTIMAGES	290
+#define	DOCUMENTHEADER	291
+#define	DOCUMENTTEXT	292
+#define	DOCUMENTBUTTONS	293
+#define	DOCUMENTARROWSBOTTOM	294
+#define	DATA	295
+
+#line 3 "zparse.y"
+
+  /* verbatim C code - functions, etc */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include "z3950cfg.h"
+
+#define YYDEBUG 1
+#define YYERROR_VERBOSE 1
+/* can't use default yyparse(), as this name is used elsewhere (eg mg)*/
+#define yyin    zconfigin
+#define yyparse zconfigparse
+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 */
+extern struct z3950cfg *zservers_cfg_file;
+
+int yylex(void);
+
+int yyerror(char *string);
+
+void errormsg(char *str);
+
+
+#line 37 "zparse.y"
+typedef union {
+  char *string;
+  struct z3950cfg *cfg;
+  struct z3950aboutlist *about;
+  int number;
+} YYSTYPE;
+#include <stdio.h>
+
+#ifndef __cplusplus
+#ifndef __STDC__
+#define const
+#endif
+#endif
+
+
+
+#define	YYFINAL		37
+#define	YYFLAG		-32768
+#define	YYNTBASE	44
+
+#define YYTRANSLATE(x) ((unsigned)(x) <= 295 ? yytranslate[x] : 56)
+
+static const char yytranslate[] = {     0,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,    42,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,    43,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     1,     3,     4,     5,     6,
+     7,     8,     9,    10,    11,    12,    13,    14,    15,    16,
+    17,    18,    19,    20,    21,    22,    23,    24,    25,    26,
+    27,    28,    29,    30,    31,    32,    33,    34,    35,    36,
+    37,    38,    39,    40,    41
+};
+
+#if YYDEBUG != 0
+static const short yyprhs[] = {     0,
+     0,     3,     5,     6,     9,    11,    20,    22,    24,    25,
+    28,    29,    32,    35,    36,    39,    42,    43,    45,    46,
+    48,    51,    55,    58,    62,    64,    66,    69,    70,    73
+};
+
+static const short yyrhs[] = {    45,
+    46,     0,     3,     0,     0,    46,    47,     0,    47,     0,
+    41,    41,    49,    41,    48,    50,    51,    52,     0,     1,
+     0,    19,     0,     0,    42,    41,     0,     0,    20,    19,
+     0,    20,    41,     0,     0,    21,    19,     0,    21,    41,
+     0,     0,    53,     0,     0,    54,     0,    53,    54,     0,
+    22,    55,    19,     0,    22,    19,     0,    41,    43,    41,
+     0,    41,     0,     1,     0,    37,    19,     0,     0,    38,
+    19,     0,     0
+};
+
+#endif
+
+#if YYDEBUG != 0
+static const short yyrline[] = { 0,
+    82,    85,    86,    88,    89,    91,   108,   111,   112,   117,
+   118,   121,   122,   125,   126,   127,   132,   134,   135,   137,
+   139,   142,   153,   175,   183,   191,   193,   194,   196,   197
+};
+#endif
+
+
+#if YYDEBUG != 0 || defined (YYERROR_VERBOSE)
+
+static const char * const yytname[] = {   "$","error","$undefined.","GSDLVERSION",
+"GENERAL_SECTION","SEARCH_SECTION","BROWSE_SECTION","MACROS_SECTION","MAINTAINER",
+"PUBLIC","TRUE","FALSE","LANGUAGES","EN","FR","MI","ZH","DE","NAME","STRING",
+"ICON","SMALLICON","ABOUT","SEARCHTEXT","DOCUMENT","SECTION","BROWSE","TYPE",
+"FORMAT","LIST","SORTEDLIST","SECTIONLIST","SORTEDSECTIONLIST","DATELIST","ICONLINK",
+"TEXTLINK","DOCUMENTIMAGES","DOCUMENTHEADER","DOCUMENTTEXT","DOCUMENTBUTTONS",
+"DOCUMENTARROWSBOTTOM","DATA","':'","'_'","z3950","version","zserverlist","zserver",
+"name","port","icon","smallicon","about","aboutList","aboutLang","lang", NULL
+};
+#endif
+
+static const short yyr1[] = {     0,
+    44,    45,    45,    46,    46,    47,    47,    48,    48,    49,
+    49,    50,    50,    50,    51,    51,    51,    52,    52,    53,
+    53,    54,    54,    55,    55,    55,    -1,    -1,    -1,    -1
+};
+
+static const short yyr2[] = {     0,
+     2,     1,     0,     2,     1,     8,     1,     1,     0,     2,
+     0,     2,     2,     0,     2,     2,     0,     1,     0,     1,
+     2,     3,     2,     3,     1,     1,     2,     0,     2,     0
+};
+
+static const short yydefact[] = {     3,
+     2,     0,     7,     0,     0,     5,    11,     4,     0,     0,
+    10,     9,     8,    14,     0,    17,    12,    13,     0,    19,
+    15,    16,     0,     6,    18,    20,    26,    23,    25,     0,
+    21,     0,    22,    24,     0,     0,     0
+};
+
+static const short yydefgoto[] = {    35,
+     2,     5,     6,    14,    10,    16,    20,    24,    25,    26,
+    30
+};
+
+static const short yypact[] = {     3,
+-32768,     2,-32768,   -34,     0,-32768,   -33,-32768,   -31,   -30,
+-32768,   -11,-32768,    -8,   -15,    -7,-32768,-32768,   -14,    -9,
+-32768,-32768,     1,-32768,    -9,-32768,-32768,-32768,   -28,    -3,
+-32768,   -24,-32768,-32768,    18,    19,-32768
+};
+
+static const short yypgoto[] = {-32768,
+-32768,-32768,    16,-32768,-32768,-32768,-32768,-32768,-32768,    -2,
+-32768
+};
+
+
+#define	YYLAST		43
+
+
+static const short yytable[] = {    -1,
+     3,    27,     3,    17,    21,     1,     7,    13,     9,    11,
+    12,    15,    23,    19,    32,    33,    34,    36,    37,    28,
+     8,     0,    31,     0,     0,    18,    22,     0,     0,     0,
+     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+     4,    29,     4
+};
+
+static const short yycheck[] = {     0,
+     1,     1,     1,    19,    19,     3,    41,    19,    42,    41,
+    41,    20,    22,    21,    43,    19,    41,     0,     0,    19,
+     5,    -1,    25,    -1,    -1,    41,    41,    -1,    -1,    -1,
+    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+    41,    41,    41
+};
+/* -*-C-*-  Note some compilers choke on comments on `#line' lines.  */
+#line 3 "/usr/share/bison.simple"
+/* This file comes from bison-1.27.  */
+
+/* Skeleton output parser for bison,
+   Copyright (C) 1984, 1989, 1990 Free Software Foundation, Inc.
+
+   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, 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., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+/* As a special exception, when this file is copied by Bison into a
+   Bison output file, you may use that output file without restriction.
+   This special exception was added by the Free Software Foundation
+   in version 1.24 of Bison.  */
+
+/* This is the parser code that is written into each bison parser
+  when the %semantic_parser declaration is not specified in the grammar.
+  It was written by Richard Stallman by simplifying the hairy parser
+  used when %semantic_parser is specified.  */
+
+#ifndef YYSTACK_USE_ALLOCA
+#ifdef alloca
+#define YYSTACK_USE_ALLOCA
+#else /* alloca not defined */
+#ifdef __GNUC__
+#define YYSTACK_USE_ALLOCA
+#define alloca __builtin_alloca
+#else /* not GNU C.  */
+#if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) || defined (__sparc) || defined (__sgi) || (defined (__sun) && defined (__i386))
+#define YYSTACK_USE_ALLOCA
+#include <alloca.h>
+#else /* not sparc */
+/* We think this test detects Watcom and Microsoft C.  */
+/* This used to test MSDOS, but that is a bad idea
+   since that symbol is in the user namespace.  */
+#if (defined (_MSDOS) || defined (_MSDOS_)) && !defined (__TURBOC__)
+#if 0 /* No need for malloc.h, which pollutes the namespace;
+	 instead, just don't use alloca.  */
+#include <malloc.h>
+#endif
+#else /* not MSDOS, or __TURBOC__ */
+#if defined(_AIX)
+/* I don't know what this was needed for, but it pollutes the namespace.
+   So I turned it off.   rms, 2 May 1997.  */
+/* #include <malloc.h>  */
+ #pragma alloca
+#define YYSTACK_USE_ALLOCA
+#else /* not MSDOS, or __TURBOC__, or _AIX */
+#if 0
+#ifdef __hpux /* haible@ilog.fr says this works for HPUX 9.05 and up,
+		 and on HPUX 10.  Eventually we can turn this on.  */
+#define YYSTACK_USE_ALLOCA
+#define alloca __builtin_alloca
+#endif /* __hpux */
+#endif
+#endif /* not _AIX */
+#endif /* not MSDOS, or __TURBOC__ */
+#endif /* not sparc */
+#endif /* not GNU C */
+#endif /* alloca not defined */
+#endif /* YYSTACK_USE_ALLOCA not defined */
+
+#ifdef YYSTACK_USE_ALLOCA
+#define YYSTACK_ALLOC alloca
+#else
+#define YYSTACK_ALLOC malloc
+#endif
+
+/* Note: there must be only one dollar sign in this file.
+   It is replaced by the list of actions, each action
+   as one case of the switch.  */
+
+#define yyerrok		(yyerrstatus = 0)
+#define yyclearin	(yychar = YYEMPTY)
+#define YYEMPTY		-2
+#define YYEOF		0
+#define YYACCEPT	goto yyacceptlab
+#define YYABORT 	goto yyabortlab
+#define YYERROR		goto yyerrlab1
+/* Like YYERROR except do call yyerror.
+   This remains here temporarily to ease the
+   transition to the new meaning of YYERROR, for GCC.
+   Once GCC version 2 has supplanted version 1, this can go.  */
+#define YYFAIL		goto yyerrlab
+#define YYRECOVERING()  (!!yyerrstatus)
+#define YYBACKUP(token, value) \
+do								\
+  if (yychar == YYEMPTY && yylen == 1)				\
+    { yychar = (token), yylval = (value);			\
+      yychar1 = YYTRANSLATE (yychar);				\
+      YYPOPSTACK;						\
+      goto yybackup;						\
+    }								\
+  else								\
+    { yyerror ("syntax error: cannot back up"); YYERROR; }	\
+while (0)
+
+#define YYTERROR	1
+#define YYERRCODE	256
+
+#ifndef YYPURE
+#define YYLEX		yylex()
+#endif
+
+#ifdef YYPURE
+#ifdef YYLSP_NEEDED
+#ifdef YYLEX_PARAM
+#define YYLEX		yylex(&yylval, &yylloc, YYLEX_PARAM)
+#else
+#define YYLEX		yylex(&yylval, &yylloc)
+#endif
+#else /* not YYLSP_NEEDED */
+#ifdef YYLEX_PARAM
+#define YYLEX		yylex(&yylval, YYLEX_PARAM)
+#else
+#define YYLEX		yylex(&yylval)
+#endif
+#endif /* not YYLSP_NEEDED */
+#endif
+
+/* If nonreentrant, generate the variables here */
+
+#ifndef YYPURE
+
+int	yychar;			/*  the lookahead symbol		*/
+YYSTYPE	yylval;			/*  the semantic value of the		*/
+				/*  lookahead symbol			*/
+
+#ifdef YYLSP_NEEDED
+YYLTYPE yylloc;			/*  location data for the lookahead	*/
+				/*  symbol				*/
+#endif
+
+int yynerrs;			/*  number of parse errors so far       */
+#endif  /* not YYPURE */
+
+#if YYDEBUG != 0
+int yydebug;			/*  nonzero means print parse trace	*/
+/* Since this is uninitialized, it does not stop multiple parsers
+   from coexisting.  */
+#endif
+
+/*  YYINITDEPTH indicates the initial size of the parser's stacks	*/
+
+#ifndef	YYINITDEPTH
+#define YYINITDEPTH 200
+#endif
+
+/*  YYMAXDEPTH is the maximum size the stacks can grow to
+    (effective only if the built-in stack extension method is used).  */
+
+#if YYMAXDEPTH == 0
+#undef YYMAXDEPTH
+#endif
+
+#ifndef YYMAXDEPTH
+#define YYMAXDEPTH 10000
+#endif
+
+
+/* Define __yy_memcpy.  Note that the size argument
+   should be passed with type unsigned int, because that is what the non-GCC
+   definitions require.  With GCC, __builtin_memcpy takes an arg
+   of type size_t, but it can handle unsigned int.  */
+
+#if __GNUC__ > 1		/* GNU C and GNU C++ define this.  */
+#define __yy_memcpy(TO,FROM,COUNT)	__builtin_memcpy(TO,FROM,COUNT)
+#else				/* not GNU C or C++ */
+#ifndef __cplusplus
+
+/* This is the most reliable way to avoid incompatibilities
+   in available built-in functions on various systems.  */
+static void
+__yy_memcpy (to, from, count)
+     char *to;
+     char *from;
+     unsigned int count;
+{
+  register char *f = from;
+  register char *t = to;
+  register int i = count;
+
+  while (i-- > 0)
+    *t++ = *f++;
+}
+
+#else /* __cplusplus */
+
+/* This is the most reliable way to avoid incompatibilities
+   in available built-in functions on various systems.  */
+static void
+__yy_memcpy (char *to, char *from, unsigned int count)
+{
+  register char *t = to;
+  register char *f = from;
+  register int i = count;
+
+  while (i-- > 0)
+    *t++ = *f++;
+}
+
+#endif
+#endif
+
+
+#line 216 "/usr/share/bison.simple"
+
+/* The user can define YYPARSE_PARAM as the name of an argument to be passed
+   into yyparse.  The argument should have type void *.
+   It should actually point to an object.
+   Grammar actions can access the variable by casting it
+   to the proper pointer type.  */
+
+#ifdef YYPARSE_PARAM
+#ifdef __cplusplus
+#define YYPARSE_PARAM_ARG void *YYPARSE_PARAM
+#define YYPARSE_PARAM_DECL
+#else /* not __cplusplus */
+#define YYPARSE_PARAM_ARG YYPARSE_PARAM
+#define YYPARSE_PARAM_DECL void *YYPARSE_PARAM;
+#endif /* not __cplusplus */
+#else /* not YYPARSE_PARAM */
+#define YYPARSE_PARAM_ARG
+#define YYPARSE_PARAM_DECL
+#endif /* not YYPARSE_PARAM */
+
+/* Prevent warning if -Wstrict-prototypes.  */
+#ifdef __GNUC__
+#ifdef YYPARSE_PARAM
+int yyparse (void *);
+#else
+int yyparse (void);
+#endif
+#endif
+
+int
+yyparse(YYPARSE_PARAM_ARG)
+     YYPARSE_PARAM_DECL
+{
+  register int yystate;
+  register int yyn;
+  register short *yyssp;
+  register YYSTYPE *yyvsp;
+  int yyerrstatus;	/*  number of tokens to shift before error messages enabled */
+  int yychar1 = 0;		/*  lookahead token as an internal (translated) token number */
+
+  short	yyssa[YYINITDEPTH];	/*  the state stack			*/
+  YYSTYPE yyvsa[YYINITDEPTH];	/*  the semantic value stack		*/
+
+  short *yyss = yyssa;		/*  refer to the stacks thru separate pointers */
+  YYSTYPE *yyvs = yyvsa;	/*  to allow yyoverflow to reallocate them elsewhere */
+
+#ifdef YYLSP_NEEDED
+  YYLTYPE yylsa[YYINITDEPTH];	/*  the location stack			*/
+  YYLTYPE *yyls = yylsa;
+  YYLTYPE *yylsp;
+
+#define YYPOPSTACK   (yyvsp--, yyssp--, yylsp--)
+#else
+#define YYPOPSTACK   (yyvsp--, yyssp--)
+#endif
+
+  int yystacksize = YYINITDEPTH;
+  int yyfree_stacks = 0;
+
+#ifdef YYPURE
+  int yychar;
+  YYSTYPE yylval;
+  int yynerrs;
+#ifdef YYLSP_NEEDED
+  YYLTYPE yylloc;
+#endif
+#endif
+
+  YYSTYPE yyval;		/*  the variable used to return		*/
+				/*  semantic values from the action	*/
+				/*  routines				*/
+
+  int yylen;
+
+#if YYDEBUG != 0
+  if (yydebug)
+    fprintf(stderr, "Starting parse\n");
+#endif
+
+  yystate = 0;
+  yyerrstatus = 0;
+  yynerrs = 0;
+  yychar = YYEMPTY;		/* Cause a token to be read.  */
+
+  /* Initialize stack pointers.
+     Waste one element of value and location stack
+     so that they stay on the same level as the state stack.
+     The wasted elements are never initialized.  */
+
+  yyssp = yyss - 1;
+  yyvsp = yyvs;
+#ifdef YYLSP_NEEDED
+  yylsp = yyls;
+#endif
+
+/* Push a new state, which is found in  yystate  .  */
+/* In all cases, when you get here, the value and location stacks
+   have just been pushed. so pushing a state here evens the stacks.  */
+yynewstate:
+
+  *++yyssp = yystate;
+
+  if (yyssp >= yyss + yystacksize - 1)
+    {
+      /* Give user a chance to reallocate the stack */
+      /* Use copies of these so that the &'s don't force the real ones into memory. */
+      YYSTYPE *yyvs1 = yyvs;
+      short *yyss1 = yyss;
+#ifdef YYLSP_NEEDED
+      YYLTYPE *yyls1 = yyls;
+#endif
+
+      /* Get the current used size of the three stacks, in elements.  */
+      int size = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+      /* Each stack pointer address is followed by the size of
+	 the data in use in that stack, in bytes.  */
+#ifdef YYLSP_NEEDED
+      /* This used to be a conditional around just the two extra args,
+	 but that might be undefined if yyoverflow is a macro.  */
+      yyoverflow("parser stack overflow",
+		 &yyss1, size * sizeof (*yyssp),
+		 &yyvs1, size * sizeof (*yyvsp),
+		 &yyls1, size * sizeof (*yylsp),
+		 &yystacksize);
+#else
+      yyoverflow("parser stack overflow",
+		 &yyss1, size * sizeof (*yyssp),
+		 &yyvs1, size * sizeof (*yyvsp),
+		 &yystacksize);
+#endif
+
+      yyss = yyss1; yyvs = yyvs1;
+#ifdef YYLSP_NEEDED
+      yyls = yyls1;
+#endif
+#else /* no yyoverflow */
+      /* Extend the stack our own way.  */
+      if (yystacksize >= YYMAXDEPTH)
+	{
+	  yyerror("parser stack overflow");
+	  if (yyfree_stacks)
+	    {
+	      free (yyss);
+	      free (yyvs);
+#ifdef YYLSP_NEEDED
+	      free (yyls);
+#endif
+	    }
+	  return 2;
+	}
+      yystacksize *= 2;
+      if (yystacksize > YYMAXDEPTH)
+	yystacksize = YYMAXDEPTH;
+#ifndef YYSTACK_USE_ALLOCA
+      yyfree_stacks = 1;
+#endif
+      yyss = (short *) YYSTACK_ALLOC (yystacksize * sizeof (*yyssp));
+      __yy_memcpy ((char *)yyss, (char *)yyss1,
+		   size * (unsigned int) sizeof (*yyssp));
+      yyvs = (YYSTYPE *) YYSTACK_ALLOC (yystacksize * sizeof (*yyvsp));
+      __yy_memcpy ((char *)yyvs, (char *)yyvs1,
+		   size * (unsigned int) sizeof (*yyvsp));
+#ifdef YYLSP_NEEDED
+      yyls = (YYLTYPE *) YYSTACK_ALLOC (yystacksize * sizeof (*yylsp));
+      __yy_memcpy ((char *)yyls, (char *)yyls1,
+		   size * (unsigned int) sizeof (*yylsp));
+#endif
+#endif /* no yyoverflow */
+
+      yyssp = yyss + size - 1;
+      yyvsp = yyvs + size - 1;
+#ifdef YYLSP_NEEDED
+      yylsp = yyls + size - 1;
+#endif
+
+#if YYDEBUG != 0
+      if (yydebug)
+	fprintf(stderr, "Stack size increased to %d\n", yystacksize);
+#endif
+
+      if (yyssp >= yyss + yystacksize - 1)
+	YYABORT;
+    }
+
+#if YYDEBUG != 0
+  if (yydebug)
+    fprintf(stderr, "Entering state %d\n", yystate);
+#endif
+
+  goto yybackup;
+ yybackup:
+
+/* Do appropriate processing given the current state.  */
+/* Read a lookahead token if we need one and don't already have one.  */
+/* yyresume: */
+
+  /* First try to decide what to do without reference to lookahead token.  */
+
+  yyn = yypact[yystate];
+  if (yyn == YYFLAG)
+    goto yydefault;
+
+  /* Not known => get a lookahead token if don't already have one.  */
+
+  /* yychar is either YYEMPTY or YYEOF
+     or a valid token in external form.  */
+
+  if (yychar == YYEMPTY)
+    {
+#if YYDEBUG != 0
+      if (yydebug)
+	fprintf(stderr, "Reading a token: ");
+#endif
+      yychar = YYLEX;
+    }
+
+  /* Convert token to internal form (in yychar1) for indexing tables with */
+
+  if (yychar <= 0)		/* This means end of input. */
+    {
+      yychar1 = 0;
+      yychar = YYEOF;		/* Don't call YYLEX any more */
+
+#if YYDEBUG != 0
+      if (yydebug)
+	fprintf(stderr, "Now at end of input.\n");
+#endif
+    }
+  else
+    {
+      yychar1 = YYTRANSLATE(yychar);
+
+#if YYDEBUG != 0
+      if (yydebug)
+	{
+	  fprintf (stderr, "Next token is %d (%s", yychar, yytname[yychar1]);
+	  /* Give the individual parser a way to print the precise meaning
+	     of a token, for further debugging info.  */
+#ifdef YYPRINT
+	  YYPRINT (stderr, yychar, yylval);
+#endif
+	  fprintf (stderr, ")\n");
+	}
+#endif
+    }
+
+  yyn += yychar1;
+  if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1)
+    goto yydefault;
+
+  yyn = yytable[yyn];
+
+  /* yyn is what to do for this token type in this state.
+     Negative => reduce, -yyn is rule number.
+     Positive => shift, yyn is new state.
+       New state is final state => don't bother to shift,
+       just return success.
+     0, or most negative number => error.  */
+
+  if (yyn < 0)
+    {
+      if (yyn == YYFLAG)
+	goto yyerrlab;
+      yyn = -yyn;
+      goto yyreduce;
+    }
+  else if (yyn == 0)
+    goto yyerrlab;
+
+  if (yyn == YYFINAL)
+    YYACCEPT;
+
+  /* Shift the lookahead token.  */
+
+#if YYDEBUG != 0
+  if (yydebug)
+    fprintf(stderr, "Shifting token %d (%s), ", yychar, yytname[yychar1]);
+#endif
+
+  /* Discard the token being shifted unless it is eof.  */
+  if (yychar != YYEOF)
+    yychar = YYEMPTY;
+
+  *++yyvsp = yylval;
+#ifdef YYLSP_NEEDED
+  *++yylsp = yylloc;
+#endif
+
+  /* count tokens shifted since error; after three, turn off error status.  */
+  if (yyerrstatus) yyerrstatus--;
+
+  yystate = yyn;
+  goto yynewstate;
+
+/* Do the default action for the current state.  */
+yydefault:
+
+  yyn = yydefact[yystate];
+  if (yyn == 0)
+    goto yyerrlab;
+
+/* Do a reduction.  yyn is the number of a rule to reduce with.  */
+yyreduce:
+  yylen = yyr2[yyn];
+  if (yylen > 0)
+    yyval = yyvsp[1-yylen]; /* implement default value of the action */
+
+#if YYDEBUG != 0
+  if (yydebug)
+    {
+      int i;
+
+      fprintf (stderr, "Reducing via rule %d (line %d), ",
+	       yyn, yyrline[yyn]);
+
+      /* Print the symbols being reduced, and their result.  */
+      for (i = yyprhs[yyn]; yyrhs[i] > 0; i++)
+	fprintf (stderr, "%s ", yytname[yyrhs[i]]);
+      fprintf (stderr, " -> %s\n", yytname[yyr1[yyn]]);
+    }
+#endif
+
+
+  switch (yyn) {
+
+case 1:
+#line 82 "zparse.y"
+{zserver_list=yyvsp[0].cfg;;
+    break;}
+case 2:
+#line 85 "zparse.y"
+{;;
+    break;}
+case 3:
+#line 86 "zparse.y"
+{fprintf(stderr,"No version - not GSDL config file?\n");exit(1);;
+    break;}
+case 4:
+#line 88 "zparse.y"
+{if (yyvsp[0].cfg!=NULL) {yyvsp[0].cfg->next=yyvsp[-1].cfg;yyval.cfg=yyvsp[0].cfg;};
+    break;}
+case 6:
+#line 92 "zparse.y"
+{
+		     if (YYRECOVERING)
+		       {yyval.cfg=NULL;YYRECOVERING=0;} 
+		     else {
+		       if((yyval.cfg=malloc(sizeof(struct z3950cfg)))==NULL)
+			 fprintf(stderr,"malloc failed\n");
+		       yyval.cfg->shortname=yyvsp[-7].string;
+		       yyval.cfg->hostname=yyvsp[-6].string;
+		       yyval.cfg->port=yyvsp[-5].number;
+		       yyval.cfg->dbname=yyvsp[-4].string;
+		       yyval.cfg->longname=yyvsp[-3].string;
+		       yyval.cfg->icon=yyvsp[-2].string;
+		       yyval.cfg->smallicon=yyvsp[-1].string;
+		       yyval.cfg->about=yyvsp[0].about;
+		     }
+		   ;
+    break;}
+case 7:
+#line 108 "zparse.y"
+{yyval.cfg=NULL;printf("discarding zserver\n");;
+    break;}
+case 8:
+#line 111 "zparse.y"
+{;;
+    break;}
+case 9:
+#line 112 "zparse.y"
+{errormsg("Database name needs to be followed by a short "
+			  "descriptive name (enclosed in \" marks)");
+	         yyval.string=NULL;
+	         YYRECOVERING=1;;
+    break;}
+case 10:
+#line 117 "zparse.y"
+{yyval.number=atoi(yyvsp[0].string);;
+    break;}
+case 11:
+#line 118 "zparse.y"
+{yyval.number=210;;
+    break;}
+case 12:
+#line 121 "zparse.y"
+{yyval.string=yyvsp[0].string;;
+    break;}
+case 13:
+#line 122 "zparse.y"
+{yyval.string=yyvsp[0].string;
+                  errormsg("Icon must be enclosed in quotes");
+	      yylex();yylex();;
+    break;}
+case 14:
+#line 125 "zparse.y"
+{yyval.string=NULL;;
+    break;}
+case 15:
+#line 126 "zparse.y"
+{yyval.string=yyvsp[0].string;;
+    break;}
+case 16:
+#line 127 "zparse.y"
+{yyval.string=yyvsp[0].string;
+	      /* this is because of the ':' */
+              errormsg("Smallicon must be enclosed in quotes.\n");
+	      yylex();yylex();
+	      ;
+    break;}
+case 17:
+#line 132 "zparse.y"
+{yyval.string=NULL;;
+    break;}
+case 18:
+#line 134 "zparse.y"
+{defLanguage=0;;
+    break;}
+case 19:
+#line 135 "zparse.y"
+{yyval.about=NULL;;
+    break;}
+case 20:
+#line 137 "zparse.y"
+{;;
+    break;}
+case 21:
+#line 139 "zparse.y"
+{yyval.about=yyvsp[0].about;yyvsp[0].about->next=yyvsp[-1].about;;
+    break;}
+case 22:
+#line 143 "zparse.y"
+{
+			       if((yyval.about=malloc(sizeof(struct z3950aboutlist)))
+				  ==NULL) {
+				 fprintf(stderr,"Malloc failed\n");
+				 exit(1);
+			       }
+			       yyval.about->lang=yyvsp[-1].string;
+			       yyval.about->text=yyvsp[0].string;
+			       yyval.about->next=NULL;
+			     ;
+    break;}
+case 23:
+#line 154 "zparse.y"
+{
+			       if (defLanguage)
+		                 {
+				   fprintf(stderr,"warning: (line %d): already have a default language in config file\n",lineno);
+				 }
+			       else defLanguage=1;
+			       
+			       if((yyval.about=malloc(sizeof(struct z3950aboutlist)))
+				  ==NULL) {
+				 fprintf(stderr,"Malloc failed\n");
+				 exit(1);
+			       }
+			       yyval.about->lang=NULL; /* default lang... */
+			       yyval.about->text=yyvsp[0].string;
+			       yyval.about->next=NULL;
+			     ;
+    break;}
+case 24:
+#line 176 "zparse.y"
+{
+			       yyval.string=malloc(strlen(yyvsp[-2].string)+strlen(yyvsp[0].string)+1);
+			       strncpy(yyval.string,yyvsp[-2].string,strlen(yyvsp[-2].string));
+			       yyval.string[strlen(yyvsp[-2].string)]='_';
+			       strncpy(yyval.string+strlen(yyvsp[-2].string)+1,yyvsp[0].string,strlen(yyvsp[0].string));
+			       free(yyvsp[-2].string);free(yyvsp[0].string);
+			     ;
+    break;}
+case 25:
+#line 183 "zparse.y"
+{;;
+    break;}
+case 26:
+#line 191 "zparse.y"
+{errormsg("missing language");;
+    break;}
+case 27:
+#line 193 "zparse.y"
+{;;
+    break;}
+case 28:
+#line 194 "zparse.y"
+{;;
+    break;}
+case 29:
+#line 196 "zparse.y"
+{;;
+    break;}
+case 30:
+#line 197 "zparse.y"
+{;;
+    break;}
+}
+   /* the action file gets copied in in place of this dollarsign */
+#line 542 "/usr/share/bison.simple"
+
+
+  yyvsp -= yylen;
+  yyssp -= yylen;
+#ifdef YYLSP_NEEDED
+  yylsp -= yylen;
+#endif
+
+#if YYDEBUG != 0
+  if (yydebug)
+    {
+      short *ssp1 = yyss - 1;
+      fprintf (stderr, "state stack now");
+      while (ssp1 != yyssp)
+	fprintf (stderr, " %d", *++ssp1);
+      fprintf (stderr, "\n");
+    }
+#endif
+
+  *++yyvsp = yyval;
+
+#ifdef YYLSP_NEEDED
+  yylsp++;
+  if (yylen == 0)
+    {
+      yylsp->first_line = yylloc.first_line;
+      yylsp->first_column = yylloc.first_column;
+      yylsp->last_line = (yylsp-1)->last_line;
+      yylsp->last_column = (yylsp-1)->last_column;
+      yylsp->text = 0;
+    }
+  else
+    {
+      yylsp->last_line = (yylsp+yylen-1)->last_line;
+      yylsp->last_column = (yylsp+yylen-1)->last_column;
+    }
+#endif
+
+  /* Now "shift" the result of the reduction.
+     Determine what state that goes to,
+     based on the state we popped back to
+     and the rule number reduced by.  */
+
+  yyn = yyr1[yyn];
+
+  yystate = yypgoto[yyn - YYNTBASE] + *yyssp;
+  if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+    yystate = yytable[yystate];
+  else
+    yystate = yydefgoto[yyn - YYNTBASE];
+
+  goto yynewstate;
+
+yyerrlab:   /* here on detecting error */
+
+  if (! yyerrstatus)
+    /* If not already recovering from an error, report this error.  */
+    {
+      ++yynerrs;
+
+#ifdef YYERROR_VERBOSE
+      yyn = yypact[yystate];
+
+      if (yyn > YYFLAG && yyn < YYLAST)
+	{
+	  int size = 0;
+	  char *msg;
+	  int x, count;
+
+	  count = 0;
+	  /* Start X at -yyn if nec to avoid negative indexes in yycheck.  */
+	  for (x = (yyn < 0 ? -yyn : 0);
+	       x < (sizeof(yytname) / sizeof(char *)); x++)
+	    if (yycheck[x + yyn] == x)
+	      size += strlen(yytname[x]) + 15, count++;
+	  msg = (char *) malloc(size + 15);
+	  if (msg != 0)
+	    {
+	      strcpy(msg, "parse error");
+
+	      if (count < 5)
+		{
+		  count = 0;
+		  for (x = (yyn < 0 ? -yyn : 0);
+		       x < (sizeof(yytname) / sizeof(char *)); x++)
+		    if (yycheck[x + yyn] == x)
+		      {
+			strcat(msg, count == 0 ? ", expecting `" : " or `");
+			strcat(msg, yytname[x]);
+			strcat(msg, "'");
+			count++;
+		      }
+		}
+	      yyerror(msg);
+	      free(msg);
+	    }
+	  else
+	    yyerror ("parse error; also virtual memory exceeded");
+	}
+      else
+#endif /* YYERROR_VERBOSE */
+	yyerror("parse error");
+    }
+
+  goto yyerrlab1;
+yyerrlab1:   /* here on error raised explicitly by an action */
+
+  if (yyerrstatus == 3)
+    {
+      /* if just tried and failed to reuse lookahead token after an error, discard it.  */
+
+      /* return failure if at end of input */
+      if (yychar == YYEOF)
+	YYABORT;
+
+#if YYDEBUG != 0
+      if (yydebug)
+	fprintf(stderr, "Discarding token %d (%s).\n", yychar, yytname[yychar1]);
+#endif
+
+      yychar = YYEMPTY;
+    }
+
+  /* Else will try to reuse lookahead token
+     after shifting the error token.  */
+
+  yyerrstatus = 3;		/* Each real token shifted decrements this */
+
+  goto yyerrhandle;
+
+yyerrdefault:  /* current state does not do anything special for the error token. */
+
+#if 0
+  /* This is wrong; only states that explicitly want error tokens
+     should shift them.  */
+  yyn = yydefact[yystate];  /* If its default is to accept any token, ok.  Otherwise pop it.*/
+  if (yyn) goto yydefault;
+#endif
+
+yyerrpop:   /* pop the current state because it cannot handle the error token */
+
+  if (yyssp == yyss) YYABORT;
+  yyvsp--;
+  yystate = *--yyssp;
+#ifdef YYLSP_NEEDED
+  yylsp--;
+#endif
+
+#if YYDEBUG != 0
+  if (yydebug)
+    {
+      short *ssp1 = yyss - 1;
+      fprintf (stderr, "Error: state stack now");
+      while (ssp1 != yyssp)
+	fprintf (stderr, " %d", *++ssp1);
+      fprintf (stderr, "\n");
+    }
+#endif
+
+yyerrhandle:
+
+  yyn = yypact[yystate];
+  if (yyn == YYFLAG)
+    goto yyerrdefault;
+
+  yyn += YYTERROR;
+  if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR)
+    goto yyerrdefault;
+
+  yyn = yytable[yyn];
+  if (yyn < 0)
+    {
+      if (yyn == YYFLAG)
+	goto yyerrpop;
+      yyn = -yyn;
+      goto yyreduce;
+    }
+  else if (yyn == 0)
+    goto yyerrpop;
+
+  if (yyn == YYFINAL)
+    YYACCEPT;
+
+#if YYDEBUG != 0
+  if (yydebug)
+    fprintf(stderr, "Shifting error token, ");
+#endif
+
+  *++yyvsp = yylval;
+#ifdef YYLSP_NEEDED
+  *++yylsp = yylloc;
+#endif
+
+  yystate = yyn;
+  goto yynewstate;
+
+ yyacceptlab:
+  /* YYACCEPT comes here.  */
+  if (yyfree_stacks)
+    {
+      free (yyss);
+      free (yyvs);
+#ifdef YYLSP_NEEDED
+      free (yyls);
+#endif
+    }
+  return 0;
+
+ yyabortlab:
+  /* YYABORT comes here.  */
+  if (yyfree_stacks)
+    {
+      free (yyss);
+      free (yyvs);
+#ifdef YYLSP_NEEDED
+      free (yyls);
+#endif
+    }
+  return 1;
+}
+#line 200 "zparse.y"
+
+/*int strncasecmp (const char *, const char *,size_t);*/
+int yyerror(char *string) {
+  fprintf(stderr,"Parse error (line %d) near \n\"%s\"<---:%s\n",lineno,
+	  yylval.string,string);
+  return(1);
+}
+
+void errormsg(char *str) {
+  fprintf(stderr,"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);
+}
+* */
Index: /trunk/gsdl/src/recpt/zparse.tab.h
===================================================================
--- /trunk/gsdl/src/recpt/zparse.tab.h	(revision 1347)
+++ /trunk/gsdl/src/recpt/zparse.tab.h	(revision 1347)
@@ -0,0 +1,48 @@
+typedef union {
+  char *string;
+  struct z3950cfg *cfg;
+  struct z3950aboutlist *about;
+  int number;
+} YYSTYPE;
+#define	GSDLVERSION	257
+#define	GENERAL_SECTION	258
+#define	SEARCH_SECTION	259
+#define	BROWSE_SECTION	260
+#define	MACROS_SECTION	261
+#define	MAINTAINER	262
+#define	PUBLIC	263
+#define	TRUE	264
+#define	FALSE	265
+#define	LANGUAGES	266
+#define	EN	267
+#define	FR	268
+#define	MI	269
+#define	ZH	270
+#define	DE	271
+#define	NAME	272
+#define	STRING	273
+#define	ICON	274
+#define	SMALLICON	275
+#define	ABOUT	276
+#define	SEARCHTEXT	277
+#define	DOCUMENT	278
+#define	SECTION	279
+#define	BROWSE	280
+#define	TYPE	281
+#define	FORMAT	282
+#define	LIST	283
+#define	SORTEDLIST	284
+#define	SECTIONLIST	285
+#define	SORTEDSECTIONLIST	286
+#define	DATELIST	287
+#define	ICONLINK	288
+#define	TEXTLINK	289
+#define	DOCUMENTIMAGES	290
+#define	DOCUMENTHEADER	291
+#define	DOCUMENTTEXT	292
+#define	DOCUMENTBUTTONS	293
+#define	DOCUMENTARROWSBOTTOM	294
+#define	DATA	295
+
+
+extern YYSTYPE yylval;
Index: /trunk/gsdl/src/recpt/zparse.y
===================================================================
--- /trunk/gsdl/src/recpt/zparse.y	(revision 1347)
+++ /trunk/gsdl/src/recpt/zparse.y	(revision 1347)
@@ -0,0 +1,222 @@
+/* RUN-TIME CONFIGURATION FILE PARSER */
+
+%{
+  /* verbatim C code - functions, etc */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include "z3950cfg.h"
+
+#define YYDEBUG 1
+#define YYERROR_VERBOSE 1
+/* can't use default yyparse(), as this name is used elsewhere (eg mg)*/
+#define yyin    zconfigin
+#define yyparse zconfigparse
+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 */
+extern struct z3950cfg *zservers_cfg_file;
+
+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       : GSDLVERSION {;}
+              | {fprintf(stderr,"No version - not GSDL config file?\n");exit(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(stderr,"malloc failed\n");
+		       $$->shortname=$1;
+		       $$->hostname=$2;
+		       $$->port=$3;
+		       $$->dbname=$4;
+		       $$->longname=$5;
+		       $$->icon=$6;
+		       $$->smallicon=$7;
+		       $$->about=$8;
+		     }
+		   }
+              | error {$$=NULL;printf("discarding zserver\n");}
+              ;
+
+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(stderr,"Malloc failed\n");
+				 exit(1);
+			       }
+			       $$->lang=$2;
+			       $$->text=$3;
+			       $$->next=NULL;
+			     }
+              | ABOUT STRING 
+                             {
+			       if (defLanguage)
+		                 {
+				   fprintf(stderr,"warning: (line %d): already have a default language in config file\n",lineno);
+				 }
+			       else defLanguage=1;
+			       
+			       if(($$=malloc(sizeof(struct z3950aboutlist)))
+				  ==NULL) {
+				 fprintf(stderr,"Malloc failed\n");
+				 exit(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(stderr,"Parse error (line %d) near \n\"%s\"<---:%s\n",lineno,
+	  yylval.string,string);
+  return(1);
+}
+
+void errormsg(char *str) {
+  fprintf(stderr,"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);
+}
+* */
