Index: harvest/ChangeLog
diff -c harvest/ChangeLog:2.30 harvest/ChangeLog:2.34
*** harvest/ChangeLog:2.30	Thu Oct 16 14:01:25 1997
--- harvest/ChangeLog	Mon Oct 27 17:56:25 1997
***************
*** 1,4 ****
--- 1,14 ----
  Changes in current version
+ 	- Fixed filter.c so both host and portnumber are made available for
+           regular expressions (Wesley Alan Wright)
+ 	- Added a SWISH based indexing engine, which is considerably more
+           efficient than Glimpse, if slightly less fully featured
+ 	  (Simon Wilkinson)
+         - Changes to nph-search.in so that the truncation warnings aren't
+ 	  erroneously displayed when the user hasn't supplied a value for
+ 	  maxobjflag (Allyn Fratkin)
+         - Added support for META client pull redirections to HTMLurls
+ 	  (Hrvoje Stipetic)
          - Increased limits in HTML.decl (Tim Riker)
  	- Fix for gather command's uncompressed transfer routine so that it
            now transfers blocks correctly in most circumstances (Marjan Erzen)
Index: harvest/components/admin/Makefile
diff -c harvest/components/admin/Makefile:2.2 harvest/components/admin/Makefile:2.3
*** harvest/components/admin/Makefile:2.2	Thu Sep 11 12:14:05 1997
--- harvest/components/admin/Makefile	Mon Oct 27 16:51:01 1997
***************
*** 1,11 ****
  #
  #  Makefile for the Admin components
  #
! #  Makefile,v 2.2 1997/09/11 16:14:05 sxw Exp
  #
  #
  
! SUBDIRS="`cat BUILD`"
  
  all: do-all
  install: do-install
--- 1,11 ----
  #
  #  Makefile for the Admin components
  #
! #  Makefile,v 2.3 1997/10/27 21:51:01 sxw Exp
  #
  #
  
! SUBDIRS=`cat BUILD`
  
  all: do-all
  install: do-install
Index: harvest/components/broker/BUILD
diff -c harvest/components/broker/BUILD:2.0 harvest/components/broker/BUILD:2.1
*** harvest/components/broker/BUILD:2.0	Sun Mar 16 16:56:26 1997
--- harvest/components/broker/BUILD	Mon Oct 27 17:47:04 1997
***************
*** 1 ****
--- 1,2 ----
  standard
+ swish
Index: harvest/components/broker/Makefile
diff -c harvest/components/broker/Makefile:2.2 harvest/components/broker/Makefile:2.4
*** harvest/components/broker/Makefile:2.2	Thu Sep 11 12:14:10 1997
--- harvest/components/broker/Makefile	Mon Oct 27 18:30:45 1997
***************
*** 1,11 ****
  #
  #  Makefile for the Broker components
  #
! #  Makefile,v 2.2 1997/09/11 16:14:10 sxw Exp
  #
  #
  
! SUBDIRS="`cat BUILD`"
  
  all: do-all
  install: do-install
--- 1,11 ----
  #
  #  Makefile for the Broker components
  #
! #  Makefile,v 2.4 1997/10/27 23:30:45 sxw Exp
  #
  #
  
! SUBDIRS=`cat BUILD`
  
  all: do-all
  install: do-install
Index: harvest/components/broker/standard/WWW/nph-search.in
diff -c harvest/components/broker/standard/WWW/nph-search.in:2.7 harvest/components/broker/standard/WWW/nph-search.in:2.8
*** harvest/components/broker/standard/WWW/nph-search.in:2.7	Sun Oct 12 16:08:09 1997
--- harvest/components/broker/standard/WWW/nph-search.in	Tue Oct 21 06:56:53 1997
***************
*** 8,14 ****
  #  $BQLOG = "/usr/local/etc/httpd/logs/BrokerQuery.log";
  $BQLOG = "/dev/null";
  
! $rcsid = 'nph-search.in,v 2.7 1997/10/12 20:08:09 sxw Exp';
  #######################################################################
  #
  #  nph-search - Customizable WWW Interface to the Harvest Broker
--- 8,14 ----
  #  $BQLOG = "/usr/local/etc/httpd/logs/BrokerQuery.log";
  $BQLOG = "/dev/null";
  
! $rcsid = 'nph-search.in,v 2.8 1997/10/21 10:56:53 sxw Exp';
  #######################################################################
  #
  #  nph-search - Customizable WWW Interface to the Harvest Broker
***************
*** 478,484 ****
                              print &expand ($CFG{'EmptySetWarning'})
                                  if ($nreturned == 0);
                              print &expand ($CFG{'TruncateWarning'})
!                                 if ($nopaquelines >= $maxresult);
                          } else { #
                              print &expand ($CFG{'FailBrokerResults'});
                          }
--- 478,486 ----
                              print &expand ($CFG{'EmptySetWarning'})
                                  if ($nreturned == 0);
                              print &expand ($CFG{'TruncateWarning'})
!                                 if ($maxresult && ($nopaquelines >= $maxresult));
! 			    print &expand ($CFG{'ObjTruncateWarning'})
! 				if ($maxfiles && ($nreturned >= $maxfiles));
                          } else { #
                              print &expand ($CFG{'FailBrokerResults'});
                          }
Index: harvest/components/broker/swish/Makefile.in
diff -c /dev/null harvest/components/broker/swish/Makefile.in:1.1
*** /dev/null	Mon Oct 27 18:40:48 1997
--- harvest/components/broker/swish/Makefile.in	Mon Oct 27 16:13:47 1997
***************
*** 0 ****
--- 1,49 ----
+ # Makefile for SWISH
+ # Kevin Hughes, 3/12/95
+ #
+ 
+ srcdir = @srcdir@
+ VPATH = @srcdir@
+ SHELL = /bin/sh
+ CC    = @CC@
+ LIBS  = @LIBS@ 
+ 
+ # CFLAGS= -O2 -DHARVEST -L../../../src/common/lib -I../../../src/common/include
+ 
+ # LIBS=	-lm -ltemplate -lutil
+ 
+ prefix = @prefix@
+ bindir = $(prefix)/lib/broker
+ 
+ INSTALL_PROG = @INSTALL@
+ 
+ TEMPLATEDIR = ../../../src/common
+ TEMPLATESRC = $(srcdir)/$(TEMPLATEDIR)
+ 
+ CFLAGS = @CFLAGS@ -I$(TEMPLATESRC)/include
+ LDFLAGS = @LDFLAGS@ -L$(TEMPLATESRC)/lib
+ 
+ OBJS=	check.o file.o index.o search.o error.o \
+ 	hash.o list.o mem.o string.o merge.o swish.o
+ 
+ .c.o:
+ 	$(CC) -c $(CFLAGS) $<
+ 
+ all:	swish
+ 
+ swish:	$(OBJS)
+ 	$(CC) $(LDFLAGS) -o swish $(OBJS) $(LIBS) -ltemplate -lutil -lm
+ 	chmod 755 swish
+ 
+ clean:
+ 	rm -f ./swish ./*.o
+ 
+ install:
+ 	$(INSTALL_PROG) swish $(bindir)/swish
+ 
+ distclean: clean 
+ 	rm -f Makefile config.cache config.log config.status
+ 
+ $(OBJS):	Makefile swish_config.h swish.h
+ 
+ 
Index: harvest/components/broker/swish/check.c
diff -c /dev/null harvest/components/broker/swish/check.c:1.2
*** /dev/null	Mon Oct 27 18:40:48 1997
--- harvest/components/broker/swish/check.c	Mon Oct 27 16:13:48 1997
***************
*** 0 ****
--- 1,125 ----
+ /*
+ ** Copyright (C) 1995, Enterprise Integration Technologies Corp.        
+ ** All Rights Reserved.
+ ** Kevin Hughes, kevinh@eit.com 
+ ** 3/11/94
+ **
+ ** This file was released under the GPL by EIT in October 1997
+ **
+ ** Heavily modified for Harvest by Simon Wilkinson (sxw@tardis.ed.ac.uk)
+ */
+ 
+ #include "swish.h"
+ #include "check.h"
+ 
+ /* Should a word be indexed? Consults the stopword hash list
+ ** and checks if the word is of a reasonable length...
+ ** If you have any good rules that can work with most languages,
+ ** please let me know...
+ */
+ 
+ int isokword(word)
+       char *word;
+ {
+         int i, same, hasnumber, hasvowel, hascons,
+ 		numberrow, vowelrow, consrow;
+ 	char lastchar;
+ 
+ 	if (word[0] == '\0')
+ 		return 0;
+ 
+         if (isstopword(word))
+                 return 0;
+         if (strlen(word) < MINWORDLIMIT || strlen(word) > MAXWORDLIMIT)
+                 return 0;
+ 
+ 	lastchar = ':';
+ 	same = 0;
+ 	hasnumber = hasvowel = hascons = 0;
+ 	numberrow = vowelrow = consrow = 0;
+ 	for (i = 0; word[i] != '\0'; i++) {
+ 		if (word[i] == lastchar) {
+ 			same++;
+ 			if (same > IGNORESAME)
+ 				return 0;
+ 		}
+ 		else
+ 			same = 0;
+ 		if (isdigit(word[i])) {
+ 			hasnumber = 1;
+ 			numberrow++;
+ 			if (numberrow > IGNOREROWN)
+ 				return 0;
+ 			vowelrow = 0;
+ 			consrow = 0;
+ 		}
+ 		else if (isvowel(word[i])) {
+ 			hasvowel = 1;
+ 			vowelrow++;
+ 			if (vowelrow > IGNOREROWV)
+ 				return 0;
+ 			numberrow = 0;
+ 			consrow = 0;
+ 		}
+ 		else if (!ispunct(word[i])) {
+ 			hascons = 1;
+ 			consrow++;
+ 			if (consrow > IGNOREROWC)
+ 				return 0;
+ 			numberrow = 0;
+ 			vowelrow = 0;
+ 		}
+ 		lastchar = word[i];
+ 	}
+ 
+ 	if (IGNOREALLV)
+ 		if (hasvowel && !hascons)
+ 			return 0;
+ 	if (IGNOREALLC)
+ 		if (hascons && !hasvowel)
+ 			return 0;
+ 	if (IGNOREALLN)
+ 		if (hasnumber && !hasvowel && !hascons)
+ 			return 0;
+ 
+ 	return 1;
+ }
+ 
+ /* Does a word have valid characters?
+ */
+ 
+ int hasokchars(word)
+      char *word;
+ {
+ 	int i, j;
+ 	char c;
+ 
+ 	c = word[strlen(word) - 1];
+ 	for (i = j = 0; BEGINCHARS[i] != '\0'; i++)
+ 		if (word[0] == BEGINCHARS[i])
+ 			j++;
+ 	if (!j)
+ 		return 0;
+ 	for (i = j = 0; ENDCHARS[i] != '\0'; i++)
+ 		if (c == ENDCHARS[i])
+ 			j++;
+ 	if (!j)
+ 		return 0;
+ 	for (i = 0; word[i] != '\0'; i++)
+ 		for (j = 0; WORDCHARS[j] != '\0'; j++)
+ 			if (word[i] == WORDCHARS[j])
+ 				return 1;
+ 	return 0;
+ }
+ 
+ /* Is a letter a vowel?
+ */
+ 
+ int isvowel(c)
+      char c;
+ {
+ 	if (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u')
+ 		return 1;
+ 	return 0;
+ }
+ 
Index: harvest/components/broker/swish/check.h
diff -c /dev/null harvest/components/broker/swish/check.h:1.2
*** /dev/null	Mon Oct 27 18:40:49 1997
--- harvest/components/broker/swish/check.h	Mon Oct 27 16:13:49 1997
***************
*** 0 ****
--- 1,15 ----
+ /*
+ ** Copyright (C) 1995, Enterprise Integration Technologies Corp.        
+ ** All Rights Reserved.
+ ** Kevin Hughes, kevinh@eit.com 
+ ** 3/11/94
+ **
+ ** Released under the GPL by EIT in October 1997.
+ **
+ ** Heavily modified for Harvest
+ */
+ 
+ int isokword();
+ int isvowel();
+ int hasokchars();
+ 
Index: harvest/components/broker/swish/configure
diff -c /dev/null harvest/components/broker/swish/configure:1.1
*** /dev/null	Mon Oct 27 18:40:49 1997
--- harvest/components/broker/swish/configure	Mon Oct 27 16:13:51 1997
***************
*** 0 ****
--- 1,1593 ----
+ #! /bin/sh
+ 
+ # Guess values for system-dependent variables and create Makefiles.
+ # Generated automatically using autoconf version 2.12 
+ # Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.
+ #
+ # This configure script is free software; the Free Software Foundation
+ # gives unlimited permission to copy, distribute and modify it.
+ 
+ # Defaults:
+ ac_help=
+ ac_default_prefix=/usr/local
+ # Any additions from configure.in:
+ ac_default_prefix=/usr/local/harvest
+ 
+ # Initialize some variables set by options.
+ # The variables have the same names as the options, with
+ # dashes changed to underlines.
+ build=NONE
+ cache_file=./config.cache
+ exec_prefix=NONE
+ host=NONE
+ no_create=
+ nonopt=NONE
+ no_recursion=
+ prefix=NONE
+ program_prefix=NONE
+ program_suffix=NONE
+ program_transform_name=s,x,x,
+ silent=
+ site=
+ srcdir=
+ target=NONE
+ verbose=
+ x_includes=NONE
+ x_libraries=NONE
+ bindir='${exec_prefix}/bin'
+ sbindir='${exec_prefix}/sbin'
+ libexecdir='${exec_prefix}/libexec'
+ datadir='${prefix}/share'
+ sysconfdir='${prefix}/etc'
+ sharedstatedir='${prefix}/com'
+ localstatedir='${prefix}/var'
+ libdir='${exec_prefix}/lib'
+ includedir='${prefix}/include'
+ oldincludedir='/usr/include'
+ infodir='${prefix}/info'
+ mandir='${prefix}/man'
+ 
+ # Initialize some other variables.
+ subdirs=
+ MFLAGS= MAKEFLAGS=
+ # Maximum number of lines to put in a shell here document.
+ ac_max_here_lines=12
+ 
+ ac_prev=
+ for ac_option
+ do
+ 
+   # If the previous option needs an argument, assign it.
+   if test -n "$ac_prev"; then
+     eval "$ac_prev=\$ac_option"
+     ac_prev=
+     continue
+   fi
+ 
+   case "$ac_option" in
+   -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+   *) ac_optarg= ;;
+   esac
+ 
+   # Accept the important Cygnus configure options, so we can diagnose typos.
+ 
+   case "$ac_option" in
+ 
+   -bindir | --bindir | --bindi | --bind | --bin | --bi)
+     ac_prev=bindir ;;
+   -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+     bindir="$ac_optarg" ;;
+ 
+   -build | --build | --buil | --bui | --bu)
+     ac_prev=build ;;
+   -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+     build="$ac_optarg" ;;
+ 
+   -cache-file | --cache-file | --cache-fil | --cache-fi \
+   | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+     ac_prev=cache_file ;;
+   -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+   | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+     cache_file="$ac_optarg" ;;
+ 
+   -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+     ac_prev=datadir ;;
+   -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+   | --da=*)
+     datadir="$ac_optarg" ;;
+ 
+   -disable-* | --disable-*)
+     ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
+     # Reject names that are not valid shell variable names.
+     if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then
+       { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+     fi
+     ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+     eval "enable_${ac_feature}=no" ;;
+ 
+   -enable-* | --enable-*)
+     ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
+     # Reject names that are not valid shell variable names.
+     if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
+       { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+     fi
+     ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+     case "$ac_option" in
+       *=*) ;;
+       *) ac_optarg=yes ;;
+     esac
+     eval "enable_${ac_feature}='$ac_optarg'" ;;
+ 
+   -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+   | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+   | --exec | --exe | --ex)
+     ac_prev=exec_prefix ;;
+   -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+   | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+   | --exec=* | --exe=* | --ex=*)
+     exec_prefix="$ac_optarg" ;;
+ 
+   -gas | --gas | --ga | --g)
+     # Obsolete; use --with-gas.
+     with_gas=yes ;;
+ 
+   -help | --help | --hel | --he)
+     # Omit some internal or obsolete options to make the list less imposing.
+     # This message is too long to be a string in the A/UX 3.1 sh.
+     cat << EOF
+ Usage: configure [options] [host]
+ Options: [defaults in brackets after descriptions]
+ Configuration:
+   --cache-file=FILE       cache test results in FILE
+   --help                  print this message
+   --no-create             do not create output files
+   --quiet, --silent       do not print \`checking...' messages
+   --version               print the version of autoconf that created configure
+ Directory and file names:
+   --prefix=PREFIX         install architecture-independent files in PREFIX
+                           [$ac_default_prefix]
+   --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
+                           [same as prefix]
+   --bindir=DIR            user executables in DIR [EPREFIX/bin]
+   --sbindir=DIR           system admin executables in DIR [EPREFIX/sbin]
+   --libexecdir=DIR        program executables in DIR [EPREFIX/libexec]
+   --datadir=DIR           read-only architecture-independent data in DIR
+                           [PREFIX/share]
+   --sysconfdir=DIR        read-only single-machine data in DIR [PREFIX/etc]
+   --sharedstatedir=DIR    modifiable architecture-independent data in DIR
+                           [PREFIX/com]
+   --localstatedir=DIR     modifiable single-machine data in DIR [PREFIX/var]
+   --libdir=DIR            object code libraries in DIR [EPREFIX/lib]
+   --includedir=DIR        C header files in DIR [PREFIX/include]
+   --oldincludedir=DIR     C header files for non-gcc in DIR [/usr/include]
+   --infodir=DIR           info documentation in DIR [PREFIX/info]
+   --mandir=DIR            man documentation in DIR [PREFIX/man]
+   --srcdir=DIR            find the sources in DIR [configure dir or ..]
+   --program-prefix=PREFIX prepend PREFIX to installed program names
+   --program-suffix=SUFFIX append SUFFIX to installed program names
+   --program-transform-name=PROGRAM
+                           run sed PROGRAM on installed program names
+ EOF
+     cat << EOF
+ Host type:
+   --build=BUILD           configure for building on BUILD [BUILD=HOST]
+   --host=HOST             configure for HOST [guessed]
+   --target=TARGET         configure for TARGET [TARGET=HOST]
+ Features and packages:
+   --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
+   --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+   --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+   --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+   --x-includes=DIR        X include files are in DIR
+   --x-libraries=DIR       X library files are in DIR
+ EOF
+     if test -n "$ac_help"; then
+       echo "--enable and --with options recognized:$ac_help"
+     fi
+     exit 0 ;;
+ 
+   -host | --host | --hos | --ho)
+     ac_prev=host ;;
+   -host=* | --host=* | --hos=* | --ho=*)
+     host="$ac_optarg" ;;
+ 
+   -includedir | --includedir | --includedi | --included | --include \
+   | --includ | --inclu | --incl | --inc)
+     ac_prev=includedir ;;
+   -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+   | --includ=* | --inclu=* | --incl=* | --inc=*)
+     includedir="$ac_optarg" ;;
+ 
+   -infodir | --infodir | --infodi | --infod | --info | --inf)
+     ac_prev=infodir ;;
+   -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+     infodir="$ac_optarg" ;;
+ 
+   -libdir | --libdir | --libdi | --libd)
+     ac_prev=libdir ;;
+   -libdir=* | --libdir=* | --libdi=* | --libd=*)
+     libdir="$ac_optarg" ;;
+ 
+   -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+   | --libexe | --libex | --libe)
+     ac_prev=libexecdir ;;
+   -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+   | --libexe=* | --libex=* | --libe=*)
+     libexecdir="$ac_optarg" ;;
+ 
+   -localstatedir | --localstatedir | --localstatedi | --localstated \
+   | --localstate | --localstat | --localsta | --localst \
+   | --locals | --local | --loca | --loc | --lo)
+     ac_prev=localstatedir ;;
+   -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+   | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+   | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+     localstatedir="$ac_optarg" ;;
+ 
+   -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+     ac_prev=mandir ;;
+   -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+     mandir="$ac_optarg" ;;
+ 
+   -nfp | --nfp | --nf)
+     # Obsolete; use --without-fp.
+     with_fp=no ;;
+ 
+   -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+   | --no-cr | --no-c)
+     no_create=yes ;;
+ 
+   -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+   | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+     no_recursion=yes ;;
+ 
+   -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+   | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+   | --oldin | --oldi | --old | --ol | --o)
+     ac_prev=oldincludedir ;;
+   -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+   | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+   | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+     oldincludedir="$ac_optarg" ;;
+ 
+   -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+     ac_prev=prefix ;;
+   -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+     prefix="$ac_optarg" ;;
+ 
+   -program-prefix | --program-prefix | --program-prefi | --program-pref \
+   | --program-pre | --program-pr | --program-p)
+     ac_prev=program_prefix ;;
+   -program-prefix=* | --program-prefix=* | --program-prefi=* \
+   | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+     program_prefix="$ac_optarg" ;;
+ 
+   -program-suffix | --program-suffix | --program-suffi | --program-suff \
+   | --program-suf | --program-su | --program-s)
+     ac_prev=program_suffix ;;
+   -program-suffix=* | --program-suffix=* | --program-suffi=* \
+   | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+     program_suffix="$ac_optarg" ;;
+ 
+   -program-transform-name | --program-transform-name \
+   | --program-transform-nam | --program-transform-na \
+   | --program-transform-n | --program-transform- \
+   | --program-transform | --program-transfor \
+   | --program-transfo | --program-transf \
+   | --program-trans | --program-tran \
+   | --progr-tra | --program-tr | --program-t)
+     ac_prev=program_transform_name ;;
+   -program-transform-name=* | --program-transform-name=* \
+   | --program-transform-nam=* | --program-transform-na=* \
+   | --program-transform-n=* | --program-transform-=* \
+   | --program-transform=* | --program-transfor=* \
+   | --program-transfo=* | --program-transf=* \
+   | --program-trans=* | --program-tran=* \
+   | --progr-tra=* | --program-tr=* | --program-t=*)
+     program_transform_name="$ac_optarg" ;;
+ 
+   -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+   | -silent | --silent | --silen | --sile | --sil)
+     silent=yes ;;
+ 
+   -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+     ac_prev=sbindir ;;
+   -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+   | --sbi=* | --sb=*)
+     sbindir="$ac_optarg" ;;
+ 
+   -sharedstatedir | --sharedstatedir | --sharedstatedi \
+   | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+   | --sharedst | --shareds | --shared | --share | --shar \
+   | --sha | --sh)
+     ac_prev=sharedstatedir ;;
+   -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+   | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+   | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+   | --sha=* | --sh=*)
+     sharedstatedir="$ac_optarg" ;;
+ 
+   -site | --site | --sit)
+     ac_prev=site ;;
+   -site=* | --site=* | --sit=*)
+     site="$ac_optarg" ;;
+ 
+   -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+     ac_prev=srcdir ;;
+   -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+     srcdir="$ac_optarg" ;;
+ 
+   -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+   | --syscon | --sysco | --sysc | --sys | --sy)
+     ac_prev=sysconfdir ;;
+   -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+   | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+     sysconfdir="$ac_optarg" ;;
+ 
+   -target | --target | --targe | --targ | --tar | --ta | --t)
+     ac_prev=target ;;
+   -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+     target="$ac_optarg" ;;
+ 
+   -v | -verbose | --verbose | --verbos | --verbo | --verb)
+     verbose=yes ;;
+ 
+   -version | --version | --versio | --versi | --vers)
+     echo "configure generated by autoconf version 2.12"
+     exit 0 ;;
+ 
+   -with-* | --with-*)
+     ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
+     # Reject names that are not valid shell variable names.
+     if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then
+       { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+     fi
+     ac_package=`echo $ac_package| sed 's/-/_/g'`
+     case "$ac_option" in
+       *=*) ;;
+       *) ac_optarg=yes ;;
+     esac
+     eval "with_${ac_package}='$ac_optarg'" ;;
+ 
+   -without-* | --without-*)
+     ac_package=`echo $ac_option|sed -e 's/-*without-//'`
+     # Reject names that are not valid shell variable names.
+     if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then
+       { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+     fi
+     ac_package=`echo $ac_package| sed 's/-/_/g'`
+     eval "with_${ac_package}=no" ;;
+ 
+   --x)
+     # Obsolete; use --with-x.
+     with_x=yes ;;
+ 
+   -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+   | --x-incl | --x-inc | --x-in | --x-i)
+     ac_prev=x_includes ;;
+   -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+   | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+     x_includes="$ac_optarg" ;;
+ 
+   -x-libraries | --x-libraries | --x-librarie | --x-librari \
+   | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+     ac_prev=x_libraries ;;
+   -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+   | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+     x_libraries="$ac_optarg" ;;
+ 
+   -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; }
+     ;;
+ 
+   *)
+     if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
+       echo "configure: warning: $ac_option: invalid host type" 1>&2
+     fi
+     if test "x$nonopt" != xNONE; then
+       { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; }
+     fi
+     nonopt="$ac_option"
+     ;;
+ 
+   esac
+ done
+ 
+ if test -n "$ac_prev"; then
+   { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; }
+ fi
+ 
+ trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+ 
+ # File descriptor usage:
+ # 0 standard input
+ # 1 file creation
+ # 2 errors and warnings
+ # 3 some systems may open it to /dev/tty
+ # 4 used on the Kubota Titan
+ # 6 checking for... messages and results
+ # 5 compiler messages saved in config.log
+ if test "$silent" = yes; then
+   exec 6>/dev/null
+ else
+   exec 6>&1
+ fi
+ exec 5>./config.log
+ 
+ echo "\
+ This file contains any messages produced by compilers while
+ running configure, to aid debugging if configure makes a mistake.
+ " 1>&5
+ 
+ # Strip out --no-create and --no-recursion so they do not pile up.
+ # Also quote any args containing shell metacharacters.
+ ac_configure_args=
+ for ac_arg
+ do
+   case "$ac_arg" in
+   -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+   | --no-cr | --no-c) ;;
+   -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+   | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
+   *" "*|*"	"*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
+   ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+   *) ac_configure_args="$ac_configure_args $ac_arg" ;;
+   esac
+ done
+ 
+ # NLS nuisances.
+ # Only set these to C if already set.  These must not be set unconditionally
+ # because not all systems understand e.g. LANG=C (notably SCO).
+ # Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'!
+ # Non-C LC_CTYPE values break the ctype check.
+ if test "${LANG+set}"   = set; then LANG=C;   export LANG;   fi
+ if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
+ if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi
+ if test "${LC_CTYPE+set}"    = set; then LC_CTYPE=C;    export LC_CTYPE;    fi
+ 
+ # confdefs.h avoids OS command line length limits that DEFS can exceed.
+ rm -rf conftest* confdefs.h
+ # AIX cpp loses on an empty file, so make sure it contains at least a newline.
+ echo > confdefs.h
+ 
+ # A filename unique to this package, relative to the directory that
+ # configure is in, which we can look for to find out if srcdir is correct.
+ ac_unique_file=swish_config.h
+ 
+ # Find the source files, if location was not specified.
+ if test -z "$srcdir"; then
+   ac_srcdir_defaulted=yes
+   # Try the directory containing this script, then its parent.
+   ac_prog=$0
+   ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
+   test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
+   srcdir=$ac_confdir
+   if test ! -r $srcdir/$ac_unique_file; then
+     srcdir=..
+   fi
+ else
+   ac_srcdir_defaulted=no
+ fi
+ if test ! -r $srcdir/$ac_unique_file; then
+   if test "$ac_srcdir_defaulted" = yes; then
+     { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; }
+   else
+     { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; }
+   fi
+ fi
+ srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`
+ 
+ # Prefer explicitly selected file to automatically selected ones.
+ if test -z "$CONFIG_SITE"; then
+   if test "x$prefix" != xNONE; then
+     CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+   else
+     CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+   fi
+ fi
+ for ac_site_file in $CONFIG_SITE; do
+   if test -r "$ac_site_file"; then
+     echo "loading site script $ac_site_file"
+     . "$ac_site_file"
+   fi
+ done
+ 
+ if test -r "$cache_file"; then
+   echo "loading cache $cache_file"
+   . $cache_file
+ else
+   echo "creating cache $cache_file"
+   > $cache_file
+ fi
+ 
+ ac_ext=c
+ # CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ ac_cpp='$CPP $CPPFLAGS'
+ ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+ cross_compiling=$ac_cv_prog_cc_cross
+ 
+ if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
+   # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
+   if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
+     ac_n= ac_c='
+ ' ac_t='	'
+   else
+     ac_n=-n ac_c= ac_t=
+   fi
+ else
+   ac_n= ac_c='\c' ac_t=
+ fi
+ 
+ 
+ # From configure.in 1.2
+ 
+ # Extract the first word of "gcc", so it can be a program name with args.
+ set dummy gcc; ac_word=$2
+ echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+ echo "configure:528: checking for $ac_word" >&5
+ if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+   echo $ac_n "(cached) $ac_c" 1>&6
+ else
+   if test -n "$CC"; then
+   ac_cv_prog_CC="$CC" # Let the user override the test.
+ else
+   IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+   for ac_dir in $PATH; do
+     test -z "$ac_dir" && ac_dir=.
+     if test -f $ac_dir/$ac_word; then
+       ac_cv_prog_CC="gcc"
+       break
+     fi
+   done
+   IFS="$ac_save_ifs"
+ fi
+ fi
+ CC="$ac_cv_prog_CC"
+ if test -n "$CC"; then
+   echo "$ac_t""$CC" 1>&6
+ else
+   echo "$ac_t""no" 1>&6
+ fi
+ 
+ if test -z "$CC"; then
+   # Extract the first word of "cc", so it can be a program name with args.
+ set dummy cc; ac_word=$2
+ echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+ echo "configure:557: checking for $ac_word" >&5
+ if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+   echo $ac_n "(cached) $ac_c" 1>&6
+ else
+   if test -n "$CC"; then
+   ac_cv_prog_CC="$CC" # Let the user override the test.
+ else
+   IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+   ac_prog_rejected=no
+   for ac_dir in $PATH; do
+     test -z "$ac_dir" && ac_dir=.
+     if test -f $ac_dir/$ac_word; then
+       if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then
+         ac_prog_rejected=yes
+ 	continue
+       fi
+       ac_cv_prog_CC="cc"
+       break
+     fi
+   done
+   IFS="$ac_save_ifs"
+ if test $ac_prog_rejected = yes; then
+   # We found a bogon in the path, so make sure we never use it.
+   set dummy $ac_cv_prog_CC
+   shift
+   if test $# -gt 0; then
+     # We chose a different compiler from the bogus one.
+     # However, it has the same basename, so the bogon will be chosen
+     # first if we set CC to just the basename; use the full file name.
+     shift
+     set dummy "$ac_dir/$ac_word" "$@"
+     shift
+     ac_cv_prog_CC="$@"
+   fi
+ fi
+ fi
+ fi
+ CC="$ac_cv_prog_CC"
+ if test -n "$CC"; then
+   echo "$ac_t""$CC" 1>&6
+ else
+   echo "$ac_t""no" 1>&6
+ fi
+ 
+   test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; }
+ fi
+ 
+ echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
+ echo "configure:605: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
+ 
+ ac_ext=c
+ # CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ ac_cpp='$CPP $CPPFLAGS'
+ ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+ cross_compiling=$ac_cv_prog_cc_cross
+ 
+ cat > conftest.$ac_ext <<EOF
+ #line 615 "configure"
+ #include "confdefs.h"
+ main(){return(0);}
+ EOF
+ if { (eval echo configure:619: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+   ac_cv_prog_cc_works=yes
+   # If we can't run a trivial program, we are probably using a cross compiler.
+   if (./conftest; exit) 2>/dev/null; then
+     ac_cv_prog_cc_cross=no
+   else
+     ac_cv_prog_cc_cross=yes
+   fi
+ else
+   echo "configure: failed program was:" >&5
+   cat conftest.$ac_ext >&5
+   ac_cv_prog_cc_works=no
+ fi
+ rm -fr conftest*
+ 
+ echo "$ac_t""$ac_cv_prog_cc_works" 1>&6
+ if test $ac_cv_prog_cc_works = no; then
+   { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
+ fi
+ echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
+ echo "configure:639: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
+ echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
+ cross_compiling=$ac_cv_prog_cc_cross
+ 
+ echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
+ echo "configure:644: checking whether we are using GNU C" >&5
+ if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
+   echo $ac_n "(cached) $ac_c" 1>&6
+ else
+   cat > conftest.c <<EOF
+ #ifdef __GNUC__
+   yes;
+ #endif
+ EOF
+ if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:653: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+   ac_cv_prog_gcc=yes
+ else
+   ac_cv_prog_gcc=no
+ fi
+ fi
+ 
+ echo "$ac_t""$ac_cv_prog_gcc" 1>&6
+ 
+ if test $ac_cv_prog_gcc = yes; then
+   GCC=yes
+   ac_test_CFLAGS="${CFLAGS+set}"
+   ac_save_CFLAGS="$CFLAGS"
+   CFLAGS=
+   echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
+ echo "configure:668: checking whether ${CC-cc} accepts -g" >&5
+ if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
+   echo $ac_n "(cached) $ac_c" 1>&6
+ else
+   echo 'void f(){}' > conftest.c
+ if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then
+   ac_cv_prog_cc_g=yes
+ else
+   ac_cv_prog_cc_g=no
+ fi
+ rm -f conftest*
+ 
+ fi
+ 
+ echo "$ac_t""$ac_cv_prog_cc_g" 1>&6
+   if test "$ac_test_CFLAGS" = set; then
+     CFLAGS="$ac_save_CFLAGS"
+   elif test $ac_cv_prog_cc_g = yes; then
+     CFLAGS="-g -O2"
+   else
+     CFLAGS="-O2"
+   fi
+ else
+   GCC=
+   test "${CFLAGS+set}" = set || CFLAGS="-g"
+ fi
+ 
+ ac_aux_dir=
+ for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+   if test -f $ac_dir/install-sh; then
+     ac_aux_dir=$ac_dir
+     ac_install_sh="$ac_aux_dir/install-sh -c"
+     break
+   elif test -f $ac_dir/install.sh; then
+     ac_aux_dir=$ac_dir
+     ac_install_sh="$ac_aux_dir/install.sh -c"
+     break
+   fi
+ done
+ if test -z "$ac_aux_dir"; then
+   { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; }
+ fi
+ ac_config_guess=$ac_aux_dir/config.guess
+ ac_config_sub=$ac_aux_dir/config.sub
+ ac_configure=$ac_aux_dir/configure # This should be Cygnus configure.
+ 
+ # Find a good install program.  We prefer a C program (faster),
+ # so one script is as good as another.  But avoid the broken or
+ # incompatible versions:
+ # SysV /etc/install, /usr/sbin/install
+ # SunOS /usr/etc/install
+ # IRIX /sbin/install
+ # AIX /bin/install
+ # AFS /usr/afsws/bin/install, which mishandles nonexistent args
+ # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+ # ./install, which can be erroneously created by make from ./install.sh.
+ echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
+ echo "configure:725: checking for a BSD compatible install" >&5
+ if test -z "$INSTALL"; then
+ if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
+   echo $ac_n "(cached) $ac_c" 1>&6
+ else
+     IFS="${IFS= 	}"; ac_save_IFS="$IFS"; IFS="${IFS}:"
+   for ac_dir in $PATH; do
+     # Account for people who put trailing slashes in PATH elements.
+     case "$ac_dir/" in
+     /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
+     *)
+       # OSF1 and SCO ODT 3.0 have their own names for install.
+       for ac_prog in ginstall installbsd scoinst install; do
+         if test -f $ac_dir/$ac_prog; then
+ 	  if test $ac_prog = install &&
+             grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
+ 	    # AIX install.  It has an incompatible calling convention.
+ 	    # OSF/1 installbsd also uses dspmsg, but is usable.
+ 	    :
+ 	  else
+ 	    ac_cv_path_install="$ac_dir/$ac_prog -c"
+ 	    break 2
+ 	  fi
+ 	fi
+       done
+       ;;
+     esac
+   done
+   IFS="$ac_save_IFS"
+ 
+ fi
+   if test "${ac_cv_path_install+set}" = set; then
+     INSTALL="$ac_cv_path_install"
+   else
+     # As a last resort, use the slow shell script.  We don't cache a
+     # path for INSTALL within a source directory, because that will
+     # break other packages using the cache if that directory is
+     # removed, or if the path is relative.
+     INSTALL="$ac_install_sh"
+   fi
+ fi
+ echo "$ac_t""$INSTALL" 1>&6
+ 
+ # Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+ # It thinks the first close brace ends the variable substitution.
+ test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+ 
+ test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+ 
+ 
+ echo $ac_n "checking for log in -lm""... $ac_c" 1>&6
+ echo "configure:776: checking for log in -lm" >&5
+ ac_lib_var=`echo m'_'log | sed 'y%./+-%__p_%'`
+ if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+   echo $ac_n "(cached) $ac_c" 1>&6
+ else
+   ac_save_LIBS="$LIBS"
+ LIBS="-lm  $LIBS"
+ cat > conftest.$ac_ext <<EOF
+ #line 784 "configure"
+ #include "confdefs.h"
+ /* Override any gcc2 internal prototype to avoid an error.  */
+ /* We use char because int might match the return type of a gcc2
+     builtin and then its argument prototype would still apply.  */
+ char log();
+ 
+ int main() {
+ log()
+ ; return 0; }
+ EOF
+ if { (eval echo configure:795: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+   rm -rf conftest*
+   eval "ac_cv_lib_$ac_lib_var=yes"
+ else
+   echo "configure: failed program was:" >&5
+   cat conftest.$ac_ext >&5
+   rm -rf conftest*
+   eval "ac_cv_lib_$ac_lib_var=no"
+ fi
+ rm -f conftest*
+ LIBS="$ac_save_LIBS"
+ 
+ fi
+ if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+   echo "$ac_t""yes" 1>&6
+     ac_tr_lib=HAVE_LIB`echo m | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+     -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+   cat >> confdefs.h <<EOF
+ #define $ac_tr_lib 1
+ EOF
+ 
+   LIBS="-lm $LIBS"
+ 
+ else
+   echo "$ac_t""no" 1>&6
+ fi
+ 
+ 
+ ac_header_dirent=no
+ for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h
+ do
+ ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+ echo $ac_n "checking for $ac_hdr that defines DIR""... $ac_c" 1>&6
+ echo "configure:828: checking for $ac_hdr that defines DIR" >&5
+ if eval "test \"`echo '$''{'ac_cv_header_dirent_$ac_safe'+set}'`\" = set"; then
+   echo $ac_n "(cached) $ac_c" 1>&6
+ else
+   cat > conftest.$ac_ext <<EOF
+ #line 833 "configure"
+ #include "confdefs.h"
+ #include <sys/types.h>
+ #include <$ac_hdr>
+ int main() {
+ DIR *dirp = 0;
+ ; return 0; }
+ EOF
+ if { (eval echo configure:841: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+   rm -rf conftest*
+   eval "ac_cv_header_dirent_$ac_safe=yes"
+ else
+   echo "configure: failed program was:" >&5
+   cat conftest.$ac_ext >&5
+   rm -rf conftest*
+   eval "ac_cv_header_dirent_$ac_safe=no"
+ fi
+ rm -f conftest*
+ fi
+ if eval "test \"`echo '$ac_cv_header_dirent_'$ac_safe`\" = yes"; then
+   echo "$ac_t""yes" 1>&6
+     ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+   cat >> confdefs.h <<EOF
+ #define $ac_tr_hdr 1
+ EOF
+  ac_header_dirent=$ac_hdr; break
+ else
+   echo "$ac_t""no" 1>&6
+ fi
+ done
+ # Two versions of opendir et al. are in -ldir and -lx on SCO Xenix.
+ if test $ac_header_dirent = dirent.h; then
+ echo $ac_n "checking for opendir in -ldir""... $ac_c" 1>&6
+ echo "configure:866: checking for opendir in -ldir" >&5
+ ac_lib_var=`echo dir'_'opendir | sed 'y%./+-%__p_%'`
+ if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+   echo $ac_n "(cached) $ac_c" 1>&6
+ else
+   ac_save_LIBS="$LIBS"
+ LIBS="-ldir  $LIBS"
+ cat > conftest.$ac_ext <<EOF
+ #line 874 "configure"
+ #include "confdefs.h"
+ /* Override any gcc2 internal prototype to avoid an error.  */
+ /* We use char because int might match the return type of a gcc2
+     builtin and then its argument prototype would still apply.  */
+ char opendir();
+ 
+ int main() {
+ opendir()
+ ; return 0; }
+ EOF
+ if { (eval echo configure:885: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+   rm -rf conftest*
+   eval "ac_cv_lib_$ac_lib_var=yes"
+ else
+   echo "configure: failed program was:" >&5
+   cat conftest.$ac_ext >&5
+   rm -rf conftest*
+   eval "ac_cv_lib_$ac_lib_var=no"
+ fi
+ rm -f conftest*
+ LIBS="$ac_save_LIBS"
+ 
+ fi
+ if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+   echo "$ac_t""yes" 1>&6
+   LIBS="$LIBS -ldir"
+ else
+   echo "$ac_t""no" 1>&6
+ fi
+ 
+ else
+ echo $ac_n "checking for opendir in -lx""... $ac_c" 1>&6
+ echo "configure:907: checking for opendir in -lx" >&5
+ ac_lib_var=`echo x'_'opendir | sed 'y%./+-%__p_%'`
+ if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+   echo $ac_n "(cached) $ac_c" 1>&6
+ else
+   ac_save_LIBS="$LIBS"
+ LIBS="-lx  $LIBS"
+ cat > conftest.$ac_ext <<EOF
+ #line 915 "configure"
+ #include "confdefs.h"
+ /* Override any gcc2 internal prototype to avoid an error.  */
+ /* We use char because int might match the return type of a gcc2
+     builtin and then its argument prototype would still apply.  */
+ char opendir();
+ 
+ int main() {
+ opendir()
+ ; return 0; }
+ EOF
+ if { (eval echo configure:926: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+   rm -rf conftest*
+   eval "ac_cv_lib_$ac_lib_var=yes"
+ else
+   echo "configure: failed program was:" >&5
+   cat conftest.$ac_ext >&5
+   rm -rf conftest*
+   eval "ac_cv_lib_$ac_lib_var=no"
+ fi
+ rm -f conftest*
+ LIBS="$ac_save_LIBS"
+ 
+ fi
+ if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+   echo "$ac_t""yes" 1>&6
+   LIBS="$LIBS -lx"
+ else
+   echo "$ac_t""no" 1>&6
+ fi
+ 
+ fi
+ 
+ echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
+ echo "configure:949: checking how to run the C preprocessor" >&5
+ # On Suns, sometimes $CPP names a directory.
+ if test -n "$CPP" && test -d "$CPP"; then
+   CPP=
+ fi
+ if test -z "$CPP"; then
+ if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then
+   echo $ac_n "(cached) $ac_c" 1>&6
+ else
+     # This must be in double quotes, not single quotes, because CPP may get
+   # substituted into the Makefile and "${CC-cc}" will confuse make.
+   CPP="${CC-cc} -E"
+   # On the NeXT, cc -E runs the code through the compiler's parser,
+   # not just through cpp.
+   cat > conftest.$ac_ext <<EOF
+ #line 964 "configure"
+ #include "confdefs.h"
+ #include <assert.h>
+ Syntax Error
+ EOF
+ ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+ { (eval echo configure:970: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ ac_err=`grep -v '^ *+' conftest.out`
+ if test -z "$ac_err"; then
+   :
+ else
+   echo "$ac_err" >&5
+   echo "configure: failed program was:" >&5
+   cat conftest.$ac_ext >&5
+   rm -rf conftest*
+   CPP="${CC-cc} -E -traditional-cpp"
+   cat > conftest.$ac_ext <<EOF
+ #line 981 "configure"
+ #include "confdefs.h"
+ #include <assert.h>
+ Syntax Error
+ EOF
+ ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+ { (eval echo configure:987: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ ac_err=`grep -v '^ *+' conftest.out`
+ if test -z "$ac_err"; then
+   :
+ else
+   echo "$ac_err" >&5
+   echo "configure: failed program was:" >&5
+   cat conftest.$ac_ext >&5
+   rm -rf conftest*
+   CPP=/lib/cpp
+ fi
+ rm -f conftest*
+ fi
+ rm -f conftest*
+   ac_cv_prog_CPP="$CPP"
+ fi
+   CPP="$ac_cv_prog_CPP"
+ else
+   ac_cv_prog_CPP="$CPP"
+ fi
+ echo "$ac_t""$CPP" 1>&6
+ 
+ echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
+ echo "configure:1010: checking for ANSI C header files" >&5
+ if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
+   echo $ac_n "(cached) $ac_c" 1>&6
+ else
+   cat > conftest.$ac_ext <<EOF
+ #line 1015 "configure"
+ #include "confdefs.h"
+ #include <stdlib.h>
+ #include <stdarg.h>
+ #include <string.h>
+ #include <float.h>
+ EOF
+ ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+ { (eval echo configure:1023: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ ac_err=`grep -v '^ *+' conftest.out`
+ if test -z "$ac_err"; then
+   rm -rf conftest*
+   ac_cv_header_stdc=yes
+ else
+   echo "$ac_err" >&5
+   echo "configure: failed program was:" >&5
+   cat conftest.$ac_ext >&5
+   rm -rf conftest*
+   ac_cv_header_stdc=no
+ fi
+ rm -f conftest*
+ 
+ if test $ac_cv_header_stdc = yes; then
+   # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+ cat > conftest.$ac_ext <<EOF
+ #line 1040 "configure"
+ #include "confdefs.h"
+ #include <string.h>
+ EOF
+ if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+   egrep "memchr" >/dev/null 2>&1; then
+   :
+ else
+   rm -rf conftest*
+   ac_cv_header_stdc=no
+ fi
+ rm -f conftest*
+ 
+ fi
+ 
+ if test $ac_cv_header_stdc = yes; then
+   # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+ cat > conftest.$ac_ext <<EOF
+ #line 1058 "configure"
+ #include "confdefs.h"
+ #include <stdlib.h>
+ EOF
+ if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+   egrep "free" >/dev/null 2>&1; then
+   :
+ else
+   rm -rf conftest*
+   ac_cv_header_stdc=no
+ fi
+ rm -f conftest*
+ 
+ fi
+ 
+ if test $ac_cv_header_stdc = yes; then
+   # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+ if test "$cross_compiling" = yes; then
+   :
+ else
+   cat > conftest.$ac_ext <<EOF
+ #line 1079 "configure"
+ #include "confdefs.h"
+ #include <ctype.h>
+ #define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+ #define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+ #define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+ int main () { int i; for (i = 0; i < 256; i++)
+ if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
+ exit (0); }
+ 
+ EOF
+ if { (eval echo configure:1090: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
+ then
+   :
+ else
+   echo "configure: failed program was:" >&5
+   cat conftest.$ac_ext >&5
+   rm -fr conftest*
+   ac_cv_header_stdc=no
+ fi
+ rm -fr conftest*
+ fi
+ 
+ fi
+ fi
+ 
+ echo "$ac_t""$ac_cv_header_stdc" 1>&6
+ if test $ac_cv_header_stdc = yes; then
+   cat >> confdefs.h <<\EOF
+ #define STDC_HEADERS 1
+ EOF
+ 
+ fi
+ 
+ 
+ echo $ac_n "checking for size_t""... $ac_c" 1>&6
+ echo "configure:1115: checking for size_t" >&5
+ if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then
+   echo $ac_n "(cached) $ac_c" 1>&6
+ else
+   cat > conftest.$ac_ext <<EOF
+ #line 1120 "configure"
+ #include "confdefs.h"
+ #include <sys/types.h>
+ #if STDC_HEADERS
+ #include <stdlib.h>
+ #include <stddef.h>
+ #endif
+ EOF
+ if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+   egrep "size_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+   rm -rf conftest*
+   ac_cv_type_size_t=yes
+ else
+   rm -rf conftest*
+   ac_cv_type_size_t=no
+ fi
+ rm -f conftest*
+ 
+ fi
+ echo "$ac_t""$ac_cv_type_size_t" 1>&6
+ if test $ac_cv_type_size_t = no; then
+   cat >> confdefs.h <<\EOF
+ #define size_t unsigned
+ EOF
+ 
+ fi
+ 
+ echo $ac_n "checking whether struct tm is in sys/time.h or time.h""... $ac_c" 1>&6
+ echo "configure:1148: checking whether struct tm is in sys/time.h or time.h" >&5
+ if eval "test \"`echo '$''{'ac_cv_struct_tm'+set}'`\" = set"; then
+   echo $ac_n "(cached) $ac_c" 1>&6
+ else
+   cat > conftest.$ac_ext <<EOF
+ #line 1153 "configure"
+ #include "confdefs.h"
+ #include <sys/types.h>
+ #include <time.h>
+ int main() {
+ struct tm *tp; tp->tm_sec;
+ ; return 0; }
+ EOF
+ if { (eval echo configure:1161: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+   rm -rf conftest*
+   ac_cv_struct_tm=time.h
+ else
+   echo "configure: failed program was:" >&5
+   cat conftest.$ac_ext >&5
+   rm -rf conftest*
+   ac_cv_struct_tm=sys/time.h
+ fi
+ rm -f conftest*
+ fi
+ 
+ echo "$ac_t""$ac_cv_struct_tm" 1>&6
+ if test $ac_cv_struct_tm = sys/time.h; then
+   cat >> confdefs.h <<\EOF
+ #define TM_IN_SYS_TIME 1
+ EOF
+ 
+ fi
+ 
+ 
+ echo $ac_n "checking for strftime""... $ac_c" 1>&6
+ echo "configure:1183: checking for strftime" >&5
+ if eval "test \"`echo '$''{'ac_cv_func_strftime'+set}'`\" = set"; then
+   echo $ac_n "(cached) $ac_c" 1>&6
+ else
+   cat > conftest.$ac_ext <<EOF
+ #line 1188 "configure"
+ #include "confdefs.h"
+ /* System header to define __stub macros and hopefully few prototypes,
+     which can conflict with char strftime(); below.  */
+ #include <assert.h>
+ /* Override any gcc2 internal prototype to avoid an error.  */
+ /* We use char because int might match the return type of a gcc2
+     builtin and then its argument prototype would still apply.  */
+ char strftime();
+ 
+ int main() {
+ 
+ /* The GNU C library defines this for functions which it implements
+     to always fail with ENOSYS.  Some functions are actually named
+     something starting with __ and the normal name is an alias.  */
+ #if defined (__stub_strftime) || defined (__stub___strftime)
+ choke me
+ #else
+ strftime();
+ #endif
+ 
+ ; return 0; }
+ EOF
+ if { (eval echo configure:1211: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+   rm -rf conftest*
+   eval "ac_cv_func_strftime=yes"
+ else
+   echo "configure: failed program was:" >&5
+   cat conftest.$ac_ext >&5
+   rm -rf conftest*
+   eval "ac_cv_func_strftime=no"
+ fi
+ rm -f conftest*
+ fi
+ 
+ if eval "test \"`echo '$ac_cv_func_'strftime`\" = yes"; then
+   echo "$ac_t""yes" 1>&6
+   cat >> confdefs.h <<\EOF
+ #define HAVE_STRFTIME 1
+ EOF
+ 
+ else
+   echo "$ac_t""no" 1>&6
+ # strftime is in -lintl on SCO UNIX.
+ echo $ac_n "checking for strftime in -lintl""... $ac_c" 1>&6
+ echo "configure:1233: checking for strftime in -lintl" >&5
+ ac_lib_var=`echo intl'_'strftime | sed 'y%./+-%__p_%'`
+ if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+   echo $ac_n "(cached) $ac_c" 1>&6
+ else
+   ac_save_LIBS="$LIBS"
+ LIBS="-lintl  $LIBS"
+ cat > conftest.$ac_ext <<EOF
+ #line 1241 "configure"
+ #include "confdefs.h"
+ /* Override any gcc2 internal prototype to avoid an error.  */
+ /* We use char because int might match the return type of a gcc2
+     builtin and then its argument prototype would still apply.  */
+ char strftime();
+ 
+ int main() {
+ strftime()
+ ; return 0; }
+ EOF
+ if { (eval echo configure:1252: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+   rm -rf conftest*
+   eval "ac_cv_lib_$ac_lib_var=yes"
+ else
+   echo "configure: failed program was:" >&5
+   cat conftest.$ac_ext >&5
+   rm -rf conftest*
+   eval "ac_cv_lib_$ac_lib_var=no"
+ fi
+ rm -f conftest*
+ LIBS="$ac_save_LIBS"
+ 
+ fi
+ if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+   echo "$ac_t""yes" 1>&6
+   cat >> confdefs.h <<\EOF
+ #define HAVE_STRFTIME 1
+ EOF
+ 
+ LIBS="-lintl $LIBS"
+ else
+   echo "$ac_t""no" 1>&6
+ fi
+ 
+ fi
+ 
+ for ac_func in strstr
+ do
+ echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+ echo "configure:1281: checking for $ac_func" >&5
+ if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+   echo $ac_n "(cached) $ac_c" 1>&6
+ else
+   cat > conftest.$ac_ext <<EOF
+ #line 1286 "configure"
+ #include "confdefs.h"
+ /* System header to define __stub macros and hopefully few prototypes,
+     which can conflict with char $ac_func(); below.  */
+ #include <assert.h>
+ /* Override any gcc2 internal prototype to avoid an error.  */
+ /* We use char because int might match the return type of a gcc2
+     builtin and then its argument prototype would still apply.  */
+ char $ac_func();
+ 
+ int main() {
+ 
+ /* The GNU C library defines this for functions which it implements
+     to always fail with ENOSYS.  Some functions are actually named
+     something starting with __ and the normal name is an alias.  */
+ #if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+ choke me
+ #else
+ $ac_func();
+ #endif
+ 
+ ; return 0; }
+ EOF
+ if { (eval echo configure:1309: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+   rm -rf conftest*
+   eval "ac_cv_func_$ac_func=yes"
+ else
+   echo "configure: failed program was:" >&5
+   cat conftest.$ac_ext >&5
+   rm -rf conftest*
+   eval "ac_cv_func_$ac_func=no"
+ fi
+ rm -f conftest*
+ fi
+ 
+ if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+   echo "$ac_t""yes" 1>&6
+     ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+   cat >> confdefs.h <<EOF
+ #define $ac_tr_func 1
+ EOF
+  
+ else
+   echo "$ac_t""no" 1>&6
+ fi
+ done
+ 
+ 
+ trap '' 1 2 15
+ cat > confcache <<\EOF
+ # This file is a shell script that caches the results of configure
+ # tests run on this system so they can be shared between configure
+ # scripts and configure runs.  It is not useful on other systems.
+ # If it contains results you don't want to keep, you may remove or edit it.
+ #
+ # By default, configure uses ./config.cache as the cache file,
+ # creating it if it does not exist already.  You can give configure
+ # the --cache-file=FILE option to use a different cache file; that is
+ # what configure does when it calls configure scripts in
+ # subdirectories, so they share the cache.
+ # Giving --cache-file=/dev/null disables caching, for debugging configure.
+ # config.status only pays attention to the cache file if you give it the
+ # --recheck option to rerun configure.
+ #
+ EOF
+ # The following way of writing the cache mishandles newlines in values,
+ # but we know of no workaround that is simple, portable, and efficient.
+ # So, don't put newlines in cache variables' values.
+ # Ultrix sh set writes to stderr and can't be redirected directly,
+ # and sets the high bit in the cache file unless we assign to the vars.
+ (set) 2>&1 |
+   case `(ac_space=' '; set) 2>&1` in
+   *ac_space=\ *)
+     # `set' does not quote correctly, so add quotes (double-quote substitution
+     # turns \\\\ into \\, and sed turns \\ into \).
+     sed -n \
+       -e "s/'/'\\\\''/g" \
+       -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p"
+     ;;
+   *)
+     # `set' quotes correctly as required by POSIX, so do not add quotes.
+     sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p'
+     ;;
+   esac >> confcache
+ if cmp -s $cache_file confcache; then
+   :
+ else
+   if test -w $cache_file; then
+     echo "updating cache $cache_file"
+     cat confcache > $cache_file
+   else
+     echo "not updating unwritable cache $cache_file"
+   fi
+ fi
+ rm -f confcache
+ 
+ trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+ 
+ test "x$prefix" = xNONE && prefix=$ac_default_prefix
+ # Let make expand exec_prefix.
+ test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+ 
+ # Any assignment to VPATH causes Sun make to only execute
+ # the first set of double-colon rules, so remove it if not needed.
+ # If there is a colon in the path, we need to keep it.
+ if test "x$srcdir" = x.; then
+   ac_vpsub='/^[ 	]*VPATH[ 	]*=[^:]*$/d'
+ fi
+ 
+ trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
+ 
+ # Transform confdefs.h into DEFS.
+ # Protect against shell expansion while executing Makefile rules.
+ # Protect against Makefile macro expansion.
+ cat > conftest.defs <<\EOF
+ s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%-D\1=\2%g
+ s%[ 	`~#$^&*(){}\\|;'"<>?]%\\&%g
+ s%\[%\\&%g
+ s%\]%\\&%g
+ s%\$%$$%g
+ EOF
+ DEFS=`sed -f conftest.defs confdefs.h | tr '\012' ' '`
+ rm -f conftest.defs
+ 
+ 
+ # Without the "./", some shells look in PATH for config.status.
+ : ${CONFIG_STATUS=./config.status}
+ 
+ echo creating $CONFIG_STATUS
+ rm -f $CONFIG_STATUS
+ cat > $CONFIG_STATUS <<EOF
+ #! /bin/sh
+ # Generated automatically by configure.
+ # Run this file to recreate the current configuration.
+ # This directory was configured as follows,
+ # on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+ #
+ # $0 $ac_configure_args
+ #
+ # Compiler output produced by configure, useful for debugging
+ # configure, is in ./config.log if it exists.
+ 
+ ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]"
+ for ac_option
+ do
+   case "\$ac_option" in
+   -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+     echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
+     exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
+   -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
+     echo "$CONFIG_STATUS generated by autoconf version 2.12"
+     exit 0 ;;
+   -help | --help | --hel | --he | --h)
+     echo "\$ac_cs_usage"; exit 0 ;;
+   *) echo "\$ac_cs_usage"; exit 1 ;;
+   esac
+ done
+ 
+ ac_given_srcdir=$srcdir
+ ac_given_INSTALL="$INSTALL"
+ 
+ trap 'rm -fr `echo "Makefile" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
+ EOF
+ cat >> $CONFIG_STATUS <<EOF
+ 
+ # Protect against being on the right side of a sed subst in config.status.
+ sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g;
+  s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF
+ $ac_vpsub
+ $extrasub
+ s%@CFLAGS@%$CFLAGS%g
+ s%@CPPFLAGS@%$CPPFLAGS%g
+ s%@CXXFLAGS@%$CXXFLAGS%g
+ s%@DEFS@%$DEFS%g
+ s%@LDFLAGS@%$LDFLAGS%g
+ s%@LIBS@%$LIBS%g
+ s%@exec_prefix@%$exec_prefix%g
+ s%@prefix@%$prefix%g
+ s%@program_transform_name@%$program_transform_name%g
+ s%@bindir@%$bindir%g
+ s%@sbindir@%$sbindir%g
+ s%@libexecdir@%$libexecdir%g
+ s%@datadir@%$datadir%g
+ s%@sysconfdir@%$sysconfdir%g
+ s%@sharedstatedir@%$sharedstatedir%g
+ s%@localstatedir@%$localstatedir%g
+ s%@libdir@%$libdir%g
+ s%@includedir@%$includedir%g
+ s%@oldincludedir@%$oldincludedir%g
+ s%@infodir@%$infodir%g
+ s%@mandir@%$mandir%g
+ s%@CC@%$CC%g
+ s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g
+ s%@INSTALL_DATA@%$INSTALL_DATA%g
+ s%@CPP@%$CPP%g
+ 
+ CEOF
+ EOF
+ 
+ cat >> $CONFIG_STATUS <<\EOF
+ 
+ # Split the substitutions into bite-sized pieces for seds with
+ # small command number limits, like on Digital OSF/1 and HP-UX.
+ ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script.
+ ac_file=1 # Number of current file.
+ ac_beg=1 # First line for current file.
+ ac_end=$ac_max_sed_cmds # Line after last line for current file.
+ ac_more_lines=:
+ ac_sed_cmds=""
+ while $ac_more_lines; do
+   if test $ac_beg -gt 1; then
+     sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file
+   else
+     sed "${ac_end}q" conftest.subs > conftest.s$ac_file
+   fi
+   if test ! -s conftest.s$ac_file; then
+     ac_more_lines=false
+     rm -f conftest.s$ac_file
+   else
+     if test -z "$ac_sed_cmds"; then
+       ac_sed_cmds="sed -f conftest.s$ac_file"
+     else
+       ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file"
+     fi
+     ac_file=`expr $ac_file + 1`
+     ac_beg=$ac_end
+     ac_end=`expr $ac_end + $ac_max_sed_cmds`
+   fi
+ done
+ if test -z "$ac_sed_cmds"; then
+   ac_sed_cmds=cat
+ fi
+ EOF
+ 
+ cat >> $CONFIG_STATUS <<EOF
+ 
+ CONFIG_FILES=\${CONFIG_FILES-"Makefile"}
+ EOF
+ cat >> $CONFIG_STATUS <<\EOF
+ for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
+   # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+   case "$ac_file" in
+   *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+        ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+   *) ac_file_in="${ac_file}.in" ;;
+   esac
+ 
+   # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories.
+ 
+   # Remove last slash and all that follows it.  Not all systems have dirname.
+   ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+   if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+     # The file is in a subdirectory.
+     test ! -d "$ac_dir" && mkdir "$ac_dir"
+     ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
+     # A "../" for each directory in $ac_dir_suffix.
+     ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
+   else
+     ac_dir_suffix= ac_dots=
+   fi
+ 
+   case "$ac_given_srcdir" in
+   .)  srcdir=.
+       if test -z "$ac_dots"; then top_srcdir=.
+       else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
+   /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
+   *) # Relative path.
+     srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
+     top_srcdir="$ac_dots$ac_given_srcdir" ;;
+   esac
+ 
+   case "$ac_given_INSTALL" in
+   [/$]*) INSTALL="$ac_given_INSTALL" ;;
+   *) INSTALL="$ac_dots$ac_given_INSTALL" ;;
+   esac
+ 
+   echo creating "$ac_file"
+   rm -f "$ac_file"
+   configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
+   case "$ac_file" in
+   *Makefile*) ac_comsub="1i\\
+ # $configure_input" ;;
+   *) ac_comsub= ;;
+   esac
+ 
+   ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+   sed -e "$ac_comsub
+ s%@configure_input@%$configure_input%g
+ s%@srcdir@%$srcdir%g
+ s%@top_srcdir@%$top_srcdir%g
+ s%@INSTALL@%$INSTALL%g
+ " $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file
+ fi; done
+ rm -f conftest.s*
+ 
+ EOF
+ cat >> $CONFIG_STATUS <<EOF
+ 
+ EOF
+ cat >> $CONFIG_STATUS <<\EOF
+ 
+ exit 0
+ EOF
+ chmod +x $CONFIG_STATUS
+ rm -fr confdefs* $ac_clean_files
+ test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
+ 
+ 
+ 
Index: harvest/components/broker/swish/configure.in
diff -c /dev/null harvest/components/broker/swish/configure.in:1.1
*** /dev/null	Mon Oct 27 18:40:53 1997
--- harvest/components/broker/swish/configure.in	Mon Oct 27 16:13:52 1997
***************
*** 0 ****
--- 1,34 ----
+ dnl
+ dnl  Configuration input file for Harvest version of SWISH
+ dnl
+ dnl  configure.in,v 1.1 1997/10/27 21:13:52 sxw Exp
+ dnl
+ 
+ AC_PREREQ(2.12)
+ 
+ AC_INIT(swish_config.h)
+ AC_REVISION(1.2)dnl
+ AC_PREFIX_DEFAULT(/usr/local/harvest)
+ 
+ dnl Check for programs
+ AC_PROG_CC
+ AC_PROG_INSTALL
+ 
+ dnl Checks for libraries.
+ AC_CHECK_LIB(m, log)
+ 
+ dnl Checks for header files.
+ AC_HEADER_DIRENT
+ AC_HEADER_STDC
+ 
+ dnl Checks for typedefs, structures, and compiler characteristics.
+ AC_TYPE_SIZE_T
+ AC_STRUCT_TM
+ 
+ dnl Checks for library functions.
+ AC_FUNC_STRFTIME
+ AC_CHECK_FUNCS(strstr)
+ 
+ AC_OUTPUT(Makefile)
+ 
+ 
Index: harvest/components/broker/swish/error.c
diff -c /dev/null harvest/components/broker/swish/error.c:1.1
*** /dev/null	Mon Oct 27 18:40:53 1997
--- harvest/components/broker/swish/error.c	Sun Oct 12 16:32:55 1997
***************
*** 0 ****
--- 1,19 ----
+ /*
+ ** Copyright (C) 1995, Enterprise Integration Technologies Corp.        
+ ** All Rights Reserved.
+ ** Kevin Hughes, kevinh@eit.com 
+ ** 3/11/94
+ */
+ 
+ #include "swish.h"
+ #include "error.h"
+ 
+ /* Whoops, something bad happened...
+ */
+ 
+ void progerr(errstring)
+      char *errstring;
+ {
+         fprintf(stderr, "swish: %s\n", errstring);
+         exit(-1);
+ }
Index: harvest/components/broker/swish/error.h
diff -c /dev/null harvest/components/broker/swish/error.h:1.1
*** /dev/null	Mon Oct 27 18:40:53 1997
--- harvest/components/broker/swish/error.h	Sun Oct 12 16:32:56 1997
***************
*** 0 ****
--- 1,8 ----
+ /*
+ ** Copyright (C) 1995, Enterprise Integration Technologies Corp.        
+ ** All Rights Reserved.
+ ** Kevin Hughes, kevinh@eit.com 
+ ** 3/11/94
+ */
+ 
+ void progerr();
Index: harvest/components/broker/swish/file.c
diff -c /dev/null harvest/components/broker/swish/file.c:1.2
*** /dev/null	Mon Oct 27 18:40:54 1997
--- harvest/components/broker/swish/file.c	Mon Oct 27 16:13:53 1997
***************
*** 0 ****
--- 1,350 ----
+ /*
+ ** Copyright (C) 1995, Enterprise Integration Technologies Corp.        
+ ** All Rights Reserved.
+ ** Kevin Hughes, kevinh@eit.com 
+ ** 3/11/94
+ **
+ ** Released under the GPL by EIT in October 1997
+ **
+ ** Heavily modified for Harvest by Simon Wilkinson
+ */
+ 
+ #include "swish.h"
+ #include "file.h"
+ 
+ /* Is a file a directory?
+ */
+ 
+ int isdirectory(path)
+      char *path;
+ {
+         struct stat stbuf;
+ 
+         if (stat(path, &stbuf))
+                 return 0;
+         return ((stbuf.st_mode & S_IFMT) == S_IFDIR) ? 1 : 0;
+ }
+ 
+ /* Is a file a regular file?
+ */
+ 
+ int isfile(path)
+      char *path;
+ {
+         struct stat stbuf;
+ 
+         if (stat(path, &stbuf))
+                 return 0;
+         return ((stbuf.st_mode & S_IFMT) == S_IFREG) ? 1 : 0;
+ }
+ 
+ /* Get the size, in bytes, of a file.
+ ** Return -1 if there's a problem.
+ */
+ 
+ int getsize(path)
+      char *path;
+ {
+         struct stat stbuf;
+ 
+         if (stat(path, &stbuf))
+                 return -1;
+         return stbuf.st_size;
+ }
+ 
+ /* Add an entry to the metaEntryList with the given value and the
+ ** appropriate index
+ */
+ 
+ struct metaEntry* addMetaEntry(metaList, metaWord)
+      struct metaEntry* metaList;
+      char* metaWord;
+ {
+   static int counter;
+   int i;
+   struct metaEntry* newEntry;
+   struct metaEntry* tmpEntry;
+ 
+   if (counter == 0)
+     counter = 2;
+   else if (counter == 1 ||  (!counter % 128) )
+     counter++;
+   for( i=0; metaWord[i]; i++)
+     metaWord[i] =  tolower(metaWord[i]);
+   newEntry = (struct metaEntry*) emalloc(sizeof(struct metaEntry));
+   newEntry->metaName = (char*)mystrdup(metaWord);
+   newEntry->index = counter++;
+   newEntry->next = NULL;
+   if (metaEntryList)
+     {
+       for(tmpEntry=metaEntryList;tmpEntry->next!=NULL;tmpEntry=tmpEntry->next)
+ 	;
+       tmpEntry->next = newEntry;
+     }
+   else
+     metaEntryList = newEntry;
+ 
+   return metaEntryList;
+ }
+ 
+ /* Reads the configuration file and puts all the right options
+ ** in the right variables and structures.
+ */
+ 
+ void getdefaults(conffile, hasdir, hasindex, plimit, flimit, hasverbose)
+      char *conffile;
+      int *hasdir;
+      int *hasindex;
+      int *plimit;
+      int *flimit;
+      int hasverbose;
+ {
+         int skiplen, gotdir, gotindex;
+         char *c, line[MAXSTRLEN], value[MAXSTRLEN];
+         FILE *fp;
+ 
+ 	gotdir = gotindex = 0;
+ 
+         if ((fp = fopen(conffile, "r")) == NULL  ||
+              !isfile(conffile) ) {
+ 		sprintf(errorstr,
+ 		"Couldn't open the configuration file \"%s\".", conffile);
+                 progerr(errorstr);
+ 	}
+         while (fgets(line, MAXSTRLEN, fp) != NULL) {
+                 if (line[0] == '#' || line[0] == '\n')
+                         continue;
+                 if (c = (char *) lstrstr(line, "IndexDir")) {
+                         c += strlen("IndexDir");
+                         while (!*hasdir) {
+                                 strcpy(value, (char *) getword(c, &skiplen));
+                                 if (!skiplen | value[0] == '\0' ||
+                                 value[0] == '\n')
+                                         break;
+                                 else {
+                                         c += skiplen;
+                                         dirlist = (struct swline *)
+                                         addswline(dirlist, value);
+ 					gotdir = 1;
+                                 }
+                         }
+                 }
+                 else if (c = (char *) lstrstr(line, "IndexFile")) {
+                         c += strlen("IndexFile");
+                         while (!*hasindex) {
+                                 strcpy(value, (char *) getword(c, &skiplen));
+                                 if (!skiplen | value[0] == '\0' ||
+                                 value[0] == '\n')
+                                         break;
+                                 else {
+                                         c += skiplen;
+                                         indexlist = (struct swline *)
+                                         addswline(indexlist, value);
+ 					gotindex = 1;
+                                 }
+                         }
+                 }
+ /* IndexVerbose is supported for backwards compatibility */
+ 		else if (c = (char *) lstrstr(line, "IndexVerbose")) {
+                         c += strlen("IndexVerbose");
+                         strcpy(value, (char *) getword(c, &skiplen));
+ 			verbose = (lstrstr(value, "yes")) ? 3 : 0;
+ 		}
+ 		else if (c = (char *) lstrstr(line, "IndexReport")) {
+                         c += strlen("IndexReport");
+                         strcpy(value, (char *) getword(c, &skiplen));
+                         if (!skiplen | value[0] == '\0' || value[0] == '\n')
+                                 continue;
+                         else {
+                                 c += skiplen;
+ 				if (!hasverbose)
+ 					verbose = atoi(value);
+                         }
+ 		}
+                 else if (c = (char *) lstrstr(line, "IndexOnly")) {
+                         c += strlen("IndexOnly");
+                         while (1) {
+                                 strcpy(value, (char *) getword(c, &skiplen));
+                                 if (!skiplen | value[0] == '\0' ||
+                                 value[0] == '\n')
+                                         break;
+                                 else {
+                                         c += skiplen;
+                                         suffixlist = (struct swline *)
+                                         addswline(suffixlist, value);
+                                 }
+                         }
+                 }
+                 else if (c = (char *) lstrstr(line, "NoContents")) {
+                         c += strlen("NoContents");
+                         while (1) {
+                                 strcpy(value, (char *) getword(c, &skiplen));
+                                 if (!skiplen | value[0] == '\0' ||
+                                 value[0] == '\n')
+                                         break;
+                                 else {
+                                         c += skiplen;
+                                         nocontentslist = (struct swline *)
+                                         addswline(nocontentslist, value);
+                                 }
+                         }
+                 }
+                 else if (c = (char *) lstrstr(line, "MetaNames")) {
+                         c += strlen("MetaNames");
+                         while (1) {
+                                 strcpy(value, (char *) getword(c, &skiplen));
+                                 if (!skiplen | value[0] == '\0' ||
+                                 value[0] == '\n')
+                                         break;
+                                 else {
+                                         c += skiplen;
+                                         metaEntryList = (struct metaEntry *)
+                                         addMetaEntry(metaEntryList, value);
+ 				      }
+ 			      }
+ 		      }
+                 else if ((c = (char *) lstrstr(line, "pathname contains")) &&
+ 		(char *) lstrstr(line, "FileRules")) {
+                         c += strlen("pathname contains");
+                         while (1) {
+                                 strcpy(value, (char *) getword(c, &skiplen));
+                                 if (!skiplen | value[0] == '\0' ||
+                                 value[0] == '\n')
+                                         break;
+                                 else {
+                                         c += skiplen;
+                                         pathconlist = (struct swline *)
+                                         addswline(pathconlist, value);
+                                 }
+                         }
+                 }
+                 else if ((c = (char *) lstrstr(line, "directory contains")) &&
+ 		(char *) lstrstr(line, "FileRules")) {
+                         c += strlen("directory contains");
+                         while (1) {
+                                 strcpy(value, (char *) getword(c, &skiplen));
+                                 if (!skiplen | value[0] == '\0' ||
+                                 value[0] == '\n')
+                                         break;
+                                 else {
+                                         c += skiplen;
+                                         dirconlist = (struct swline *)
+                                         addswline(dirconlist, value);
+                                 }
+                         }
+                 }
+                 else if ((c = (char *) lstrstr(line, "filename contains")) &&
+ 		(char *) lstrstr(line, "FileRules")) {
+                         c += strlen("filename contains");
+                         while (1) {
+                                 strcpy(value, (char *) getword(c, &skiplen));
+                                 if (!skiplen | value[0] == '\0' ||
+                                 value[0] == '\n')
+                                         break;
+                                 else {
+                                         c += skiplen;
+                                         fileconlist = (struct swline *)
+                                         addswline(fileconlist, value);
+                                 }
+                         }
+                 }
+                 else if ((c = (char *) lstrstr(line, "title contains")) &&
+ 		(char *) lstrstr(line, "FileRules")) {
+                         c += strlen("title contains");
+                         while (1) {
+                                 strcpy(value, (char *) getword(c, &skiplen));
+                                 if (!skiplen | value[0] == '\0' ||
+                                 value[0] == '\n')
+                                         break;
+                                 else {
+                                         c += skiplen;
+                                         titconlist = (struct swline *)
+                                         addswline(titconlist, value);
+                                 }
+                         }
+                 }
+                 else if ((c = (char *) lstrstr(line, "filename is")) &&
+ 		(char *) lstrstr(line, "FileRules")) {
+                         c += strlen("filename is");
+                         while (1) {
+                                 strcpy(value, (char *) getword(c, &skiplen));
+                                 if (!skiplen | value[0] == '\0' ||
+                                 value[0] == '\n')
+                                         break;
+                                 else {
+                                         c += skiplen;
+                                         fileislist = (struct swline *)
+                                         addswline(fileislist, value);
+                                 }
+                         }
+                 }
+                 else if (c = (char *) lstrstr(line, "IgnoreWords")) {
+                         c += strlen("IgnoreWords");
+                         while (1) {
+                                 strcpy(value, (char *) getword(c, &skiplen));
+                                 if (!skiplen | value[0] == '\0' ||
+                                 value[0] == '\n')
+                                         break;
+                                 else {
+                                         c += skiplen;
+ 					if (lstrstr(value, "SwishDefault"))
+ 						readdefaultstopwords();
+ 					else
+ 						addstophash(value);
+                                 }
+                         }
+                 }
+                 else if ((c = (char *) lstrstr(line, "IgnoreLimit"))) {
+                         c += strlen("IgnoreLimit");
+                         strcpy(value, (char *) getword(c, &skiplen));
+                         if (!skiplen | value[0] == '\0' || value[0] == '\n')
+                                 continue;
+                         else {
+                                 c += skiplen;
+ 				*plimit = atoi(value);
+                         }
+                         strcpy(value, (char *) getword(c, &skiplen));
+                         if (!skiplen | value[0] == '\0' || value[0] == '\n')
+                                 continue;
+                         else {
+                                 c += skiplen;
+ 				*flimit = atoi(value);
+                         }
+                 }
+                 else if (c = (char *) lstrstr(line, "ReplaceRules")) {
+                         c += strlen("ReplaceRules");
+                         while (1) {
+                                 strcpy(value, (char *) getword(c, &skiplen));
+                                 if (!skiplen | value[0] == '\0' ||
+                                 value[0] == '\n')
+                                         break;
+                                 else {
+                                         c += skiplen;
+                                         replacelist = (struct swline *)
+                                         addswline(replacelist, value);
+                                 }
+                         }
+                 }
+                 else if ((char *) getconfvalue(line, "FollowSymLinks",
+ 		value) != NULL)
+                         followsymlinks = (lstrstr(value, "yes")) ? 1 : 0;
+                 else if ((char *) getconfvalue(line, "IndexName",
+ 		value) != NULL)
+                         strcpy(indexn, value);
+                 else if ((char *) getconfvalue(line, "IndexDescription",
+ 		value) != NULL)
+                         strcpy(indexd, value);
+                 else if ((char *) getconfvalue(line, "IndexPointer",
+ 		value) != NULL)
+                         strcpy(indexp, value);
+                 else if ((char *) getconfvalue(line, "IndexAdmin",
+ 		value) != NULL)
+                         strcpy(indexa, value);
+         }
+         fclose(fp);
+ 
+ 	if (gotdir && !(*hasdir))
+ 		*hasdir = 1;
+ 	if (gotindex && !(*hasindex))
+ 		*hasindex = 1;
+ }
Index: harvest/components/broker/swish/file.h
diff -c /dev/null harvest/components/broker/swish/file.h:1.2
*** /dev/null	Mon Oct 27 18:40:55 1997
--- harvest/components/broker/swish/file.h	Mon Oct 27 16:13:54 1997
***************
*** 0 ****
--- 1,19 ----
+ /*
+ ** Copyright (C) 1995, Enterprise Integration Technologies Corp.        
+ ** All Rights Reserved.
+ ** Kevin Hughes, kevinh@eit.com 
+ ** 3/11/94
+ ** 
+ ** Released under the GPL by EIT
+ **
+ ** Heavily modified for use in Harvest
+ */
+ 
+ 
+ int isdirectory();
+ int isfile();
+ 
+ int getsize();
+ void getdefaults();
+ struct metaEntry* addMetaEntry();
+ 
Index: harvest/components/broker/swish/hash.c
diff -c /dev/null harvest/components/broker/swish/hash.c:1.1
*** /dev/null	Mon Oct 27 18:40:55 1997
--- harvest/components/broker/swish/hash.c	Sun Oct 12 16:32:58 1997
***************
*** 0 ****
--- 1,241 ----
+ /*
+ ** Copyright (C) 1995, Enterprise Integration Technologies Corp.        
+ ** All Rights Reserved.
+ ** Kevin Hughes, kevinh@eit.com 
+ ** 3/11/94
+ **
+ ** Added addStopList to support printing of common words
+ ** G. Hill 4/7/97  ghill@library.berkeley.edu
+ */
+ 
+ #include "swish.h"
+ #include "hash.h"
+ 
+ /* Hashes a string.
+ */
+ 
+ unsigned hash(s)
+      char *s;
+ {
+         unsigned hashval;
+ 
+         for (hashval = 0; *s != '\0'; s++)
+                 hashval = *s + 31 * hashval;
+         return hashval % HASHSIZE;
+ }
+ 
+ /* Hashes a string for a larger hash table.
+ */
+ 
+ unsigned bighash(s)
+      char *s;
+ {
+         unsigned hashval;
+ 
+         for (hashval = 0; *s != '\0'; s++)
+                 hashval = *s + 31 * hashval;
+         return hashval % BIGHASHSIZE;
+ }
+ 
+ /* Reads the internal list of default stopwords.
+ */
+ 
+ void readdefaultstopwords()
+ {
+         int i;
+ 
+         for (i = 0; defaultstopwords[i] != NULL; i++)
+                 addstophash(defaultstopwords[i]);
+ }
+ 
+ /* Adds a stop word to the list of removed common words
+ */
+ void addStopList(word)
+      char * word;
+ {
+   char* arrayWord;
+   
+   if (isstopword(word) )
+     return;
+   
+   arrayWord = (char *) mystrdup (word);
+   stopList[stopPos++] = arrayWord;
+ }
+ 
+ 
+ /* Adds a stop word to a hash table.
+ */
+ 
+ void addstophash(word)
+      char *word;
+ {
+         unsigned hashval;
+         struct swline *sp;
+ 
+ 	if (isstopword(word))
+ 		return;
+ 
+         sp = (struct swline *) emalloc(sizeof(struct swline));
+         sp->line = (char *) mystrdup(word);
+ 
+         hashval = hash(word);
+         sp->next = hashstoplist[hashval];
+         hashstoplist[hashval] = sp;
+ }
+ 
+ /* Sees if a word is a stop word by looking it up in the hash table.
+ */
+ 
+ int isstopword(word)
+      char *word;
+ {
+         unsigned hashval;
+         struct swline *sp;
+ 
+         hashval = hash(word);
+         sp = hashstoplist[hashval];
+ 
+         while (sp != NULL) {
+                 if (!strcmp(sp->line, word))
+                         return 1;
+                 sp = sp->next;
+         }
+         return 0;
+ }
+ 
+ /* Adds a file number and its associated file location
+ ** to a hash table.
+ */
+ 
+ void addtofilehashlist(fileshort, filelong)
+      int fileshort;
+      long filelong;
+ {
+         unsigned hashval;
+         struct filenum *fp;
+         char tmpstr[MAXSTRLEN];
+ 
+         fp = (struct filenum *) emalloc(sizeof(struct filenum));
+         fp->fileshort = fileshort;
+         fp->filelong = filelong;
+ 
+         sprintf(tmpstr, "%d", fileshort);
+         hashval = bighash(tmpstr);
+         fp->next = filehashlist[hashval];
+         filehashlist[hashval] = fp;
+ }
+ 
+ /* Looks up a file number in the hash table and
+ ** returns the file position of the associated file info.
+ */
+ 
+ long getfilenum(filenum)
+      int filenum;
+ {
+         unsigned hashval;
+         struct filenum *fp;
+         char tmpstr[MAXSTRLEN];
+ 
+         sprintf(tmpstr, "%d", filenum);
+         hashval = bighash(tmpstr);
+         fp = filehashlist[hashval];
+ 
+         while (fp != NULL) {
+                 if (fp->fileshort == filenum)
+                         return fp->filelong;
+                 fp = fp->next;
+         }
+         return 0;
+ }
+ 
+ /* Adds a file number and the number of indexed words
+ ** to a hash table.
+ */
+ 
+ void addtofwordtotals(filenum, ftotalwords)
+      int filenum;
+      int ftotalwords;
+ {
+         unsigned hashval;
+         struct fwordtotal *fp;
+         char tmpstr[MAXSTRLEN];
+ 
+         fp = (struct fwordtotal *) emalloc(sizeof(struct fwordtotal));
+         fp->filenum = filenum;
+         fp->totalwords = ftotalwords;
+         fp->next = NULL;
+ 
+         sprintf(tmpstr, "%d", filenum);
+         hashval = bighash(tmpstr);
+         fp->next = fwordtotals[hashval];
+         fwordtotals[hashval] = fp;
+ }
+ 
+ /* Looks up a file number in the hash table and
+ ** returns the total number of words indexed in it.
+ */
+ 
+ int gettotalwords(filenum)
+      int filenum;
+ {
+         unsigned hashval;
+         struct fwordtotal *fp;
+         char tmpstr[MAXSTRLEN];
+ 
+         sprintf(tmpstr, "%d", filenum);
+         hashval = bighash(tmpstr);
+         fp = fwordtotals[hashval];
+ 
+         while (fp != NULL) {
+                 if (fp->filenum == filenum)
+                         return fp->totalwords;
+                 fp = fp->next;
+         }
+         return 0;
+ }
+ 
+ /* Adds a file number to a hash table of results.
+ ** If the entry's alrady there, add the ranks,
+ ** else make a new entry.
+ */
+ 
+ void mergeresulthashlist(filenum, rank, structure)
+      int filenum;
+      int rank;
+      int structure;
+ {
+         unsigned hashval;
+         struct result *rp, *newrp;
+         char word[MAXWORDLEN];
+ 
+         sprintf(word, "%d", filenum);
+ 	hashval = hash(word);
+ 
+ 	rp = resulthashlist[hashval];
+ 	while (rp != NULL) {
+ 		if (rp->filenum == filenum) {
+ 			rp->rank += rank;
+ 			rp->structure |= structure;
+ 			return;
+ 		}
+ 		rp = rp->next;
+ 	}
+ 	
+         newrp = (struct result *) emalloc(sizeof(struct result));
+         newrp->filenum = filenum;
+         newrp->rank = rank;
+ 	newrp->structure = structure;
+         newrp->next = resulthashlist[hashval];
+         resulthashlist[hashval] = newrp;
+ }
+ 
+ /* Initializes the result hash list.
+ */
+ 
+ void initresulthashlist()
+ {
+ 	int i;
+ 
+ 	for (i = 0; i < HASHSIZE; i++)
+ 		resulthashlist[i] = NULL;
+ }
Index: harvest/components/broker/swish/hash.h
diff -c /dev/null harvest/components/broker/swish/hash.h:1.1
*** /dev/null	Mon Oct 27 18:40:56 1997
--- harvest/components/broker/swish/hash.h	Sun Oct 12 16:32:59 1997
***************
*** 0 ****
--- 1,19 ----
+ /*
+ ** Copyright (C) 1995, Enterprise Integration Technologies Corp.        
+ ** All Rights Reserved.
+ ** Kevin Hughes, kevinh@eit.com 
+ ** 3/11/94
+ */
+ 
+ unsigned hash();
+ unsigned bighash();
+ void readdefaultstopwords();
+ void addstophash();
+ int isstopword();
+ void addtofilehashlist();
+ long getfilenum();
+ void addtofwordtotals();
+ int gettotalwords();
+ void mergeresulthashlist();
+ void initresulthashlist();
+ void addStopList();
Index: harvest/components/broker/swish/index.c
diff -c /dev/null harvest/components/broker/swish/index.c:1.2
*** /dev/null	Mon Oct 27 18:40:56 1997
--- harvest/components/broker/swish/index.c	Mon Oct 27 16:13:55 1997
***************
*** 0 ****
--- 1,742 ----
+ /*
+ ** Copyright (C) 1995, Enterprise Integration Technologies Corp.        
+ ** All Rights Reserved.
+ ** Kevin Hughes, kevinh@eit.com 
+ ** 3/11/94
+ ** 
+ ** Released under the GPL 1997
+ **
+ ** Modifications to index Harvest SOIF records - Simon Wilkinson 12/10/97
+ */
+ 
+ #include "swish.h"
+ #include "index.h"
+ #include "hash.h"
+ #include "util.h"
+ #include "template.h"
+ 
+ 
+ /* Recursively goes into a directory and calls the word-indexing
+ ** functions for each file that's found.
+ */
+ 
+ void indexadir(dir)
+      char *dir;
+ {
+         DIR *dfd;
+ #ifdef NEXTSTEP
+         struct direct *dp;
+ #else
+         struct dirent *dp;
+ #endif
+ 	static char s[MAXFILELEN], title[MAXSTRLEN];
+         struct sortentry *sortfilelist, *sortdirlist;
+ 
+         sortfilelist = sortdirlist = NULL;
+ 
+         if (dir[strlen(dir) - 1] == '/')
+                 dir[strlen(dir) - 1] = '\0';
+ 
+         if ((dfd = opendir(dir)) == NULL)
+                 return;
+ 
+         while ((dp = readdir(dfd)) != NULL) {
+ 
+                 if ((dp->d_name)[0] == '.')
+                         continue;
+ 
+                 sprintf(s, "%s%s%s", dir, dir[strlen(dir) - 1] == '/' ?
+                 "" : "/", dp->d_name);
+ 
+                 if (!isdirectory(s)) {
+ 			title[0]='\0';
+                         sortfilelist = (struct sortentry *)
+                         addsortentry(sortfilelist, s, title);
+                 }
+                 else {
+                         sortdirlist = (struct sortentry *)
+                         addsortentry(sortdirlist, s, s);
+                 }
+         }
+ 
+         closedir(dfd);
+ 
+         printfiles(sortfilelist);
+         printdirs(sortdirlist);
+ }
+ 
+ /* Calls the word-indexing function for a single file.
+ */
+ 
+ void indexafile(path)
+      char *path;
+ {
+         char title[MAXSTRLEN];
+         struct sortentry *fileentry;
+ 
+         if (path[strlen(path) - 1] == '/')
+                 path[strlen(path) - 1] = '\0';
+ 
+ 	title[0]='\0';
+ 
+         fileentry = (struct sortentry *) emalloc(sizeof(struct sortentry));
+         fileentry->filename = (char *) mystrdup(path);
+         fileentry->title = (char *) mystrdup(title);
+         fileentry->left = fileentry->right = NULL;
+ 
+         printfiles(fileentry);
+ }
+ 
+ /* Indexes the words in the tree of files in alphabetical order.
+ */
+ 
+ void printfiles(e)
+      struct sortentry *e;
+ {
+         int wordcount;
+ 	char *s;
+ 
+         if (e != NULL) {
+                 printfiles(e->left);
+                 if (verbose == 3) {
+ 			if ((s = (char *) strrchr(e->filename, '/')) == NULL)
+                         	printf("  %s", e->filename);
+ 			else
+                         	printf("  %s", s + 1);
+ 		}
+                 wordcount = countwords(e->filename, e->title);
+                 if (verbose == 3) {
+                         if (wordcount)
+                                 printf(" (%d words)\n", wordcount);
+                         else
+                                 printf(" (no words)\n");
+                         fflush(stdout);
+                 }
+ 		free(e->filename);
+ 		free(e->title);
+                 printfiles(e->right);
+ 		free(e);
+         }
+ }
+ 
+ /* Prints out the directory names as things are getting indexed.
+ ** Calls indexadir() so directories in the tree are indexed,
+ ** in alphabetical order...
+ */
+ 
+ void printdirs(e)
+      struct sortentry *e;
+ {
+         if (e != NULL) {
+                 printdirs(e->left);
+                 if (verbose == 3)
+                         printf("\nIn dir \"%s\":\n", e->filename);
+                 else if (verbose == 2)
+                         printf("Checking dir \"%s\"...\n", e->filename);
+                 indexadir(e->filename);
+ 		free(e->filename);
+ 		free(e->title);
+                 printdirs(e->right);
+ 		free(e);
+         }
+ }
+ 
+ /* Stores file names in alphabetical order so they can be
+ ** indexed alphabetically. No big whoop.
+ */
+ 
+ struct sortentry *addsortentry(e, filename, title)
+      struct sortentry *e;
+      char *filename;
+      char *title;
+ {
+         if (e == NULL) {
+                 e = (struct sortentry *) emalloc(sizeof(struct sortentry));
+                 e->filename = (char *) mystrdup(filename);
+                 e->title = (char *) mystrdup(title);
+                 e->left = e->right = NULL;
+         }
+         else {
+                 if (strcmp(e->filename, filename) > 0)
+                         e->left = (struct sortentry *)
+                         addsortentry(e->left, filename, title);
+                 else
+                         e->right = (struct sortentry *)
+                         addsortentry(e->right, filename, title);
+         }
+ 
+         return e;
+ }
+ 
+ /* Adds a word to the master index tree.
+ */
+ 
+ struct entry *addentry(e, word, filenum, emphasized, structure, metaName)
+      struct entry *e;
+      char *word;
+      int filenum;
+      int emphasized;
+      int structure;
+      int metaName;
+ {
+   int isbigger;
+   struct location *tp, *oldtp;
+   
+   if (e == NULL) {
+     e = (struct entry *) emalloc(sizeof(struct entry));
+     e->word = (char *) mystrdup(word);
+     e->tfrequency = 1;
+     e->locationlist = (struct location *)
+       emalloc(sizeof(struct location));
+     e->locationlist->filenum = filenum;
+     e->locationlist->frequency = 1;
+     e->locationlist->emphasized = emphasized;
+     e->locationlist->structure = structure;
+     e->locationlist->metaName = metaName;
+     e->locationlist->next = NULL;
+     e->left = e->right = NULL;
+     totalwords++;
+   }
+   else {
+     isbigger = wordcompare(e->word, word);
+     if (isbigger == 0) {
+       tp = e->locationlist;
+       while (tp != NULL) {
+ 	if (tp->filenum == filenum && tp->metaName == metaName) 
+ 	  break;
+ 	oldtp = tp;
+ 	tp = tp->next;
+       }
+       if (tp == NULL) {
+ 	tp = (struct location *) emalloc(sizeof(struct
+ 						location));
+ 	tp->filenum = filenum;
+ 	tp->frequency = 1;
+ 	tp->emphasized = emphasized;
+ 	tp->structure = structure;
+ 	tp->metaName = metaName;
+ 	tp->next = NULL;
+ 	oldtp->next = tp;
+ 	if (!emphasized)
+ 	  e->tfrequency = e->tfrequency + 1;
+       }
+       else {
+ 	if ( (tp->filenum == filenum) 
+ 	    && (tp->metaName == metaName) ) {
+ 	  tp->frequency = tp->frequency + 1;
+ 	  if (emphasized)
+ 	    tp->emphasized =
+ 	      tp->emphasized + 1;
+ 	  tp->structure |= structure;
+ 	}
+       }
+     }
+     else if (isbigger > 0)
+       e->left = (struct entry *)
+ 	addentry(e->left, word, filenum, emphasized,
+ 		 structure, metaName);
+     else
+       e->right = (struct entry *)
+ 	addentry(e->right, word, filenum, emphasized,
+ 		 structure, metaName);
+   }
+   
+   return e;
+ }
+ 
+ /* Adds a file to the master list of files and file numbers.
+ */
+ 
+ struct file *addtofilelist(filep, filename, title, size)
+      struct file *filep;
+      char *filename;
+      char *title;
+      int size;
+ {
+         struct file *newnode;
+         static struct file *filelistp = NULL;
+ 
+         newnode = (struct file *) emalloc(sizeof(struct file));
+         newnode->filename = (char *) mystrdup(filename);
+         newnode->title = (char *) mystrdup(title);
+         newnode->size = size;
+         newnode->next = NULL;
+ 
+         if (filep == NULL)
+                 filep = newnode;
+         else if (filelistp != NULL)
+                 filelistp->next = newnode;
+ 
+         filelistp = newnode;
+ 
+         return filep;
+ }
+ 
+ /* Just goes through the master list of files and
+ ** counts 'em.
+ */
+ 
+ int getfilecount(filep)
+      struct file *filep;
+ {
+         int i;
+ 
+         for (i = 0; filep != NULL; filep = filep->next)
+                 i++;
+ 
+         return i;
+ }
+ 
+ /* Returns the nicely formatted date.
+ */
+ 
+ char *getthedate()
+ {
+ 	static char date[MAXSTRLEN];
+ 	time_t time;
+ 
+ 	time = (time_t) getthetime();
+ 	strftime(date, MAXSTRLEN, "%x %X", (struct tm *) localtime(&time));
+ 	strftime(date, MAXSTRLEN, "%d/%m/%y %H:%M:%S %Z",
+ 	(struct tm *) localtime(&time));
+ 
+ 	return date;
+ }
+ 
+ /* Indexes all the words in a file and adds the appropriate information
+ ** to the appropriate structures.
+ */
+ 
+ int countwords(filename, title)
+      char *filename;
+      char *title;
+ {
+ 	int ftotalwords;
+ 	Template *template;
+ 	AVList *walker;
+         static int filenum;
+         FILE *fp;
+ 
+         if ((fp = fopen(filename, "r")) == NULL)
+                 return 0;
+ 
+         ftotalwords = 0;
+ 
+         filelist = addtofilelist(filelist, filename, title, getsize(filename));
+         filenum++;
+         if (!(filenum % 128))
+                 filenum++;
+ 
+ 	init_parse_template_file(fp);
+         template=parse_template();
+ 	if (template==NULL) 
+ 	   progerr("Badly formed SOIF file found");
+ 	else {
+ 	   ftotalwords+=add_attrval(filenum,"url",template->url,sizeof(template->url));
+ 	   
+ 	   for (walker = template->list; walker ; walker=walker->next) {
+ 	      if (walker->data->vsize == 0) continue;
+               ftotalwords+=add_attrval(filenum,walker->data->attribute,walker->data->value,
+ 			   walker->data->vsize);
+            }
+         }
+         free_template(template);
+         fclose(fp);
+ 
+         addtofwordtotals(filenum, ftotalwords);
+         return(ftotalwords);
+ }
+ 
+ int add_attrval(int filenum, char *attr, char *val, size_t valsize) {
+         int c, i, inword, ftotalwords, emphasized, structure;
+ 	int metaName;
+         char word[MAXWORDLEN];
+ 	int ptr;
+ 
+ 	ftotalwords=0;
+ 	i = 0;
+         inword = 0;
+         emphasized = 0;
+ 	structure = 1;
+ 	metaName = 1;
+ 	ptr = 0;
+ 
+         while (ptr <valsize) {
+ 	  c=val[ptr]; ptr++;
+ 
+           if (!inword) {
+              if (iswordchar(c)) {
+                 i = 0;
+                 word[i++] = c;
+ 		if (i == MAXWORDLEN) i--;
+                 inword = 1;
+              }
+           }
+           else {
+              if (!iswordchar(c)) {
+                 word[i++] = '\0';
+ 		if (i == MAXWORDLEN) word[--i] = '\0';
+                 for (i = 0; word[i]; i++)
+                    word[i] = tolower(word[i]);
+ 		i = 0;
+                 if (hasokchars(word) && isokword(word)) {
+                    entrylist = (struct entry *) addentry(entrylist, word,
+                                                          filenum, emphasized, 
+                                                          structure, metaName);
+                    ftotalwords++;
+                 }
+                 inword = 0;
+              }
+              else {
+                 word[i++] = c;
+ 	        if (i == MAXWORDLEN) i--;
+ 	     }
+ 	  }
+ 	}
+ 	return(ftotalwords);
+ }
+ 
+ /* Removes words that occur in over _plimit_ percent of the files and
+ ** that occur in over _flimit_ files (marks them as stopwords, that is).
+ */
+ 
+ int removestops(ep, totalfiles, plimit, flimit)
+      struct entry *ep;
+      int totalfiles;
+      int plimit;
+      int flimit;
+ {
+ 	int percent, wordfilecount, stopwords;
+         struct location *lp;
+ 
+ 	stopwords = 0;
+ 	if (ep != NULL) {
+ 		stopwords += removestops(ep->left, totalfiles, plimit, flimit);
+                 lp = ep->locationlist;
+ 		wordfilecount = 0;
+                 while (lp != NULL) {
+ 			wordfilecount++;
+                         lp = lp->next;
+                 }
+ 		percent = ((float) wordfilecount / (float) totalfiles) * 100.0;
+ 		if (percent >= plimit && wordfilecount >= flimit) {
+ 			addStopList(ep->word);
+ 			addstophash(ep->word);
+ 			stopwords++;
+ 		}
+ 		stopwords += removestops(ep->right,totalfiles, plimit, flimit);
+ 	}
+ 	return stopwords;
+ }
+ 
+ /* This is somewhat similar to the rank calculation algorithm
+ ** from WAIS (I think). Any suggestions for improvements?
+ ** Note that ranks can't be smaller than 1, emphasized words
+ ** (words in titles, headers) have ranks multiplied by at least 5
+ ** (just a guess), and ranks divisible by 128 are bumped up by one
+ ** (to make the compression scheme with with '\0' as a line delimiter
+ ** work). Fudging with the ranks doesn't seem to make much difference.
+ */
+ 
+ int getrank(freq, tfreq, words, emphasized)
+      int freq;
+      int tfreq;
+      int words;
+      int emphasized;
+ {
+         float d, e, f;
+         int tmprank;
+         char rankstr[MAXSTRLEN];
+ 
+         if (freq < 5)
+                 freq = 5;
+         d = 1.0 / (double) tfreq;
+         e = ((log((double) freq) + 10.0) * d) / words;
+         f = e * 10000.0;
+ 
+         sprintf(rankstr, "%f", f);
+         tmprank = atoi(rankstr);
+         if (tmprank <= 0)
+                 tmprank = 1;
+         if (emphasized)
+                 tmprank *= emphasized;
+         if (!(tmprank % 128))
+                 tmprank++;
+ 
+         return tmprank;
+ }
+ 
+ /* Prints the index information at the head of index files.
+ */
+ 
+ void printheader(fp, filename, totalwords, totalfiles)
+      FILE *fp;
+      char *filename;
+      int totalwords;
+      int totalfiles;
+ {
+ 	char *c;
+ 
+ 	c = (char *) strrchr(filename, '/');
+ 
+ 	fprintf(fp, "%s\n", INDEXHEADER);
+ 	fprintf(fp, "# Name: %s\n", (indexn[0] == '\0') ? "(no name)" :
+ 	indexn);
+ 	fprintf(fp, "# Saved as: %s\n", (c == NULL && c + 1 != '\0') ?
+ 		filename : c + 1);
+ 	fprintf(fp, "# Counts: ");
+ 	if (totalwords)
+ 		fprintf(fp, "%d words%s", totalwords, (totalfiles) ? ", " : "");
+ 	if (totalfiles)
+ 		fprintf(fp, "%d files", totalfiles);
+ 	fprintf(fp, "\n");
+ 	fprintf(fp, "# Indexed on: %s\n", getthedate());
+ 	fprintf(fp, "# Description: %s\n", (indexd[0] == '\0') ?
+ 	"(no description)" : indexd);
+ 	fprintf(fp, "# Pointer: %s\n", (indexp[0] == '\0') ?
+ 	"(no pointer)" : indexp);
+ 	fprintf(fp, "# Maintained by: %s\n", (indexa[0] == '\0') ?
+ 	"(no maintainer)" : indexa);
+ }
+ 
+ /* Print the index entries that hold the word, rank, and other information.
+ */
+ 
+ void printindex(ep, fp)
+      struct entry *ep;
+      FILE *fp;
+ {
+         int i, rank;
+         struct location *lp;
+ 
+         if (ep != NULL) {
+                 printindex(ep->left, fp);
+ 		if (!isstopword(ep->word)) {
+ 
+ 			for (i = 0; indexchars[i] != '\0'; i++)
+ 				if ((ep->word)[0] == indexchars[i] &&
+ 				!offsets[i])
+ 					offsets[i] = ftell(fp);
+ 
+ 	                fprintf(fp, "%s:", ep->word);
+ 			lp = ep->locationlist;
+ 			while (lp != NULL) {
+ 				compress(lp->filenum, fp);
+ 				rank = getrank(lp->frequency, ep->tfrequency,
+ 				gettotalwords(lp->filenum), lp->emphasized);
+ 				compress(rank, fp);
+ 				compress(lp->structure, fp);
+ 				compress(lp->metaName, fp);
+ 				lp = lp->next;
+                 	}
+                 	fputc(0, fp);
+ 
+ 		}
+                 printindex(ep->right, fp);
+         }
+ }
+ 
+ /* Prints the list of stopwords into the index file.
+ */
+ 
+ void printstopwords(fp)
+      FILE *fp;
+ {
+ 	int hashval;
+ 	struct swline *sp;
+ 
+ 	offsets[STOPWORDPOS] = ftell(fp);
+ 	for (hashval = 0; hashval < HASHSIZE; hashval++) {
+         	sp = hashstoplist[hashval];
+ 		while (sp != NULL) {
+ 			fprintf(fp, "%s ", sp->line);
+ 			sp = sp->next;
+ 		}
+ 	}
+ 	fprintf(fp, "\n");
+ }
+ 
+ /* Prints the list of files, titles, and sizes into the index file.
+ */
+ 
+ void printfilelist(filep, fp)
+      struct file *filep;
+      FILE *fp;
+ {
+ 	int i;
+ 
+ 	i = 0;
+ 	offsets[FILELISTPOS] = ftell(fp);
+         while (filep != NULL) {
+ 		addtofilehashlist(i++, ftell(fp));
+                 fprintf(fp, "%s \"%s\" %d\n", ruleparse(filep->filename),
+                 filep->title, filep->size);
+                 filep = filep->next;
+         }
+ }
+ 
+ /* Prints the list of metaNames into the file index
+ */
+ 
+ void printMetaNames(fp)
+      FILE *fp;
+ {
+   struct metaEntry* entry;
+   
+   offsets[METANAMEPOS] = ftell(fp);
+   for (entry = metaEntryList; entry; entry = entry->next)
+     {
+       fprintf(fp, "%s ", entry->metaName);
+     }
+   fprintf(fp, "\n");
+ }
+ 
+ /* Prints the list of file offsets into the index file.
+  */
+ 
+ void printfileoffsets(fp)
+      FILE *fp;
+ {
+ 	int i;
+ 
+ 	offsets[FILEOFFSETPOS] = ftell(fp);
+ 	for (i = 0; getfilenum(i) != 0; i++)
+ 		fprintf(fp, "%016li", getfilenum(i));
+ 	fprintf(fp,"\n");
+ }
+ 
+ /* Takes a number and prints it to a file using the simple
+ ** accordion scheme of storing numbers.
+ */
+ 
+ void compress(num, fp)
+      int num;
+      FILE *fp;
+ {
+         int i, r;
+         static char s[8];
+ 
+         i = 0;
+         while (num) {
+                 r = num % 128;
+                 num /= 128;
+                 s[i++] = r;
+         }
+         while (i-- >= 0)
+                 fputc(s[i] | (i ? 128 : 0), fp);
+ }
+ 
+ /* Prints out the decompressed values in an index file.
+ */
+ 
+ void decompress(fp)
+      FILE *fp;
+ {
+         int c, x, inword;
+ 	long pos;
+         char line[MAXSTRLEN], header[MAXHEADCHARS + 1];
+ 
+ 	readoffsets(fp);
+ 	fseek(fp, 0, 0);
+         inword = 1;
+ 
+         while (1) {
+                 c = fgetc(fp);
+                 ungetc(c, fp);
+                 if (c == '#') {
+                         fgets(line, MAXSTRLEN, fp);
+ 			printf("%s", line);
+                         continue;
+                 }
+                 else {
+                         fgets(header, MAXHEADCHARS + 1, fp);
+ 			printf("%s", header);
+                         break;
+                 }
+         }
+ 
+         while ((c = fgetc(fp)) != EOF) {
+                 if (c == ':' && inword) {
+                         inword = 0;
+                         putchar(c);
+                 }
+                 if (inword)
+                         putchar(c);
+                 else {
+                         x = 0;
+                         do {
+                                 c = fgetc(fp);
+ 				pos = ftell(fp);
+ 				if (pos == offsets[STOPWORDPOS]) {
+ 					putchar('\n');
+ 					while (fgets(line, MAXSTRLEN, fp)
+ 					!= NULL)
+ 						printf("%s", line);
+ 						return;
+ 				}
+                                 if (c == 0) {
+                                         putchar('\n');
+                                         inword = 1;
+                                         break;
+                                 }
+                                 x *= 128;
+                                 x += c & 127;
+                         } while (c & 128);
+                         if (x)
+                                 printf(" %d", x);
+                 }
+         }
+ }
+ 
+ /* Parses lines according to the ReplaceRules directives.
+ */
+ 
+ char *ruleparse(line)
+      char *line;
+ {
+         char rule[MAXSTRLEN];
+         static char tmpline[MAXSTRLEN], newtmpline[MAXSTRLEN];
+         static char line1[MAXSTRLEN], line2[MAXSTRLEN];
+         struct swline *tmplist;
+ 
+ 	if (replacelist == NULL)
+ 		return line;
+ 
+         tmplist = replacelist;
+         strcpy(tmpline, line);
+         while(1) {
+ 		if (tmplist == NULL)
+ 			return tmpline;
+                 strcpy(rule, tmplist->line);
+ 		tmplist = tmplist->next;
+ 		if (tmplist == NULL)
+ 			return tmpline;
+                 if (rule == NULL) {
+                         replacelist = tmplist;
+                         return tmpline;
+                 }
+                 else {
+                         if (lstrstr(rule, "replace")) {
+                                 strcpy(line1, tmplist->line);
+ 				tmplist = tmplist->next;
+                                 strcpy(line2, tmplist->line);
+ 				tmplist = tmplist->next;
+                                 strcpy(newtmpline, (char *) replace(tmpline,
+                                 line1, NOWORD));
+                                 strcpy(newtmpline, (char *) replace(newtmpline,
+                                 NOWORD, line2));
+                         }
+                         else if (lstrstr(rule, "append")) {
+ 				sprintf(newtmpline, "%s%s", tmpline,
+ 				tmplist->line);
+ 				tmplist = tmplist->next;
+ 			}
+ 			else if (lstrstr(rule, "prepend")) {
+ 				sprintf(newtmpline, "%s%s", tmplist->line,
+ 				tmpline);
+ 				tmplist = tmplist->next;
+ 			}
+ 			strcpy(tmpline, newtmpline);
+                 }
+         }
+ }
Index: harvest/components/broker/swish/index.h
diff -c /dev/null harvest/components/broker/swish/index.h:1.1
*** /dev/null	Mon Oct 27 18:40:57 1997
--- harvest/components/broker/swish/index.h	Sun Oct 12 16:33:01 1997
***************
*** 0 ****
--- 1,35 ----
+ /*
+ ** Copyright (C) 1995, Enterprise Integration Technologies Corp.        
+ ** All Rights Reserved.
+ ** Kevin Hughes, kevinh@eit.com 
+ ** 3/11/94
+ **
+ */
+ 
+ int getMeta();
+ int parseMetaData();
+ void createMetaEntryList();
+ void indexadir();
+ void indexafile();
+ void printfiles();
+ void printdirs();
+ void printMetaNames();
+ struct sortentry *addsortentry();
+ struct entry *addentry();
+ struct file *addtofilelist();
+ int getfilecount();
+ char *getthedate();
+ int countwords();
+ int countwordstr();
+ int getstructure();
+ int parsecomment();
+ int removestops();
+ int getrank();
+ void printheader();
+ void printindex();
+ void printfilelist();
+ void printstopwords();
+ void printfileoffsets();
+ void compress();
+ void decompress();
+ char *ruleparse();
Index: harvest/components/broker/swish/list.c
diff -c /dev/null harvest/components/broker/swish/list.c:1.1
*** /dev/null	Mon Oct 27 18:40:57 1997
--- harvest/components/broker/swish/list.c	Sun Oct 12 16:33:01 1997
***************
*** 0 ****
--- 1,28 ----
+ /* This is a generic function that adds lines to a list -
+ ** these lists hold file rules, index files, files to be
+ ** indexed, etc.
+ */
+ 
+ #include "swish.h"
+ #include "list.h"
+ 
+ struct swline *addswline(rp, line)
+      struct swline *rp;
+      char *line;
+ {
+         struct swline *newnode;
+         static struct swline *nodep;
+ 
+         newnode = (struct swline *) emalloc(sizeof(struct swline));
+         newnode->line = (char *) mystrdup(line);
+         newnode->next = NULL;
+ 
+         if (rp == NULL)
+                 rp = newnode;
+         else
+                 nodep->next = newnode;
+ 
+         nodep = newnode;
+ 
+         return rp;
+ }
Index: harvest/components/broker/swish/list.h
diff -c /dev/null harvest/components/broker/swish/list.h:1.1
*** /dev/null	Mon Oct 27 18:40:58 1997
--- harvest/components/broker/swish/list.h	Sun Oct 12 16:33:02 1997
***************
*** 0 ****
--- 1,8 ----
+ /*
+ ** Copyright (C) 1995, Enterprise Integration Technologies Corp.        
+ ** All Rights Reserved.
+ ** Kevin Hughes, kevinh@eit.com 
+ ** 3/11/94
+ */
+ 
+ struct swline *addswline();
Index: harvest/components/broker/swish/mem.c
diff -c /dev/null harvest/components/broker/swish/mem.c:1.1
*** /dev/null	Mon Oct 27 18:40:58 1997
--- harvest/components/broker/swish/mem.c	Sun Oct 12 16:33:03 1997
***************
*** 0 ****
--- 1,33 ----
+ /*
+ ** Copyright (C) 1995, Enterprise Integration Technologies Corp.        
+ ** All Rights Reserved.
+ ** Kevin Hughes, kevinh@eit.com 
+ ** 3/11/94
+ */
+ 
+ #include "swish.h"
+ #include "mem.h"
+ 
+ /* Error-checking malloc()...
+ */
+ 
+ void *emalloc(i)
+      int i;
+ {
+         void *p;
+  
+         if ((p = (void *) malloc(i)) == NULL)
+                 progerr("Ran out of memory (could not allocate enough)!");
+         return p;
+ }
+ 
+ void *erealloc(ptr, i)
+      void *ptr;
+      int i;
+ {
+         void *p;
+  
+         if ((p = (void *) realloc(ptr, i)) == NULL)
+                 progerr("Ran out of memory (could not reallocate enough)!");
+         return p;
+ }
Index: harvest/components/broker/swish/mem.h
diff -c /dev/null harvest/components/broker/swish/mem.h:1.1
*** /dev/null	Mon Oct 27 18:40:58 1997
--- harvest/components/broker/swish/mem.h	Sun Oct 12 16:33:04 1997
***************
*** 0 ****
--- 1,9 ----
+ /*
+ ** Copyright (C) 1995, Enterprise Integration Technologies Corp.        
+ ** All Rights Reserved.
+ ** Kevin Hughes, kevinh@eit.com 
+ ** 3/11/94
+ */
+ 
+ void *emalloc();
+ void *erealloc();
Index: harvest/components/broker/swish/merge.c
diff -c /dev/null harvest/components/broker/swish/merge.c:1.1
*** /dev/null	Mon Oct 27 18:40:58 1997
--- harvest/components/broker/swish/merge.c	Sun Oct 12 16:33:05 1997
***************
*** 0 ****
--- 1,936 ----
+ /*
+ ** Copyright (C) 1995, Enterprise Integration Technologies Corp.        
+ ** All Rights Reserved.
+ ** Kevin Hughes, kevinh@eit.com 
+ ** 3/11/94
+ **
+ ** Fixed the merge option -M
+ ** G. Hill 3/7/97
+ **
+ ** Changed readindexline, mergeindexentries, printindexentry and
+ ** added marknumMerge, addtoresultlistMerge, markentrylistMerge,
+ ** ismarkedMerge to add support for METADATA
+ ** G. Hill 3/26/97 ghill@library.berkeley.edu
+ */
+ 
+ #include "swish.h"
+ #include "merge.h"
+ 
+ /* The main merge functions - it accepts three file names.
+ ** This is a bit hairy. It basically acts as a zipper,
+ ** zipping up both index files into one.
+ */
+ 
+ void readmerge(file1, file2, outfile)
+      char *file1;
+      char *file2;
+      char *outfile;
+ {
+ 	int i, j, indexfilenum1, indexfilenum2, result, totalfiles,
+ 		skipwords, skipfiles;
+ 	long limit1, limit2, fileinfo1, fileinfo2, offsetstart;
+ 	long metainfo1, metainfo2;
+ 	char line[MAXSTRLEN];
+ 	struct indexentry *ip1, *ip2, *ip3;
+ 	struct indexentry *buffer1, *buffer2;
+ 	FILE *fp1, *fp2, *fp3;
+ 	struct metaMergeEntry *metaFile1, *metaFile2;
+ 
+ 	initindexfilehashlist();
+ 
+ 	/* remapVar is used into addindexfilelist and need to be
+ 	** initialized each time two indexes are merged.
+ 	*/
+ 	remapVar = 0;
+ 	metaFile1 = metaFile2 = NULL;
+ 
+ 	initmapentrylist();
+ 
+ 	if ((fp1 = fopen(file1, "r")) == NULL) {
+ 		sprintf(errorstr, "Couldn't read the index file \"%s\".",
+ 		file1);
+ 		progerr(errorstr);
+ 	}
+ 	if (!isokindexheader(fp1)) {
+ 		sprintf(errorstr, "\"%s\" has an unknown format.",
+ 		file1);
+ 		progerr(errorstr);
+ 	}
+ 	if ((fp2 = fopen(file2, "r")) == NULL) {
+ 		sprintf(errorstr, "Couldn't read the index file \"%s\".",
+ 		file2);
+ 		progerr(errorstr);
+ 	}
+ 	if (!isokindexheader(fp2)) {
+ 		sprintf(errorstr, "\"%s\" has an unknown format.",
+ 		file2);
+ 		progerr(errorstr);
+ 	}
+ 
+ 	ip1 = ip2 = ip3 = NULL;
+ 	buffer1 = buffer2 = NULL;
+ 	if (verbose)
+ 		printf("Counting files... ");
+ 	indexfilenum1 = getindexfilenum(fp1);
+ 	indexfilenum2 = getindexfilenum(fp2);
+ 	totalfiles = indexfilenum1 + indexfilenum2;
+ 	if (verbose) {
+ 		printf("%d files.\n", indexfilenum1 + indexfilenum2);
+ 		printf("Reading stopwords...");
+ 	}
+ 	readoffsets(fp1);
+ 	readstopwords(fp1);
+ 	limit1 = offsets[STOPWORDPOS];
+ 	fileinfo1 = offsets[FILELISTPOS];
+ 	metaFile1 = readMergeMeta(metaFile1,fp1);
+ 
+ 	readoffsets(fp2);
+ 	readstopwords(fp2);
+ 	limit2 = offsets[STOPWORDPOS];
+ 	fileinfo2 = offsets[FILELISTPOS];
+ 	metaFile2 = readMergeMeta(metaFile2,fp2);
+ 
+         /* Create the merged list and modify the
+ 	   individual ones with the new meta index
+         */	   
+ 	metaEntryList = createMetaMerge(metaFile1, metaFile2);
+ 
+ 	if (verbose)
+ 		printf("\nReading file info...");
+ 	fseek(fp1, fileinfo1, 0);
+ 	for (i = 1; i <= indexfilenum1; i++) {
+ 		fgets(line, MAXSTRLEN, fp1);
+ 		addindexfilelist(i, line, &totalfiles);
+ 	}
+ 	fseek(fp2, fileinfo2, 0);
+ 	for (i = 1; i <= indexfilenum2; i++) {
+ 		fgets(line, MAXSTRLEN, fp2);
+ 		addindexfilelist(i + indexfilenum1, line, &totalfiles);
+ 	}
+ 
+ 	if ((fp3 = fopen(outfile, "w")) == NULL) {
+ 		sprintf(errorstr,
+ 		"Couldn't write the merged index file \"%s\".",
+ 		outfile);
+ 		progerr(errorstr);
+ 	}
+ 
+ 	if (verbose)
+ 		printf("\nMerging words... ");
+ 
+ 	printheader(fp3, outfile, 0, totalfiles);
+ 
+         offsetstart = ftell(fp3);
+         for (i = 0; i < MAXCHARS; i++)
+                 fprintf(fp3, "%016li", offsets[i]);
+         fputc('\n', fp3);
+ 
+ 	readoffsets(fp1);
+ 	readoffsets(fp2);
+ 
+ 	for (i = 0; i < MAXCHARS; i++)
+ 		offsets[i] = 0;
+ 
+ 	skipwords = 0;
+ 	while (1) {
+ 		if (buffer1 == NULL) {
+ 			ip1 = (struct indexentry *) 
+ 			  readindexline(fp1, limit1,metaFile1);
+ 			if (ip1 == NULL) {
+ 			  if (ip2 == NULL) {
+ 			    break;
+ 			  }
+ 			}
+ 			buffer1 = ip1;
+ 		}
+ 		if (buffer2 == NULL) {
+ 			ip2 = (struct indexentry *) 
+ 			  readindexline(fp2, limit2,metaFile2);
+ 			if (ip2 == NULL){
+ 			  if (ip1 == NULL) {
+ 			    break;
+ 			  }
+ 			}
+ 			else 
+ 			  addfilenums(ip2, indexfilenum1);
+ 			buffer2 = ip2;
+ 		}
+ 		if (ip1 == NULL)
+ 		  result = 1;
+ 		else if (ip2 == NULL)
+ 		  result = -1;
+ 		else
+ 		  result = wordcompare(ip1->word, ip2->word);
+ 		if (!result) {
+ 			ip3 = (struct indexentry *) mergeindexentries(ip1, ip2);
+ 			printindexentry(ip3, fp3);
+ 			freeindexentry(ip1);
+ 			freeindexentry(ip2);
+ 			freeindexentry(ip3);
+ 			buffer1 = buffer2 = NULL;
+ 			skipwords++;
+ 		}
+ 		else if (result < 0) {
+ 			printindexentry(ip1, fp3);
+ 			freeindexentry(ip1);
+ 			buffer1 = NULL;
+ 		}
+ 		else {
+ 			printindexentry(ip2, fp3);
+ 			freeindexentry(ip2);
+ 			buffer2 = NULL;
+ 		}
+ 	}
+ 
+ 	if (verbose) {
+ 		if (skipwords)
+ 			printf("%d redundant word%s.", skipwords,
+ 			(skipwords == 1) ? "" : "s");
+ 		else
+ 			printf("no redundant words.");
+ 	}
+ 
+         printstopwords(fp3);
+ 
+ 	if (verbose)
+ 		printf("\nMerging file info... ");
+ 
+ 	offsets[FILELISTPOS] = ftell(fp3);
+ 	for (i = j = 1; i <= indexfilenum1 + indexfilenum2; i++)
+ 		if (getmap(i) == j) {
+ 			addtofilehashlist(j++ - 1, ftell(fp3));
+ 			fprintf(fp3, "%s", lookupindexfilenum(i));
+ 		}
+ 
+ 	skipfiles = (indexfilenum1 + indexfilenum2) - totalfiles;
+ 	if (verbose) {
+ 		if (skipfiles)
+ 			printf("%d redundant file%s.", skipfiles,
+ 			(skipfiles == 1) ? "" : "s");
+ 		else
+ 			printf("no redundant files.");
+ 	}
+ 	printfileoffsets(fp3);
+ 	printMetaNames(fp3);
+ 
+ 	fseek(fp3, offsetstart, 0);
+         for (i = 0; i < MAXCHARS; i++)
+                 fprintf(fp3, "%016li", offsets[i]);
+ 	fclose(fp3);
+ 
+ 	fclose(fp1);
+ 	fclose(fp2);
+ 
+ 	if (verbose)
+ 		printf("\nDone.\n");
+ }
+ 
+ /* Gets the number of files in an index file.
+ */
+ 
+ int getindexfilenum(fp)
+      FILE *fp;
+ {
+ 	int i;
+ 	char line[MAXSTRLEN];
+ 
+ 	readoffsets(fp);
+ 	fseek(fp, offsets[FILELISTPOS], 0);
+ 
+ 	i = 0;
+ 	while(ftell(fp) != offsets[FILEOFFSETPOS]) {
+ 		fgets(line, MAXSTRLEN, fp);
+ 		i++;
+ 	}
+ 
+ 	return i;
+ }
+ 
+ /* This adds an offset to the file numbers in a particular
+ ** result list. For instance, file 1 has file numbers going from
+ ** 1 to 10, but so does file 2, so I have to add 10 to all the
+ ** file numbers in file 2 before merging.
+ */
+ 
+ void addfilenums(ip, num)
+      struct indexentry *ip;
+      int num;
+ {
+ 	struct resultMerge *rp;
+ 
+ 	rp = ip->result;
+ 	while (rp != NULL) {
+ 		rp->filenum =
+ 		encodefilenum(getmap(decodefilenum(rp->filenum) + num));
+ 		rp = rp->next;
+ 	}
+ }
+ 
+ /* This reads the next line in the index file and puts the results
+ ** in a result structure.
+ */
+ 
+ struct indexentry *readindexline(fp, limit,metaFile)
+      FILE *fp;
+      long limit;
+      struct metaMergeEntry *metaFile;
+ {
+         int i, c, x, countnum, rank, filenum, structure,metaName;
+         char fileword[MAXWORDLEN];
+         struct resultMerge *rp;
+ 	struct indexentry *ip;
+ 	struct metaMergeEntry* tmp;
+ 
+         rp = NULL;
+ 
+ 	if (limit == ftell(fp))
+ 		return NULL;
+         for (i = 0; (c = fgetc(fp)) != 0; ) {
+                 if (c == ':') {
+                         fileword[i] = '\0';
+                         break;
+                 }
+                 else
+                         fileword[i++] = c;
+         }
+ 
+         countnum = 1;
+ 
+         ungetc(c, fp);
+         while ((c = fgetc(fp)) != 0) {
+                 x = 0;
+                 do {
+                         c = fgetc(fp);
+                         if (c == 0)
+                                 break;
+                         x *= 128;
+                         x += c & 127;
+                 } while (c & 128);
+ 		if (c == 0)
+ 			break;
+                 if (x) {
+                         if (countnum == 1) {
+                                 filenum = x;
+                                 countnum++;
+                         }
+                         else if (countnum == 2) {
+                                 rank = x;
+                                 countnum++;
+                         }
+                         else if (countnum == 3) {
+                                 structure = x;
+ 				countnum++;
+                         }
+ 			else if (countnum ==4) {
+ 			        metaName = x;
+ 				/*Need to modify metaName with new list*/
+ 				for(tmp=metaFile;tmp;tmp=tmp->next) {
+ 				  if (tmp->oldIndex == metaName) {
+ 				    metaName = tmp->newIndex;
+ 				    break;
+ 				  }
+ 				}
+                                 rp = (struct resultMerge *)
+                                 addtoresultlistMerge(rp, filenum,
+ 				rank, structure,metaName);
+ 				countnum = 1;
+                         }
+                 }
+         }
+ 
+ 	ip = (struct indexentry *) emalloc(sizeof(struct indexentry));
+ 	ip->word = (char *) mystrdup(fileword);
+ 	ip->result = rp;
+ 
+         return ip;
+ }
+ 
+ /* This puts all the file info into a hash table so that it can
+ ** be looked up by its pathname and filenumber. This is how
+ ** we find redundant file information.
+ */
+ 
+ void addindexfilelist(num, info, totalfiles)
+      int num;
+      char *info;
+      int *totalfiles;
+ {
+ 	int i;
+ 	unsigned hashval;
+ 	char tmpstr[MAXSTRLEN], path[MAXSTRLEN];
+ 	struct indexfileinfo *ip1, *ip2;
+ 
+ 	strcpy(path, extractpath(info));
+ 
+ 	i = lookupindexfilepath(path);
+ 	if (i != -1) {
+ 		*totalfiles = *totalfiles - 1;
+ 		remap(num, i);
+ 		return;
+ 	}
+ 
+ 	remap(num, remapVar + 1);
+ 	remapVar++;
+ 
+ 	ip1 = (struct indexfileinfo *) emalloc(sizeof(struct indexfileinfo));
+ 	ip1->filenum = num;
+ 	ip1->fileinfo = (char *) mystrdup(info);
+ 	ip1->path = (char *) mystrdup(path);
+ 
+ 	sprintf(tmpstr, "%d", num);
+ 	hashval = bighash(tmpstr);
+ 	ip1->next = indexfilehashlist[hashval];
+ 	indexfilehashlist[hashval] = ip1;
+ 
+ 	ip2 = (struct indexfileinfo *) emalloc(sizeof(struct indexfileinfo));
+ 	ip2->filenum = num;
+ 	ip2->fileinfo = (char *) mystrdup(info);
+ 	ip2->path = (char *) mystrdup(path);
+ 
+ 	hashval = bighash(path);
+ 	ip2->next = indexfilehashlist[hashval];
+ 	indexfilehashlist[hashval] = ip2;
+ }
+ 
+ /* This extracts the pathname information from the file information
+ ** line as stored in the index file.
+ */
+ 
+ char *extractpath(s)
+      char *s;
+ {
+ 	int i;
+ 	static char path[MAXSTRLEN];
+ 
+ 	for (i = 0; s[i] && s[i] != '\"'; i++)
+ 		path[i] = s[i];
+ 	path[i - 1] = '\0';
+ 	path[i] = '\0';
+ 
+ 	return path;
+ }
+ 
+ /* This returns the file information corresponding to a file number.
+ */
+ 
+ char *lookupindexfilenum(num)
+      int num;
+ {
+ 	unsigned hashval;
+ 	char tmpstr[MAXSTRLEN];
+ 	struct indexfileinfo *ip;
+ 
+ 	sprintf(tmpstr, "%d", num);
+ 	hashval = bighash(tmpstr);
+ 	ip = indexfilehashlist[hashval];
+ 
+ 	while (ip != NULL) {
+ 		if (ip->filenum == num)
+ 			return ip->fileinfo;
+ 		ip = ip->next;
+ 	}
+ 	return NULL;
+ }
+ 
+ /* This returns the file number corresponding to a pathname.
+ */
+ 
+ int lookupindexfilepath(path)
+      char *path;
+ {
+ 	unsigned hashval;
+ 	struct indexfileinfo *ip;
+ 
+ 	hashval = bighash(path);
+ 	ip = indexfilehashlist[hashval];
+ 
+ 	while (ip != NULL) {
+ 		if (!strcmp(ip->path, path))
+ 			return ip->filenum;
+ 		ip = ip->next;
+ 	}
+ 	return -1;
+ }
+ 
+ /* This simply concatenates two information lists that correspond
+ ** to a word found in both index files.
+ */
+ 
+ struct indexentry *mergeindexentries(ip1, ip2)
+      struct indexentry *ip1;
+      struct indexentry *ip2;
+ {
+ 	struct resultMerge *newrp, *rp1, *rp2;
+ 	struct indexentry *ep;
+ 
+ 	rp1 = ip1->result;
+ 	rp2 = ip2->result;
+ 	newrp = NULL;
+ 
+ 	while (rp1 != NULL) {
+ 		newrp = (struct resultMerge *) addtoresultlistMerge(newrp,
+ 		rp1->filenum, rp1->rank, rp1->structure,rp1->metaName);
+ 		rp1 = rp1->next;
+ 	}
+ 	while (rp2 != NULL) {
+ 		newrp = (struct resultMerge *) addtoresultlistMerge(newrp,
+ 		rp2->filenum, rp2->rank, rp2->structure,rp2->metaName);
+ 		rp2 = rp2->next;
+ 	}
+ 
+ 	ep = (struct indexentry *) emalloc(sizeof(struct indexentry));
+ 	ep->word = (char *) mystrdup(ip1->word);
+ 	ep->result = newrp;
+ 
+ 	return ep;
+ }
+ 
+ /* This prints a new word entry into the merged index file,
+ ** removing redundant file information as it goes along.
+ */
+ 
+ void printindexentry(ip, fp)
+      struct indexentry *ip;
+      FILE *fp;
+ {
+ 	int i, num, metaName;
+ 	struct resultMerge *rp;
+ 
+ 	for (i = 0; indexchars[i] != '\0'; i++)
+ 		if ((ip->word)[0] == indexchars[i] && !offsets[i])
+ 			offsets[i] = ftell(fp);
+ 	fprintf(fp, "%s:", ip->word);
+ 	initmarkentrylistMerge();
+ 	rp = ip->result;
+ 	while (rp != NULL) {
+ 		num = rp->filenum;
+ 		metaName = rp->metaName;
+ 		if (!ismarkedMerge(num,metaName)) {
+ 			marknumMerge(num,metaName);
+ 			compress(num, fp);
+ 			compress(rp->rank, fp);
+ 			compress(rp->structure, fp);
+ 			compress(rp->metaName,fp);
+ 		}
+ 		rp = rp->next;
+ 	}
+ 	fputc(0, fp);
+ }
+ 
+ /* This associates a number with a new number.
+ ** This function is used to remap file numbers from index
+ ** files to a new merged index file.
+ */
+ 
+ void remap(oldnum, newnum)
+      int oldnum;
+      int newnum;
+ {
+ 	unsigned hashval;
+ 	char tmpstr[MAXSTRLEN];
+ 	struct mapentry *mp;
+ 
+ 	mp = (struct mapentry *) emalloc(sizeof(struct mapentry));
+ 	mp->oldnum = oldnum;
+ 	mp->newnum = newnum;
+ 
+ 	sprintf(tmpstr, "%d", oldnum);
+ 	hashval = bighash(tmpstr);
+ 	mp->next = mapentrylist[hashval];
+ 	mapentrylist[hashval] = mp;
+ }
+ 
+ /* This retrieves the number associated with another.
+ */
+ 
+ int getmap(num)
+      int num;
+ {
+ 	unsigned hashval;
+ 	char tmpstr[MAXSTRLEN];
+ 	struct mapentry *mp;
+ 
+ 	sprintf(tmpstr, "%d", num);
+ 	hashval = bighash(tmpstr);
+ 	mp = mapentrylist[hashval];
+ 
+ 	while (mp != NULL) {
+ 		if (mp->oldnum == num)
+ 			return mp->newnum;
+ 		mp = mp->next;
+ 	}
+ 	return num;
+ }
+ 
+ /* This marks a number as having been printed.
+ */
+ 
+ void marknum(num)
+      int num;
+ {
+ 	unsigned hashval;
+ 	char tmpstr[MAXSTRLEN];
+ 	struct markentry *mp;
+ 
+ 	mp = (struct markentry *) emalloc(sizeof(struct markentry));
+ 	mp->num = num;
+ 
+ 	sprintf(tmpstr, "%d", num);
+ 	hashval = bighash(tmpstr);
+ 	mp->next = markentrylist[hashval];
+ 	markentrylist[hashval] = mp;
+ }
+ 
+ /* Same thing but for merge only */
+ void marknumMerge(num, metaName)
+      int num;
+      int metaName;
+ {
+         unsigned hashval;
+         char tmpstr[MAXSTRLEN];
+         struct markentryMerge *mp;
+  
+         mp = (struct markentryMerge *) emalloc(sizeof(struct markentryMerge));
+         mp->num = num;
+ 	mp->metaName = metaName;
+  
+         sprintf(tmpstr, "%d", num);
+         hashval = bighash(tmpstr);
+         mp->next = markentrylistMerge[hashval];
+         markentrylistMerge[hashval] = mp;
+ }      
+ 
+ /* Has a number been printed?
+ */
+ 
+ int ismarked(num)
+      int num;
+ {
+ 	unsigned hashval;
+ 	char tmpstr[MAXSTRLEN];
+ 	struct markentry *mp;
+ 
+ 	sprintf(tmpstr, "%d", num);
+ 	hashval = bighash(tmpstr);
+ 	mp = markentrylist[hashval];
+ 
+ 	while (mp != NULL) {
+ 		if (mp->num == num)
+ 			return 1;
+ 		mp = mp->next;
+ 	}
+ 	return 0;
+ }
+ 
+ 
+ int ismarkedMerge(num,metaName)
+      int num;
+      int metaName;
+ {
+         unsigned hashval;
+         char tmpstr[MAXSTRLEN];
+         struct markentryMerge *mp;
+  
+         sprintf(tmpstr, "%d", num);
+         hashval = bighash(tmpstr);
+         mp = markentrylistMerge[hashval];
+  
+         while (mp != NULL) {
+                 if ( (mp->num == num) && (mp->metaName == metaName) )
+                         return 1;
+                 mp = mp->next;
+ 	      }
+         return 0;
+       }
+ 
+ /* Initialize the marking list.
+ */
+ 
+ void initmarkentrylist()
+ {
+ 	int i;
+ 	struct markentry *mp;
+ 
+ 	for (i = 0; i < BIGHASHSIZE; i++) {
+ 		mp = markentrylist[i];
+ 		if (mp != NULL)
+ 			free(mp);
+ 		markentrylist[i] = NULL;
+ 	}
+ }
+ 
+ void initmarkentrylistMerge()
+ {
+         int i;
+         struct markentryMerge *mp;
+  
+         for (i = 0; i < BIGHASHSIZE; i++) {
+                 mp = markentrylistMerge[i];
+                 if (mp != NULL)
+                         free(mp);
+                 markentrylistMerge[i] = NULL;
+ 	      }
+ }      
+ 
+ 
+ /* Initialize the main file list.
+ */
+ 
+ void initindexfilehashlist()
+ {
+   int i;
+   struct indexfileinfo *ip;
+   
+   for (i = 0; i < BIGHASHSIZE; i++) {
+     ip = indexfilehashlist[i];
+     if (ip != NULL)
+       free(ip);
+     indexfilehashlist[i] = NULL;
+   }
+ }
+ 
+ /* Initialize the mapentrylist 
+ */
+ 
+ void initmapentrylist()
+ {
+   int i;
+   struct mapentry *ip;
+   
+   for (i = 0; i < BIGHASHSIZE; i++) {
+     ip = mapentrylist[i];
+     if (ip != NULL)
+       free(ip);
+     mapentrylist[i] = NULL;
+   }
+ }
+ 
+ 
+ 
+ /* Frees up used index entries, my best attempt at memory management...
+ ** I still have bytes leaking elsewhere...
+ */
+ 
+ void freeindexentry(ip)
+      struct indexentry *ip;
+ {
+ 	struct resultMerge *rp, *oldp;
+ 
+ 	free(ip->word);
+ 	rp = ip->result;
+ 	while (rp != NULL) {
+ 		oldp = rp;
+ 		rp = rp->next;
+ 		free(oldp);
+ 	}
+ 	free(ip);
+ }
+ 
+ /* Translates a file number into something that can be compressed.
+ */
+ 
+ int encodefilenum(num)
+      int num;
+ {
+ 	int i, j;
+ 
+ 	for (i = j = 0; i != num; i++) {
+ 		j++;
+ 		if (!(j % 128))
+ 			j++;
+ 	}
+ 	return j;
+ }
+ 
+ /* Translates a compressed file number into a correct file number.
+ */
+ 
+ int decodefilenum(num)
+      int num;
+ {
+         int i, extra;
+ 
+         for (i = 1, extra = 0; i < num; i++)
+                 if (!(i % 128)) {
+                         extra++;
+                         i++;
+                 }
+         num -= extra;
+ 
+ 	return num;
+ }
+ /* Similar to addtoresultlist, but also adding the meta name
+ */
+ 
+ struct resultMerge *addtoresultlistMerge(rp, filenum, rank, 
+ 					 structure, metaName)
+      struct resultMerge *rp;
+      int filenum;
+      int rank;
+      int structure;
+      int metaName;
+ {
+         struct resultMerge *newnode;
+         static struct resultMerge *head;
+  
+         newnode = (struct resultMerge *) emalloc(sizeof(struct resultMerge));
+         newnode->filenum = filenum;
+         newnode->rank = rank;
+         newnode->structure = structure;
+ 	newnode->metaName = metaName;
+         newnode->next = NULL;
+  
+         if (rp == NULL)
+                 rp = newnode;
+         else
+                 head->next = newnode;
+  
+         head = newnode;
+  
+         return rp;
+ }
+ 
+ /* Reads the meta names from the index. Needs to be different from
+ ** readMetaNames because needs to zero out the counter.
+ */
+ struct metaMergeEntry* readMergeMeta(metaFile,fp)
+      struct metaMergeEntry* metaFile;
+      FILE* fp;
+ {     
+   int i, c, counter;
+   char word[MAXWORDLEN];
+   
+   counter = 0;
+   fseek(fp, offsets[METANAMEPOS], 0);
+   for (i = 0; (c = fgetc(fp)) != '\n' && c != EOF; ){
+     if (!isspace(c))
+       word[i++] = c;
+     else {
+       word[i] = '\0';
+       metaFile = addMetaMerge(metaFile, word,&counter);
+       i = 0;
+     }
+   }
+   return metaFile;
+ }
+ 
+ /* Adds an entry to the list of meta names for one index, 
+ ** setting the new index to 0 - it will then be set by 
+ ** createMetaMerge.
+ */
+ 
+ struct metaMergeEntry* addMetaMerge(metaFile, metaWord,counter)
+      struct metaMergeEntry* metaFile;
+      char* metaWord;
+      int* counter;
+ {
+   int i;
+   struct metaMergeEntry* newEntry;
+   struct metaMergeEntry* tmpEntry;
+   
+   if (*counter == 0)
+     *counter = 2;
+   else if ((*counter) == 1 ||  (!((*counter) % 128)) )
+    (*counter)++;
+   for( i=0; metaWord[i]; i++)
+     metaWord[i] =  tolower(metaWord[i]);
+   newEntry = (struct metaMergeEntry*) emalloc(sizeof(struct metaMergeEntry));
+   newEntry->metaName = (char*)mystrdup(metaWord);
+   newEntry->oldIndex = (*counter)++;
+   newEntry->newIndex = 0;
+   newEntry->next = NULL;
+   if (metaFile)
+     {
+       for(tmpEntry=metaFile;tmpEntry->next!=NULL;tmpEntry=tmpEntry->next)
+         ;
+       tmpEntry->next = newEntry;
+     }
+   else
+     metaFile = newEntry;
+   
+   return metaFile;
+ }
+ 
+ /* Creates a list of all the meta names in the indexes
+ */
+ struct metaEntry* createMetaMerge(metaFile1, metaFile2)
+      struct metaMergeEntry* metaFile1;
+      struct metaMergeEntry* metaFile2;
+ {
+   struct metaMergeEntry* tmpEntry;
+   int counter;
+ 
+   metaEntryList = NULL;
+   counter = 0;
+   for (tmpEntry=metaFile1;tmpEntry;tmpEntry=tmpEntry->next)
+     metaEntryList = addMetaMergeList(metaEntryList,tmpEntry,&counter);
+   
+   for (tmpEntry=metaFile2;tmpEntry;tmpEntry=tmpEntry->next)
+     metaEntryList = addMetaMergeList(metaEntryList,tmpEntry,&counter);
+ 
+   return metaEntryList;
+ }
+ 
+ /* Adds an entry to the merged meta names list and changes the
+  ** new index in the idividual file entry
+  */
+ 
+ struct metaEntry* addMetaMergeList(metaEntryList,metaFileEntry,count)
+      struct metaEntry* metaEntryList;
+      struct metaMergeEntry* metaFileEntry;
+      int* count;
+ {
+   int i, wordExists, newIndex;
+   struct metaEntry* newEntry;
+   struct metaEntry* tmpEntry;
+   struct metaEntry* last;
+   char *metaWord, *compWord;
+   
+   wordExists = 0;
+   if ((*count) == 0)
+     *count = 2;
+   else if ((*count) == 1 ||  (!((*count) % 128)) )
+     (*count)++;
+   metaWord = metaFileEntry->metaName;
+   
+   for( i=0; metaWord[i]; i++)
+     metaWord[i] =  tolower(metaWord[i]);
+   if (metaEntryList)
+     {
+       for(tmpEntry=metaEntryList;tmpEntry;tmpEntry=tmpEntry->next)
+ 	{
+ 	  if (tmpEntry->next == NULL)
+ 	    last = tmpEntry;
+ 	  compWord = tmpEntry->metaName;
+ 	  if (!strcmp(compWord,metaWord) ) 
+ 	    {
+ 	      wordExists = 1;
+ 	      newIndex = tmpEntry->index;
+ 	      break;
+ 	    }
+ 	}
+       if (wordExists)
+ 	metaFileEntry->newIndex = newIndex;
+       else {
+ 	newEntry = (struct metaEntry*) emalloc(sizeof(struct metaEntry));
+ 	newEntry->metaName = (char*)mystrdup(metaWord);
+ 	newEntry->index = *count;
+ 	newEntry->next = NULL;
+ 	metaFileEntry->newIndex = (*count)++;
+ 	last->next = newEntry;
+       }
+     }
+   else {
+     newEntry = (struct metaEntry*) emalloc(sizeof(struct metaEntry));
+     newEntry->metaName = (char*)mystrdup(metaWord);
+     newEntry->index = *count;
+     newEntry->next = NULL;
+     metaFileEntry->newIndex = (*count)++;
+     metaEntryList = newEntry;
+   }
+   return metaEntryList;
+ }
+   
+   
+     
+   
Index: harvest/components/broker/swish/merge.h
diff -c /dev/null harvest/components/broker/swish/merge.h:1.1
*** /dev/null	Mon Oct 27 18:41:00 1997
--- harvest/components/broker/swish/merge.h	Sun Oct 12 16:33:05 1997
***************
*** 0 ****
--- 1,91 ----
+ /*
+ ** Copyright (C) 1995, Enterprise Integration Technologies Corp.        
+ ** All Rights Reserved.
+ ** Kevin Hughes, kevinh@eit.com 
+ ** 3/11/94
+ **
+ ** Added remapVar and initmapentrylist to fix the merge option -M
+ ** G. Hill 3/7/97
+ **
+ */
+ 
+ struct indexentry {
+         char *word;
+         struct resultMerge *result;
+ };
+ 
+ struct resultMerge{
+         int filenum;
+ 	int rank;
+ 	int structure;
+ 	int metaName;
+ 	struct resultMerge *next;
+ };
+ 
+ struct indexfileinfo {
+         int filenum;
+         char *fileinfo;
+ 	char *path;
+         struct indexfileinfo *next;
+ };
+ 
+ struct mapentry {
+ 	int oldnum;
+ 	int newnum;
+ 	struct mapentry *next;
+ };
+ 
+ struct markentry {
+ 	int num;
+ 	struct markentry *next;
+ };
+ 
+ struct markentryMerge {
+         int num;
+ 	int metaName;
+ 	struct markentryMerge *next;
+ };	
+ 
+ struct metaMergeEntry {
+   char* metaName;
+   int oldIndex;
+   int newIndex;
+   struct metaMergeEntry* next;
+ };
+ 
+ struct indexfileinfo *indexfilehashlist[BIGHASHSIZE];
+ struct mapentry *mapentrylist[BIGHASHSIZE];
+ struct markentry *markentrylist[BIGHASHSIZE];
+ struct markentryMerge *markentrylistMerge[BIGHASHSIZE];
+ int remapVar;
+ 
+ void readmerge();
+ int getindexfilenum();
+ void addfilenums();
+ struct indexentry *readindexline();
+ void addindexfilelist();
+ char *extractpath();
+ char *lookupindexfilenum();
+ int lookupindexfilepath();
+ struct indexentry *mergeindexentries();
+ void printindexentry();
+ void remap();
+ int getmap();
+ void marknum();
+ void marknumMerge();
+ int ismarked();
+ int ismarkedMerge();
+ void initmarkentrylist();
+ void initmarkentrylistMerge();
+ void initindexfilehashlist();
+ void freeindexentry();
+ int encodefilenum();
+ int decodefilenum();
+ void initmapentrylist();
+ struct resultMerge *addtoresultlistMerge();
+ struct metaMergeEntry* readMergeMeta();
+ struct metaMergeEntry* addMetaMerge();
+ struct metaEntry* createMetaMerge();
+ struct metaEntry* addMetaMergeList();
+ 
+ 
Index: harvest/components/broker/swish/search.c
diff -c /dev/null harvest/components/broker/swish/search.c:1.1
*** /dev/null	Mon Oct 27 18:41:01 1997
--- harvest/components/broker/swish/search.c	Sun Oct 12 16:33:06 1997
***************
*** 0 ****
--- 1,1032 ----
+ /*
+ ** Copyright (C) 1995, Enterprise Integration Technologies Corp.        
+ ** All Rights Resereved.
+ ** Kevin Hughes, kevinh@eit.com 
+ ** 3/11/94
+ **
+ ** Changes in expandstar and parseterm to fix the wildcard * problem.
+ ** G. Hill, ghill@library.berkeley.edu  3/11/97
+ **
+ ** Changes in notresultlist, parseterm, and fixnot to fix the NOT problem
+ ** G. Hill, ghill@library.berkeley.edu 3/13/97
+ **
+ ** Changes in search, parseterm, fixnot, operate, getfileinfo
+ ** to support METADATA
+ ** G. Hill 3/18/97 ghill@library.berkeley.edu
+ */
+ 
+ #include "swish.h"
+ #include "search.h"
+ #include "file.h"
+ 
+ /* The main search function.
+ ** Parentheses are stripped out, things made lowercase,
+ ** extra blanks removed, etc.
+ */
+ 
+ void search(words, indexlist, structure)
+      char *words;
+      struct swline *indexlist;
+      int structure;
+ {
+   int i, j, metaName;
+   float num;
+   char word[MAXWORDLEN];
+   struct result *resultlist;
+   struct sortresult *sortresultlist;
+   struct swline *tmplist;
+   FILE *fp;
+ #ifdef DEBUG
+   struct swline *newp2;
+ #endif
+   
+   searchwordlist = NULL;
+   metaName = 1;
+   
+   for (i = j = 0; words[i] != '\0' && words[i] != '\n'; i++) {
+     if (isspace(words[i]) || words[i] == '(' ||
+ 	words[i] == ')' || words[i] == '=') {
+       if (words[i] == '=')
+ 	{ if (j != 0)
+ 	    {if (words[i-1] != '/')
+ 	       { 
+ 		 word[j] = '\0';
+ 		 searchwordlist = (struct swline *)
+ 		   addswline(searchwordlist, (char *)
+ 			     convertentities(word));
+ 		 j = 0;
+ 		 searchwordlist = (struct swline *)
+ 		   addswline(searchwordlist, "=");
+ 	       }
+ 	     else
+ 	       { /* Needs to erase the '/' */
+ 		 j--;
+ 		 word[j++] = tolower(words[i]);
+ 	       }
+ 	   }
+ 	  else
+ 	    searchwordlist = (struct swline *)
+ 	      addswline(searchwordlist, "=");
+ 	}
+       else
+ 	{
+ 	  if (j) {
+ 	    word[j] = '\0';
+ 	    searchwordlist = (struct swline *)
+ 	      addswline(searchwordlist, (char *)
+ 			convertentities(word));
+ 	    j = 0;
+ 	  }
+ 	  if (words[i] == '(') {
+ 	    searchwordlist = (struct swline *)
+ 	      addswline(searchwordlist, "(");
+ 	  }
+ 	  if (words[i] == ')') {
+ 	    searchwordlist = (struct swline *)
+ 	      addswline(searchwordlist, ")");
+ 	  }
+ 	}
+     }
+     else
+       word[j++] = tolower(words[i]);
+   }
+   if (j) {
+     word[j] = '\0';
+     searchwordlist = (struct swline *)
+       addswline(searchwordlist, (char *) convertentities(word));
+   }
+   
+   printf("%s\n", INDEXHEADER);
+   if (words[0] == '\0') {
+     printf("err: no search words specified\n.\n");
+     exit(0);
+   }
+   
+   printf("# Search words:");
+   tmplist = searchwordlist;
+   while (tmplist != NULL) {
+     printf(" %s", tmplist->line);
+     tmplist = tmplist->next;
+   }
+   putchar('\n');
+   
+   while (indexlist != NULL) {
+     
+     commonerror = bigrank = 0;
+     
+     if ((fp = fopen(indexlist->line, "r")) == NULL) {
+       printf("# Name: unknown index\n");
+       printf("err: could not open index file\n.\n");
+       exit(0);
+     }
+     
+     if (!isokindexheader(fp)) {
+       printf("err: the index file format is unknown\n.\n");
+       exit(0);
+     }
+     
+     getheader(fp);
+     
+     if (!getindexfilenum(fp)) {
+       printf("err: the index file is empty\n.\n");
+       exit(0);
+     }
+     
+     readoffsets(fp);
+     readstopwords(fp);
+     readfileoffsets(fp);
+     readMetaNames(fp);
+     
+     resultlist = NULL;
+     tmplist = searchwordlist;
+     tmplist = (struct swline *) fixnot(tmplist, fp);
+     searchwordlist = (struct swline *) expandstar(tmplist, fp);
+ #ifdef DEBUG
+     newp2 = searchwordlist;
+     while (newp2 != NULL) {
+       printf("%s ", newp2->line);
+       newp2 = newp2->next;
+     }
+     putchar('\n');
+ #endif
+ 
+     resultlist = (struct result *) parseterm(fp, 0, metaName);
+     
+     sortresultlist = NULL;
+     while (resultlist != NULL) {
+       if (resultlist->structure & structure)
+ 	sortresultlist = (struct sortresult *)
+ 	  addsortresult(sortresultlist, resultlist->rank,
+ 			lookupfile(resultlist->filenum, fp));
+       resultlist = resultlist->next;
+     }
+     
+     fclose(fp);
+     
+     if (sortresultlist == NULL) {
+       if (commonerror)
+ 	printf("err: a word is too common\n");
+       else
+ 	printf("err: no results\n");
+     }
+     else {
+       if (bigrank)
+ 	num = 1000.0 / (float) bigrank;
+       else
+ 	num = 1000;
+       printsortedresults(sortresultlist, num);
+     }
+     
+     searchwordlist = tmplist;
+     indexlist = indexlist->next;
+     
+   }
+   
+   printf(".\n");
+ }
+ 
+ /* This puts parentheses in the right places around not structures
+ ** so the parser can do its thing correctly.
+ ** It does it both for 'not' and '='; the '=' is used for the METADATA (GH)
+ */
+ 
+ struct swline *fixnot(sp)
+      struct swline *sp;
+ {
+ 	int openparen, hasnot;
+ 	int openMeta, hasMeta;
+ 	struct swline *tmpp, *newp;
+ #ifdef DEBUG
+ 	struct swline *newp2;
+ #endif
+ 
+ 	tmpp = sp;
+ 	newp = NULL;
+ 
+ 	openparen = 0;
+ 	openMeta = 0;
+ 	hasMeta = 0;
+ 	hasnot = 0;
+ 	while (tmpp != NULL) {
+ 		if ( ((tmpp->line)[0] == '(') && hasnot)
+ 			openparen++;
+ 		else if ( ((tmpp->line)[0] == '(') && hasMeta)
+ 		        openMeta++;
+ 		else if ( ((tmpp->line)[0] == ')') && hasnot)
+ 			openparen--;
+ 		else if ( ((tmpp->line)[0] == ')') && hasMeta)
+ 		        openMeta--;
+ 		if (isMetaName(tmpp->next)) {
+ 		  /* If it is a metaName add the name and = and skip to next */
+ 		  hasMeta = 1;
+ 		  newp = (struct swline *) addswline(newp, "(");
+ 		  newp = (struct swline *) addswline(newp, tmpp->line);
+                   newp = (struct swline *) addswline(newp, "=");
+ 		  tmpp = tmpp->next;
+ 		  tmpp = tmpp->next;
+ 		  continue;
+ 		}
+ 		if (!strcmp(tmpp->line, "not") ) {
+ 			hasnot = 1;
+ 			newp = (struct swline *) addswline(newp, "(");
+ 		}
+ 		else if (hasnot && !openparen) {
+ 			hasnot = 0;
+ 			newp = (struct swline *) addswline(newp, tmpp->line);
+ 			newp = (struct swline *) addswline(newp, ")");
+ 			tmpp = tmpp->next;
+ 			continue;
+ 		}
+ 		else if (hasMeta && !openMeta) {
+ 		        hasMeta = 0;
+ 		        newp = (struct swline *) addswline(newp, tmpp->line);
+ 		        newp = (struct swline *) addswline(newp, ")");
+ 		        tmpp = tmpp->next;
+ 		        continue;
+ 		}
+ 		newp = (struct swline *) addswline(newp, tmpp->line);
+ 		if (!strcmp(tmpp->line, "=") ) {
+ 		        hasMeta = 1;
+ 		        newp = (struct swline *) addswline(newp, "(");
+ 		}
+ 		tmpp = tmpp->next;
+ 	}
+ 
+ #ifdef DEBUG
+ 	newp2 = newp;
+ 	while (newp2 != NULL) {
+ 		printf("%s ", newp2->line);
+ 		newp2 = newp2->next;
+ 	}
+ 	putchar('\n');
+ #endif
+ 
+ 	return newp;
+ }
+ 
+ /* Expands words with asterisks as wildcards into a series of
+ ** "or" searches. Terms like "quick\*" are expanded into
+ ** "quicktime or quickly", etc.
+ */
+ 
+ struct swline *expandstar(sp, fp)
+      struct swline *sp;
+      FILE *fp;
+ {
+ 	int i, firsttime, gotstar;
+ 	char foundword[MAXWORDLEN], searchword[MAXWORDLEN];
+         struct swline *newp;
+ 
+ 	newp = NULL;
+ 	while (sp != NULL) {
+ 		strcpy(searchword, sp->line);
+ 		if (searchword[0] != '*' && strchr(searchword, '*')) {
+ 			for (i = gotstar = 0; searchword[i]; i++)
+ 				if (gotstar)
+ 					searchword[i] = '\0';
+ 				else if (searchword[i] == '*') {
+ 					searchword[i] = '\0';
+ 					gotstar = 1;
+ 				}
+ 			firsttime = 0;
+ 			do {
+ 				strcpy(foundword, getmatchword(searchword,
+ 				fp, firsttime));
+ 				if (strcmp(foundword, NOWORD)) {
+ 				        /* Add "(" if it is the first time */
+ 				        if (firsttime == 0) 
+ 					        newp = (struct swline *)
+ 					             addswline(newp, "(");
+ 					if (firsttime)
+ 						newp = (struct swline *)
+ 						addswline(newp, "or");
+ 					newp = (struct swline *)
+ 					addswline(newp, foundword);
+ 				}
+ 				else {
+ 					if (!firsttime)
+ 						newp = (struct swline *)
+ 						addswline(newp, NOWORD);
+ 					else  /*Add ")" if last of many */
+ 					  newp = (struct swline *)
+ 					       addswline(newp, ")");
+ 					break;
+ 				}
+ 				firsttime++;
+ 			} while (strcmp(foundword, NOWORD));
+ 		}
+ 		else {
+ 			newp = (struct swline *) addswline(newp,
+ 			searchword);
+ 		}
+ 		sp = sp->next;
+ 	}
+ 	return newp;
+ }
+ 
+ /* If firsttime is 1, returns the first match to a beginnng of a word.
+ ** Else if it's 0, returns the next match, until nothing is found,
+ ** in which case NULL is returned.
+ */
+ 
+ char *getmatchword(word, fp, firsttime)
+      char *word;
+      FILE *fp;
+      int firsttime;
+ {
+ 	int i, c, found;
+         char *d;
+ 	static char fileword[MAXWORDLEN];
+ 
+ 	if (!firsttime) {
+ 		for (i = found = 0; indexchars[i] != '\0'; i++)
+ 			if (word[0] == indexchars[i]) {
+ 				fseek(fp, offsets[i], 0);
+ 				found = 1;
+ 			}
+ 		if (!found)
+ 			return NOWORD;
+ 	}
+ 
+ 	if (offsets[STOPWORDPOS] == ftell(fp))
+ 		return NOWORD;
+         for (i = 0; (c = fgetc(fp)) != 0; ) {
+                 if (c == ':') {
+                         fileword[i] = '\0';
+ 			i = 0;
+ 			while ((c = fgetc(fp)) != 0)
+ 				;
+ 			if (fileword[0] != word[0])
+ 				return NOWORD;
+ 			d = (char *) strstr(fileword, word);
+                         if (d != NULL && d == &fileword[0])
+                                 return fileword;
+ 			else {
+ 				if (offsets[STOPWORDPOS] == ftell(fp))
+ 					return NOWORD;
+ 			}
+                 }
+ 		else
+ 			fileword[i++] = c;
+ 	}
+ 	return NOWORD;
+ }
+ 
+ /* Reads and prints the header of an index file.
+ */
+ 
+ void getheader(fp)
+      FILE *fp;
+ {
+ 	int c;
+ 	char line[MAXSTRLEN];
+ 
+ 	fgets(line, MAXSTRLEN, fp);
+         while (1) {
+                 c = fgetc(fp);
+                 ungetc(c, fp);
+                 if (c == '#') {
+                         fgets(line, MAXSTRLEN, fp);
+                         printf("%s", line);
+                         continue;
+                 }
+ 		else
+ 			break;
+ 	}
+ 	fseek(fp, 0, 0);
+ }
+ 
+ /* Reads the offsets in the index file so word lookup is faster.
+ */
+ 
+ void readoffsets(fp)
+      FILE *fp;
+ {
+ 	int c, i, k;
+ 	long j, num;
+ 
+ 	for (i = 0; i < MAXCHARS; i++)
+ 		offsets[i] = 0;
+ 
+ 	fseek(fp, 0, 0);
+ 	while (1) {
+ 		c = fgetc(fp);
+ 		if (c == '#') {
+ 			do {
+ 				c = fgetc(fp);
+ 			} while (c && c != '\n');
+ 			continue;
+ 		}
+ 		else
+ 			break;
+ 	}
+ 
+         j = 0;
+         while (c != EOF && c != '\n') {
+ 		k = MAXLONGLEN;
+                 for (num = 0; c && isdigit(c) && k--; ) {
+                         num = (num * 10) + (c - '0');
+ 			c = fgetc(fp);
+ 		}
+                 offsets[j++] = num;
+         }
+ }
+ 
+ /* Reads the stopwords in the index file.
+ */
+ 
+ void readstopwords(fp)
+      FILE *fp;
+ {
+ 	int i, c;
+ 	char word[MAXWORDLEN];
+ 
+ 	fseek(fp, offsets[STOPWORDPOS], 0);
+ 	for (i = 0; (c = fgetc(fp)) != '\n' && c != EOF; )
+ 		if (!isspace(c))
+ 			word[i++] = c;
+ 		else {
+ 			word[i] = '\0';
+ 			addstophash(word);
+ 			i = 0;
+ 		}
+ }
+ 
+ /* Reads the metaNames from the index
+ */
+ 
+ void readMetaNames(fp)
+      FILE *fp;
+ {
+ 	int i, c;
+ 	char word[MAXWORDLEN];
+ 
+ 	fseek(fp, offsets[METANAMEPOS], 0);
+ 	for (i = 0; (c = fgetc(fp)) != '\n' && c != EOF; )
+ 		if (!isspace(c))
+ 			word[i++] = c;
+ 		else {
+ 			word[i] = '\0';
+ 			metaEntryList = addMetaEntry(metaEntryList, word);
+ 			i = 0;
+ 		}
+ }
+ 
+ /* Reads the file offset table in the index file.
+ */
+ 
+ void readfileoffsets(fp)
+      FILE *fp;
+ {
+ 	int j, k, c;
+ 	long num;
+ 
+         j = 0;
+         fseek(fp, offsets[FILEOFFSETPOS], 0);
+         c = fgetc(fp);
+         while (c != EOF && c != '\n') {
+                 k = MAXLONGLEN;
+                 for (num = 0; c != EOF && isdigit(c) && k--; ) {
+                         num = (num * 10) + (c - '0');
+                         c = fgetc(fp);
+                 }
+                 addtofilehashlist(j++, num);
+         }
+ }
+ 
+ /* The recursive parsing function.
+ ** This was a headache to make but ended up being surprisingly easy. :)
+ ** parseone tells the function to only operate on one word or term.
+ */
+ 
+ struct result *parseterm(fp, parseone, metaName)
+      FILE *fp;
+      int parseone;
+      int metaName;
+ {
+ 	int rulenum;
+         char word[MAXWORDLEN];
+ 	struct result *rp, *newrp;
+ 
+ 	rp = NULL;
+ 
+ 	rulenum = OR_RULE;
+ 	while (searchwordlist != NULL) {
+ 		strcpy(word, searchwordlist->line);
+ 
+ 		if (rulenum == NO_RULE)
+ 			rulenum = DEFAULT_RULE;
+ 		if (isunaryrule(word)) {
+ 			searchwordlist = searchwordlist->next;
+ 			rp = (struct result *) parseterm(fp, 1, metaName);
+ 			rp = (struct result *) notresultlist(rp, fp);
+ 			/* Wild goose chase */
+ 			rulenum = NO_RULE;
+ 			continue;
+ 		}
+ 		else if (isbooleanrule(word)) {
+ 			rulenum = getrulenum(word);
+ 			searchwordlist = searchwordlist->next;
+ 			continue;
+ 		}
+ 
+ 		if (word[0] == '(') {
+ 
+ 			searchwordlist = searchwordlist->next;
+ 			newrp = (struct result *) parseterm(fp, 0, metaName);
+ 
+ 			if (rulenum == AND_RULE)
+ 				rp = (struct result *)
+ 				andresultlists(rp, newrp);
+ 			else if (rulenum == OR_RULE)
+ 				rp = (struct result *)
+ 				orresultlists(rp, newrp);
+ 			if (searchwordlist == NULL)
+ 				break;
+ 
+ 			rulenum = NO_RULE;
+ 			continue;
+ 
+ 		}
+ 		else if (word[0] == ')') {
+ 			searchwordlist = searchwordlist->next;
+ 			break;
+ 		}
+ 
+ 		/* Check if the next word is '=' */
+ 		if ( isMetaName(searchwordlist->next) ) {
+ 		  metaName = getMetaName(word);
+ 		  if (metaName == 1){
+ 		    printf ("err: The metaName %s doesn't exist in  user configfile\n",
+ 			    word);
+ 		    exit(0);
+ 		  }
+ 		  /* Skip both the metaName end the '=' */
+ 		  searchwordlist = searchwordlist->next->next;
+ 		  newrp = (struct result *) parseterm(fp, 1, metaName);
+ 		  if (rulenum == AND_RULE)
+ 		    rp = (struct result *) andresultlists(rp, newrp);
+ 		  else if (rulenum == OR_RULE)
+ 		    rp = (struct result *) orresultlists(rp, newrp);
+ 		  if (searchwordlist == NULL)
+ 		    break;
+ 
+ 		  rulenum = NO_RULE;
+ 		  metaName = 1;
+ 		  continue;
+ 		}
+ 
+ 		rp = (struct result *) operate(rp, rulenum, word, 
+ 					       fp, metaName);
+ 
+ 		if (parseone) {
+ 			searchwordlist = searchwordlist->next;
+ 			break;
+ 		}
+ 		rulenum = NO_RULE;
+ 
+ 		searchwordlist = searchwordlist->next;
+         }
+ 
+ 	return rp;
+ }
+ 
+ /* Looks up a word in the index file -
+ ** it calls getfileinfo(), which does the real searching.
+ */
+ 
+ struct result *operate(rp, rulenum, word, fp, metaName)
+      struct result *rp;
+      int rulenum;
+      int metaName;
+      char *word;
+      FILE *fp;
+ {
+         int i, found;
+ 	struct result *newrp, *returnrp;
+ 
+ 	if (isstopword(word) && !isrule(word)) {
+ 		if (rulenum == OR_RULE && rp != NULL)
+ 			return rp;
+ 		else
+ 			commonerror = 1;
+ 	}
+ 
+ 	for (i = found = 0; indexchars[i] != '\0'; i++)
+ 		if (word[0] == indexchars[i]) {
+ 			fseek(fp, offsets[i], 0);
+ 			found = 1;
+ 		}
+ 	if (!found) {
+ 		if (rulenum == AND_RULE)
+ 			return NULL;
+ 		else if (rulenum == OR_RULE)
+ 			return rp;
+ 	}
+ 
+ 	newrp = (struct result *) getfileinfo(word, fp, metaName);
+ 	if (rulenum == AND_RULE)
+ 		returnrp = (struct result *) andresultlists(rp, newrp);
+ 	else if (rulenum == OR_RULE)
+ 		returnrp = (struct result *) orresultlists(rp, newrp);
+ 	else if (rulenum == NOT_RULE)
+ 		returnrp = (struct result *) notresultlist(newrp, fp);
+ 	return returnrp;
+ }
+ 
+ /* Looks up a file name in the index file.
+ */
+ 
+ char *lookupfile(filenum, fp)
+      int filenum;
+      FILE *fp;
+ {
+         static char line[MAXSTRLEN];
+ 
+         fseek(fp, getfilenum(decodefilenum(filenum) - 1), 0);
+         fgets(line, MAXSTRLEN, fp);
+ 
+ 	return line;
+ }
+ 
+ /* Finds a word and returns its corresponding file and rank information list.
+ ** If not found, NULL is returned.
+ */
+ 
+ struct result *getfileinfo(word, fp, metaName)
+      char *word;
+      FILE *fp;
+      int metaName;
+ {
+ 	int i, c, x, countnum, rank, filenum, structure;
+         char fileword[MAXWORDLEN];
+         struct result *rp;
+ 
+ 	rp = NULL;
+ 
+         for (i = 0; (c = fgetc(fp)) != 0; ) {
+                 if (c == ':') {
+                         fileword[i] = '\0';
+ 			i = 0;
+                         if (!strcmp(word, fileword))
+                                 break;
+                         else {
+ 				while ((c = fgetc(fp)) != 0)
+ 					;
+ 				if (offsets[STOPWORDPOS] == ftell(fp))
+ 					return NULL;
+ 				continue;
+ 			}
+                 }
+ 		else
+ 			fileword[i++] = c;
+ 	}
+ 	if (c == 0)
+ 		return NULL;
+ 
+         countnum = 1;
+ 
+ 	ungetc(c, fp);
+ 	while ((c = fgetc(fp)) != 0) {
+ 		x = 0;
+ 		do {
+ 			c = fgetc(fp);
+ 			if (c == 0)
+ 				return rp;
+ 			x *= 128;
+ 			x += c & 127;
+ 		} while (c & 128);
+ 		if (x) {
+ 			if (countnum == 1) {
+ 				filenum = x;
+ 				countnum++;
+ 			}
+ 			else if (countnum == 2) {
+ 				rank = x;
+ 				countnum++;
+ 			}
+ 			else if (countnum == 3) {
+               			  structure = x;
+ 		        	  countnum++;
+ 			}
+ 			else if (countnum == 4) {
+ 			  if ( x == metaName )
+ 			    rp = (struct result *)
+ 			      addtoresultlist(rp,filenum, rank,structure);
+ 			  countnum = 1;
+ 			}
+ 		      }
+ 	      }
+ 	
+ 	return rp;
+ }
+ 
+ /* Is a word a rule?
+ */
+ 
+ int isrule(word)
+      char *word;
+ {
+ 	if (!strcmp(word, "and") || !strcmp(word, "or") || !strcmp(word, "not"))
+ 		return 1;
+ 	else
+ 		return 0;
+ }
+ 
+ /* Is a word a boolean rule?
+ */
+ 
+ int isbooleanrule(word)
+      char *word;
+ {
+ 	if (!strcmp(word, "and") || !strcmp(word, "or"))
+ 		return 1;
+ 	else
+ 		return 0;
+ }
+ 
+ /* Is a word a unary rule?
+ */
+ 
+ int isunaryrule(word)
+      char *word;
+ {
+ 	if (!strcmp(word, "not"))
+ 		return 1;
+ 	else
+ 		return 0;
+ }
+ 
+ /* Return the number for a rule.
+ */
+ 
+ int getrulenum(word)
+      char *word;
+ {
+ 	if (!strcmp(word, "and"))
+ 		return AND_RULE;
+ 	else if (!strcmp(word, "or"))
+ 		return OR_RULE;
+ 	else if (!strcmp(word, "not"))
+ 		return NOT_RULE;
+ 	return NO_RULE;
+ }
+ 
+ /* Takes two lists of results from searches and ANDs them together.
+ */
+ 
+ struct result *andresultlists(r1, r2)
+      struct result *r1;
+      struct result *r2;
+ {
+         static struct result *tmpnode, *newnode;
+ 
+         if (r1 == NULL || r2 == NULL)
+                 return NULL;
+ 
+         newnode = NULL;
+ 
+         while (r1 != NULL) {
+                 tmpnode = r2;
+                 while (tmpnode != NULL) {
+                         if (r1->filenum == tmpnode->filenum)
+                                 newnode = (struct result *)
+                                 addtoresultlist(newnode, r1->filenum,
+                                 (r1->rank + tmpnode->rank) / 2,
+ 				r1->structure & tmpnode->structure);
+                         tmpnode = tmpnode->next;
+                 }
+                 r1 = r1->next;
+         }
+ 
+         return newnode;
+ }
+ 
+ /* Takes two lists of results from searches and ORs them together.
+ */
+ 
+ struct result *orresultlists(r1, r2)
+      struct result *r1;
+      struct result *r2;
+ {
+         int i;
+         struct result *rp;
+         static struct result *newnode;
+ 
+ 	newnode = NULL;
+ 
+         if (r1 == NULL)
+                 return r2;
+         else if (r2 == NULL)
+                 return r1;
+ 
+ 	initresulthashlist();
+ 	while (r1 != NULL) {
+ 		mergeresulthashlist(r1->filenum, r1->rank, r1->structure);
+ 		r1 = r1->next;
+ 	}
+ 	while (r2 != NULL) {
+ 		mergeresulthashlist(r2->filenum, r2->rank, r2->structure);
+ 		r2 = r2->next;
+ 	}
+ 	for (i = 0; i < HASHSIZE; i++) {
+ 		rp = resulthashlist[i];
+ 		while (rp != NULL) {
+ 			newnode = (struct result *) addtoresultlist(newnode,
+ 			rp->filenum, rp->rank, rp->structure);
+ 			rp = rp->next;
+ 		}
+ 	}
+ 
+         return newnode;
+ }
+ 
+ /* This performs the NOT unary operation on a result list.
+ ** NOTed files are marked with a default rank of 1000.
+ **
+ ** Basically it returns all the files that have not been
+ ** marked (GH)
+ */
+ 
+ struct result *notresultlist(rp, fp)
+      struct result *rp;
+      FILE *fp;
+ {
+ 	int i, filenums;
+         struct result *newp;
+ 
+ 	newp = NULL;
+ 
+ 	initmarkentrylist();
+ 	while (rp != NULL) {
+ 		marknum(rp->filenum);
+ 		rp = rp->next;
+ 	}
+ 
+ 	filenums = getindexfilenum(fp);
+ 	for (i = 1; i <= filenums; i++) {
+ 	  if (!ismarked(i))
+ 	    newp = (struct result *) addtoresultlist(newp,
+ 						     i, 1000, IN_ALL);
+ 	}
+ 
+ 	return newp;
+ }
+ 
+ /* Adds a file number and rank to a list of results.
+ */
+ 
+ struct result *addtoresultlist(rp, filenum, rank, structure)
+      struct result *rp;
+      int filenum;
+      int rank;
+      int structure;
+ {
+         struct result *newnode;
+         static struct result *head;
+ 
+         newnode = (struct result *) emalloc(sizeof(struct result));
+         newnode->filenum = filenum;
+         newnode->rank = rank;
+         newnode->structure = structure;
+         newnode->next = NULL;
+ 
+         if (rp == NULL)
+                 rp = newnode;
+         else
+                 head->next = newnode;
+ 
+         head = newnode;
+ 
+         return rp;
+ }
+ 
+ /* Adds the results of a search, sorts them by rank.
+ */
+ 
+ struct sortresult *addsortresult(sp, rank, fileinfo)
+      struct sortresult *sp;
+      int rank;
+      char *fileinfo;
+ {
+         if (rank > bigrank)
+                 bigrank = rank;
+ 
+         if (sp == NULL) {
+                 sp = (struct sortresult *) emalloc(sizeof(struct sortresult));
+                 sp->rank = rank;
+                 sp->fileinfo = (char *) mystrdup(fileinfo);
+                 sp->left = sp->right = NULL;
+         }
+         else {
+                 if (sp->rank < rank)
+                         sp->left = (struct sortresult *)
+                         addsortresult(sp->left, rank, fileinfo);
+                 else
+                         sp->right = (struct sortresult *)
+                         addsortresult(sp->right, rank, fileinfo);
+         }
+ 
+         return sp;
+ }
+ 
+ /* Prints the final results of a search.
+ */
+ 
+ void printsortedresults(sp, num)
+      struct sortresult *sp;
+      float num;
+ {
+         int rank;
+ 
+         if (sp != NULL) {
+                 printsortedresults(sp->left, num);
+                 rank = (int) ((float) sp->rank * num);
+                 if (rank >= 999)
+                         rank = 1000;
+ 		if (maxhits) {
+                 	if (maxhits == -1)
+ 				printf("%d %s", (rank <= 0) ? 1 :
+ 				rank, sp->fileinfo);
+ 			else if (maxhits > 0) {
+ 				printf("%d %s", (rank <= 0) ? 1 :
+ 				rank, sp->fileinfo);
+ 				maxhits--;
+ 			}
+ 		}
+                 printsortedresults(sp->right, num);
+         }
+ }
+ 
+ /* Reads a compressed line. This is just here for testing, etc.
+ */
+ 
+ void getrawindexline(fp)
+      FILE *fp;
+ {
+         int c, inword;
+ 
+         inword = 1;
+         while ((c = fgetc(fp)) != EOF) {
+                 if (c == ':' && inword)
+                         inword = 0;
+                 if (!inword) {
+                         do {
+                                 c = fgetc(fp);
+                                 if (c == 0)
+                                         return;
+                         } while (c & 128);
+                 }
+         }
+ }
+ 
+ /* Does an index file have a readable format?
+ */
+ 
+ int isokindexheader(fp)
+      FILE *fp;
+ {
+ 	char line[MAXSTRLEN];
+ 
+ 	fseek(fp, 0, 0);
+ 	fgets(line, MAXSTRLEN, fp);
+ 	if (line[strlen(line) - 1] == '\n')
+ 		line[strlen(line) - 1] = '\0';
+ 	if (strcmp(line, INDEXHEADER)) {
+ 		fseek(fp, 0, 0);
+ 		return 0;
+ 	}
+ 	fseek(fp, 0, 0);
+ 	return 1;
+ }
+ 
+ /* Returns the value associated with the metaName if it exists
+ */
+ 
+ int getMetaName(word)
+      char * word;
+ {
+   struct metaEntry* temp;
+   
+   for (temp = metaEntryList; temp != NULL; temp = temp->next) 
+     if (!strcmp(temp->metaName, word) )
+       return temp->index;
+ 
+   return 1;
+ }
+ 
+ /* Checks if the next word is "="
+ */
+ 
+ int isMetaName (searchWord)
+      struct swline* searchWord;
+ {
+   if (searchWord == NULL)
+     return 0;
+   if (!strcmp(searchWord->line, "=") )
+     return 1;
+   return 0;
+ }
+ 
+ 
+       
Index: harvest/components/broker/swish/search.h
diff -c /dev/null harvest/components/broker/swish/search.h:1.1
*** /dev/null	Mon Oct 27 18:41:03 1997
--- harvest/components/broker/swish/search.h	Sun Oct 12 16:33:07 1997
***************
*** 0 ****
--- 1,43 ----
+ /*
+ ** Copyright (C) 1995, Enterprise Integration Technologies Corp.        
+ ** All Rights Reserved.
+ ** Kevin Hughes, kevinh@eit.com 
+ ** 3/11/94
+ **
+ ** Added getMetaName & isMetaName 
+ ** to support METADATA
+ ** G. Hill 3/18/97 ghill@library.berkeley.edu
+ */
+ 
+ void search();
+ struct swline *fixnot();
+ struct swline *expandstar();
+ char *getmatchword();
+ void getheader();
+ void readoffsets();
+ void readstopwords();
+ void readfileoffsets();
+ void readMetaNames();
+ int getMetaName();
+ 
+ struct result *parseterm();
+ struct result *operate();
+ char *lookupfile();
+ struct result *getfileinfo();
+ 
+ int isrule();
+ int isbooleanrule();
+ int isunaryrule();
+ int isMetaName();
+ int getrulenum();
+ 
+ struct result *andresultlists();
+ struct result *orresultlists();
+ struct result *notresultlist();
+ struct result *addtoresultlist();
+ 
+ struct sortresult *addsortresult();
+ void printsortedresults();
+ 
+ void getrawindexline();
+ int isokindexheader();
Index: harvest/components/broker/swish/string.c
diff -c /dev/null harvest/components/broker/swish/string.c:1.2
*** /dev/null	Mon Oct 27 18:41:03 1997
--- harvest/components/broker/swish/string.c	Mon Oct 27 16:13:56 1997
***************
*** 0 ****
--- 1,388 ----
+ /*
+ ** Copyright (C) 1995, Enterprise Integration Technologies Corp.        
+ ** All Rights Reserved.
+ ** Kevin Hughes, kevinh@eit.com 
+ ** 3/11/94
+ **
+ ** Release under the GPL by EIT - 1997
+ **
+ ** Heavily patched for Harvest by Simon Wilkinson
+ */
+ 
+ #include "swish.h"
+ #include "string.h"
+ 
+ /* My own case-insensitive strstr().
+ */
+ 
+ char *lstrstr(s, t)
+      char *s;
+      char *t;
+ {
+ 
+ 	int i, j, k, l;
+ 
+ 	for (i = 0; s[i]; i++) {
+ 		for (j = 0, l = k = i; s[k] && t[j] &&
+ 		tolower(s[k]) == tolower(t[j]); j++, k++)
+ 			;
+ 		if (t[j] == '\0')
+ 			return s + l;
+ 	}
+ 	return NULL;
+ }
+ 
+ /* Gets the next word in a line. If the word's in quotes,
+ ** include blank spaces in the word or phrase.
+ */
+ 
+ char *getword(line, skiplen)
+      char *line;
+      int *skiplen;
+ {
+         int i, inquotes;
+         char *start;
+         static char word[MAXSTRLEN];
+ 
+         start = line;
+         if (!(*line))
+                 return "\0";
+         while (isspace(*line))
+                 line++;
+         if (!(*line))
+                 return "\0";
+         if (*line == '\"') {
+                 inquotes = 1;
+                 line++;
+         }
+         else
+                 inquotes = 0;
+         for (i = 0; *line && i < MAXSTRLEN &&
+         ((inquotes) ? (*line != '\"') : (!isspace(*line))); line++)
+                 word[i++] = *line;
+         word[i] = '\0';
+         if (!(*line))
+                 return "\0";
+         if (*line == '\"')
+                 line++;
+ 
+         *skiplen = line - start;
+ 
+         return word;
+ }
+ 
+ /* Gets the value of a variable in a line of the configuration file.
+ ** Basically, anything in quotes or an argument to a variable.
+ */
+ 
+ char *getconfvalue(line, var, value)
+      char *line;
+      char *var;
+      char *value;
+ {
+         int i;
+         char *c;
+         static char tmpvalue[MAXSTRLEN];
+ 
+         if ((c = (char *) lstrstr(line, var)) != NULL) {
+                 if (c != line)
+                         return NULL;
+                 c += strlen(var);
+                 while (isspace(*c) || *c == '\"')
+                         c++;
+                 if (*c == '\0')
+                         return NULL;
+                 for (i = 0; *c != '\0' && *c != '\"' && *c != '\n' &&
+                 i < MAXSTRLEN; c++)
+                         tmpvalue[i++] = *c;
+                 tmpvalue[i] = '\0';
+                 strcpy(value, tmpvalue);
+                 return tmpvalue;
+         }
+         else
+                 return NULL;
+ }
+ 
+ /* Malloc()'s a string, returns it.
+ */
+ 
+ char *mystrdup(s)
+      char *s;
+ {
+         char *p;
+ 
+         p = (char *) emalloc(strlen(s) + 1);
+         strcpy(p, s);
+         return p;
+ }
+ 
+ /* Is a character a valid word character?
+ */
+ 
+ int iswordchar(c)
+      char c;
+ {
+ 	int d, i;
+ 
+ 	d = tolower(c);
+ 	for (i = 0; WORDCHARS[i] != '\0'; i++)
+ 		if (d == WORDCHARS[i])
+ 			return 1;
+         return 0;
+ }
+ 
+ /* In a string, replaces all occurrences of "oldpiece" with "newpiece".
+ ** This is not really bulletproof yet.
+ */
+ 
+ char *replace(string, oldpiece, newpiece)
+      char *string;
+      char *oldpiece;
+      char *newpiece;
+ {
+         int i, j, limit;
+         char *c;
+         char beforestring[MAXSTRLEN], afterstring[MAXSTRLEN];
+         static char newstring[MAXSTRLEN];
+ 
+         if ((c = (char *) strstr(string, oldpiece)) == NULL)
+                 return string;
+         limit = c - string;
+ 
+         for (i = 0; i < limit; i++)
+                 beforestring[i] = string[i];
+         beforestring[i] = '\0';
+ 
+         i += strlen(oldpiece);
+ 
+         for (j = 0; string[i] != '\0'; i++)
+                 afterstring[j++] = string[i];
+         afterstring[j] = '\0';
+ 
+         sprintf(newstring, "%s%s%s", beforestring, newpiece, afterstring);
+ 
+         while (strstr(newstring, oldpiece))
+                 strcpy(newstring, replace(newstring, oldpiece, newpiece));
+ 
+         return newstring;
+ }
+ 
+ /* Like strcmp(), but the order of sorting the first char is
+ ** determined by the order of the characters in the wordchars array.
+ */
+ 
+ int wordcompare(s1, s2)
+      char *s1;
+      char *s2;
+ {
+ 	register int i, j;
+ 
+ 	if (s1[0] != s2[0]) {
+ 		for (i = 0; WORDCHARS[i] != '\0'; i++)
+ 			if (s1[0] == WORDCHARS[i])
+ 				break;
+ 		for (j = 0; WORDCHARS[j] != '\0'; j++)
+ 			if (s2[0] == WORDCHARS[j])
+ 				break;
+ 		if (i < j)
+ 			return -1;
+ 		else
+ 			return 1;
+ 	}
+ 	else
+ 		return strcmp(s1, s2);
+ }
+ 
+ /* This converts HTML numbered entities (such as &#169;)
+ ** to strings (like &copy;). Much is this function is
+ ** simply adding semicolons in the right places.
+ ** This and the functions it calls are not very fast
+ ** and could be made faster.
+ */
+ 
+ char *convertentities(s)
+      char *s;
+ {
+ 	int i, skip;
+ 	char ent[MAXENTLEN];
+ 	static char newword[MAXWORDLEN];
+ 
+ 	if ((char *) strchr(s, '&') == NULL)
+ 		return s;
+ 	if (strlen(s) > MAXWORDLIMIT)
+ 		return s;
+ 
+ 	for (i = 0; i < MAXWORDLEN; i++)
+ 		newword[i] = '\0';
+ 	for (; *s != '\0'; s++) {
+ 		if (*s == '&') {
+ 			strcpy(ent, getent(s, &skip));
+ 			if (ent[0] == '\0') {
+ 				sprintf(newword, "%s&", newword);
+ 				continue;
+ 			}
+ 			s += skip;
+ 			if (*s == ';')
+ 				s++;
+ 			sprintf(newword, "%s%s;", newword, ent);
+ 			s--;
+ 		}
+ 		else
+ 			sprintf(newword, "%s%c", newword, *s);
+ 	}
+ 
+ 	strcpy(newword, (char *) converttonamed(newword));
+ 	if (ASCIIENTITIES)
+ 		strcpy(newword, (char *) converttoascii(newword));
+ 
+ 	return newword;
+ }
+ 
+ /* Returns a matching entity that matches the beginning of a string, if any.
+ */
+ 
+ char *getent(s, skip)
+      char *s;
+      int *skip;
+ {
+ 	int i;
+ 	static char ent[MAXENTLEN], testent[MAXENTLEN];
+ 
+ 	*skip = 0;
+ 	strncpy(ent, s, MAXENTLEN);
+ 	if (ent[1] == '#') {
+ 		if (isdigit(ent[5]))
+ 			return "\0";
+ 		for (i = 2; ent[i] != '\0' && isdigit(ent[i]); i++)
+ 			;
+ 		while (ent[i] != '\0' && !isdigit(ent[i]))
+ 			ent[i++] = '\0';
+ 		*skip = strlen(ent);
+ 		return ent;
+ 	}
+ 	else {
+ 		for (i = 0; entities[i] != NULL; i += 3) {
+ 			strcpy(testent, entities[i]);
+ 			if (testent[0] != '\0') {
+ 				if (!strncmp(testent, ent, strlen(testent))) {
+ 					strcpy(ent, testent);
+ 					*skip = strlen(ent);
+ 					return ent;
+ 				}
+ 			}
+ 		}
+ 	}
+ 
+ 	return "\0";
+ }
+ 
+ /* This is the real function called by convertentities() that
+ ** changes numbered to named entities.
+ */
+ 
+ char *converttonamed(s)
+      char *s;
+ {
+ 	int i;
+ 	char testent[MAXENTLEN], newent[MAXENTLEN];
+ 	static char newword[MAXWORDLEN];
+ 
+ 	strcpy(newword, s);
+ 	for (i = 0; entities[i] != NULL; i += 3) {
+ 		sprintf(testent, "%s;", entities[i + 1]);
+ 		if (strstr(newword, testent) != NULL &&
+ 		(entities[i])[0] != '\0') {
+ 			sprintf(newent, "%s;", entities[i]);
+ 			strcpy(newword, (char *) replace(newword,
+ 			testent, newent));
+ 		}
+ 	}
+ 
+ 	while (hasnumbered(newword))
+ 		strcpy(newword, (char *) converttonamed(newword));
+ 
+ 	return newword;
+ }
+ 
+ /* Does a string still contain numbered entities that can be converted?
+ */
+ 
+ int hasnumbered(s)
+      char *s;
+ {
+ 	int i;
+ 	char testent[MAXENTLEN];
+ 
+ 	for (i = 0; entities[i] != NULL; i += 3) {
+ 		sprintf(testent, "%s;", entities[i + 1]);
+ 		if (strstr(s, testent) != NULL && (entities[i])[0] != '\0')
+ 			return 1;
+ 	}
+ 	return 0;
+ }
+ 
+ /* This function converts all convertable named and numbered
+ ** entities to their ASCII equivalents, if they exist.
+ */
+ 
+ char *converttoascii(s)
+      char *s;
+ {
+ 	int i;
+ 	char *c, *d, wrdent[MAXENTLEN], nument[MAXENTLEN];
+ 	static char newword[MAXWORDLEN];
+ 
+ 	strcpy(newword, s);
+ 	for (i = 0; entities[i] != NULL; i += 3) {
+ 
+ 		sprintf(wrdent, "%s;", entities[i]);
+ 		sprintf(nument, "%s;", entities[i + 1]);
+ 
+ 		c = d = NULL;
+ 		if ((entities[i])[0] != '\0')
+ 			c = (char *) strstr(newword, wrdent);
+ 		if ((entities[i + 1])[0] != '\0')
+ 			d = (char *) strstr(newword, nument);
+ 		if ((entities[i + 2])[0] != '\0') {
+ 			if (c != NULL)
+ 				strcpy(newword, (char *) replace(newword,
+ 				wrdent, entities[i + 2]));
+ 			if (d != NULL)
+ 				strcpy(newword, (char *) replace(newword,
+ 				nument, entities[i + 2]));
+ 		}
+ 	}
+ 
+ 	while (hasnonascii(newword))
+ 		strcpy(newword, (char *) converttoascii(newword));
+ 
+ 	return newword;
+ }
+ 
+ /* Does a string still contain numbered or named entities that can
+ ** be converted to ascii equivalents?
+ */
+ 
+ int hasnonascii(s)
+        char *s;
+   {
+        int i;
+        char *c, *d, wrdent[MAXENTLEN], nument[MAXENTLEN];
+   
+        for (i = 0; entities[i] != NULL; i += 3) {
+  
+               sprintf(wrdent, "%s;", entities[i]);
+               sprintf(nument, "%s;", entities[i + 1]);
+  
+                c = d = NULL;
+               if ((entities[i])[0] != '\0')
+                       c = (char *) strstr(s, wrdent);
+                if ((entities[i + 1])[0] != '\0')
+                       d = (char *) strstr(s, nument);
+                if ((entities[i + 2])[0] != '\0')
+                        if (c != NULL || d != NULL)
+                               return 1;
+ 	}
+ 
+ 	return 0;
+ }
Index: harvest/components/broker/swish/string.h
diff -c /dev/null harvest/components/broker/swish/string.h:1.1
*** /dev/null	Mon Oct 27 18:41:04 1997
--- harvest/components/broker/swish/string.h	Sun Oct 12 16:33:08 1997
***************
*** 0 ****
--- 1,21 ----
+ /*
+ ** Copyright (C) 1995, Enterprise Integration Technologies Corp.        
+ ** All Rights Reserved.
+ ** Kevin Hughes, kevinh@eit.com 
+ ** 3/11/94
+ */
+ 
+ char *lstrstr();
+ char *getword();
+ char *getconfvalue();
+ char *parsetitle();
+ char *mystrdup();
+ int iswordchar();
+ char *replace();
+ int wordcompare();
+ char *convertentities();
+ char *getent();
+ char *converttonamed();
+ int hasnumbered();
+ char *converttoascii();
+ int hasnonascii();
Index: harvest/components/broker/swish/swish.c
diff -c /dev/null harvest/components/broker/swish/swish.c:1.1
*** /dev/null	Mon Oct 27 18:41:04 1997
--- harvest/components/broker/swish/swish.c	Sun Oct 12 16:33:09 1997
***************
*** 0 ****
--- 1,495 ----
+ /*
+ ** Copyright (C) 1995, Enterprise Integration Technologies Corp.        
+ ** All Rights Reserved.
+ ** Kevin Hughes, kevinh@eit.com 
+ ** 3/11/94
+ **
+ ** Added support for METADATA
+ ** G. Hill ghill@library.berkeley.edu 3/18/97
+ **
+ ** Added printing of common words
+ ** G.Hill 4/7/97 ghill@library.berkeley.edu
+ **
+ */
+ 
+ #define MAIN_FILE
+ #include "swish.h"
+ 
+ int main(argc, argv)
+      int argc;
+      char **argv;
+ {
+         char c, word[MAXWORDLEN], wordlist[MAXSTRLEN],
+ 		maxhitstr[MAXSTRLEN], structstr[MAXSTRLEN];
+ 	char tmpindex1[MAXFILELEN], tmpindex2[MAXFILELEN],
+ 		index1[MAXSTRLEN], index2[MAXSTRLEN],
+ 		index3[MAXSTRLEN], index4[MAXSTRLEN];
+         int i, j, hasindex, hasdir, hasconf, hasverbose, structure,
+ 		totalfiles, stopwords, index, decode, merge, pos,
+ 	        hasMetaName;
+ 	long offsetstart, starttime, stoptime, plimit, flimit;
+         FILE *fp1, *fp2;
+         struct file *filep;
+         struct entry *entryp;
+ 	struct swline *conflist, *tmplist;
+ 
+         index = decode = merge = 0;
+         hasindex = hasdir = hasconf = hasverbose = hasMetaName = 0;
+ 	followsymlinks = stopwords = 0;
+         totalwords = stopwords = stopPos = 0;
+         filelist = NULL;
+         entrylist = NULL;
+ 	dirlist = indexlist = conflist = tmplist = NULL;
+         suffixlist = nocontentslist = replacelist = NULL;
+         pathconlist = dirconlist = fileconlist = NULL;
+ 	titconlist = fileislist = NULL;
+         metaEntryList = NULL;
+         maxhits = -1;
+         verbose = VERBOSE;
+ 	plimit = PLIMIT;
+ 	flimit = FLIMIT;
+ 	structure = 1;
+         wordlist[0] = '\0';
+ 	structstr[0] = '\0';
+ 	indexn[0] = '\0';
+ 	indexd[0] = '\0';
+ 	indexp[0] = '\0';
+ 	indexa[0] = '\0';
+ 
+         if (argc == 1)
+                 usage();
+         while (--argc > 0) {
+                 ++argv;
+                 if ((*argv)[0] != '-')
+                         usage();
+                 c = (*argv)[1];
+ 		if ((*argv)[2] != '\0' && isalpha((*argv)[2]))
+ 			usage();
+                 if (c == 'i') {
+                         index = 1;
+                         while ((argv + 1)[0] != '\0' && *(argv + 1)[0] != '-') {
+ 				dirlist = (struct swline *)
+ 				addswline(dirlist, (++argv)[0]);
+                                 argc--;
+                         }
+                 }
+                 else if (c == 'w') {
+                         while ((argv + 1)[0] != '\0' && *(argv + 1)[0] != '-') {                                strcpy(word, (++argv)[0]);
+                                 argc--;
+                                 sprintf(wordlist, "%s%s%s", wordlist,
+                                 (wordlist[0] == '\0') ? "" : " ", word);
+                         }
+                 }
+                 else if (c == 'f') {
+                         while ((argv + 1)[0] != '\0' && *(argv + 1)[0] != '-') {
+ 				indexlist = (struct swline *)
+ 				addswline(indexlist, (++argv)[0]);
+                                 argc--;
+                         }
+                 }
+                 else if (c == 'c') {
+                         index = 1;
+                         hasconf = 1;
+                         while ((argv + 1)[0] != '\0' && *(argv + 1)[0] != '-') {
+ 				conflist = (struct swline *)
+ 				addswline(conflist, (++argv)[0]);
+                                 argc--;
+                         }
+                 }
+ 		else if (c == 'C') {
+                         while ((argv + 1)[0] != '\0' && *(argv + 1)[0] != '-')
+ 			  {
+                                 conflist = (struct swline *)
+                                 addswline(conflist, (++argv)[0]);
+                                 argc--;
+ 			      }
+ 			if (conflist == NULL)
+ 			  progerr("Specifiy the configuration file.");
+ 			else
+ 			  hasMetaName = 1;
+ 		      }
+                 else if (c == 'l') {
+ 		   followsymlinks = 1;
+ 			argc--;
+ 		 }
+                 else if (c == 'm') {
+ 			if ((argv + 1)[0] == '\0')
+ 				maxhits = -1;
+ 			else {
+ 				strcpy(maxhitstr, (++argv)[0]);
+ 				if (lstrstr(maxhitstr, "all"))
+ 					maxhits = -1;
+ 				else if (isdigit(maxhitstr[0]))
+                         		maxhits = atoi(maxhitstr);
+ 				else
+ 					maxhits = -1;
+                         	argc--;
+ 			}
+                 }
+                 else if (c == 't') {
+ 			if ((argv + 1)[0] == '\0')
+ 				progerr("Specify tag fields (HBtheca).");
+ 			else {
+ 				structure = 0;
+                         	strcpy(structstr, (++argv)[0]);
+                         	argc--;
+ 			}
+                 }
+                 else if (c == 'v') {
+ 			hasverbose = 1;
+ 			if ((argv + 1)[0] == '\0') {
+ 				verbose = 3;
+ 				break;
+ 			}
+ 			else if (!isdigit((argv + 1)[0][0]))
+ 				verbose = 3;
+ 			else
+                         	verbose = atoi((++argv)[0]);
+                         argc--;
+                 }
+                 else if (c == 'V')
+                         printversion();
+                 else if (c == 'z' || c == 'h' || c == '?')
+                         usage();
+                 else if (c == 'M') {
+ 			merge = 1;
+                         while ((argv + 1)[0] != '\0' && *(argv + 1)[0] != '-') {
+ 				indexlist = (struct swline *)
+ 				addswline(indexlist, (++argv)[0]);
+                                 argc--;
+                         }
+ 		}
+                 else if (c == 'D') {
+ 			decode = 1;
+                         while ((argv + 1)[0] != '\0' && *(argv + 1)[0] != '-') {
+ 				indexlist = (struct swline *)
+ 				addswline(indexlist, (++argv)[0]);
+                                 argc--;
+                         }
+                 }
+                 else
+                         usage();
+                 if (argc == 0)
+                         break;
+         }
+ 
+ 	hasdir = (dirlist == NULL) ? 0 : 1;
+ 	hasindex = (indexlist == NULL) ? 0 : 1;
+ 
+ 	if (index && merge)
+ 		index = 0;
+ 
+ 	if (decode) {
+ 
+ 		if (!hasindex)
+ 			progerr("Specify the index file to decode.");
+ 
+ 		while (indexlist != NULL) {
+ 
+                 	if ((fp1 = fopen(indexlist->line, "r")) == NULL) {
+ 				sprintf(errorstr,
+ 				"Couldn't open the index file \"%s\".",
+ 				indexlist->line);
+ 				progerr(errorstr);
+ 			}
+ 			if (!isokindexheader(fp1)) {
+ 				sprintf(errorstr,
+ 				"\"%s\" has an unknown format.",
+ 				indexlist->line);
+ 				progerr(errorstr);
+ 			}
+ 
+                 	decompress(fp1);
+ 			putchar('\n');
+                 	fclose(fp1);
+ 
+ 			indexlist = indexlist->next;
+ 		}
+ 		exit(0);
+ 
+ 	}
+         else if (index) {
+ 
+                 if (hasconf)
+ 			while (conflist != NULL) {
+                         	getdefaults(conflist->line, &hasdir, &hasindex,
+ 				&plimit, &flimit, hasverbose);
+ 				conflist = conflist->next;
+ 			}
+ 		if (!hasindex)
+ 			indexlist = (struct swline *)
+ 			addswline(indexlist, INDEXFILE);
+ 		if (!hasdir)
+ 			progerr("Specify directories or files to index.");
+ 
+ 		if (verbose < 0)
+ 			verbose = 0;
+ 		if (verbose > 3)
+ 			verbose = 3;
+ 		if (verbose)
+ 			starttime = getthetime();
+ 
+ 		while (dirlist != NULL) {
+ 			if (isdirectory(dirlist->line)) {
+ 				if (verbose >= 2)
+ 					printf("\nChecking dir \"%s\"...\n",
+ 					dirlist->line);
+ 	                	indexadir(dirlist->line);
+ 			}
+ 			else if (isfile(dirlist->line)) {
+ 				if (verbose >= 2)
+ 					printf("\nChecking file \"%s\"...\n",
+ 					dirlist->line);
+ 	                	indexafile(dirlist->line);
+ 			}
+ 			dirlist = dirlist->next;
+ 		}
+ 
+                 if ((fp1 = fopen(indexlist->line, "w")) == NULL) {
+ 			sprintf(errorstr,
+ 			"Couldn't write the index file \"%s\".",
+ 			indexlist->line);
+                         progerr(errorstr);
+ 		}
+ 
+ 		if (verbose > 1)
+ 			putchar('\n');
+ 		if (verbose)
+ 			printf("Removing very common words... ");
+ 
+                 filep = filelist;
+ 		totalfiles = getfilecount(filep);
+ 		entryp = entrylist;
+ 		stopwords = removestops(entryp, totalfiles, plimit, flimit);
+ 		
+ 		if (verbose) {
+ 		  if (stopwords) {
+ 		    printf("%d word%s removed.\n",
+ 			   stopwords, (stopwords == 1) ? "" : "s");
+ 		    printf("%d words removed not in common words array:\n",
+ 			   stopPos);
+ 		    for (pos = 0; pos < stopPos; pos++) 
+ 		      printf("%s, ", stopList[pos]);
+ 		    printf("\n");
+ 		  }
+ 		  else
+ 		    printf("no words removed.\n");
+ 		  printf("Writing main index... ");
+ 		}
+ 		
+ 		printheader(fp1, indexlist->line, totalwords, totalfiles);
+ 		
+ 		offsetstart = ftell(fp1);
+                 for (i = 0; i < MAXCHARS; i++)
+ 		  fprintf(fp1, "%016li", offsets[i]);
+                 fputc('\n', fp1);
+ 		
+                 printindex(entrylist, fp1);
+ 		printstopwords(fp1);
+ 		
+ 		if (verbose) {
+ 		  if (totalwords)
+ 		    printf("%d unique word%s indexed.\n",
+ 			   totalwords, (totalwords == 1) ? "" : "s");
+ 		  else
+ 		    printf("no unique words indexed.\n");
+ 		  printf("Writing file index... ");
+ 		}
+ 		
+                 printfilelist(filelist, fp1);
+ 		printfileoffsets(fp1);
+ 		printMetaNames(fp1);
+                 fclose(fp1);
+ 		
+                 fp2 = fopen(indexlist->line, "r+");
+ 		fseek(fp2, offsetstart, 0);
+                 for (i = 0; i < MAXCHARS; i++)
+ 		  fprintf(fp2, "%016li", offsets[i]);
+                 fclose(fp2);
+ 		
+ 		if (verbose) {
+ 		  if (totalfiles)
+ 		    printf("%d file%s indexed.\n", totalfiles,
+ 			   (totalfiles == 1) ? "" : "s");
+ 		  else
+ 		    printf("no files indexed.\n");
+ 		  
+ 		  stoptime = getthetime();
+ 		  
+ 		  printrunning(starttime, stoptime);
+ 		  printf("Indexing done!\n");
+ 		}
+ #ifdef INDEXPERMS
+                 chmod(indexlist->line, INDEXPERMS);
+ #endif
+ 		exit(0);
+ 
+         }
+         else if (merge) {
+ 
+ 		if (indexlist == NULL)
+ 			progerr("Specify index files and an output file.");
+                 if (hasconf)
+ 			while (conflist != NULL) {
+                         	getdefaults(conflist->line, &hasdir, &hasindex,
+ 				&plimit, &flimit, hasverbose);
+ 				conflist = conflist->next;
+ 			}
+ 
+ 		tmplist = indexlist;
+ 		for (i = 0; tmplist != NULL; i++) {
+ 			strcpy(index4, tmplist->line);
+ 			tmplist = tmplist->next;
+ 		}
+ 		j = i - 2;
+ 		if (i < 3)
+ 			progerr("Specify index files and an output file.");
+ 
+ 		sprintf(tmpindex1, tmpnam(NULL));
+ 		sprintf(tmpindex2, tmpnam(NULL));
+ 
+ 		i = 1;
+ 		strcpy(index1, indexlist->line);
+ 		indexlist = indexlist->next;
+ 		while (i <= j) {
+ 			strcpy(index2, indexlist->line);
+ 			if (i % 2) {
+ 				if (i != 1)
+ 					strcpy(index1, tmpindex2);
+ 				strcpy(index3, tmpindex1);
+ 			}
+ 			else {
+ 				strcpy(index1, tmpindex1);
+ 				strcpy(index3, tmpindex2);
+ 			}
+ 			if (i == j)
+ 				strcpy(index3, index4);
+ 			readmerge(index1, index2, index3);
+ 			indexlist = indexlist->next;
+ 			i++;
+ 		}
+ #ifdef INDEXPERMS
+                 chmod(index3, INDEXPERMS);
+ #endif
+ 		if (isfile(tmpindex1))
+ 			remove(tmpindex1);
+ 		if (isfile(tmpindex2))
+ 			remove(tmpindex2);
+ 
+ 	}
+         else {
+ 
+ 		for (i = 0; structstr[i] != '\0'; i++)
+ 			switch (structstr[i]) {
+ 			case 'H':
+ 				structure |= IN_HEAD;
+ 				break;
+ 			case 'B':
+ 				structure |= IN_BODY;
+ 				break;
+ 			case 't':
+ 				structure |= IN_TITLE;
+ 				break;
+ 			case 'h':
+ 				structure |= IN_HEADER;
+ 				break;
+ 			case 'e':
+ 				structure |= IN_EMPHASIZED;
+ 				break;
+ 			case 'c':
+ 				structure |= IN_COMMENTS;
+ 				break;
+ 			default:
+ 				structure |= IN_FILE;
+ 				break;
+ 			}
+ 
+ 		if (maxhits <= 0)
+ 			maxhits = -1;
+ 		if (!hasindex)
+ 			indexlist = (struct swline *)
+ 			addswline(indexlist, INDEXFILE);
+ 		if (hasMetaName)
+ 		  while (conflist != NULL) {
+ 		    getdefaults(conflist->line, &hasdir, &hasindex,
+                                 &plimit, &flimit, hasverbose);
+ 		    conflist = conflist->next;
+ 		  }
+ 		search(wordlist, indexlist, structure);
+ 
+ 	}
+ 
+         exit(0);
+ }
+ 
+ /* Gets the current time in seconds since the epoch.
+ */
+ 
+ long getthetime()
+ {
+         long thetime;
+         time_t tp;
+ 
+         thetime = (long) time(&tp);
+         return thetime;
+ }
+ 
+ /* Prints the running time (the time it took for indexing).
+ */
+ 
+ void printrunning(starttime, stoptime)
+      long starttime;
+      long stoptime;
+ {
+         int minutes, seconds;
+ 
+         minutes = (stoptime - starttime) / SECSPERMIN;
+         seconds = (stoptime - starttime) % SECSPERMIN;
+         printf("Running time: ");
+         if (minutes)
+                 printf("%d minute%s", minutes, (minutes == 1) ? "" : "s");
+         if (minutes && seconds)
+                 printf(", ");
+         if (seconds)
+                 printf("%d second%s", seconds, (seconds == 1) ? "" : "s");
+         if (!minutes && !seconds)
+                 printf("Less than a second");
+         printf(".\n");
+ }
+ 
+ /* Prints the SWISH usage.
+ */
+ 
+ void usage()
+ {
+ 	printf("  usage: swish [-i dir file ... ] [-c file] [-f file] [-l] [-v (num)]\n");
+ 	printf("         swish -w word1 word2 ... [-f file1 file2 ...] [-C file] [-m num] [-t str]\n");
+ 	printf("         swish -M index1 index2 ... outputfile\n");
+ 	printf("         swish -D file\n");
+ 	printf("         swish -V\n");
+ 	putchar('\n');
+         printf("options: defaults are in brackets\n");
+         printf("         -i : create an index from the specified files\n");
+         printf("         -w : search for words \"word1 word2 ...\"\n");
+         printf("         -t : tags to search in - specify as a string\n");
+         printf("              \"HBthec\" - in head, body, title, header,\n");
+ 	printf("              emphasized, comments\n");
+         printf("         -f : index file to create or search from [%s]\n", INDEXFILE);
+         printf("         -c : configuration file to use for indexing\n");
+ 	printf("         -C : configuration file to use for metaNames in search\n");
+         printf("         -v : verbosity level (0 to 3) [%d]\n", VERBOSE);
+         printf("         -l : follow symbolic links when indexing\n");
+         printf("         -m : the maximum number of results to return [%d]\n", MAXHITS);
+ 	printf("         -M : merges index files\n");
+ 	printf("         -D : decodes an index file\n");
+         printf("         -V : prints the current version\n\n");
+         printf("version: %s\n", VERSION);
+         printf("   docs: http://www.eit.com/software/swish/\n");
+         exit(1);
+ }
+ 
+ void printversion()
+ {
+         printf("SWISH %s\n", VERSION);
+         exit(0);
+ }
Index: harvest/components/broker/swish/swish.h
diff -c /dev/null harvest/components/broker/swish/swish.h:1.2
*** /dev/null	Mon Oct 27 18:41:05 1997
--- harvest/components/broker/swish/swish.h	Mon Oct 27 16:13:57 1997
***************
*** 0 ****
--- 1,299 ----
+ /*
+ ** Copyright (C) 1995, Enterprise Integration Technologies Corp.        
+ ** All Rights Reserved.
+ ** Kevin Hughes, kevinh@eit.com 
+ ** 3/11/94
+ **
+ ** Added support for METADATA
+ ** G. Hill  ghill@library.berkeley.edu   3/18/97
+ */
+ 
+ #include <stdio.h>
+ #include <string.h>
+ #include <math.h>
+ #include <sys/types.h>
+ #include <sys/stat.h>
+ #ifdef NEXTSTEP
+ #include <sys/dir.h>
+ #else
+ #include <dirent.h>
+ #endif
+ #include <ctype.h>
+ #include <stdlib.h>
+ #include <time.h>
+ #include <setjmp.h>
+ 
+ #define VERSION "1.1.1"
+ #define INDEXFILE "index.swish"
+ #define INDEXHEADER "# SWISH format 1.1"
+ 
+ #define MAXFILELEN 1000
+ #define MAXSTRLEN 1000
+ #define MAXWORDLEN 1000
+ #define MAXTITLELEN 200
+ #define MAXSUFFIXLEN 10
+ #define MAXENTLEN 10
+ #define HASHSIZE 101
+ #define BIGHASHSIZE 1009
+ 
+ #define TI_OPEN 1
+ #define TI_CLOSE 2
+ #define TI_FOUND 4
+ #define NOWORD "thisisnotaword"
+ #define SECSPERMIN 60
+ 
+ #define NO_RULE 0
+ #define AND_RULE 1
+ #define OR_RULE 2
+ #define NOT_RULE 3
+ 
+ #define IN_FILE 1
+ #define IN_TITLE 2
+ #define IN_HEAD 4
+ #define IN_BODY 8
+ #define IN_COMMENTS 16
+ #define IN_HEADER 32
+ #define IN_EMPHASIZED 64
+ #define IN_ALL 127
+ 
+ #define MAXLONGLEN 16
+ #define MAXCHARS 69
+ #define MAXHEADCHARS MAXLONGLEN * MAXCHARS
+ #define METANAMEPOS MAXCHARS - 4
+ #define STOPWORDPOS MAXCHARS - 3
+ #define FILELISTPOS MAXCHARS - 2
+ #define FILEOFFSETPOS MAXCHARS - 1
+ 
+ #include "swish_config.h"
+ 
+ struct metaEntry {
+         char* metaName;
+ 	int index;
+ 	struct metaEntry* next;
+ };
+ 
+ struct sortresult {
+         char *fileinfo;
+         int rank;
+         struct sortresult *left;
+         struct sortresult *right;
+ };
+ 
+ struct result {
+         int filenum;
+         int rank;
+ 	int structure;
+         struct result *next;
+ };
+ 
+ struct file {
+         char *filename;
+         char *title;
+         int size;
+         struct file *next;
+ };
+ 
+ struct filenum {
+ 	int fileshort;
+ 	long filelong;
+ 	struct filenum *next;
+ };
+ 
+ struct location {
+         int filenum;
+         int frequency;
+         int emphasized;
+ 	int structure;
+ 	int metaName;
+         struct location *next;
+ };
+ 
+ struct entry {
+         char *word;
+         int tfrequency;
+         struct location *locationlist;
+         struct entry *left;
+         struct entry *right;
+ };
+ 
+ struct sortentry {
+         char *filename;
+         char *title;
+         struct sortentry *left;
+         struct sortentry *right;
+ };
+ 
+ struct swline {
+         char *line;
+         struct swline *next;
+ };
+ 
+ struct fwordtotal {
+         int filenum;
+         int totalwords;
+         struct fwordtotal *next;
+ };
+ 
+ #ifndef MAIN_FILE
+ #define VAR extern
+ #else
+ #define VAR
+ #endif
+ 
+ VAR struct file *filelist;
+ VAR struct entry *entrylist;
+ 
+ VAR struct swline *pathconlist;
+ VAR struct swline *dirconlist;
+ VAR struct swline *fileconlist;
+ VAR struct swline *titconlist;
+ VAR struct swline *fileislist;
+ VAR struct swline *suffixlist;
+ VAR struct swline *nocontentslist;
+ VAR struct swline *replacelist;
+ VAR struct swline *searchwordlist;
+ VAR struct swline *dirlist;
+ VAR struct swline *indexlist;
+ VAR struct swline *hashstoplist[HASHSIZE];
+ VAR char *stopList[HASHSIZE];
+ 
+ VAR struct result *resulthashlist[HASHSIZE];
+ VAR struct fwordtotal *fwordtotals[BIGHASHSIZE];
+ VAR struct filenum *filehashlist[BIGHASHSIZE];
+ VAR struct metaEntry* metaEntryList;
+ 
+ VAR long offsets[MAXCHARS];
+ VAR int verbose;
+ VAR int bigrank;
+ VAR int maxhits;
+ VAR int totalwords;
+ VAR int followsymlinks;
+ VAR int commonerror;
+ VAR int stopPos;
+ 
+ VAR char indexn[MAXSTRLEN];
+ VAR char indexd[MAXSTRLEN];
+ VAR char indexp[MAXSTRLEN];
+ VAR char indexa[MAXSTRLEN];
+ VAR char errorstr[MAXSTRLEN];
+ 
+ #ifdef MAIN_FILE
+ 
+ char *indexchars = "abcdefghijklmnopqrstuvwxyz&#;0123456789_\\|/-+=?!@$%^'\"`~,.<>[]{}";
+ 
+ char *defaultstopwords[] = {
+ "a", "above", "according", "across", "actually", "adj", "after", 
+ "afterwards", "again", "against", "all", "almost", "alone", "along", 
+ "already", "also", "although", "always", "among", "amongst", "an", "and", 
+ "another", "any", "anyhow", "anyone", "anything", "anywhere", "are", "aren", 
+ "aren't", "around", "as", "at", "be", "became", "because", "become", "becomes", 
+ "becoming", "been", "before", "beforehand", "begin", "beginning", "behind", 
+ "being", "below", "beside", "besides", "between", "beyond", "billion", "both", 
+ "but", "by", "can", "can't", "cannot", "caption", "co", "could", "couldn",
+ "couldn't", "did", "didn", "didn't", "do", "does", "doesn", "doesn't", "don",
+ "don't", "down", "during", "each", "eg", "eight", "eighty", "either", "else",
+ "elsewhere", "end", "ending", "enough", "etc", "even", "ever", "every",
+ "everyone", "everything", "everywhere", "except", "few", "fifty", "first",
+ "five", "for", "former", "formerly", "forty", "found", "four", "from",
+ "further", "had", "has", "hasn", "hasn't", "have", "haven", "haven't",
+ "he", "hence", "her", "here", "hereafter", "hereby", "herein", "hereupon", 
+ "hers", "herself", "him", "himself", "his", "how", "however", "hundred", 
+ "ie", "i.e.", "if", "in", "inc", "inc.", "indeed", "instead", "into", "is",
+ "isn", "isn't", "it", "its", "itself", "last", "later", "latter", "latterly",
+ "least", "less", "let", "like", "likely", "ll", "ltd", "made", "make",
+ "makes", "many", "maybe", "me", "meantime", "meanwhile", "might", "million",
+ "miss", "more", "moreover", "most", "mostly", "mr", "mrs", "much", "must",
+ "my", "myself", "namely", "neither", "never", "nevertheless", "next", "nine",
+ "ninety", "no", "nobody", "none", "nonetheless", "noone", "nor", "not",
+ "nothing", "now", "nowhere", "of", "off", "often", "on", "once", "one",
+ "only", "onto", "or", "others", "otherwise", "our", "ours",
+ "ourselves", "out", "over", "overall", "own", "per", "perhaps", "rather",
+ "re", "recent", "recently", "same", "seem", "seemed", "seeming", "seems",
+ "seven", "seventy", "several", "she", "should", "shouldn", "shouldn't",
+ "since", "six", "sixty", "so", "some", "somehow", "someone", "something",
+ "sometime", "sometimes", "somewhere", "still", "stop", "such", "taking",
+ "ten", "than", "that", "the", "their", "them", "themselves", "then",
+ "thence", "there", "thereafter", "thereby", "therefore", "therein",
+ "thereupon", "these", "they", "thirty", "this", "those", "though",
+ "thousand", "three", "through", "throughout", "thru", "thus", "to",
+ "together", "too", "toward", "towards", "trillion", "twenty", "two", "under",
+ "unless", "unlike", "unlikely", "until", "up", "upon", "us", "used", "using",
+ "ve", "very", "via", "was", "wasn", "we", "we", "well", "were", "weren",
+ "weren't", "what", "whatever", "when", "whence", "whenever", "where", 
+ "whereafter", "whereas", "whereby", "wherein", "whereupon", "wherever", 
+ "whether", "which", "while", "whither", "who", "whoever", "whole", "whom", 
+ "whomever", "whose", "why", "will", "with", "within", "without", "won", 
+ "would", "wouldn", "wouldn't", "yes", "yet", "you", "your", "yours",
+ "yourself", "yourselves", NULL };
+ 
+ char *entities[] = {
+ "", "&#32", " ", "", "&#33", "!", "&quot", "&#34", "\"", "", "&#35", "#",
+ "", "&#36", "$", "", "&#37", "%", "&amp", "&#38", "&", "", "&#39", "'",
+ "", "&#43", "+", "", "&#44", ",", "", "&#45", "-", "", "&#46", ".",
+ "", "&#47", "/", "", "&#48", "0", "", "&#49", "1", "", "&#50", "2",
+ "", "&#51", "3", "", "&#52", "4", "", "&#53", "5", "", "&#54", "6",
+ "", "&#55", "7", "", "&#56", "8", "", "&#57", "9", "", "&#58", "",
+ "", "&#59", ";", "&lt", "&#60", "<", "", "&#61", "=", "&gt", "&#62", ">",
+ "", "&#63", "?", "", "&#64", "@", "", "&#65", "A", "", "&#66", "B",
+ "", "&#67", "C", "", "&#68", "D", "", "&#69", "E", "", "&#70", "F",
+ "", "&#71", "G", "", "&#72", "H", "", "&#73", "I", "", "&#74", "J",
+ "", "&#75", "K", "", "&#76", "L", "", "&#77", "M", "", "&#78", "N",
+ "", "&#79", "O", "", "&#80", "P", "", "&#81", "Q", "", "&#82", "R",
+ "", "&#83", "S", "", "&#84", "T", "", "&#85", "U", "", "&#86", "V",
+ "", "&#87", "W", "", "&#88", "X", "", "&#89", "Y", "", "&#90", "Z",
+ "", "&#91", "[", "", "&#92", "\\", "", "&#93", "]", "", "&#94", "^",
+ "", "&#95", "-", "", "&#96", "`", "", "&#97", "a", "", "&#98", "b",
+ "", "&#99", "c", "", "&#100", "d", "", "&#101", "e", "", "&#102", "f",
+ "", "&#103", "g", "", "&#104", "h", "", "&#105", "i", "", "&#106", "j",
+ "", "&#107", "k", "", "&#108", "l", "", "&#109", "m", "", "&#110", "n",
+ "", "&#111", "o", "", "&#112", "p", "", "&#113", "q", "", "&#114", "r",
+ "", "&#115", "s", "", "&#116", "t", "", "&#117", "u", "", "&#118", "v",
+ "", "&#119", "w", "", "&#120", "x", "", "&#121", "y", "", "&#122", "z",
+ "", "&#123", "{", "", "&#124", "|", "", "&#125", "}", "", "&#126", "~",
+ "&nbsp", "&#160", " ", "&iexcl", "&#161", "", "&cent", "&#162", "",
+ "&pound", "&#163", "", "&curren", "&#164", "", "&yen", "&#165", "",
+ "&brvbar", "&#166", "", "&sect", "&#167", "", "&die", "&#168", "",
+ "&copy", "&#169", "", "&ordf", "&#170", "", "&laquo", "&#171", "",
+ "&not", "&#172", "", "&shy", "&#173", "", "&reg", "&#174", "",
+ "&macron", "&#175", "", "&degree", "&#176", "", "&plusmn", "&#177", "",
+ "&sup2", "&#178", "", "&sup3", "&#179", "", "&acute", "&#180", "",
+ "&micro", "&#181", "", "&mu", "&#182", "", "&middot", "&#183", "",
+ "&Cedilla", "&#184", "", "&sup1", "&#185", "", "&ordm", "&#186", "",
+ "&raquo", "&#187", "", "&frac14", "&#188", "", "&frac12", "&#189", "",
+ "&frac34", "&#190", "", "&iquest", "&#191", "", "&Agrave", "&#192", "A",
+ "&Aacute", "&#193", "A", "&Acirc", "&#194", "A", "&Atilde", "&#195", "A",
+ "&Auml", "&#196", "A", "&Aring", "&#197", "A", "&AElig", "&#198", "A",
+ "&Ccedil", "&#199", "C", "&Egrave", "&#200", "E", "&Eacute", "&#201", "E",
+ "&Ecirc", "&#202", "E", "&Euml", "&#203", "E", "&Igrave", "&#204", "E",
+ "&Iacute", "&#205", "I", "&Icirc", "&#206", "I", "&Iuml", "&#207", "I",
+ "&ETH", "&#208", "", "&Ntilde", "&#209", "N", "&Ograve", "&#210", "O",
+ "&Oacute", "&#211", "O", "&Ocirc", "&#212", "O", "&Otilde", "&#213", "O",
+ "&Ouml", "&#214", "O", "&times", "&#215", "", "&Oslash", "&#216", "O",
+ "&Ugrave", "&#217", "U", "&Uacute", "&#218", "U", "&Ucirc", "&#219", "U",
+ "&Uuml", "&#220", "U", "&Yacute", "&#221", "Y", "&THORN", "&#222", "",
+ "&szlig", "&#223", "", "&agrave", "&#224", "a", "&aacute", "&#225", "a",
+ "&acirc", "&#226", "a", "&atilde", "&#227", "a", "&auml", "&#228", "a",
+ "&aring", "&#229", "a", "&aelig", "&#230", "a", "&ccedil", "&#231", "c",
+ "&egrave", "&#232", "e", "&eacute", "&#233", "e", "&ecirc", "&#234", "e",
+ "&euml", "&#235", "e", "&igrave", "&#236", "i", "&iacute", "&#237", "i",
+ "&icirc", "&#238", "i", "&iuml", "&#239", "i", "&eth", "&#240", "",
+ "&ntilde", "&#241", "n", "&ograve", "&#242", "o", "&oacute", "&#243", "o",
+ "&ocirc", "&#244", "o", "&otilde", "&#245", "o", "&ouml", "&#246", "o",
+ "&divide", "&#247", "", "&oslash", "&#248", "o", "&ugrave", "&#249", "u",
+ "&uacute", "&#250", "u", "&ucirc", "&#251", "u", "&uuml", "&#252", "u",
+ "&yacute", "&#253", "y", "&thorn", "&#254", "", "&yuml", "&#255", "y",
+ NULL };
+ 
+ #else
+ extern char *indexchars;
+ extern char *defaultstopwords[];
+ extern char *entities[];
+ #endif
+ 
+ #ifdef MAIN_FILE
+ int main();
+ void usage();
+ void printversion();
+ void printrunning();
+ long getthetime();
+ #endif
Index: harvest/components/broker/swish/swish_config.h
diff -c /dev/null harvest/components/broker/swish/swish_config.h:1.1
*** /dev/null	Mon Oct 27 18:41:06 1997
--- harvest/components/broker/swish/swish_config.h	Mon Oct 27 16:13:58 1997
***************
*** 0 ****
--- 1,141 ----
+ /*
+ ** SWISH Default Configuration File
+ **
+ ** Kevin Hughes, kevinh@eit.com 
+ ** 3/11/94
+ **
+ ** The following are user-definable options that you can change
+ ** to fine-tune SWISH's default options.
+ */
+ 
+ /* #define NEXTSTEP */
+ 
+ /* You may need to define this if compiling on a NeXTstep machine.
+ */
+ 
+ #define INDEXPERMS 0644
+ 
+ /* After SWISH generates an index file, it changes the permissions
+ ** of the file to this mode. Change to the mode you like
+ ** (note that it must be an octal number). If you don't want
+ ** permissions to be changed for you, comment out this line.
+ */
+ 
+ #define PLIMIT 99
+ #define FLIMIT 10000
+ 
+ /* SWISH uses these parameters to automatically mark words as
+ ** being too common while indexing. For instance, if I defined PLIMIT
+ ** as 80 and FLIMIT as 256, SWISH would define a common word as
+ ** a word that occurs in over 80% of all indexed files and over
+ ** 256 files. Making these numbers lower will most likely make your
+ ** index files smaller. Making PLIMIT and FLIMIT small will also
+ ** ensure that searching consumes only so much CPU resources.
+ */
+ 
+ #define VERBOSE 1
+ 
+ /* You can define VERBOSE to be a number from 0 to 3. 0 is totally
+ ** silent operation; 3 is very verbose.
+ */
+ 
+ #define MAXHITS 5000
+ 
+ /* MAXHITS is the maximum number of results to return from a search.
+ */
+ 
+ #define DEFAULT_RULE AND_RULE
+ 
+ /* If a list of search words is specified without booleans,
+ ** SWISH will assume they are connected by a default rule.
+ ** This can be AND_RULE or OR_RULE.
+ */
+ 
+ #define MINWORDLIMIT 2
+ 
+ /* This is the minimum length of a word. Anything shorter will not
+ ** be indexed.
+ */
+ 
+ #define MAXWORDLIMIT 40
+ 
+ /* This is the maximum length of a word. Anything longer will not
+ ** be indexed.
+ */
+ 
+ #define ASCIIENTITIES 1
+ 
+ /* If defined as 1, all entities in search words and indexed
+ ** words will be converted to an ASCII equivalent. For instance,
+ ** with this feature you can index the word "resum&eacute;" or
+ ** "resum&#233;" and it will be indexed as the word "resume".
+ ** If defined as 0, only numerical entities will be converted
+ ** to named entities, if they exist.
+ */
+ 
+ #define IGNOREALLV 0
+ #define IGNOREALLC 0
+ #define IGNOREALLN 0
+ 
+ /* If IGNOREALLV is 1, words containing all vowels won't be indexed.
+ ** If IGNOREALLC is 1, words containing all consonants won't be indexed.
+ ** If IGNOREALLN is 1, words containing all digits won't be indexed.
+ ** Define as 0 to allow words with consistent characters.
+ ** Vowels are defined as "aeiou", digits are "0123456789".
+ */
+ 
+ #define IGNOREROWV 60
+ #define IGNOREROWC 60
+ #define IGNOREROWN 60
+ 
+ /* IGNOREROWV is the maximum number of consecutive vowels a word can have.
+ ** IGNOREROWC is the maximum number of consecutive consonants a word can have.
+ ** IGNOREROWN is the maximum number of consecutive digits a word can have.
+ ** Vowels are defined as "aeiou", digits are "0123456789".
+ */
+ 
+ #define IGNORESAME 100
+ 
+ /* IGNORESAME is the maximum times a character can repeat in a word.
+ */
+ 
+ #define WORDCHARS "abcdefghijklmnopqrstuvwxyz=�����������������������،�����ݟ��������������������������������������&#;0123456789.@\\|/,-'[]{}()~!@$%^_+?"
+ 
+ /* WORDCHARS is a string of characters which SWISH permits to
+ ** be in words. Any strings which do not include these characters
+ ** will not be indexed. You can choose from any character in
+ ** the following string:
+ **
+ ** abcdefghijklmnopqrstuvwxyz0123456789_\|/-+=?!@$%^'\"`~,.[]{}()
+ **
+ ** Note that if you omit "0123456789&#;" you will not be able to
+ ** index HTML entities. DO NOT use the asterisk (*), lesser than
+ ** and greater than signs (<), (>), or colon (:).
+ **
+ ** Including any of these four characters may cause funny things to happen.
+ ** If you have a pressing need to index 8-bit characters, please contact
+ ** me for possible user testing in the future.
+ **
+ ** Also note that if you specify the backslash character (\) or
+ ** double quote (") you need to type a backslash before them to
+ ** make the compiler understand them.
+ */
+ 
+ #define BEGINCHARS "abcdefghijklmnopqrstuvwxyz�����������������������،�����ݟ��������������������������������������&0123456789"
+ 
+ /* Of the characters that you decide can go into words, this is
+ ** a list of characters that words can begin with. It should be
+ ** a subset of (or equal to) WORDCHARS.
+ */
+ 
+ #define ENDCHARS "abcdefghijklmnopqrstuvwxyz�����������������������،�����ݟ��������������������������������������.0123456789,'"
+ 
+ /* This is the same as BEGINCHARS, except you're testing for
+ ** valid characters at the ends of words.
+ */
+ 
+ /* Note that if you really want to edit the default stopwords, (words
+ ** that are deemed too common to be indexed) then you can do so in the
+ ** file "swish.h". They don't have to be in alphabetical order.
+ */
+ 
Index: harvest/components/gatherer/Makefile
diff -c harvest/components/gatherer/Makefile:2.1 harvest/components/gatherer/Makefile:2.2
*** harvest/components/gatherer/Makefile:2.1	Thu Sep 11 12:14:16 1997
--- harvest/components/gatherer/Makefile	Mon Oct 27 16:51:04 1997
***************
*** 1,11 ****
  #
  #  Makefile for the Gatherer components
  #
! #  Makefile,v 2.1 1997/09/11 16:14:16 sxw Exp
  #
  #
  
! SUBDIRS="`cat BUILD`"
  
  all: do-all
  install: do-install
--- 1,11 ----
  #
  #  Makefile for the Gatherer components
  #
! #  Makefile,v 2.2 1997/10/27 21:51:04 sxw Exp
  #
  #
  
! SUBDIRS=`cat BUILD`
  
  all: do-all
  install: do-install
Index: harvest/src/broker/CreateBroker
diff -c harvest/src/broker/CreateBroker:2.2 harvest/src/broker/CreateBroker:2.3
*** harvest/src/broker/CreateBroker:2.2	Wed Sep  3 07:52:41 1997
--- harvest/src/broker/CreateBroker	Mon Oct 27 17:47:05 1997
***************
*** 8,14 ****
  #
  #  	For example, CreateBroker /usr/local/harvest/brokers/skeleton
  #
! #  CreateBroker,v 2.2 1997/09/03 11:52:41 sxw Exp
  #
  #############################################################################
  #
--- 8,14 ----
  #
  #  	For example, CreateBroker /usr/local/harvest/brokers/skeleton
  #
! #  CreateBroker,v 2.3 1997/10/27 22:47:05 sxw Exp
  #
  #############################################################################
  #
***************
*** 215,220 ****
--- 215,221 ----
  	   	next if ($key eq "Skeleton-Directory");
  		next if ($key =~ /glimpse/io && $INDEXER ne "glimpse");
  		next if ($key =~ /wais/io && $INDEXER ne "wais");
+ 		next if ($key =~ /swish/io && $INDEXER ne "swish");
  		printf "%21s: ", $key;
  		if ($vals{$key} eq "No_Default") {
  			print "none";
***************
*** 246,251 ****
--- 247,253 ----
  	$vals{"glimpse-Command"} = "$ENV{'HARVEST_HOME'}/lib/broker/glimpse";
  	$vals{"glimpseindex-Command"} = "$vals{'glimpse-Command'}index";
  	$vals{"glimpseserver-Command"} = "$vals{'glimpse-Command'}server";
+ 	$vals{"swish-Command"} = "$ENV{'HARVEST_HOME'}/lib/broker/swish";
  	$vals{'Broker-WAIS-Host'} = $vals{'Broker-Host'};
  	$vals{'Broker-WAIS-Port'} = $vals{'Broker-Port'} + 1;
  	$vals{'Broker-Glimpse-Host'} = $vals{'Broker-Host'};
***************
*** 306,319 ****
  &get_ans("Enter the name of the attribute that will be displayed to the\nuser as one-line object description in search results",
  	   "Broker-Description-Tag");
  $vals{"Indexer"} = "glimpse";
! &get_ans("Do you want to use Glimpse or WAIS as an Indexer",
  	   "Indexer");
  $INDEXER = "glimpse";
- if ($vals{"Indexer"} =~ /wais/io) {
- 	$INDEXER = "wais";
- } 
  
! if ($vals{"Indexer"} =~ /glimpse/io) {
  	&get_ans("Enter the pathname to the glimpse command", 
  	   	"glimpse-Command");
  	&get_ans("Enter the pathname to the glimpseindex command", 
--- 308,322 ----
  &get_ans("Enter the name of the attribute that will be displayed to the\nuser as one-line object description in search results",
  	   "Broker-Description-Tag");
  $vals{"Indexer"} = "glimpse";
! &get_ans("Do you want to use Glimpse, WAIS or Swish as an Indexer",
  	   "Indexer");
  $INDEXER = "glimpse";
  
! if ($vals{"Indexer"} =~ /swish/io) {
! 	$INDEXER = "swish";
!         &get_ans("Enter the pathname to the swish command", "swish-Command");
! } elsif ($vals{"Indexer"} =~ /glimpse/io) {
!        	$INDEXER = "glimpse";
  	&get_ans("Enter the pathname to the glimpse command", 
  	   	"glimpse-Command");
  	&get_ans("Enter the pathname to the glimpseindex command", 
***************
*** 322,328 ****
  	   	"glimpseserver-Command");
  	&get_ans("Enter the host on which to run glimpseserver", 
  	   	"Broker-Glimpse-Host");
! } else {
  	$vals{'Broker-WAIS-Host'} = $vals{'Broker-Host'};
  	$vals{'Broker-WAIS-Port'} = $vals{'Broker-Port'} + 1;
  	$vals{'WAIS-Flavor'} = "WAIS";
--- 325,332 ----
  	   	"glimpseserver-Command");
  	&get_ans("Enter the host on which to run glimpseserver", 
  	   	"Broker-Glimpse-Host");
! } elsif ($vals{"Indexer"} =~ /wais/io) {
!         $INDEXER = "Wais";
  	$vals{'Broker-WAIS-Host'} = $vals{'Broker-Host'};
  	$vals{'Broker-WAIS-Port'} = $vals{'Broker-Port'} + 1;
  	$vals{'WAIS-Flavor'} = "WAIS";
***************
*** 381,386 ****
--- 385,391 ----
  
  	$vals{'Broker-Indexer-Type'} = "Glimpse";
  	$vals{'Broker-Indexer-Type'} = "WAIS" if ($INDEXER =~ /wais/io);
+ 	$vals{'Broker-Indexer-Type'} = "Swish" if ($INDEXER =~ /swish/io);
  	#  Make the broker directory
  	mkdir($vals{'Destination-Directory'}, 0755) || die 
  		"Cannot make $vals{'Destination-Directory'}: $!\n";
***************
*** 412,417 ****
--- 417,423 ----
  	s/\@THIS_BROKER_PORT\@/$vals{'Broker-Port'}/g;
  	s/\@THIS_BROKER_PASSWORD\@/$vals{'Broker-Password'}/g;
  	s/\@THIS_BROKER_HOST\@/$vals{'Broker-Host'}/g;
+ 	s/\@THIS_BROKER_SWISH\@/$vals{'swish-Command'}/g;
  	s/\@THIS_BROKER_GLIMPSE\@/$vals{'glimpse-Command'}/g;
  	s/\@THIS_BROKER_GLIMPSEINDEX\@/$vals{'glimpseindex-Command'}/g;
  	s/\@THIS_BROKER_GLIMPSESERVER\@/$vals{'glimpseserver-Command'}/g;
Index: harvest/src/broker/Makefile.in
diff -c harvest/src/broker/Makefile.in:2.3 harvest/src/broker/Makefile.in:2.4
*** harvest/src/broker/Makefile.in:2.3	Thu Sep 11 12:14:57 1997
--- harvest/src/broker/Makefile.in	Mon Oct 27 17:47:06 1997
***************
*** 1,7 ****
  #
  #  Makefile for the Harvest Broker
  #
! #  Makefile.in,v 2.3 1997/09/11 16:14:57 sxw Exp
  #
  prefix = @prefix@
  INSTALL_BINDIR	= $(prefix)/bin
--- 1,7 ----
  #
  #  Makefile for the Harvest Broker
  #
! #  Makefile.in,v 2.4 1997/10/27 22:47:06 sxw Exp
  #
  prefix = @prefix@
  INSTALL_BINDIR	= $(prefix)/bin
***************
*** 25,36 ****
  LFLAGS		= 
  YFLAGS  	= -d #-t #-v
  
! INDEX_OBJS	= Glimpse/index.o Wais/index.o
  # 		  Netfind/index.o
  #		  Grass/index.o
  #		  PLWeb/index.o
  
! INDEX_SUPPORT	= -DUSE_GLIMPSE -DUSE_WAIS
  #		  -DUSE_NEBULA
  #		  -DUSE_VERITY
  #		  -DUSE_PLWEB
--- 25,36 ----
  LFLAGS		= 
  YFLAGS  	= -d #-t #-v
  
! INDEX_OBJS	= Glimpse/index.o Wais/index.o Swish/index.o
  # 		  Netfind/index.o
  #		  Grass/index.o
  #		  PLWeb/index.o
  
! INDEX_SUPPORT	= -DUSE_GLIMPSE -DUSE_WAIS -DUSE_SWISH
  #		  -DUSE_NEBULA
  #		  -DUSE_VERITY
  #		  -DUSE_PLWEB
***************
*** 82,87 ****
--- 82,90 ----
  
  Grass/index.o:	Grass/index.c
  	$(CC) $(CFLAGS) -c -o $@ Grass/index.c
+ 
+ Swish/index.o:                Swish/index.c
+ 	$(CC) $(CFLAGS) -c -o $@ Swish/index.c
  
  dumpregistry:	stor_reg.o dumpregistry.o brkutil.o gid.o
  	$(CC) -o $@ stor_reg.o dumpregistry.o brkutil.o gid.o $(LDFLAGS) $(LIBS)
Index: harvest/src/broker/main.c
diff -c harvest/src/broker/main.c:2.3 harvest/src/broker/main.c:2.4
*** harvest/src/broker/main.c:2.3	Thu Jun 12 21:07:23 1997
--- harvest/src/broker/main.c	Mon Oct 27 17:47:07 1997
***************
*** 1,4 ****
! static char rcsid[] = "main.c,v 2.3 1997/06/13 01:07:23 sxw Exp";
  /*
   *  main.c -- main module of the Harvest Broker.
   *
--- 1,4 ----
! static char rcsid[] = "main.c,v 2.4 1997/10/27 22:47:07 sxw Exp";
  /*
   *  main.c -- main module of the Harvest Broker.
   *
***************
*** 185,190 ****
--- 185,193 ----
  #ifdef USE_PLWEB
  #include "PLWeb/index.h"
  #endif
+ #ifdef USE_SWISH
+ #include "Swish/index.h"
+ #endif
  
  /*  These are the valid Indexer types from broker.conf */
  #define Valid_Indexer_Type(type)        \
***************
*** 194,200 ****
  	!strcmp(type, "Grass")   || \
  	!strcmp(type, "Verity")   || \
  	!strcmp(type, "PLWeb")   || \
! 	!strcmp(type, "WAIS") \
  	)
  
  /*  This is the structure that is used to map the Indexing routines */
--- 197,204 ----
  	!strcmp(type, "Grass")   || \
  	!strcmp(type, "Verity")   || \
  	!strcmp(type, "PLWeb")   || \
! 	!strcmp(type, "WAIS")    || \
! 	!strcmp(type, "Swish") \
  	)
  
  /*  This is the structure that is used to map the Indexing routines */
***************
*** 288,293 ****
--- 292,312 ----
  	 VERITY_IND_do_query,
  	 VERITY_IND_Init_Flags,
  	 VERITY_IND_Set_Flags
+ 	}
+ #endif
+ #ifdef USE_SWISH
+ 	{"Swish",
+ 	 Swish_IND_Index_Start,
+ 	 Swish_IND_Index_Flush,
+ 	 Swish_IND_New_Object,
+ 	 Swish_IND_Destroy_Obj,
+ 	 Swish_IND_Index_Full,
+ 	 Swish_IND_Index_Incremental,
+ 	 Swish_IND_initialize,
+ 	 Swish_IND_config,
+ 	 Swish_IND_do_query,
+ 	 Swish_IND_Init_Flags,
+ 	 Swish_IND_Set_Flags
  	}
  #endif
  };
Index: harvest/src/broker/Swish/index.c
diff -c /dev/null harvest/src/broker/Swish/index.c:1.1
*** /dev/null	Mon Oct 27 18:41:24 1997
--- harvest/src/broker/Swish/index.c	Mon Oct 27 17:47:08 1997
***************
*** 0 ****
--- 1,415 ----
+ static char rcsid[] = "index.c,v 1.1 1997/10/27 22:47:08 sxw Exp";
+ /*
+  *  index.c -- Swish indexer interface
+  *
+  *  Simon Wilkinson 14/10/97
+  *
+  */
+ #include "broker.h"
+ #include "log.h"
+ #include "Swish/index.h"
+ 
+ /* Global variables */
+ extern char *DIRpath;
+ extern char *brk_obj_url;
+ extern int IndexType;
+ 
+ int SW_illegal_query = 0;
+ char *SW_SwishInd = NULL;
+ int SW_lifetime = 15 * 60;
+ int SW_max_lifetime = 15 * 60;
+ int SW_NewObj = 0;
+ 
+ #define BIG_BUFSIZ      (8*BUFSIZ) 
+ 
+ #define BADQ_STR \
+         "103 - ERROR: Swish Indexer cannot support your query.\n"
+ 
+ static fd_t SW_getfd(char *line) {
+   char *tmp =NULL;
+   
+   if ((tmp = strstr(line, "/OBJ")) == NULL) return ERROR;
+   tmp+=4;
+   return((fd_t) atol(tmp));
+ }
+ 
+ static int SW_Start_Indexing(char *comm)
+ {
+   int pid, status = 0;
+   
+   Debug(103,1,("Command: %s\n",comm));
+   
+   if ((pid = fork()) < 0) {
+     log_errno("fork");
+     return ERROR;
+   } 
+   if (pid == 0) {
+     char *argv[64];
+     
+     memset(argv, '\0', sizeof(argv));
+     parse_argv(argv, comm);
+     execvp(argv[0],argv);
+     perror(argv[0]);
+     _exit(1);
+   }
+   Log("Waiting for swish to finish indexing...\n");
+   while(waitpid(pid, &status, WNOHANG) !=pid) {
+     select_loop(15, 0, 0); /* No connections */
+     if (kill(pid, 0) != 0)
+       break; /* child dead and reaped */
+   }
+   
+   return SUCCESS;
+ }
+ 
+ static int SW_bulk_query(int rsock, FILE* indexfp, time_t ptime) {
+   static char ret[BIG_BUFSIZ];
+   fd_t qfd;
+   fd_t oldfd = -1;
+   int cnt = 0;
+   reg_t *bentry = NULL;
+   FILE *fp = NULL;
+   
+   if ((fp = fdopen(rsock, "w")) == NULL) {
+     log_errno("fdopen");
+     QM_send_bulk_err(rsock);
+     return ERROR;
+   }
+   QM_send_bulk_begin(rsock);
+   while (fgets(ret, BIG_BUFSIZ, indexfp) != NULL)
+     if (((qfd = SW_getfd(ret)) != ERROR) &&
+ 	((bentry = RG_Get_Entry(qfd)) != NULL) &&
+ 	(bentry->update_time >= ptime))
+       QM_send_bulk_fd(qfd, fp, bentry) == SUCCESS;
+   fflush(fp);
+   QM_send_bulk_end(rsock);
+   fclose(fp);
+   return SUCCESS;
+ }
+ 
+ static int SW_del_query(int rsock, FILE *indexfp) {
+   char ret[BUFSIZ];
+   fd_t qfd;
+   int cnt =0;
+   reg_t *rme;
+   
+   while (fgets(ret, BUFSIZ, indexfp) !=NULL)
+     if (((qfd = SW_getfd(ret)) != ERROR) &&
+ 	((rme = RG_Get_Entry(qfd)) != NULL)) {
+       COL_DEL_Obj(rme);
+       cnt ++;
+     }
+   Log("Deleted %d objects based on query.\n", cnt);
+   return SUCCESS;
+ }
+ 
+ static int SW_user_query(int rsock, FILE *indexfp) {
+   fd_t fd;
+   char inb[BUFSIZ], opb[BUFSIZ], *opdata[BUFSIZ], *tmp, *s;
+   int opsize = 0, obcnt = 0, i;
+   
+   /* If the query was illegal give up */
+   if (SW_illegal_query) {
+     SWRITE(rsock, BADQ_STR, strlen(BADQ_STR));
+     return ERROR;
+   }
+   
+   /* Check the clients not gone bye-bye */
+   (void) write(rsock, PIPECHK, strlen(PIPECHK));
+   if (write(rsock, PIPECHK, strlen(PIPECHK)) == -1) {
+     errorlog("Client is gone -- aborting user query results.\n");
+     close(rsock);
+     return ERROR;
+   }
+   memset(opdata, '\0', BUFSIZ * sizeof(char *));
+   while (fgets(inb, BUFSIZ, indexfp) !=NULL) {
+     if ((fd = SW_getfd(inb)) == ERROR)
+       continue;
+     if (QM_user_object(rsock, fd, opsize, opdata) == SUCCESS)
+       obcnt++;
+   }
+   QM_user_done(rsock, obcnt);
+   
+   return SUCCESS;
+ }
+ 
+ static char *SW_build_select(qlist_t *ql)
+ {
+   char *tmp = NULL;
+   
+   if (ql->op == EXACT || ql->op == REGEX) {
+     tmp = (char *) xmalloc(BUFSIZ);
+     tmp[0] = '\0';
+     if (ql->llist) {
+       sprintf(tmp, "%s=%s",ql->llist,ql->rlist);
+       xfree(ql->rlist); ql->rlist=NULL;
+       xfree(ql->llist); ql->llist=NULL;
+       return(tmp);
+     }
+     sprintf(tmp, "%s", ql->rlist);
+     xfree(ql->rlist); ql->rlist=NULL;
+     return(tmp);
+   }
+   return NULL;
+ }
+ 
+ static char *SW_do_qlist(qlist_t *ql)
+ {
+   char *ll, *rl , *nl;
+   
+   if (ql==NULL) return NULL;
+   
+   
+   if (ql->type == LOGICAL) {
+     
+     nl = (char *) xmalloc(BUFSIZ);
+     
+     ll = SW_do_qlist((qlist_t *) ql->llist);
+     
+     if ((rl = SW_do_qlist((qlist_t *) ql->rlist)) == NULL) {
+       if (ll!=NULL) xfree(ll);
+       return NULL;
+     }
+     nl[0]= '\0';
+     
+     if (ll!=NULL) strcat(nl,ll);
+     
+     switch (ql->op) {
+     case AND:
+       strncat(nl, " and ", 5);
+       break;
+     case OR:
+       strncat(nl, " or ", 4);
+       break;
+     case NOT:
+       strncat(nl, " not ", 5);
+       break;
+     default:
+       xfree(nl);
+       xfree(rl);
+       if (ll!=NULL) xfree(ll);
+       return NULL;
+     }
+     strcat(nl, rl);
+     if (ll!=NULL) xfree(ll);
+     xfree(rl);
+     return(nl);
+   }
+   return (SW_build_select(ql));
+ }
+ 
+ 		
+ /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX *
+ 
+                               PUBLIC FUNCTIONS                      
+ 
+  * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
+ 
+ /* ----------------------------------------------------------------- *
+    Swish_IND_New_Object -- index a new object
+  * ----------------------------------------------------------------- */
+ int Swish_IND_New_Object(reg_t *entry)
+ {
+   int ret = SUCCESS;
+   
+   if (IndexType == I_PER_OBJ) {
+     Log("The Swish broker doesn't support per object indexing\n");
+     ret = FAIL;
+   }
+   
+   if (ret == SUCCESS) SW_NewObj++;
+   
+   return ret;
+ }
+ 
+ /* ----------------------------------------------------------------- *
+    Swish_IND_Index_Full -- builds an index of all of the object files.
+  * ----------------------------------------------------------------- */ 
+ int Swish_IND_Index_Full()
+ {
+   char comm[BUFSIZ];
+   
+   Log("Begin Swish Full Indexing ...\n");
+   sprintf(comm,  "%s -i %s/objects -f %s/index",SW_SwishInd, DIRpath,
+ 	  DIRpath);
+   SW_Start_Indexing(comm);
+   Log("Finished Swish Full Indexing.\n");
+   return SUCCESS;
+ }
+ 
+ /* ----------------------------------------------------------------- *
+    Swish_IND_Index_Incremental -- do a full incremental update of the index.
+  * ----------------------------------------------------------------- */ 
+ int Swish_IND_Index_Incremental()
+ {
+   Log("The SWISH broker doesn't support incremental indexing\n");
+   Log("Using full indexing instead ...\n");
+   return Swish_IND_Index_Full();
+ }
+ 
+ /* ----------------------------------------------------------------- *
+    Swish_IND_Index_Start -- prepare for indexing a stream of objects.
+  * ----------------------------------------------------------------- */
+ int Swish_IND_Index_Start()
+ {
+   SW_NewObj = 0;
+   return SUCCESS;
+ }
+ 
+ /* ----------------------------------------------------------------- *
+    Swish_IND_Index_Flush -- finish indexing a stream of objects.
+  * ----------------------------------------------------------------- */
+ int Swish_IND_Index_Flush()
+ {
+   if (SW_NewObj > 0) {
+     switch (IndexType) {
+     case I_FULL:
+       return (Swish_IND_Index_Full());
+     case I_INCR:
+       return (Swish_IND_Index_Incremental());
+     case I_PER_OBJ:
+       break;
+     default:
+       fatal("Swish_IND_Index_Flush: Internal error.\n");
+     }
+   }
+   return SUCCESS;
+ }
+ 
+ /* ----------------------------------------------------------------- *
+    Swish_IND_Destroy_Obj -- remove an object from the indexer.
+  * ----------------------------------------------------------------- */
+ int Swish_IND_Destroy_Obj(reg_t *entry)
+ {
+   return SUCCESS;
+ }
+ 
+ 
+ /* ----------------------------------------------------------------- *
+    Swish_IND_initialize -- initialize interface to indexer
+  * ----------------------------------------------------------------- */
+ int Swish_IND_initialize()
+ {
+   /* Force full indexing */
+   IndexType = I_FULL;
+   
+   return SUCCESS;
+ }
+ 
+ /* ----------------------------------------------------------------- *
+    Swish_IND_Init_Flags -- initialize parser flags
+  * ----------------------------------------------------------------- */
+ void Swish_IND_Init_Flags()
+ {
+ }
+ 
+ /* ----------------------------------------------------------------- *
+    Swish_IND_Set_Flags -- set query parser flag
+    * ----------------------------------------------------------------- */
+ void Swish_IND_Set_Flags(char *flag, char *val)
+ {
+ }
+ 
+ /* ----------------------------------------------------------------- *
+    Swish_IND_config -- configure indexer specific variables
+  * ----------------------------------------------------------------- */
+ int Swish_IND_config(char *value, char *tag)
+ {
+   if (tag == NULL || value == NULL)
+     return ERROR;
+   
+   if (strcasecmp(tag, "Swish") == 0) {
+     SW_SwishInd= xstrdup(value);
+     if (verify_exe(SW_SwishInd) == ERROR) return ERROR;
+   }
+   return SUCCESS;
+ }
+ 
+ 
+ /* ----------------------------------------------------------------- *
+    Swish_IND_do_query -- construct a query based upon the query list 
+ 			 structure.
+  * ----------------------------------------------------------------- */ 
+ int Swish_IND_do_query(qlist_t *ql, int rsock, int qflag, time_t ptime)
+ {
+   char *patstr = NULL;
+   static char commandstr[BUFSIZ];
+   char *tfn = NULL;
+   int err=SUCCESS;
+   FILE *indexfp = NULL;
+   
+   patstr = SW_do_qlist(ql);
+   
+   if (patstr != NULL) {
+     sprintf(commandstr,"%s -f %s/index -w '%s'",SW_SwishInd,
+ 	    DIRpath, patstr);
+     xfree(patstr);
+     
+     /* Need (for now) a tmpfile for the output */
+     if ((tfn = tempnam(NULL, "query")) != NULL) {
+       strcat(commandstr, " > ");
+       strcat(commandstr, tfn);
+     } else {
+       SWRITE(rsock, IND_FAIL, IND_FAIL_S);
+       return ERROR;
+     }
+     Log("Swish search command: %s\n", commandstr);
+     
+     /* Run the query, but restrict its lifetime */
+     do_system_lifetime(commandstr, SW_lifetime);
+     
+     /* Now process the tempfile that should contain the results */
+     if ((indexfp = fopen(tfn, "r")) == NULL) {
+       log_errno(tfn);
+       unlink(tfn);
+       xfree(tfn);
+       if (qflag == UQUERY) 
+ 	SWRITE(rsock, IND_FAIL, IND_FAIL_S)
+       else
+ 	QM_send_bulk_err(rsock);
+       close(rsock);
+       return ERROR;
+     }
+     switch(qflag) {
+     case QBULK:
+ #ifdef FORK_ON_BULK
+       if (fork() == 0) {      /* child */
+ 	int e[3];
+ 	e[0] = rsock;
+ 	e[1] = fileno(indexfp);
+ 	e[2] = -1;
+ 	close_all_fds_except(3, e);
+ 	SW_bulk_query(rsock, indexfp, ptime);
+ 	fclose(indexfp);
+ 	unlink(tfn);
+ 	close(rsock);
+ 	_exit(0);
+       }
+       err = SUCCESS;
+ #else
+       err = SW_bulk_query(rsock,indexfp,ptime);
+ #endif
+       break;
+     case UQUERY:
+       err = SW_user_query(rsock,indexfp);
+       break;
+     case QDELETE:
+       err = SW_del_query(rsock, indexfp);
+     default:
+       break;
+     }
+     fclose(indexfp);
+     unlink(tfn);
+     xfree(tfn);
+   } else if (qflag == QBULK) {
+     QM_send_bulk_err(rsock);
+     err = ERROR;
+   } else {
+     write (rsock, ERR_MSG, strlen(ERR_MSG));
+     err = ERROR;
+   }
+   close(rsock);
+   
+   return err;
+ }
+ 
Index: harvest/src/broker/Swish/index.h
diff -c /dev/null harvest/src/broker/Swish/index.h:1.1
*** /dev/null	Mon Oct 27 18:41:25 1997
--- harvest/src/broker/Swish/index.h	Mon Oct 27 17:47:09 1997
***************
*** 0 ****
--- 1,25 ----
+ /* 
+  *   index.h -- Swish indexer interface header file
+  *
+  *   index.h,v 1.1 1997/10/27 22:47:09 sxw Exp
+  */
+ 
+ #ifndef _PARAMS
+ #if defined(__STDC__) || defined(__cplusplus) || defined(__STRICT_ANSI__)
+ #define _PARAMS(ARGS) ARGS
+ #else				/* Traditional C */
+ #define _PARAMS(ARGS) ()
+ #endif				/* __STDC__ */
+ #endif				/* _PARAMS */
+ 
+ int Swish_IND_Index_Start _PARAMS((void));
+ int Swish_IND_Index_Flush _PARAMS((void));
+ int Swish_IND_New_Object _PARAMS((reg_t *));
+ int Swish_IND_Destroy_Obj _PARAMS((reg_t *));
+ int Swish_IND_Index_Full _PARAMS((void));
+ int Swish_IND_Index_Incremental _PARAMS((void));
+ int Swish_IND_initialize _PARAMS((void));
+ int Swish_IND_config _PARAMS((char *, char *));
+ int Swish_IND_do_query _PARAMS((qlist_t *, int, int, time_t));
+ void Swish_IND_Init_Flags _PARAMS((void));
+ void Swish_IND_Set_Flags _PARAMS((char *, char *));
Index: harvest/src/broker/example/brokers/skeleton/admin/broker.conf.in
diff -c harvest/src/broker/example/brokers/skeleton/admin/broker.conf.in:2.1 harvest/src/broker/example/brokers/skeleton/admin/broker.conf.in:2.2
*** harvest/src/broker/example/brokers/skeleton/admin/broker.conf.in:2.1	Fri May  9 19:28:52 1997
--- harvest/src/broker/example/brokers/skeleton/admin/broker.conf.in	Mon Oct 27 17:47:10 1997
***************
*** 10,16 ****
  #
  #  The Indexer-Type is the type of indexing subsystem to use.
  #  This should always be the first option in this file.
! #  The possible values are: Glimpse or WAIS.
  #
  Indexer-Type @THIS_BROKER_INDEXER_TYPE@
  
--- 10,16 ----
  #
  #  The Indexer-Type is the type of indexing subsystem to use.
  #  This should always be the first option in this file.
! #  The possible values are: Glimpse, Swish or WAIS.
  #
  Indexer-Type @THIS_BROKER_INDEXER_TYPE@
  
***************
*** 194,199 ****
--- 194,207 ----
  #  queries then increase this value.
  #
  Read-Query-Timeout 500000
+ 
+ #######################################################################
+ # The Swish tags below will only apply if you choose Swish as your engine
+ #######################################################################
+ #
+ #  The Swish tag is the pathname to the SWISH program
+ #
+ Swish @THIS_BROKER_SWISH@
  
  #######################################################################
  # The Glimpse tags below will only apply if you choose Glimpse as your engine
Index: harvest/src/common/include/version.h
diff -c harvest/src/common/include/version.h:2.2 harvest/src/common/include/version.h:2.3
*** harvest/src/common/include/version.h:2.2	Thu Apr 17 13:29:48 1997
--- harvest/src/common/include/version.h	Mon Oct 27 18:29:16 1997
***************
*** 3,7 ****
   */
  #ifndef HARVEST_VERSION
  /* UPDATE VERSION HERE */
! #define HARVEST_VERSION	"1.5"
  #endif
--- 3,7 ----
   */
  #ifndef HARVEST_VERSION
  /* UPDATE VERSION HERE */
! #define HARVEST_VERSION	"1.5pl14"
  #endif
Index: harvest/src/gatherer/enumerate/HTMLurls.c
diff -c harvest/src/gatherer/enumerate/HTMLurls.c:2.2 harvest/src/gatherer/enumerate/HTMLurls.c:2.3
*** harvest/src/gatherer/enumerate/HTMLurls.c:2.2	Mon Mar 24 19:44:40 1997
--- harvest/src/gatherer/enumerate/HTMLurls.c	Mon Oct 20 12:43:46 1997
***************
*** 1,4 ****
! static char rcsid[] = "HTMLurls.c,v 2.2 1997/03/25 00:44:40 sxw Exp";
  /* 
   *  HTMLurls - Prints all of the URLs from an HTML file.
   *
--- 1,4 ----
! static char rcsid[] = "HTMLurls.c,v 2.3 1997/10/20 16:43:46 sxw Exp";
  /* 
   *  HTMLurls - Prints all of the URLs from an HTML file.
   *
***************
*** 234,239 ****
--- 234,307 ----
      printf("FOLLOW: %s\n",RobotsFollow?"Yes":"No");
      */
  }
+ 
+ /*
+  * process_metapull - extract the URL from the META tag for client pull
+  * <META HTTP-EQUIV="REFRESH" CONTENT="<secs>; URL=http://www.some.dom/">
+  * HS, 20-Oct-1997
+  */
+ void process_metapull(s)
+      char *s;
+ {
+     char *p, *q, *tmps;
+ 
+     /* Find the HTTP-EQUIV in the META */
+     if ((tmps = strstr_icase(s, "http-equiv")) == NULL)
+       return;
+ 
+     /* Skip over the HTTP-EQUIV from the HTTP-EQUIV = tag */
+     if ((p = strchr(tmps, '=')) == NULL)
+       return;
+ 
+     p++;                    /* skip '=' */
+     while (isspace(*p) || (*p == '\"'))
+       p++;                /* skip space '"'s */
+ 
+     q = xstrdup(p);          /* copy name */
+ 
+     if ((p = strchr(q, '\"')) != NULL)      /* terminate string */
+       *p = '\0';
+     if ((p = strchr(q, ' ')) != NULL)       /* terminate string */
+       *p = '\0';
+     /* printf("HTTP-EQUIV: %s\n",q); */
+     if (strcasecmp("REFRESH",q)!=0) {        /* check for 'REFRESH' */
+       xfree(q);
+       return;
+     }
+     xfree(q);                               /* finished with that bit */
+ 
+     if ((tmps = strstr_icase(s, "content")) == NULL) /* Find content bit */
+       return;
+     if ((p = strchr(tmps, '=')) == NULL)    /* Find equals */
+       return;
+ 
+     if ((tmps = strstr_icase(p, "url")) == NULL) /* Find 'URL' */
+       return;
+     if ((p = strchr(tmps, '=')) == NULL)    /* Find equals */
+       return;
+     p++;                                    /* skip '=' */
+     while (isspace(*p))
+       p++;                                  /* skip spaces */
+ 
+     q = xstrdup(p);                         /* copy name */
+     if ((p = strchr(q, '\"')) != NULL) {    /* terminate string on '"' */
+       *p = '\0';
+     } else {
+       if ((p = strchr(q, '>')) != NULL)     /* terminate string on '>' */
+       *p = '\0';
+     }
+ 
+     /* q should now contain the URL */
+ 
+     if (q != (char *) NULL) {             /* Just in case... */
+       add_buffer(urls, q, strlen(q));     /* Add URL to urls */
+       add_buffer(urls, "\n", 1);
+       xfree(q);
+     }
+     return;
+ }
+ 
+ 
  /*
   *  process_framesrc() - Extracts the URL from the frame src tag.
   *
***************
*** 389,397 ****
          process_anchor(mp->start);
      
      if ((mp->type == M_META) &&
! 	(mp->start != NULL) && (strlen(mp->start) > 5))
!         process_metarobots(mp->start);
! 
  }
  
  
--- 457,466 ----
          process_anchor(mp->start);
      
      if ((mp->type == M_META) &&
!         (mp->start != NULL) && (strlen(mp->start) > 5)) {
!             process_metarobots(mp->start);
!             process_metapull(mp->start);	/* HS */
!         }
  }
  
  
Index: harvest/src/gatherer/enumerate/filter.c
diff -c harvest/src/gatherer/enumerate/filter.c:2.1 harvest/src/gatherer/enumerate/filter.c:2.2
*** harvest/src/gatherer/enumerate/filter.c:2.1	Fri Mar 21 14:21:30 1997
--- harvest/src/gatherer/enumerate/filter.c	Mon Oct 27 17:56:28 1997
***************
*** 1,4 ****
! static char rcsid[] = "filter.c,v 2.1 1997/03/21 19:21:30 sxw Exp";
  /*
   *  filter.c - RootNode URL enumerator filter support
   *
--- 1,4 ----
! static char rcsid[] = "filter.c,v 2.2 1997/10/27 22:56:28 sxw Exp";
  /*
   *  filter.c - RootNode URL enumerator filter support
   *
***************
*** 146,153 ****
      Host *h = NULL;
  
      if (host_filter != NULL && nhost_filter > 0) {
! 	if ((h = get_host(up->host)))
! 	    host_dotaddr = xstrdup(h->dotaddr);
  	else
  	    host_dotaddr = (char *) 0;
  	if ((up->type == URL_HTTP) || (up->type == URL_FTP) ||
--- 146,156 ----
      Host *h = NULL;
  
      if (host_filter != NULL && nhost_filter > 0) {
!         if ((h = get_host(up->host))) {
! /*    waw be sure we get dot address AND port! */
!             host_dotaddr = xmalloc(strlen(h->dotaddr) + 10);
!             sprintf(host_dotaddr, "%s:%d", h->dotaddr, up->port);
!         }
  	else
  	    host_dotaddr = (char *) 0;
  	if ((up->type == URL_HTTP) || (up->type == URL_FTP) ||
