diff --git a/examples/add.pike b/examples/add.pike
--- a/examples/add.pike
+++ b/examples/add.pike
@@ -1,34 +1,36 @@
 import Public.Xapian;
 
 
 int main(int argc, array argv)
 {
   object database = WriteableDatabase(argv[1], DB_CREATE_OR_OPEN);
 
   string doc = Stdio.read_file(argv[2]);
 
   doc = map(doc, lambda(int i){ return (!(i > 'z' || i < '0'))?i:' '; });
   
   array terms = (doc / " ") - ({""});
 
   object s = Stem("english");
   object d = Document();
 
 
   d->add_value(0, argv[2]);
 
+  // adding terms to the database
+  // see http://xapian.org/docs/termgenerator.html
   foreach(terms; int i; string term)
   {
     term = lower_case(term);
     werror("term: " + term + " -> " + s(term) + "\n");
     d->add_posting(term, i, 1);
     if(!(term[0] >= '0' && term[0] <= '9'))
       d->add_term("Z" + s(term), 1);
   }
 
   d->set_data(Stdio.read_file(argv[2]));
   d->add_value(0, argv[2]);
   database->add_document(d);
   database = 0;
   return 0;
 }
diff --git a/xapian.ccmod b/xapian.ccmod
--- a/xapian.ccmod
+++ b/xapian.ccmod
@@ -1,5474 +1,5688 @@
 /*! @module Public
  */
 
 /*! @module Xapian
  *!  An interface to the Xapian full text engine.
  *! 
  *!  For details, please see http://www.xapian.org
  */
 
 #define _GNU_SOURCE
 
 extern "C" {
 #include "xapian_config.h"
 #include "util.h"
 
 }
 
 #include <xapian.h>
 
 #include <algorithm>
 #include <iostream>
 #include <string>
 #include <vector>
 
 using namespace Xapian;
 using namespace std;
 
 #include <ctype.h>
 
 #define OBJ2_MSET(o) ((struct MSet_struct *)get_storage(o, MSet_program))
 #define OBJ2_ESET(o) ((struct ESet_struct *)get_storage(o, ESet_program))
 #define OBJ2_STEM(o) ((struct Stem_struct *)get_storage(o, Stem_program))
 #define OBJ2_STOPPER(o) ((struct Stopper_struct *)get_storage(o, Stopper_program))
 #define OBJ2_MSETITERATOR(o) ((struct MSetIterator_struct *)get_storage(o, MSetIterator_program))
 #define OBJ2_ESETITERATOR(o) ((struct ESetIterator_struct *)get_storage(o, ESetIterator_program))
 #define OBJ2_VALUEITERATOR(o) ((struct ValueIterator_struct *)get_storage(o, ValueIterator_program))
 #define OBJ2_TERMITERATOR(o) ((struct TermIterator_struct *)get_storage(o, TermIterator_program))
 #define OBJ2_POSITIONITERATOR(o) ((struct PositionIterator_struct *)get_storage(o, PositionIterator_program))
 #define OBJ2_DOCUMENT(o) ((struct Document_struct *)get_storage(o, Document_program))
 #define OBJ2_DATABASE(o) ((struct Database_struct *)get_storage(o, Database_program))
 #define OBJ2_QUERY(o) ((struct Query_struct *)get_storage(o, Query_program))
+#define OBJ2_TERMGENERATOR(o) ((struct TermGenerator_struct *)get_storage(o, TermGenerator_program))
 #define OBJ2_VALUERANGEPROCESSOR(o) ((struct ValueRangeProcessor_struct *)get_storage(o, ValueRangeProcessor_program))
 
 
 extern "C" struct program * Document_program;
 extern "C" struct program * MSetIterator_program;
 extern "C" struct program * ValueIterator_program;
 extern "C" struct program * TermIterator_program;
 extern "C" struct program * PositionIterator_program;
 extern "C" struct program * MSet_program;
 extern "C" struct program * Stem_program;
+extern "C" struct program * TermGenerator_program;
 extern "C" struct program * ValueRangeProcessor_program;
 extern "C" typedef struct
 {
     Database *database;
 } XAPIAN_DATABASE_OBJECT_DATA;
 
 extern "C" typedef struct
 {
     Stem *stem;
 } XAPIAN_STEM_OBJECT_DATA;
 
 extern "C" typedef struct
 {
     Weight *weight;
 } XAPIAN_WEIGHT_OBJECT_DATA;
 
 extern "C" typedef struct
 {
+    TermGenerator *termgenerator;
+} XAPIAN_TERMGENERATOR_OBJECT_DATA;
+
+extern "C" typedef struct
+{
     QueryParser *parser;
 } XAPIAN_QUERYPARSER_OBJECT_DATA;
 
 extern "C" typedef struct
 {
     Stopper *stopper;
 } XAPIAN_STOPPER_OBJECT_DATA;
 
 extern "C" typedef struct
 {
     Enquire *enquire;
 } XAPIAN_ENQUIRE_OBJECT_DATA;
 
 extern "C" typedef struct
 {
     Query *query;
 } XAPIAN_QUERY_OBJECT_DATA;
 
 extern "C" typedef struct
 {
     MSet *mset;
 } XAPIAN_MSET_OBJECT_DATA;
 
 extern "C" typedef struct
 {
     RSet *rset;
 } XAPIAN_RSET_OBJECT_DATA;
 
 extern "C" typedef struct
 {
     MSetIterator *mseti;
 } XAPIAN_MSETITERATOR_OBJECT_DATA;
 
 extern "C" typedef struct
 {
     ValueIterator *valuei;
 } XAPIAN_VALUEITERATOR_OBJECT_DATA;
 
 extern "C" typedef struct
 {
     PositionIterator *positioni;
 } XAPIAN_POSITIONITERATOR_OBJECT_DATA;
 
 extern "C" typedef struct
 {
     ESet *eset;
 } XAPIAN_ESET_OBJECT_DATA;
 
 extern "C" typedef struct
 {
     ESetIterator *eseti;
 } XAPIAN_ESETITERATOR_OBJECT_DATA;
 
 extern "C" typedef struct
 {
     TermIterator *termi;
 } XAPIAN_TERMITERATOR_OBJECT_DATA;
 
 extern "C" typedef struct
 {
     Document *document;
 } XAPIAN_DOCUMENT_OBJECT_DATA;
 
 extern "C" typedef struct
 {
     ValueRangeProcessor *processor;
 } XAPIAN_VALUERANGEPROCESSOR_OBJECT_DATA;
 
 /*! @decl string sortable_serialise(float value)
  *! 
  *! Convert a floating point number to a string, preserving sort order.  
  */
 PIKEFUN string sortable_serialise(float value)
 {
   string str = sortable_serialise(value);
   pop_stack();
   push_text(str.c_str());  
 }
 
 /*! @decl float sortable_unserialise(string value)
  *!
  *! Convert a string encoded using sortable_serialise back to a floating 
  *! point number. 
  */
 PIKEFUN float sortable_unserialise(string value)
 {
    double f;
    string str((const char *)value->str, (size_t)value->len);
    f = sortable_unserialise(str);
    push_float(f);
 }
 
 /*! @decl int minor_version()
  */
 PIKEFUN int minor_version()
 {
   push_int(minor_version());
 }
 
 /*! @decl int major_version()
  */
 PIKEFUN int major_version()
 {
   push_int(major_version());
 }
 
 /*! @decl int revision()
  */
 PIKEFUN int revision()
 {
   push_int(revision());
 }
 
 
 /*! @decl string version_string()
  *! Report the version string of the library which the program is linked 
  *! with. 
  */
 PIKEFUN string version_string()
 {
    push_text(version_string());
 }
 
-
 /*! @class Weight
 */
 PIKECLASS Weight
 {
 CVAR XAPIAN_WEIGHT_OBJECT_DATA   *object_data;
 
 /*  Weight.int get_sumpart_needs_doclength() */
 /*! @decl int get_sumpart_needs_doclength()
  *!
  *! returns false if the weight object doesn't need doclength   
  *! @returns
  *!  
  *!
  */
 PIKEFUN int get_sumpart_needs_doclength()
 {
   Weight *weight;
   weight = THIS->object_data->weight;
 
   bool i = weight->get_sumpart_needs_doclength();
 
   push_int(i?1:0);
 }
 
 /*  Weight.float get_maxpart() */
 /*! @decl float get_maxpart()
  *!
  *!  Gets the maximum value that @[get_sumpart]() may return. 
  *!  
  *!  This is used in optimising searches, by having the postlist tree 
  *!  decay appropriately when parts of it can have limited, or no, further 
  *!  effect.
  *! @returns
  *!  
  *!
  */
 PIKEFUN float get_maxpart()
 {
   Weight *weight;
   weight = THIS->object_data->weight;
 
   Xapian::weight i = weight->get_maxpart();
 
   push_float((FLOAT_TYPE)i);
 }
 
 /*  Weight.float get_maxextra() */
 /*! @decl float get_maxextra()
  *!
  *!  Gets the maximum value that @[get_sumextra]() may return. 
  *!  
  *!  This is used in optimising searches.
  *! @returns
  *!  
  *!
  */
 PIKEFUN float get_maxextra()
 {
   Weight *weight;
   weight = THIS->object_data->weight;
 
   Xapian::weight i = weight->get_maxextra();
 
   push_float((FLOAT_TYPE)i);
 }
 
 /*  Weight.float get_sumextra(int len) */
 /*! @decl float get_sumextra(int len)
  *!
  *!  Get an extra weight for a document to add to the sum calculated over 
  *!  the query terms. 
  *! 
  *! This returns a weight for a given document, and is used by some 
  *! weighting schemes to account for influence such as document length.
  *! @param len
  *!  the (unnormalised) document length.
  *!
  *! @returns
  *!  
  *!
  */
 PIKEFUN float get_sumextra(int len)
 {
   Weight *weight;
   weight = THIS->object_data->weight;
 
   Xapian::weight i = weight->get_sumextra((doclength)len);
 
   push_float((FLOAT_TYPE)i);
 }
 
 /*  Weight.float get_sumpart(int wdf, int len) */
 /*! @decl float get_sumpart(int wdf, int len)
  *!Get a weight which is part of the sum over terms being performed.
  *! 
  *! This returns a weight for a given term and document. These weights are 
  *! summed to give a total weight for the document.
  *!  
  *! @param wdf
  *!  the within document frequency of the term.
 * !
  *! @param len
  *!  the (unnormalised) document length.
 * !
  *! @returns
  *!  
  *!
  */
 PIKEFUN float get_sumpart(int wdf, int len)
 {
   Weight *weight;
   weight = THIS->object_data->weight;
 
   Xapian::weight i = weight->get_sumpart((termcount)wdf, (doclength)len);
 
   push_float((FLOAT_TYPE)i);
 }
 
 
 /*  Weight.string serialise() */
 /*! @decl string serialise()
  *!
  *!  Serialise object parameters into a string.
  *! @returns
  *!  
  *!
  */
 PIKEFUN string serialise()
 {
   Weight *weight;
   weight = THIS->object_data->weight;
 
   string str = weight->serialise();
 
   push_text(str.c_str());
 }
 
 /*  Weight.string name() */
 /*! @decl string name()
  *!
  *!  Name of the weighting scheme.
  *! 
  *! If the subclass is called FooWeight, this should return "Foo".
  *! @returns
  *!  
  *!
  */
 PIKEFUN string name()
 {
   Weight *weight;
   weight = THIS->object_data->weight;
 
   string str = weight->name();
 
   push_text(str.c_str());
 }
 
 INIT
 {
     XAPIAN_WEIGHT_OBJECT_DATA * dta = 
 	(XAPIAN_WEIGHT_OBJECT_DATA*)malloc(sizeof(XAPIAN_WEIGHT_OBJECT_DATA));
     if (!dta)
         Pike_error("init_sample: Out of memory!\n");
 
     dta->weight = NULL;
     THIS->object_data = dta;
 }
 
 /*  Weight.void destroy() */
 /*! @decl void destroy()
  *!
  *!  
  *!
  */
 PIKEFUN void destroy()
 {
 
     Weight *weight;
     weight = THIS->object_data->weight;
 
     if(weight) 
     {
      delete weight;
     }
 
 }
 
 EXIT 
 {
   if(THIS->object_data)
   {
 
     Weight  *weight;
     weight = THIS->object_data->weight;
 //    printf("shutting down!\n");
     free(THIS->object_data);
   }
 }
 
 }
 
 /*!  @endclass
 */
 
 /*! @class BM25Weight
  *! @inherit Weight
  *! BM25 weighting scheme.
 */
 
 PIKECLASS BM25Weight
 {
   INHERIT Weight;
 
   PIKEFUN void create(float k1, float k2, float k3, float b, float min_normlen)
   {
     BM25Weight * weight;
     
     weight = new BM25Weight((double)k1, (double)k2, (double)k3, (double)b, (double)min_normlen);
 
     THIS->object_data->weight = weight;
   }
 
   PIKEFUN object clone()
   {
     BM25Weight * weight;
     BM25Weight * weight2;
     struct object * obj;
 
     weight = (BM25Weight *)THIS->object_data->weight;
     weight2 = weight->clone();
 
     obj = fast_clone_object(BM25Weight_program);
     OBJ2_WEIGHT(obj)->object_data->weight = (Weight *)weight2;
 
     push_object(obj);    
   }
 }
 
 /*!  @endclass
 */
 
 /*! @class BoolWeight
  *! @inherit Weight
  *! Boolean weighting scheme (everything gets 0).
 */
 
 PIKECLASS BoolWeight
 {
   INHERIT Weight;
 
   PIKEFUN void create()
   {
     BoolWeight * weight;
     
     weight = new BoolWeight();
 
     THIS->object_data->weight = weight;
   }
 }
 
 /*!  @endclass
 */
 
 /*! @class TradWeight
  *! @inherit Weight
  *! Traditional probabilistic weighting scheme.
  *! 
  *! This class implements the Traditional Probabilistic Weighting scheme, 
  *! as described by the early papers on Probabilistic Retrieval. @[BM25Weight]
  *! generally gives better results. 
 */
 
 PIKECLASS TradWeight
 {
   INHERIT Weight;
 
   PIKEFUN void create(float k)
   {
     TradWeight * weight;
     
     weight = new TradWeight((double)k);
 
     THIS->object_data->weight = weight;
   }
 }
 
 /*!  @endclass
 */
 
 /*! @class ValueRangeProcessor
  *! Base class for value range processors. 
 */
 
 PIKECLASS ValueRangeProcessor
 {
 CVAR XAPIAN_VALUERANGEPROCESSOR_OBJECT_DATA   *object_data;
 
 /*! @decl int `()(string begin, string end)
  *!
  *!  	Is term a stop-word?   
  *! @returns
  *!  1 if true, 0 otherwise.
  *!
  */
 PIKEFUN int `()(string begin, string end)
 {
   ValueRangeProcessor * vrp;
   bool i;
   vrp = THIS->object_data->processor;
   string str1((const char *)begin->str, (size_t)begin->len);
   string str2((const char *)end->str, (size_t)end->len);
 
   i = (*vrp)(str1, str2);  
 
   push_int(i?1:0);
 }
 
 INIT
 {
     XAPIAN_VALUERANGEPROCESSOR_OBJECT_DATA * dta = 
 	(XAPIAN_VALUERANGEPROCESSOR_OBJECT_DATA*)malloc(sizeof(XAPIAN_VALUERANGEPROCESSOR_OBJECT_DATA));
     if (!dta)
         Pike_error("init_sample: Out of memory!\n");
 
     dta->processor = NULL;
     THIS->object_data = dta;
 }
 
 /*! @decl void destroy()
  *!
  *!  
  *!
  */
 PIKEFUN void destroy()
 {
     ValueRangeProcessor  *vrp;
     vrp = THIS->object_data->processor;
 
     if(vrp) 
     {
      delete vrp;
     }
 }
 
 EXIT 
 {
   if(THIS->object_data)
   {
 
     ValueRangeProcessor  *vrp;
     vrp = THIS->object_data->processor;
  //   printf("shutting down!\n");
     free(THIS->object_data);
   }
 }
 
 }
 /*!  @endclass
 */
 
 
 /*! @class StringValueRangeProcessor
  *! @inherit ValueRangeProcessor
  *!
  *! Handle a string range.
  *!
  *! The end points can be any strings. 
  */
 
 PIKECLASS StringValueRangeProcessor
 {
   INHERIT ValueRangeProcessor;
 
   PIKEFUN void create(int valueno)
   {
     StringValueRangeProcessor * vrp = new StringValueRangeProcessor(valueno);
 
     THIS_VALUERANGEPROCESSOR->object_data->processor = (ValueRangeProcessor*) vrp ;
     pop_n_elems(args);
   }
 
 }
 /*!  @endclass
 */
 
 
 /*! @class NumberValueRangeProcessor
  *! @inherit ValueRangeProcessor
  *!
  *! Handle a number range.
  *!
  *! This class must be used on values which have been encoded using 
  *! @[Public.Xapian.sortable_serialise]() which turns numbers into strings 
  *! which will sort in the same order as the numbers (the same values can 
  *! be used to implement a numeric sort).
  *!
  */
 
 PIKECLASS NumberValueRangeProcessor
 {
   INHERIT ValueRangeProcessor;
 
   PIKEFUN void create(int valueno)
   {
     NumberValueRangeProcessor * vrp = new NumberValueRangeProcessor(valueno);
 
     THIS_VALUERANGEPROCESSOR->object_data->processor = (ValueRangeProcessor*) vrp ;
     pop_n_elems(args);
   }
 
 /*! @decl void create(int valueno, string _str, int[0..1] is_prefix)
  *! The string supplied in str_ is used by operator() to decide whether 
  *! the pair of strings supplied to it constitute a valid range. If 
  *! prefix_ is true, the first value in a range must begin with str_ (and 
  *! the second value may optionally begin with str_); if prefix_ is 
  *! false, the second value in a range must end with str_ (and the first 
  *! value may optionally end with str_).
  *! 
  *! If str_ is empty, the setting of prefix_ is irrelevant, and no special 
  *! strings are required at the start or end of the strings defining the 
  *! range.
  *! 
  *! The remainder of both strings defining the endpoints must be valid 
  *! floating point numbers. (FIXME: define format recognised).
  *! 
  *! For example, if str_ is "$" and prefix_ is true, and the range 
  *! processor has been added to the queryparser, the queryparser will 
  *! accept "$10..50" or "$10..50", but not "10..50" or "10..$50" as valid 
  *! ranges. If str_ is 
  *! "kg" and prefix_ is false, the queryparser will accept "10..50kg" or 
  *! "10kg..50kg", but not "10..50" or "10kg..50" as valid ranges. 
  */
   PIKEFUN void create(int valueno, string _str, int is_prefix)
   {
     NumberValueRangeProcessor * vrp;
     string str((const char *)_str->str, (size_t)_str->len);
 
     vrp = new NumberValueRangeProcessor(valueno, str, is_prefix);
 
     THIS_VALUERANGEPROCESSOR->object_data->processor = (ValueRangeProcessor*) vrp ;
     pop_n_elems(args);
   }
 
 }
 /*!  @endclass
 */
 
 /*! @class NumberValueRangeProcessor
  *! @inherit ValueRangeProcessor
  *!
  *! Handle a number range.
  *!
  *! This class must be used on values which have been encoded using 
  *! @[Public.Xapian.sortable_serialise]() which turns numbers into strings 
  *! which will sort in the same order as the numbers (the same values can 
  *! be used to implement a numeric sort).
  *!
  */
 
 PIKECLASS DateValueRangeProcessor
 {
   INHERIT ValueRangeProcessor;
 
 /*! @decl void create(int valueno, int[0..1] prefer_mdy, int epoch_year)
  *! @param valueno
  *!    The value number to return from `()().
  *! @param prefer_mdy
  *!    Should ambiguous dates be interpreted as month/day/year rather than 
  *!    day/month/year?
  *! @param epoch_year
  *!    Year to use as the epoch for dates with 2 digit years (default: 
  *!    1970, so 1/1/69 is 2069 while 1/1/70 is 1970).
  */
   PIKEFUN void create(int valueno, int prefer_mdy, int epoch_year)
   {
     DateValueRangeProcessor * vrp = new DateValueRangeProcessor(valueno, prefer_mdy, epoch_year);
 
     THIS_VALUERANGEPROCESSOR->object_data->processor = (ValueRangeProcessor*) vrp ;
     pop_n_elems(args);
   }
 
 }
 /*!  @endclass
 */
 
 /*! @class Stopper
  *! Base class for stop-word decision functor. 
 */
 
 PIKECLASS Stopper
 {
 CVAR XAPIAN_STOPPER_OBJECT_DATA   *object_data;
 
 /*! @decl int `()(string word)
  *!
  *!  	Is term a stop-word?   
  *! @returns
  *!  1 if true, 0 otherwise.
  *!
  */
 PIKEFUN int `()(string word)
 {
   Stopper  *stopper;
   bool i;
   stopper = THIS->object_data->stopper;
   string str((const char *)word->str, (size_t)word->len);
 
   i = (*stopper)(str);  
 
   push_int(i?1:0);
 }
 
 /*  Stopper.string get_description() */
 /*! @decl string get_description()
  *!
  *!  
  *! @returns
  *!  
  *!
  */
 PIKEFUN string get_description()
 {
   Stopper  *stopper;
   stopper = THIS->object_data->stopper;
 
   string str = stopper->get_description();
 
   push_text(str.c_str());
 }
 
 PIKEFUN string _sprintf(int conversion_type, mapping params)
 {
   Stopper  *stopper;
   if(THIS && THIS->object_data && conversion_type == 'O')
   {
     stopper = THIS->object_data->stopper;
 
     string str = stopper->get_description();
     pop_n_elems(args);
     push_text(str.c_str());
   }
   else
   {
     pop_n_elems(args);
     push_int(0);
   }
 }
 
 
 INIT
 {
     XAPIAN_STOPPER_OBJECT_DATA * dta = 
 	(XAPIAN_STOPPER_OBJECT_DATA*)malloc(sizeof(XAPIAN_STOPPER_OBJECT_DATA));
     if (!dta)
         Pike_error("init_sample: Out of memory!\n");
 
     dta->stopper = NULL;
     THIS->object_data = dta;
 }
 
 /*  Stopper.void destroy() */
 /*! @decl void destroy()
  *!
  *!  
  *!
  */
 PIKEFUN void destroy()
 {
 
     Stopper  *stopper;
     stopper = THIS->object_data->stopper;
 
     if(stopper) 
     {
      delete stopper;
     }
 
 }
 
 EXIT 
 {
   if(THIS->object_data)
   {
 
     Stopper  *stopper;
     stopper = THIS->object_data->stopper;
  //   printf("shutting down!\n");
     free(THIS->object_data);
   }
 }
 
 }
 
 /*!  @endclass
 */
 
 /*! @class SimpleStopper
  *! @inherit Stopper
  *! Simple implementation of Stopper class - this will suit most users.
  */
 
 PIKECLASS SimpleStopper
 {
   INHERIT Stopper;
 
   PIKEFUN void create()
   {
     SimpleStopper * stopper = new SimpleStopper();
 
     THIS->object_data->stopper = (Stopper*) stopper;
     pop_n_elems(args);
   }
 
   PIKEFUN void create(array words)
   {
     int i;
     vector<string> v;
 
     for(i = 0; i < words->size; i++)
     {  
        string str((const char *)(ITEM(words)[i].u.string->str), 
                   (size_t)(ITEM(words)[i].u.string->len));
        v.push_back(str);
     }
     
     SimpleStopper * stopper = new SimpleStopper(v.begin(), v.end());
 
     THIS_STOPPER->object_data->stopper = (Stopper*) stopper;
     pop_n_elems(args);
   }
 
 /*! @decl void add(string word)
  *! Add a single stop word.
  */
   PIKEFUN void add(string word)
   {
     SimpleStopper * stopper;
     string str((const char*)word->str, (size_t)word->len);
     stopper = (SimpleStopper *)THIS_STOPPER->object_data->stopper;
     stopper->add(str);
     pop_stack();
     
   }
 
   
 }
 
 /*!  @endclass
 */
 
 /*! @class Stem
  *! Class representing a stemming algorithm.
 */
 
 PIKECLASS Stem
 {
 CVAR XAPIAN_STEM_OBJECT_DATA   *object_data;
 
 
 /*  Stem.void create(string language) */
 /*! @decl void create(string language)
  *!
  *!  Construct a @[Stem] object for a particular language.
  *! @param language
  *!      	Either the English name for the language or the two letter ISO639 code.
 *!
 *! The following language names are understood (aliases follow the name):
 *!
 *!    * none - don't stem terms
 *!    * danish (da)
 *!    * dutch (nl)
 *!    * english (en) - Martin Porter's 2002 revision of his stemmer
 *!    * english_lovins (lovins) - Lovin's stemmer
 *!    * english_porter (porter) - Porter's stemmer as described in his 1980 paper
 *!    * finnish (fi)
 *!    * french (fr)
 *!    * german (de)
 *!    * italian (it)
 *!    * norwegian (no)
 *!    * portuguese (pt)
 *!    * russian (ru)
 *!    * spanish (es)
 *!    * swedish (sv)
 *!
 * ! @note
  *!  an error will be thrown if the specified language is unknown.
  */
 PIKEFUN void create(string language)
 {
   Stem* stem;
   const string str((const char *)language->str, (size_t)language->len);
 
   try
   {
     stem = new Stem(str);
   }
 
   catch(InvalidArgumentError &e)
   {
     pop_n_elems(args);
     Pike_error("InvalidArgumentError\n");
   }
 
   pop_n_elems(args);
 
   THIS->object_data->stem = stem;
 }
 
 /*  Stem.void create() */
 /*! @decl void create()
  *!
  *!  
  *!
  */
 PIKEFUN void create()
 {
     Stem* stem = new Stem();
 
     pop_n_elems(args);
 
     THIS->object_data->stem = stem;
 }
 
 /*  Stem.string stem_word(string word) */
 /*! @decl string `()(string word)
  *!   stem a word
  *!  
  *! @param word
  *!   word to be stemmed
 * !
  *! @returns
  *!   the word stem  
  *!
  */
 PIKEFUN string `()(string word)
 {
   Stem  *stem;
   string foo;
   const string str((const char *)word->str, (size_t)word->len);
   stem = THIS->object_data->stem;
 
   foo = (*stem)(str);
   pop_n_elems(args);
   push_text(foo.c_str());
 }
 
 /*  Stem.string get_description() */
 /*! @decl string get_description()
  *!
  *!  
  *! @returns
  *!  
  *!
  */
 PIKEFUN string get_description()
 {
   Stem  *stem;
   stem = THIS->object_data->stem;
 
   string str = stem->get_description();
 
   push_text(str.c_str());
 }
 
 PIKEFUN string _sprintf(int conversion_type, mapping params)
 {
   Stem  *stem;
   if(THIS && THIS->object_data && conversion_type == 'O')
   {
     stem = THIS->object_data->stem;
 
     string str = stem->get_description();
     pop_n_elems(args);
     push_text(str.c_str());
   }
   else
   {
     pop_n_elems(args);
     push_int(0);
   }
 }
 
 
 INIT
 {
     XAPIAN_STEM_OBJECT_DATA * dta = 
 	(XAPIAN_STEM_OBJECT_DATA*)malloc(sizeof(XAPIAN_STEM_OBJECT_DATA));
     if (!dta)
         Pike_error("init_sample: Out of memory!\n");
 
     dta->stem = NULL;
     THIS->object_data = dta;
 }
 
 /*  Stem.void destroy() */
 /*! @decl void destroy()
  *!
  *!  
  *!
  */
 PIKEFUN void destroy()
 {
 
     Stem  *stem;
     stem = THIS->object_data->stem;
 
     if(stem) 
     {
      delete stem;
     }
 
 }
 
 EXIT 
 {
   if(THIS->object_data)
   {
 
     Stem  *stem;
     stem = THIS->object_data->stem;
  //   printf("shutting down!\n");
     free(THIS->object_data);
   }
 }
 
 }
 
 /*!  @endclass
 */
 
 /*! @class Query
 *! Class representing a query.
 *!
 *! Queries are represented as a tree of objects. 
 */
 
 PIKECLASS Query
 {
 
 CVAR XAPIAN_QUERY_OBJECT_DATA   *object_data;
 
 
 /*  Query.void create() */
 /*! @decl void create()
  *!
  *! Default constructor: makes an empty query which matches no documents.
  *! 
  *! Also useful for defining a Query object to be assigned to later.
  *!
  *! @note
  *! An exception will be thrown if an attempt is made to use an undefined 
  *! query when building up a composite query.
  *!
  */
 PIKEFUN void create()
 {
   try
   {
     Query* query = new Query();
 
     pop_n_elems(args);
 
     THIS->object_data->query = query;
   }
 
   catch(...) 
   {
     Pike_error("an error occurred!\n");
   }
 }
 
 /*  Query.void create(string term, int wqf, int pos) */
 /*! @decl void create(string term, int wqf, int pos)
  *!
  *!    A query consisting of a single term.
  *! @param term
  *!  
 * !
  *! @param wqf
  *!  
 * !
  *! @param pos
  *!  
 * !
  *!
  */
 PIKEFUN void create(string term, int wqf, int pos)
 {
   try
   {
 	string str((const char *)term->str, (size_t)term->len);
     Query* query = new Query(str, (termcount)wqf, (termpos)pos);
 
     pop_n_elems(args);
 
     THIS->object_data->query = query;
   }
 
   catch(...) 
   {
     Pike_error("an error occurred!\n");
   }
 }
 
 /*  Query.void create(int op, string left, string right) */
 /*! @decl void create(int op, string left, string right)
  *!
  *!  A query consisting of two terms, opp-ed together.
  *! @param op
  *!  
 * !
  *! @param left
  *!  
 * !
  *! @param right
  *!  
 * !
  *!
  */
 PIKEFUN void create(int op, string left, string right)
 {
   try
   {
 	string lstr((const char *)left->str, (size_t)left->len);
 	string rstr((const char *)right->str, (size_t)right->len);
     Query* query = new Query((Xapian::Query::op)op, lstr, rstr);
 
     pop_n_elems(args);
 
     THIS->object_data->query = query;
   }
 
   catch(...) 
   {
     Pike_error("an error occurred!\n");
   }
 }
 
 
 /*  Query.void create(int op, object left, object right) */
 /*! @decl void create(int op, object left, object right)
  *!
  *!  A query consisting of two subqueries, opp-ed together.
  *! @param op
  *!  
 * !
  *! @param left
  *!  
 * !
  *! @param right
  *!  
 * !
  *!
  */
 PIKEFUN void create(int op, object left, object right)
 {
   Query * l;
   Query * r;
 
   l = OBJ2_QUERY(left)->object_data->query;
   r = OBJ2_QUERY(right)->object_data->query;
 
   try
   {
     Query* query = new Query((Xapian::Query::op)op, l, r);
 
     pop_n_elems(args);
 
     THIS->object_data->query = query;
   }
 
   catch(...) 
   {
     Pike_error("an error occurred!\n");
   }
 }
 
 /*  Query.void create(int op, Query query) */
 /*! @decl void create(int op, Query query)
  *! Apply the specified operator to a single @[Query] object, with a 
  *! double parameter.
  *!  
  *! @param op
  *!  
 * !
  *! @param query
  *!  
 * !
  *!
  */
 PIKEFUN void create(int op, object query, float param)
 {
   Query * q;
 
   q = OBJ2_QUERY(query)->object_data->query;
 
   try
   {
     Query* qe = new Query((Xapian::Query::op)op, *q);
 
     pop_n_elems(args);
 
     THIS->object_data->query = qe;
   }
 
   catch(...) 
   {
     Pike_error("an error occurred!\n");
   }
 }
 
 /*  Query.int get_length() */
 /*! @decl int get_length()
  *!
  *!  Get the length of the query, used by some ranking formulae.
  *!
  *! This value is calculated automatically - if you want to override it 
  *! you can pass a different value to @[Enquire.set_query]().
  *! @returns
  *!  
  *!
  */
 PIKEFUN int get_length()
 {
   Query  *query;
   query = THIS->object_data->query;
   termcount i = query->get_length();
 
   push_int(i);
 }
 
 /*  Query.int empty() */
 /*! @decl int empty()
  *!  Test if the query is empty (i.e. was constructed using the default 
  *! constructor).
  *!  
  *! @returns
  *!  
  *!
  */
 PIKEFUN int empty()
 {
   Query  *query;
   query = THIS->object_data->query;
   bool i = query->empty();
 
   push_int(i?1:0);
 }
 
 
 /*  Query.string get_description() */
 /*! @decl string get_description()
  *!
  *!  
  *! @returns
  *!  
  *!
  */
 PIKEFUN string get_description()
 {
   Query  *query;
   query = THIS->object_data->query;
 
   string str = query->get_description();
 
   push_text(str.c_str());
 }
 
 PIKEFUN string _sprintf(int conversion_type, mapping params)
 {
   Query  *query;
   if(THIS && THIS->object_data && conversion_type == 'O')
   {
     query = THIS->object_data->query;
 
     string str = query->get_description();
     pop_n_elems(args);
     push_text(str.c_str());
   }
   else
   {
     pop_n_elems(args);
     push_int(0);
   }
 }
 
 INIT
 {
     XAPIAN_QUERY_OBJECT_DATA * dta = 
 	(XAPIAN_QUERY_OBJECT_DATA*)malloc(sizeof(XAPIAN_QUERY_OBJECT_DATA));
     if (!dta)
         Pike_error("init_sample: Out of memory!\n");
 
     dta->query = NULL;
     THIS->object_data = dta;
 }
 
 EXIT 
 {
   if(THIS->object_data)
   {
     Query  *query;
     query = THIS->object_data->query;
      if(query) delete query;
     free(THIS->object_data);
   }
 }
 
 EXTRA
 {
 /*! @decl constant OP_AND
  *! Return iff both subqueries are satisfied.
  */
 add_integer_constant("OP_AND", Query::OP_AND, 0);
 /*! @decl constant OP_OR
  *! Return if either subquery is satisfied. 
  */
 add_integer_constant("OP_OR", Query::OP_OR, 0);
 /*! @decl constant OP_AND_NOT
  *! Return if left but not right satisfied.
  */
 add_integer_constant("OP_AND_NOT", Query::OP_AND_NOT, 0);
 /*! @decl constant OP_XOR
  *! Return if one query satisfied, but not both.
  */
 add_integer_constant("OP_XOR", Query::OP_XOR, 0);
 /*! @decl constant OP_AND_MAYBE
  *! Return iff left satisfied, but use weights from both.
  */
 add_integer_constant("OP_AND_MAYBE", Query::OP_AND_MAYBE, 0);
 /*! @decl constant OP_FILTER
  *! As AND, but use only weights from left subquery.
  */
 add_integer_constant("OP_FILTER", Query::OP_FILTER, 0);
 /*! @decl constant OP_NEAR
  *! Find occurrences of a list of terms with all the terms occurring 
  *! within a specified window of positions.
  *! 
  *! Each occurrence of a term must be at a different position, but the 
  *! order they appear in is irrelevant.
  *! 
  *! The window parameter should be specified for this operation, but will 
  *! default to the number of terms in the list. 
  */
 add_integer_constant("OP_NEAR", Query::OP_NEAR, 0);
 /*! @decl constant OP_PHRASE
  *!  Find occurrences of a list of terms with all the terms occurring 
  *! within a specified window of positions, and all the terms appearing 
  *! in the order specified.
  *! 
  *! Each occurrence of a term must be at a different position.
  *! 
  *! The window parameter should be specified for this operation, but will 
  *! default to the number of terms in the list. 
  */
 add_integer_constant("OP_PHRASE", Query::OP_PHRASE, 0);
 /*! @decl constant OP_ELITE_SET
  *! Select an elite set from the subqueries, and perform a query with 
  *! these combined as an OR query. 
  */
 add_integer_constant("OP_ELITE_SET", Query::OP_ELITE_SET, 0);
 /*! @decl constant OP_VALUE_RANGE
  *! Filter by a range test on a document value.
  */
 add_integer_constant("OP_VALUE_RANGE", Query::OP_VALUE_RANGE, 0);
 /*! @decl constant OP_SCALE_WEIGHT
  *! Scale the weight of a subquery by the specified factor.
  *! 
  *! A factor of 0 means this subquery will contribute no weight to the 
  *! query - it will act as a purely boolean subquery.
  *! 
  *! If the factor is negative, an error will be 
  *! thrown. 
  */
 add_integer_constant("OP_SCALE_WEIGHT", Query::OP_SCALE_WEIGHT, 0);
 }
 
 }
 
 /*!  @endclass
 */
 
 /*! @class PositionIterator
 */
 
 PIKECLASS PositionIterator
 {
   CVAR PositionIterator * pie;
   CVAR int current_index;
   CVAR XAPIAN_POSITIONITERATOR_OBJECT_DATA   *object_data;
 
   PIKEFUN object next()
   {
     PositionIterator  *pi;
     pi = THIS->object_data->positioni;
 
     struct object * o;
 (*pi)++;
 
    THIS->current_index++;
     if(*pi == *(THIS->pie)) {push_int(0); return;}
     push_int(1);    
   }
 
   PIKEFUN mixed index()
   {
     push_int(THIS->current_index);
   }
 
   PIKEFUN object value()
   {
     push_object(this_object());
   }
 
   PIKEFUN int `==(mixed arg)
   {
     struct object * o;
     PositionIterator  *posi;
     PositionIterator  *posb;
     struct PositionIterator_struct * pis;    
 
     if(arg->type!= T_OBJECT) RETURN(0);
     o = arg->u.object;
     posi = (PositionIterator*)THIS->object_data->positioni;
     pis = OBJ2_POSITIONITERATOR(o);
     if(!pis) RETURN(0);
 
     posb = pis->object_data->positioni;
     if(*posi == *posb) RETURN(1);
     else RETURN(0);
   }
 
 /*! @decl void skip_to(int pos)
  *!
  *!  
  *! @returns
  *!  
  *!
  */
   PIKEFUN void skip_to(int pos)
   {
     
     PositionIterator  *posi;
     try 
     {
       posi = (PositionIterator*)THIS->object_data->positioni;
       posi->skip_to(pos);
       pop_stack();
       push_int(0);
     }
     catch(RangeError &e)
     {
       pop_n_elems(args);
       Pike_error("RangeError\n");
     }
 
 
   }
 
 /*! @decl int get_position()
  *!
  *!  
  *! @returns
  *!  
  *!
  */
   PIKEFUN int get_position()
   {
     PositionIterator  *posi;
     int i;
     try
     {
       posi = (PositionIterator*)THIS->object_data->positioni;
       i = (*(*posi));
       push_int(i);
     }
     catch(RangeError &e)
     {
       pop_n_elems(args);
       Pike_error("RangeError\n");
     }
   }
 
   PIKEFUN mixed `+=(int i)
   {
     PositionIterator  *pi;
     pi = THIS->object_data->positioni;
     
     for(int x = 0; x < i; x++)
     {
       (*pi)++;
       if(*pi == *(THIS->pie)) {
         pop_stack(); push_int(0); return;}
     }
     THIS->current_index++;
     pop_stack();
     push_object(this_object());
   }
  
   PIKEFUN int `!()
   {
     PositionIterator  *pi;
     pi = THIS->object_data->positioni;
     if(*pi == *(THIS->pie)) { push_int(1); }
     else
       push_int(0);
   }
 
 /*! @decl string get_description()
  *!
  *!  
  *! @returns
  *!  
  *!
  */
 PIKEFUN string get_description()
 {
   PositionIterator  *pi;
   pi = THIS->object_data->positioni;
 
   string str = pi->get_description();
 
   push_text(str.c_str());
 }
 
 PIKEFUN string _sprintf(int conversion_type, mapping params)
 {
   PositionIterator  *it;
   if(THIS && THIS->object_data && conversion_type == 'O')
   {
     it = THIS->object_data->positioni;
 
     string str = it->get_description();
     pop_n_elems(args);
     push_text(str.c_str());
   }
   else
   {
     pop_n_elems(args);
     push_int(0);
   }
 }
 
 
 INIT
 {
     XAPIAN_POSITIONITERATOR_OBJECT_DATA * dta = 
 	(XAPIAN_POSITIONITERATOR_OBJECT_DATA*)malloc(sizeof(XAPIAN_POSITIONITERATOR_OBJECT_DATA));
     if (!dta)
         Pike_error("init_sample: Out of memory!\n");
 
     dta->positioni = NULL;
     THIS->object_data = dta;
 }
 
 EXIT 
 {
   if(THIS->object_data)
   {
     PositionIterator  *positioni;
     positioni = THIS->object_data->positioni;
     if(positioni) delete positioni;
     free(THIS->object_data);
   }
 }
 
 }
 
 /*!  @endclass
 */
 
 /*! @class ValueIterator
 */
 
 PIKECLASS ValueIterator
 {
   CVAR ValueIterator * vie;
   CVAR int current_index;
   CVAR XAPIAN_VALUEITERATOR_OBJECT_DATA   *object_data;
 
   PIKEFUN object next()
   {
     ValueIterator  *valuei;
     valuei = THIS->object_data->valuei;
     ValueIterator *valuei2;
 
     struct object * o;
 
     valuei2 = new ValueIterator((*valuei)++);
 
     o = fast_clone_object(ValueIterator_program);
 
     OBJ2_VALUEITERATOR(o)->object_data->valuei = valuei;
 
     push_object(o);    
   }
 
   PIKEFUN mixed index()
   {
     push_int(THIS->current_index);
   }
 
   PIKEFUN object value()
   {
     push_object(this_object());
   }
 
   PIKEFUN int `==(mixed arg)
   {
     struct object * o;
     ValueIterator  *valuei;
     ValueIterator  *valueb;
     struct ValueIterator_struct * vis;    
 
     if(arg->type!= T_OBJECT) RETURN(0);
     o = arg->u.object;
     valuei = (ValueIterator*)THIS->object_data->valuei;
     vis = OBJ2_VALUEITERATOR(o);
     if(!vis) RETURN(0);
 
     valueb = vis->object_data->valuei;
     if(*valuei == *valueb) RETURN(1);
     else RETURN(0);
   }
 
 /*! @decl int get_valueno()
  *!
  *!  
  *! @returns
  *!  
  *!
  */
   PIKEFUN int get_valueno()
   {
     
     ValueIterator  *valuei;
     valueno i;
     try 
     {
       valuei = (ValueIterator*)THIS->object_data->valuei;
       i = valuei->get_valueno();
       push_int((INT_TYPE)i);
     }
     catch(RangeError &e)
     {
       pop_n_elems(args);
       Pike_error("RangeError\n");
     }
 
 
   }
 
 /*! @decl int get_value()
  *!
  *!  
  *! @returns
  *!  
  *!
  */
   PIKEFUN string get_value()
   {
     ValueIterator  *valuei;
     string i;
 
     try
     {
       valuei = (ValueIterator*)THIS->object_data->valuei;
       i = (*(*valuei));
       push_text(i.c_str());
     }
     catch(RangeError &e)
     {
       pop_n_elems(args);
       Pike_error("RangeError\n");
     }
   }
 
   PIKEFUN mixed `+=(int i)
   {
     ValueIterator  *vi;
     vi = THIS->object_data->valuei;
     
     for(int x = 0; x < i; x++)
     {
       (*vi)++;
       if(*vi == *(THIS->vie)) {
         pop_stack(); push_int(0); return;}
     }
     THIS->current_index++;
     pop_stack();
     push_object(this_object());
   }
  
   PIKEFUN int `!()
   {
     ValueIterator  *vi;
     vi = THIS->object_data->valuei;
     if(*vi == *(THIS->vie)) { push_int(1); }
     else
       push_int(0);
   }
 
 /*  ValueIterator.string get_description() */
 /*! @decl string get_description()
  *!
  *!  
  *! @returns
  *!  
  *!
  */
 PIKEFUN string get_description()
 {
   ValueIterator  *valuei;
   valuei = THIS->object_data->valuei;
 
   string str = valuei->get_description();
 
   push_text(str.c_str());
 }
 
 PIKEFUN string _sprintf(int conversion_type, mapping params)
 {
   ValueIterator  *it;
   if(THIS && THIS->object_data && conversion_type == 'O')
   {
     it = THIS->object_data->valuei;
 
     string str = it->get_description();
     pop_n_elems(args);
     push_text(str.c_str());
   }
   else
   {
     pop_n_elems(args);
     push_int(0);
   }
 }
 
 
 INIT
 {
     XAPIAN_VALUEITERATOR_OBJECT_DATA * dta = 
 	(XAPIAN_VALUEITERATOR_OBJECT_DATA*)malloc(sizeof(XAPIAN_VALUEITERATOR_OBJECT_DATA));
     if (!dta)
         Pike_error("init_sample: Out of memory!\n");
 
     dta->valuei = NULL;
     THIS->object_data = dta;
 }
 
 EXIT 
 {
   if(THIS->object_data)
   {
     ValueIterator  *valuei;
     valuei = THIS->object_data->valuei;
     if(valuei) delete valuei;
     free(THIS->object_data);
   }
 }
 
 }
 
 /*!  @endclass
 */
 
 /*! @class TermIterator
 */
 
 PIKECLASS TermIterator
 {
   CVAR TermIterator * tie;
   CVAR int current_index;
   CVAR XAPIAN_TERMITERATOR_OBJECT_DATA   *object_data;
 
   PIKEFUN object next()
   {
     TermIterator  * termi;
     termi = THIS->object_data->termi;
     TermIterator *termi2;
 
     struct object * o;
 
     termi2 = new TermIterator(++(*termi));
 
     o = fast_clone_object(TermIterator_program);
 
     OBJ2_TERMITERATOR(o)->object_data->termi = termi;
 
     push_object(o);    
   }
 
   PIKEFUN mixed index()
   {
     push_int(THIS->current_index);
   }
 
   PIKEFUN object value()
   {
     push_object(this_object());
   }
 
   PIKEFUN int `==(mixed arg)
   {
     struct object * o;
     TermIterator  *termi;
     TermIterator  *termb;
     struct TermIterator_struct * tis;    
 
     if(arg->type!= T_OBJECT) RETURN(0);
     o = arg->u.object;
     termi = (TermIterator*)THIS->object_data->termi;
     tis = OBJ2_TERMITERATOR(o);
     if(!tis) RETURN(0);
 
     termb = tis->object_data->termi;
     if(*termi == *termb) RETURN(1);
     else RETURN(0);
   }
 
 /*! @decl object position_iterator()
  *!
  *!  @returns
  *!    an object which can be passed to @[foreach]()
  *!  
  *!
  */
   PIKEFUN object position_iterator()
   {
     TermIterator  *ti;
     ti = THIS->object_data->termi;
 
     PositionIterator pi;
     PositionIterator * pi2;
     struct object * o;
 
     pi = ti->positionlist_begin();
     pi2 = new PositionIterator(pi);
 
     o = fast_clone_object(PositionIterator_program);
 
     OBJ2_POSITIONITERATOR(o)->object_data->positioni = pi2;
     OBJ2_POSITIONITERATOR(o)->pie = new PositionIterator(ti->positionlist_end());
 
     push_object(o);    
   }
 
 /*! @decl int get_wdf()
  *!
  *!  
  *! @returns
  *!  
  *!
  */
   PIKEFUN int get_wdf()
   {
     TermIterator  *termi;
     termcount i;
     termi = (TermIterator*)THIS->object_data->termi;
     i = termi->get_wdf();
     push_int((INT_TYPE)i);
   }
 
 /*! @decl int get_termfreq()
  *!
  *!  
  *! @returns
  *!  
  *!
  */
   PIKEFUN int get_termfreq()
   {
     TermIterator  *termi;
     doccount i;
     termi = (TermIterator*)THIS->object_data->termi;
     i = termi->get_termfreq();
     push_int((INT_TYPE)i);
   }
 
 /*! @decl int positionlist_count()
  *!
  *!  
  *! @returns
  *!  
  *!
  */
   PIKEFUN int positionlist_count()
   {
     TermIterator  *termi;
     termcount i;
     termi = (TermIterator*)THIS->object_data->termi;
     i = termi->positionlist_count();
     push_int((INT_TYPE)i);
   }
 
 
 /*! @decl string get_term()
  *!
  *!  
  *! @returns
  *!  
  *!
  */
   PIKEFUN string get_term()
   {
     TermIterator  *termi;
     string i;
     termi = (TermIterator*)THIS->object_data->termi;
     i = (*(*termi));
     push_text(i.c_str());
   }
 
   PIKEFUN mixed `+=(int i)
   {
     TermIterator  *ti;
     ti = THIS->object_data->termi;
     
     for(int x = 0; x < i; x++)
     {
       (*ti)++;
       if(*ti == *(THIS->tie)) {
         pop_stack(); push_int(0); return;}
     }
     THIS->current_index++;
     pop_stack();
     push_object(this_object());
   }
  
   PIKEFUN int `!()
   {
     TermIterator  *ti;
     ti = THIS->object_data->termi;
     if(*ti == *(THIS->tie)) { push_int(1); }
     else
       push_int(0);
   }
 
 /*  TermIterator.string get_description() */
 /*! @decl string get_description()
  *!
  *!  
  *! @returns
  *!  
  *!
  */
 PIKEFUN string get_description()
 {
   TermIterator  *termi;
   termi = THIS->object_data->termi;
 
   string str = termi->get_description();
 
   push_text(str.c_str());
 }
 
 PIKEFUN string _sprintf(int conversion_type, mapping params)
 {
   TermIterator  *it;
   if(THIS && THIS->object_data && conversion_type == 'O')
   {
     it = THIS->object_data->termi;
 
     string str = it->get_description();
     pop_n_elems(args);
     push_text(str.c_str());
   }
   else
   {
     pop_n_elems(args);
     push_int(0);
   }
 }
 
 
 INIT
 {
     XAPIAN_TERMITERATOR_OBJECT_DATA * dta = 
 	(XAPIAN_TERMITERATOR_OBJECT_DATA*)malloc(sizeof(XAPIAN_TERMITERATOR_OBJECT_DATA));
     if (!dta)
         Pike_error("init_sample: Out of memory!\n");
 
     dta->termi = NULL;
     THIS->object_data = dta;
 }
 
 EXIT 
 {
   if(THIS->object_data)
   {
     TermIterator  *termi;
     termi = THIS->object_data->termi;
     if(termi) delete termi;
     free(THIS->object_data);
   }
 }
 
 }
 
 /*!  @endclass
 */
 
 /*! @class Document
  *! A document in the database - holds data, values, terms, and postings.
 */
 
 PIKECLASS Document
 {
 
 CVAR XAPIAN_DOCUMENT_OBJECT_DATA   *object_data;
 
 
 /*  Document.void create() */
 /*! @decl void create()
  *!
  *!  
  *!
  */
 PIKEFUN void create()
 {
   try
   {
     Document* document = new Document();
 
     pop_n_elems(args);
 
     THIS->object_data->document = document;
   }
 
   catch(...) 
   {
     Pike_error("an error occurred!\n");
   }
 }
 
 /*  Document.void set_data(string data) */
 /*! @decl void set_data(string data)
  *!
  *!  Set data stored in the document.
  *!
  *! @param data
  *!  
 * !
  *!
  */
 PIKEFUN void set_data(string data)
 {
   Document  *doc;
   doc = THIS->object_data->document;
   string str((const char *)data->str, (size_t)data->len);
 
   doc->set_data(str);  
 
   pop_n_elems(args);
 }
 
 /*! @decl ValueIterator value_iterator()
  *! Get an iterator for the values in this document.
  *!  @returns
  *!    a @[ValueIterator] object which can be passed to @[foreach]()
  *!  
  *!
  */
 PIKEFUN object value_iterator()
 {
   Document  *doc;
   doc = THIS->object_data->document;
 
   ValueIterator vi;
   ValueIterator * vi2;
   struct object * o;
 
   vi = doc->values_begin();
   vi2 = new ValueIterator(vi);
 
   o = fast_clone_object(ValueIterator_program);
 
   OBJ2_VALUEITERATOR(o)->object_data->valuei = vi2;
   OBJ2_VALUEITERATOR(o)->vie = new ValueIterator(doc->values_end());
 
   push_object(o);    
 }
 
 /*! @decl TermIterator term_iterator()
  *!  Get an iterator for the terms in this document.
  *!  @returns
  *!    a @[TermIterator] object which can be passed to @[foreach]()
  */
 PIKEFUN object term_iterator()
 {
   Document  *doc;
   doc = THIS->object_data->document;
 
   TermIterator ti;
   TermIterator * ti2;
   struct object * o;
 
   ti = doc->termlist_begin();
   ti2 = new TermIterator(ti);
 
   o = fast_clone_object(TermIterator_program);
 
   OBJ2_TERMITERATOR(o)->object_data->termi = ti2;
   OBJ2_TERMITERATOR(o)->tie = new TermIterator(doc->termlist_end());
 
   push_object(o);    
 }
 
 /*  Document.void clear_terms() */
 /*! @decl void clear_terms()
  *!
  *! Remove all terms (and postings) from the document.  
  *!
  */
 PIKEFUN void clear_terms()
 {
   Document  *doc;
   doc = THIS->object_data->document;
 
   doc->clear_terms();
 }
 
 /*  Document.void clear_values() */
 /*! @decl void clear_values()
  *!
  *!  Remove all values associated with the document.
  *!
  */
 PIKEFUN void clear_values()
 {
   Document  *doc;
   doc = THIS->object_data->document;
 
   doc->clear_values();
 }
 
 /*  Document.string get_data() */
 /*! @decl string get_data()
  *!  Get data stored in the document.
  *! This is a potentially expensive operation, and shouldn't normally be 
  *! used in a match decider function. Put data for use by match deciders 
  *! in a value instead.
  *!  
  *! @returns
  *!  
  *!
  */
 PIKEFUN string get_data()
 {
   Document  *doc;
   doc = THIS->object_data->document;
 
   string str = doc->get_data();
 
   push_text(str.c_str());
 }
 
 /*  Document.string get_description() */
 /*! @decl string get_description()
  *!
  *!  
  *! @returns
  *!  
  *!
  */
 PIKEFUN string get_description()
 {
   Document  *doc;
   doc = THIS->object_data->document;
 
   string str = doc->get_description();
 
   push_text(str.c_str());
 }
 
 PIKEFUN string _sprintf(int conversion_type, mapping params)
 {
   Document  *doc;
   if(THIS && THIS->object_data && conversion_type == 'O')
   {
     doc = THIS->object_data->document;
 
     string str = doc->get_description();
     pop_n_elems(args);
     push_text(str.c_str());
   }
   else
   {
     pop_n_elems(args);
     push_int(0);
   }
 }
 
 
 /*  Document.string get_value(int val) */
 /*! @decl string get_value(int val)
  *!  Get value by number.
  *!  
  *! @param val
  *!   	The number of the value.
 * !
  *! @returns
  *! Returns an empty string if no value with the given number is present 
  *! in the document.
  *!  
  *!
  */
 PIKEFUN string get_value(int val)
 {
   Document  *doc;
   doc = THIS->object_data->document;
 
   string str = doc->get_value(val);
 
   pop_n_elems(args);
 
   if(str.length())
     push_text(str.c_str());
   else 
     push_int(0);
 }
 
 /*  Document.void remove_value(int val) */
 /*! @decl void remove_value(int val)
  *!
  *! Remove any value with the given number.  
  *! @param val
  *!  
 * !
  *!
  */
 PIKEFUN void remove_value(int val)
 {
   Document  *doc;
   doc = THIS->object_data->document;
 
   doc->remove_value(val);
 
   pop_n_elems(args);
 }
 
 /*  Document.void add_term(string tname, int termcount) */
 /*! @decl void add_term(string tname, int termcount)
  *!
  *! Add a term to the document, without positional information.
  *!
  *! Any existing positional information for the term will be left unmodified.  
  *! @param tname
  *!  The name of the term.
 * !
  *! @param termcount
  *!  The increment that will be applied to the wdf for this term. 
 * !
  *!
  */
 PIKEFUN void add_term(string tname, int termcount)
 {
   Document  *doc;
   doc = THIS->object_data->document;
 
   string str(tname->str, tname->len);
   
   doc->add_term(str, (unsigned int)termcount);
 
   pop_n_elems(args);
 }
 
 /*  Document.void add_posting(string tname, int termpos, int termcount) */
 /*! @decl void add_posting(string tname, int termpos, int termcount)
  *!Add an occurrence of a term at a particular position.
  *!
  *! Multiple occurrences of the term at the same position are represented 
  *! only once in the positional information, but do increase the wdf.
  *!
  *! If the term is not already in the document, it will be added to it.
  *!  
  *! @param tname
  *!  The name of the term.
 * !
  *! @param termpos
  *!  The position of the term.
 * !
  *! @param termcount
  *!  The increment that will be applied to the wdf for this term.
 * !
  *!
  */
 PIKEFUN void add_posting(string tname, int termpos, int termcount)
 {
   Document  *doc;
   doc = THIS->object_data->document;
 
   string str(tname->str, tname->len);
 
   try 
   {  
 
     doc->add_posting(str, (unsigned int)termpos, (unsigned int)termcount);
   }
 
   catch(InvalidArgumentError &e)
   {
     pop_n_elems(args);
     Pike_error(e.get_msg().c_str());
   }
   
   pop_n_elems(args);
 }
 
 /*  Document.void remove_term(string tname) */
 /*! @decl void remove_term(string tname)
  *!  Remove a term and all postings associated with it.
  *!  
  *! @param tname
  *!  The name of the term.
 * ! @note
  *!  An error will be thrown if the term is not present in the document.
  */
 PIKEFUN void remove_term(string tname)
 {
   Document  *doc;
   doc = THIS->object_data->document;
 
   string str(tname->str, tname->len);
   
   try
   {
     doc->remove_term(str);
   }
   catch(InvalidArgumentError &e)
   {
     pop_n_elems(args);
     Pike_error("InvalidArgumentError\n");
   }
 
   pop_n_elems(args);
 }
 
 /*! @decl void remove_posting(string tname, int tpos, int wdfdec)
  *!Remove a posting of a term from the document.
  *!
  *! Note that the term will still index the document even if all 
  *! occurrences are removed. To remove a term from a document completely, 
  *! use @[remove_term]().
  *!
  *! @param tname
  *!  The name of the term.
  *! @param tpos
  *!  The position of the term.
  *! @param wdfdec
  *!   The decrement that will be applied to the wdf when removing this 
  *!   posting. The wdf will not go below the value of 0.
  *! 
  *! @note
  *!   An error will be thrown if the term is not at the position specified 
  *!   in the position list for this term in this document or if the term 
  *!   is not in the document.
  */
 PIKEFUN void remove_posting(string tname, int tpos, int wdfdec)
 {
   Document  *doc;
   doc = THIS->object_data->document;
 
   string str(tname->str, tname->len);
   
   try
   {
     doc->remove_posting(str, tpos, wdfdec);
   }
   catch(InvalidArgumentError &e)
   {
     pop_n_elems(args);
     Pike_error("InvalidArgumentError\n");
   }
 
   pop_n_elems(args);
 }
 
 /*  Document.void add_value(int valueno, string value) */
 /*! @decl void add_value(int valueno, string value)
  *!Add a new value.
  *!
  *! It will replace any existing value with the same number. 
  *!  
  *! @param valueno
  *!  
 * !
  *! @param value
  *!  
 * !
  *!
  */
 PIKEFUN void add_value(int valueno, string value)
 {
   Document  *doc;
   doc = THIS->object_data->document;
   string str(value->str, value->len);
 
   doc->add_value(valueno, str);
 
   pop_n_elems(args);
 }
 
 /*  Document.int termlist_count() */
 /*! @decl int termlist_count()
  *!
  *! Count the terms in this document.  
  *! @returns
  *!  the number of terms in the document.
  *!
  */
 PIKEFUN int termlist_count()
 {
   Document  *doc;
   doc = THIS->object_data->document;
   unsigned int i;
 
   i = doc->termlist_count();
 
   push_int((INT_TYPE)i);
 
   return;
 }
 
 /*  Document.int values_count() */
 /*! @decl int values_count()
  *!
  *!  Count the values in this document. 
  *! @returns
  *!  the number of values in the document.
  *!
  */
 PIKEFUN int values_count()
 {
   Document  *doc;
   doc = THIS->object_data->document;
   unsigned int i;
 
   i = doc->values_count();
 
   push_int((INT_TYPE)i);
 
   return;
 }
 
 
 INIT
 {
     XAPIAN_DOCUMENT_OBJECT_DATA * dta = 
 	(XAPIAN_DOCUMENT_OBJECT_DATA*)malloc(sizeof(XAPIAN_DOCUMENT_OBJECT_DATA));
     if (!dta)
         Pike_error("init_sample: Out of memory!\n");
 
     dta->document = NULL;
     THIS->object_data = dta;
 }
 
 EXIT 
 {
   if(THIS->object_data)
   {
     
     Document  *doc;
     doc = THIS->object_data->document;
     if(doc) delete doc;
 // hrm... odd.
       free(THIS->object_data);
   }
 }
 
 }
 
 /*!  @endclass
 */
 
 
 /*
      here are some important helper classes that we'll include 
      rather than compile separately.
 */
 #include "PikeMatchDeciderProxy.cc"
 #include "PikeExpandDeciderProxy.cc"
 
 
 
 /*! @class MSetIterator
 */
 
 PIKECLASS MSetIterator
 {
   CVAR int current_index;
   CVAR MSetIterator * msete;
   CVAR XAPIAN_MSETITERATOR_OBJECT_DATA   *object_data;
 
   PIKEFUN object get_document()
   {
     MSetIterator  *mseti;
     Document doc;
     Document *doc2;
     struct object * o;
     try {
     mseti = (MSetIterator*)THIS->object_data->mseti;
     doc = mseti->get_document();    
     doc2 = new Document(doc);
 
     o = fast_clone_object(Document_program);
     OBJ2_DOCUMENT(o)->object_data->document = doc2;
 
     push_object(o);
   }
   catch(RangeError &e)
   {
     pop_n_elems(args);
     Pike_error("RangeError\n");
   }
 
   }
 
   PIKEFUN mixed index()
   {
     push_int(THIS->current_index);
   }
 
   PIKEFUN object value()
   {
     push_object(this_object());
   }
 
   PIKEFUN int get_docid()
   {
     MSetIterator  *mseti;
     docid i;
     mseti = (MSetIterator*)THIS->object_data->mseti;
     i = (*(*mseti));
     push_int((INT_TYPE)i);
   }
 
   PIKEFUN int get_percent()
   {
     MSetIterator  *mseti;
     docid i;
     mseti = (MSetIterator*)THIS->object_data->mseti;
     i = mseti->get_percent();
     push_int((INT_TYPE)i);
   }
   
   PIKEFUN float get_weight()
   {
     MSetIterator  *mseti;
     weight i;
     mseti = (MSetIterator*)THIS->object_data->mseti;
     i = mseti->get_weight();
     push_float((FLOAT_TYPE)i);
   }
   
   PIKEFUN int get_collapse_count()
   {
     MSetIterator  *mseti;
     docid i;
     mseti = (MSetIterator*)THIS->object_data->mseti;
     i = mseti->get_collapse_count();
     push_int((INT_TYPE)i);
   }
   
   PIKEFUN object next()
   {
     MSetIterator  *mseti;
     mseti = THIS->object_data->mseti;
     MSetIterator *mseti2;
 
     struct object * o;
 (*mseti)++;
 
    THIS->current_index++;
     if(*mseti == *(THIS->msete)) {push_int(0); return;}
     push_int(1);    
   }
 /*
   PIKEFUN object prev()
   {
     MSetIterator  *mseti;
     mseti = THIS->object_data->mseti;
     MSetIterator *mseti2;
 
     struct object * o;
 
     mseti2 = new MSetIterator((*mseti)--);
 
     o = fast_clone_object(MSetIterator_program);
 
     OBJ2_MSETITERATOR(o)->object_data->mseti = mseti2;
 
     push_object(o);    
   }
 */
   PIKEFUN mixed `+=(int i)
   {
     MSetIterator  *mseti;
     mseti = THIS->object_data->mseti;
     
     for(int x = 0; x < i; x++)
     {
       (*mseti)++;
       if(*mseti == *(THIS->msete)) {
         pop_stack(); push_int(0); return;}
     }
     THIS->current_index++;
     pop_stack();
     push_object(this_object());
   }
  
   PIKEFUN int `!()
   {
     MSetIterator  *mseti;
     mseti = THIS->object_data->mseti;
     if(*mseti == *(THIS->msete)) { push_int(1); }
     else
       push_int(0);
   }
 
   PIKEFUN int `==(mixed arg)
   {
     struct object * o;
     struct MSetIterator_struct * msis;    
     MSetIterator  *mseti;
     MSetIterator  *msetb;
     if(arg->type!= T_OBJECT) {RETURN(0);}
     o = arg->u.object;
     mseti = (MSetIterator*)THIS->object_data->mseti;
     msis = OBJ2_MSETITERATOR(o);
     if(!msis) {RETURN(0);}
 
     msetb = msis->object_data->mseti;
     if(*mseti == *msetb) {RETURN(1);}
     else {RETURN(0);}
   }
 
 INIT
 {
     XAPIAN_MSETITERATOR_OBJECT_DATA * dta = 
 	(XAPIAN_MSETITERATOR_OBJECT_DATA*)malloc(sizeof(XAPIAN_MSETITERATOR_OBJECT_DATA));
     if (!dta)
         Pike_error("init_sample: Out of memory!\n");
 
     dta->mseti = NULL;
     THIS->object_data = dta;
 }
 
 EXIT 
 {
   if(THIS->object_data)
   {
     MSetIterator  *mseti;
     mseti = THIS->object_data->mseti;
     if(mseti) delete mseti;
     free(THIS->object_data);
   }
 }
 
 }
 
 /*!  @endclass
 */
 
 /*! @class ESetIterator
 */
 
 PIKECLASS ESetIterator
 {
   CVAR int current_index;
   CVAR ESetIterator * esete;
   CVAR XAPIAN_ESETITERATOR_OBJECT_DATA   *object_data;
 
   PIKEFUN string get_term()
   {
     ESetIterator  *eseti;
     string i;
     eseti = (ESetIterator*)THIS->object_data->eseti;
     i = (*(*eseti));
     push_text(i.c_str());
   }
 
   PIKEFUN float get_weight()
   {
     ESetIterator  *eseti;
     weight i;
     eseti = (ESetIterator*)THIS->object_data->eseti;
     i = eseti->get_weight();
     push_float((FLOAT_TYPE)i);
   }  
 
   PIKEFUN mixed index()
   {
     push_int(THIS->current_index);
   }
 
   PIKEFUN object value()
   {
     push_object(this_object());
   }
 
   PIKEFUN object next()
   {
     ESetIterator  *eseti;
     eseti = THIS->object_data->eseti;
     ESetIterator *eseti2;
 
 (*eseti)++;
 
    THIS->current_index++;
     if(*eseti == *(THIS->esete)) {push_int(0); return;}
     push_int(1);    
   }
 
 /*
   PIKEFUN object prev()
   {
     ESetIterator  *eseti;
     eseti = THIS->object_data->eseti;
     ESetIterator *eseti2;
 
     struct object * o;
 
     eseti2 = new ESetIterator((*eseti)--);
 
     o = fast_clone_object(ESetIterator_program);
 
     OBJ2_ESETITERATOR(o)->object_data->eseti = eseti2;
 
     push_object(o);    
   }
 */
 
   PIKEFUN mixed `+=(int i)
   {
     ESetIterator  *eseti;
     eseti = THIS->object_data->eseti;
     
     for(int x = 0; x < i; x++)
     {
       (*eseti)++;
       if(*eseti == *(THIS->esete)) {
         pop_stack(); push_int(0); return;}
     }
     THIS->current_index++;
     pop_stack();
     push_object(this_object());
   }
 
   PIKEFUN int `!()
   {
     ESetIterator  *eseti;
     eseti = THIS->object_data->eseti;
     if(*eseti == *(THIS->esete)) { push_int(1); }
     else
       push_int(0);
   }
 
   PIKEFUN int `==(mixed arg)
   {
     struct object * o;
     ESetIterator  *eseti;
     ESetIterator  *esetb;
     struct ESetIterator_struct * esis;    
 
     if(arg->type!= T_OBJECT) RETURN(0);
     o = arg->u.object;
     eseti = (ESetIterator*)THIS->object_data->eseti;
 
     esis = OBJ2_ESETITERATOR(o);
     if(!esis) RETURN(0);
 
     esetb = esis->object_data->eseti;
     if(eseti == esetb) RETURN(1);
     else RETURN(0);
   }
 
 INIT
 {
     XAPIAN_ESETITERATOR_OBJECT_DATA * dta = 
 	(XAPIAN_ESETITERATOR_OBJECT_DATA*)malloc(sizeof(XAPIAN_ESETITERATOR_OBJECT_DATA));
     if (!dta)
         Pike_error("init_sample: Out of memory!\n");
 
     dta->eseti = NULL;
     THIS->object_data = dta;
 }
 
 EXIT 
 {
   if(THIS->object_data)
   {
     ESetIterator  *eseti;
     eseti = THIS->object_data->eseti;
     if(eseti) delete eseti;
     free(THIS->object_data);
   }
 }
 
 }
 
 /*!  @endclass
 */
 
 /*! @class MSet
 */
 
 PIKECLASS MSet
 {
 CVAR XAPIAN_MSET_OBJECT_DATA *object_data;
 
 INIT
 {
     XAPIAN_MSET_OBJECT_DATA * dta = 
 	(XAPIAN_MSET_OBJECT_DATA*)malloc(sizeof(XAPIAN_MSET_OBJECT_DATA));
 //printf("allocated mset data.\n");
     if (!dta)
         Pike_error("init_sample: Out of memory!\n");
 
     dta->mset = NULL;
     THIS->object_data = dta;
 }
 
 EXIT 
 {
   if(THIS->object_data)
   {
     MSet  *mset;
     mset = THIS->object_data->mset;
     if(mset) delete mset;
     free(THIS->object_data);
   }
 }
 
 
 /*  MSet.void create() */
 /*! @decl void create()
  *!
  *!  
  *!
  */
 PIKEFUN void create()
 {
   try
   {
     MSet * mset = new MSet();
 
     pop_n_elems(args);
 
     THIS->object_data->mset = mset;
   }
 
   catch(...) 
   {
     Pike_error("an error occurred!\n");
   }
 }
 
 /*  MSet.object begin() */
 /*! @decl object begin()
  *!
  *!  
  *! @returns
  *!  
  *!
  */
 PIKEFUN object begin()
 {
   MSet  *mset;
   mset = THIS->object_data->mset;
 
   MSetIterator mseti;
   MSetIterator *mseti2;
   struct object * o;
 
   mseti = mset->begin();
 
   mseti2 = new MSetIterator(mseti);
 
   o = fast_clone_object(MSetIterator_program);
 
   OBJ2_MSETITERATOR(o)->object_data->mseti = mseti2;
 
   push_object(o);    
 }
 
 PIKEFUN object _get_iterator()
 {
   MSet  *mset;
   mset = THIS->object_data->mset;
 
   MSetIterator mseti;
   MSetIterator *mseti2;
   struct object * o;
 
   mseti = mset->begin();
 
   mseti2 = new MSetIterator(mseti);
 
   o = fast_clone_object(MSetIterator_program);
 
   OBJ2_MSETITERATOR(o)->object_data->mseti = mseti2;
   OBJ2_MSETITERATOR(o)->msete = new MSetIterator(mset->end());
 
   push_object(o);    
 }
 
 /*  MSet.object end() */
 /*! @decl object end()
  *!
  *!  
  *! @returns
  *!  
  *!
  */
 PIKEFUN object end()
 {
   MSet  *mset;
   mset = THIS->object_data->mset;
 
   MSetIterator mseti;
   MSetIterator *mseti2;
   struct object * o;
 
   mseti = mset->end();
 
   mseti2 = new MSetIterator(mseti);
   o = fast_clone_object(MSetIterator_program);
 
   OBJ2_MSETITERATOR(o)->object_data->mseti = mseti2;
 
   push_object(o);    
 }
 
 /*  MSet.object back() */
 /*! @decl object back()
  *!
  *!  
  *! @returns
  *!  
  *!
  */
 PIKEFUN object back()
 {
   MSet  *mset;
   mset = THIS->object_data->mset;
 
   MSetIterator mseti;
   MSetIterator *mseti2;
   struct object * o;
 
   mseti = mset->back();
 
   mseti2 = new MSetIterator(mseti);
 
   o = fast_clone_object(MSetIterator_program);
 
   OBJ2_MSETITERATOR(o)->object_data->mseti = mseti2;
 
   push_object(o);    
 }
 
 /*  MSet.void fetch() */
 /*! @decl void fetch()
  *!
  *!  
  *!
  */
 PIKEFUN void fetch()
 {
   MSet  *mset;
   mset = THIS->object_data->mset;
 
   mset->fetch();
 }
 
 /*  MSet.int size() */
 /*! @decl int size()
  *!
  *!  
  *! @returns
  *!  
  *!
  */
 PIKEFUN int size()
 {
   MSet  *mset;
   mset = THIS->object_data->mset;
   doccount i;
 
   i = mset->size();
 
   push_int(i);
 }
 
 /*  MSet.int get_matches_estimated() */
 /*! @decl int get_matches_estimated()
  *!
  *!  
  *! @returns
  *!  
  *!
  */
 PIKEFUN int get_matches_estimated()
 {
   MSet  *mset;
   mset = THIS->object_data->mset;
   doccount i;
 
   i = mset->get_matches_estimated();
 
   push_int(i);
 }
 
 /*  MSet.int get_matches_upper_bound() */
 /*! @decl int get_matches_upper_bound()
  *!
  *!  
  *! @returns
  *!  
  *!
  */
 PIKEFUN int get_matches_upper_bound()
 {
   MSet  *mset;
   mset = THIS->object_data->mset;
   doccount i;
 
   i = mset->get_matches_upper_bound();
 
   push_int(i);
 }
 
 /*  MSet.int get_firstitem() */
 /*! @decl int get_firstitem()
  *!
  *!  
  *! @returns
  *!  
  *!
  */
 PIKEFUN int get_firstitem()
 {
   MSet  *mset;
   mset = THIS->object_data->mset;
   doccount i;
 
   i = mset->get_firstitem();
 
   push_int(i);
 }
 
 /*  MSet.int get_matches_lower_bound() */
 /*! @decl int get_matches_lower_bound()
  *!
  *!  
  *! @returns
  *!  
  *!
  */
 PIKEFUN int get_matches_lower_bound()
 {
   MSet  *mset;
   mset = THIS->object_data->mset;
   doccount i;
 
   i = mset->get_matches_lower_bound();
 
   push_int(i);
 }
 
 /*  MSet.string get_description() */
 /*! @decl string get_description()
  *!
  *!  
  *! @returns
  *!  
  *!
  */
 PIKEFUN string get_description()
 {
   MSet  *mset;
   mset = THIS->object_data->mset;
 
   string str = mset->get_description();
 
   push_text(str.c_str());
 }
 
 PIKEFUN string _sprintf(int conversion_type, mapping params)
 {
   MSet  *mset;
   if(THIS && THIS->object_data && conversion_type == 'O')
   {
     mset = THIS->object_data->mset;
 
     string str = mset->get_description();
     pop_n_elems(args);
     push_text(str.c_str());
   }
   else
   {
     pop_n_elems(args);
     push_int(0);
   }
 }
 
 
 
 }
 
 /*!  @endclass
 */
 
 /*! @class RSet
 */
 
 PIKECLASS RSet
 {
 CVAR XAPIAN_RSET_OBJECT_DATA *object_data;
 
 INIT
 {
     XAPIAN_RSET_OBJECT_DATA * dta = 
 	(XAPIAN_RSET_OBJECT_DATA*)malloc(sizeof(XAPIAN_RSET_OBJECT_DATA));
 //printf("allocated eset data.\n");
     if (!dta)
         Pike_error("init_sample: Out of memory!\n");
 
     dta->rset = NULL;
     THIS->object_data = dta;
 }
 
 EXIT 
 {
   if(THIS->object_data)
   {
     RSet  *rset;
     rset = THIS->object_data->rset;
     if(rset) delete rset;
     free(THIS->object_data);
   }
 }
 
 /*  RSet.void create() */
 /*! @decl void create()
  *!
  *!  
  *!
  */
 PIKEFUN void create()
 {
   try
   {
     RSet * rset = new RSet();
 
     pop_n_elems(args);
 
     THIS->object_data->rset = rset;
   }
 
   catch(...) 
   {
     Pike_error("an error occurred!\n");
   }
 }
 
 /*  RSet.int size() */
 /*! @decl int size()
  *!
  *!  
  *! @returns
  *!  
  *!
  */
 PIKEFUN int size()
 {
   RSet  *rset;
   rset = THIS->object_data->rset;
   doccount i;
 
   i = rset->size();
 
   push_int(i);
 }
 
 /*  RSet.int empty() */
 /*! @decl int empty()
  *!
  *!  
  *! @returns
  *!  
  *!
  */
 PIKEFUN int empty()
 {
   RSet  *rset;
   rset = THIS->object_data->rset;
   bool i;
 
   i = rset->empty();
 
   push_int(i?1:0);
 }
 
 /*  RSet.void add_document(int docid) */
 /*! @decl void add_document(int docid)
  *!
  *!  
  *! @param docid
  *!  
 * !
  *!
  */
 PIKEFUN void add_document(int docid)
 {
   RSet  *rset;
   rset = THIS->object_data->rset;
 
   rset->add_document((Xapian::docid)docid);
 
   pop_n_elems(args);
 }
 
 /*  RSet.void add_document(object iterator) */
 /*! @decl void add_document(object iterator)
  *!
  *!  
  *! @param iterator
  *!  
 * !
  *!
  */
 PIKEFUN void add_document(object iterator)
 {
   RSet  *rset;
   rset = THIS->object_data->rset;
 
   MSetIterator * i;
 
   i = OBJ2_MSETITERATOR(iterator)->object_data->mseti;
 
   rset->add_document(*i);
 
   pop_n_elems(args);
 }
 
 /*  RSet.void remove_document(int docid) */
 /*! @decl void remove_document(int docid)
  *!
  *!  
  *! @param docid
  *!  
 * !
  *!
  */
 PIKEFUN void remove_document(int docid)
 {
   RSet  *rset;
   rset = THIS->object_data->rset;
 
   rset->remove_document((Xapian::docid)docid);
 
   pop_n_elems(args);
 }
 
 /*  RSet.void remove_document(object iterator) */
 /*! @decl void remove_document(object iterator)
  *!
  *!  
  *! @param iterator
  *!  
 * !
  *!
  */
 PIKEFUN void remove_document(object iterator)
 {
   RSet  *rset;
   rset = THIS->object_data->rset;
 
   MSetIterator * i;
 
   i = OBJ2_MSETITERATOR(iterator)->object_data->mseti;
 
   rset->remove_document(*i);
 
   pop_n_elems(args);
 }
 
 /*  RSet.int contains(int docid) */
 /*! @decl int contains(int docid)
  *!
  *!  
  *! @param docid
  *!  
 * !
  *! @returns
  *!  
  *!
  */
 PIKEFUN int contains(int docid)
 {
   RSet  *rset;
   rset = THIS->object_data->rset;
   bool r;
 
   r = rset->contains((Xapian::docid)docid);
 
   pop_n_elems(args);
   push_int(r?1:0);
 }
 
 /*  RSet.int contains(object iterator) */
 /*! @decl int contains(object iterator)
  *!
  *!  
  *! @param iterator
  *!  
 * !
  *! @returns
  *!  
  *!
  */
 PIKEFUN int contains(object iterator)
 {
   RSet  *rset;
   rset = THIS->object_data->rset;
   bool r;
   MSetIterator * i;
 
   i = OBJ2_MSETITERATOR(iterator)->object_data->mseti;
 
   r = rset->contains(*i);
 
   pop_n_elems(args);
 
   push_int(r?1:0);
 }
 
 /*  RSet.string get_description() */
 /*! @decl string get_description()
  *!
  *!  
  *! @returns
  *!  
  *!
  */
 PIKEFUN string get_description()
 {
   RSet  *rset;
   rset = THIS->object_data->rset;
 
   string str = rset->get_description();
 
   push_text(str.c_str());
 }
 
 PIKEFUN string _sprintf(int conversion_type, mapping params)
 {
   RSet  *rset;
   if(THIS && THIS->object_data && conversion_type == 'O')
   {
     rset = THIS->object_data->rset;
 
     string str = rset->get_description();
     pop_n_elems(args);
     push_text(str.c_str());
   }
   else
   {
     pop_n_elems(args);
     push_int(0);
   }
 }
 
 
 }
 
 /*!  @endclass
 */
 
 /*! @class ESet
 */
 
 PIKECLASS ESet
 {
 CVAR XAPIAN_ESET_OBJECT_DATA *object_data;
 
 INIT
 {
     XAPIAN_ESET_OBJECT_DATA * dta = 
 	(XAPIAN_ESET_OBJECT_DATA*)malloc(sizeof(XAPIAN_ESET_OBJECT_DATA));
 //printf("allocated eset data.\n");
     if (!dta)
         Pike_error("init_sample: Out of memory!\n");
 
     dta->eset = NULL;
     THIS->object_data = dta;
 }
 
 EXIT 
 {
   if(THIS->object_data)
   {
     ESet  *eset;
     eset = THIS->object_data->eset;
     if(eset) delete eset;
     free(THIS->object_data);
   }
 }
 
 
 /*  ESet.void create() */
 /*! @decl void create()
  *!
  *!  
  *!
  */
 PIKEFUN void create()
 {
   try
   {
     ESet * eset = new ESet();
 
     pop_n_elems(args);
 
     THIS->object_data->eset = eset;
   }
 
   catch(...) 
   {
     Pike_error("an error occurred!\n");
   }
 }
 
 /*  ESet.object begin() */
 /*! @decl object begin()
  *!
  *!  
  *! @returns
  *!  
  *!
  */
 PIKEFUN object begin()
 {
   ESet  *eset;
   eset = THIS->object_data->eset;
 
   ESetIterator eseti;
   ESetIterator *eseti2;
   struct object * o;
 
   eseti = eset->begin();
 
   eseti2 = new ESetIterator(eseti);
 
   o = fast_clone_object(ESetIterator_program);
 
   OBJ2_ESETITERATOR(o)->object_data->eseti = eseti2;
 
   push_object(o);    
 }
 
 /*  ESet.object end() */
 /*! @decl object end()
  *!
  *!  
  *! @returns
  *!  
  *!
  */
 PIKEFUN object end()
 {
   ESet  *eset;
   eset = THIS->object_data->eset;
 
   ESetIterator eseti;
   ESetIterator *eseti2;
   struct object * o;
 
   eseti = eset->end();
 
   eseti2 = new ESetIterator(eseti);
 
   o = fast_clone_object(ESetIterator_program);
 
   OBJ2_ESETITERATOR(o)->object_data->eseti = eseti2;
 
   push_object(o);    
 }
 
 /*  ESet.object back() */
 /*! @decl object back()
  *!
  *!  
  *! @returns
  *!  
  *!
  */
 PIKEFUN object back()
 {
   ESet  *eset;
   eset = THIS->object_data->eset;
 
   ESetIterator eseti;
   ESetIterator *eseti2;
   struct object * o;
 
   eseti = eset->back();
 
   eseti2 = new ESetIterator(eseti);
 
   o = fast_clone_object(ESetIterator_program);
 
   OBJ2_ESETITERATOR(o)->object_data->eseti = eseti2;
 
   push_object(o);    
 }
 
 /*  ESet.object `[](int i) */
 /*! @decl object `[](int i)
  *!
  *!  
  *! @param i
  *!  
 * !
  *! @returns
  *!  
  *!
  */
 PIKEFUN object `[](int i)
 {
   ESet  *eset;
   eset = THIS->object_data->eset;
 
   ESetIterator eseti;
   ESetIterator *eseti2;
   struct object * o;
 
   eseti = (*eset)[(termcount)i];
 
   eseti2 = new ESetIterator(eseti);
 
   o = fast_clone_object(ESetIterator_program);
 
   OBJ2_ESETITERATOR(o)->object_data->eseti = eseti2;
 
   push_object(o);    
 }
 
 /*  ESet.int size() */
 /*! @decl int size()
  *!
  *!  
  *! @returns
  *!  
  *!
  */
 PIKEFUN int size()
 {
   ESet  *eset;
   eset = THIS->object_data->eset;
   termcount i;
 
   i = eset->size();
 
   push_int(i);
 }
 
 /*  ESet.int empty() */
 /*! @decl int empty()
  *!
  *!  
  *! @returns
  *!  
  *!
  */
 PIKEFUN int empty()
 {
   ESet  *eset;
   eset = THIS->object_data->eset;
   bool i;
 
   i = eset->empty();
 
   push_int(i?1:0);
 }
 
 /*  ESet.int max_size() */
 /*! @decl int max_size()
  *!
  *!  
  *! @returns
  *!  
  *!
  */
 PIKEFUN int max_size()
 {
   ESet  *eset;
   eset = THIS->object_data->eset;
   termcount i;
 
   i = eset->max_size();
 
   push_int(i);
 }
 
 /*  ESet.int get_ebound() */
 /*! @decl int get_ebound()
  *!
  *!  
  *! @returns
  *!  
  *!
  */
 PIKEFUN int get_ebound()
 {
   ESet  *eset;
   eset = THIS->object_data->eset;
   termcount i;
 
   i = eset->get_ebound();
 
   push_int(i);
 }
 
 /*  ESet.string get_description() */
 /*! @decl string get_description()
  *!
  *!  
  *! @returns
  *!  
  *!
  */
 PIKEFUN string get_description()
 {
   ESet  *eset;
   eset = THIS->object_data->eset;
 
   string str = eset->get_description();
 
   push_text(str.c_str());
 }
 
 PIKEFUN string _sprintf(int conversion_type, mapping params)
 {
   ESet  *eset;
   if(THIS && THIS->object_data && conversion_type == 'O')
   {
     eset = THIS->object_data->eset;
 
     string str = eset->get_description();
     pop_n_elems(args);
     push_text(str.c_str());
   }
   else
   {
     pop_n_elems(args);
     push_int(0);
   }
 }
 
 
 }
 
 /*!  @endclass
 */
 
 /*! @class Database
 */
 
 PIKECLASS Database
 {
 CVAR XAPIAN_DATABASE_OBJECT_DATA   *object_data;
 
 /*  Database.void create(string path) */
 /*! @decl void create(string path)
  *!
  *!  
  *! @param path
  *!  
 * !
  *!
  */
 PIKEFUN void create(string path)
 {
   string str((const char *)path->str, (size_t)path->len);
   Database * db = new Database(str);
   THIS->object_data->database = db;
 
   pop_n_elems(args);  
 }
 
 /*  Database.void create() */
 /*! @decl void create()
  *!
  *!  
  *!
  */
 PIKEFUN void create()
 {
   Database * db = new Database();
 
   THIS->object_data->database = db;
 }
 
 /*  Database.void reopen() */
 /*! @decl void reopen()
  *!
  *!  
  *!
  */
 PIKEFUN void reopen()
 {
   Database * db = THIS->object_data->database;
 
   db->reopen();
 }
 
 /*  Database.void keep_alive() */
 /*! @decl void keep_alive()
  *!
  *!  
  *!
  */
 PIKEFUN void keep_alive()
 {
   Database * db = THIS->object_data->database;
 
   db->keep_alive();
 }
 
 
 /*  Database.int get_doclength(int did) */
 /*! @decl int get_doclength(int did)
  *!
  *!  
  *! @param did
  *!  
 * !
  *! @returns
  *!  
  *!
  */
 PIKEFUN int get_doclength(int did)
 {
   Database  *db;
   db = THIS->object_data->database;
 
   doclength i = db->get_doclength((docid)did);
   pop_n_elems(args);
   push_int((INT_TYPE)i);
 }
 
 /*  Database.int get_doccount() */
 /*! @decl int get_doccount()
  *!
  *!  
  *! @returns
  *!  
  *!
  */
 PIKEFUN int get_doccount()
 {
   Database  *db;
   db = THIS->object_data->database;
 
   doccount i = db->get_doccount();
   push_int(i);
 }
 
 /*  Database.int get_avlength() */
 /*! @decl int get_avlength()
  *!
  *!  
  *! @returns
  *!  
  *!
  */
 PIKEFUN int get_avlength()
 {
   Database  *db;
   db = THIS->object_data->database;
 
   doclength i = db->get_avlength();
   push_int((INT_TYPE)i);
 }
 
 /*  Database.int get_lastdocid() */
 /*! @decl int get_lastdocid()
  *!
  *!  
  *! @returns
  *!  
  *!
  */
 PIKEFUN int get_lastdocid()
 {
   Database  *db;
   db = THIS->object_data->database;
 
   docid i = db->get_lastdocid();
   push_int((INT_TYPE)i);
 }
 
 
 /*  Database.int has_positions() */
 /*! @decl int has_positions()
  *!
  *!  
  *! @returns
  *!  
  *!
  */
 PIKEFUN int has_positions()
 {
   Database  *db;
   db = THIS->object_data->database;
 
   bool i = db->has_positions();
 
   push_int(i?1:0);
 }
 
 /*! @decl TermIterator synonyms_iterator(string term)
  *!  Get an iterator for the synonyms of a term.
  *!  @returns
  *!    a @[TermIterator] object which can be passed to @[foreach]()
  */
 PIKEFUN object synonyms_iterator(string term)
 {
   Database  *db;
 
   db = (Database*)THIS->object_data->database;
 
 
   TermIterator ti;
   TermIterator * ti2;
   struct object * o;
 
   string str((const char *)term->str, (size_t)term->len);
 
   ti = db->synonyms_begin(str);
   ti2 = new TermIterator(ti);
 
   o = fast_clone_object(TermIterator_program);
 
   OBJ2_TERMITERATOR(o)->object_data->termi = ti2;
   OBJ2_TERMITERATOR(o)->tie = new TermIterator(db->synonyms_end(str));
 
   push_object(o);    
 }
 
 
 
 /*  Database.object get_document(int id) */
 /*! @decl object get_document(int id)
  *!
  *!  
  *! @param id
  *!  
 * !
  *! @returns
  *!  
  *!
  */
 PIKEFUN object get_document(int id)
 {
   Database  *db;
   Document doc;
   struct object * obj;
   struct Document_struct * od;
 
   db = (Database*)THIS->object_data->database;
 
   try
   {
     doc = db->get_document((docid)id);
   }
 
   catch(DocNotFoundError &e)
   {
     pop_n_elems(args);
     Pike_error("DocumentNotFoundError\n");
   }
 
   pop_n_elems(args);
 
   obj = fast_clone_object(Document_program);
 
   od = OBJ2_DOCUMENT(obj);
 
   od->object_data->document = new Document(doc);
     
   push_object(obj);
 
 }
 
 /*! @decl object get_spelling_terms()
  *!
  *! @returns
  *!   a @[TermIterator] object which can also be passed to @[foreach]()
  */
 PIKEFUN object get_spelling_terms()
 {
   TermIterator ti;
   TermIterator * ti2;
   struct object * o;
 
   Database  *db;
   db = THIS->object_data->database;
 
 
   ti = db->spellings_begin();
   ti2 = new TermIterator(ti);
 
   o = fast_clone_object(TermIterator_program);
 
   OBJ2_TERMITERATOR(o)->object_data->termi = ti2;
   OBJ2_TERMITERATOR(o)->tie = new TermIterator(db->spellings_end());
 
   push_object(o);    
 }
 
 /*! @decl object get_synonym_terms(string)
  *!
  *! @returns
  *!   a @[TermIterator] object which can also be passed to @[foreach]()
  */
 PIKEFUN object get_spelling_terms(string term)
 {
   TermIterator ti;
   TermIterator * ti2;
   struct object * o;
 
   Database  *db;
   db = THIS->object_data->database;
 
 
   ti = db->synonyms_begin(term->str);
   ti2 = new TermIterator(ti);
 
   o = fast_clone_object(TermIterator_program);
 
   OBJ2_TERMITERATOR(o)->object_data->termi = ti2;
   OBJ2_TERMITERATOR(o)->tie = new TermIterator(db->synonyms_end(term->str));
 
   push_object(o);    
 }
 
 
 /*! @decl string get_spelling_suggestion(string word, int max_edit_distance)
  *! Suggest a spelling correction.
  *!
  *! @param word
  *! The potentially misspelled word.
  *! @param max_edit_distance 	
  *! Only consider words which are at most max_edit_distance edits from 
  *! word. An edit is a character insertion, deletion, or the transposition 
  *! of two adjacent characters (a reasonable starting value is 2).
  */
 PIKEFUN string get_spelling_suggestion(string word, int max_edit_distance)
 {
   Database  *db;
 
   db = (Database*)THIS->object_data->database;
 
   string str((const char *)word->str, (size_t)word->len);
   string nstr = db->get_spelling_suggestion(str, max_edit_distance);
 
   pop_n_elems(args);
 
   push_text(str.c_str());
 }
 /*  Database.string get_description() */
 /*! @decl string get_description()
  *!
  *!  
  *! @returns
  *!  
  *!
  */
 PIKEFUN string get_description()
 {
   Database  *db;
   db = THIS->object_data->database;
 
   string str = db->get_description();
 
   push_text(str.c_str());
 }
 
 PIKEFUN string _sprintf(int conversion_type, mapping params)
 {
   Database  *db;
   if(THIS && THIS->object_data && conversion_type == 'O')
   {
     db = THIS->object_data->database;
 
     string str = db->get_description();
     pop_n_elems(args);
     push_text(str.c_str());
   }
   else
   {
     pop_n_elems(args);
     push_int(0);
   }
 }
 
 
 INIT
 {
     XAPIAN_DATABASE_OBJECT_DATA * dta = 
 	(XAPIAN_DATABASE_OBJECT_DATA*)malloc(sizeof(XAPIAN_DATABASE_OBJECT_DATA));
     if (!dta)
         Pike_error("init_sample: Out of memory!\n");
 
     dta->database = NULL;
     THIS->object_data = dta;
 }
 
 /*  Database.void destroy() */
 /*! @decl void destroy()
  *!
  *!  
  *!
  */
 PIKEFUN void destroy()
 {
     Database  *db;
     db = THIS->object_data->database;
 
     if(db) 
     {
       //printf("deleting db\n");
       delete db;
     }
 }
 
 EXIT 
 {
   if(THIS->object_data)
   {   
     Database  *db;
     db = THIS->object_data->database;
     free(THIS->object_data);
   }
 }
 
 }
 
 /*!  @endclass
 */
 
 /*! @class WriteableDatabase
  *! @inherit Database
 */
 
 PIKECLASS WriteableDatabase
 {
 INHERIT Database;
 
 /*  WriteableDatabase.void create(string path, int mode) */
 /*! @decl void create(string path, int mode)
  *!
  *!  
  *! @param path
  *!  
 * !
  *! @param mode
  *!  
 * !
  *!
  */
 PIKEFUN void create(string path, int mode)
 {
   try
   {
     const string str((const char *)path->str, (size_t)path->len);
 
     WritableDatabase* database = new WritableDatabase(str, mode);
 
     pop_n_elems(args);
 
     THIS->object_data->database = database;
   }
 
   catch(DatabaseLockError &e)
   {
     Pike_error("DatabaseLockError\n");
   }
   catch(DatabaseOpeningError &e) 
   {
     Pike_error("DatabaseOpeningError\n");
   }
   catch(InvalidArgumentError &e) 
   {
     Pike_error("InvalidArgumentError\n");
   }
 }
 
 /*  WriteableDatabase.void flush() */
 /*! @decl void flush()
  *!
  *!  
  *!
  */
 PIKEFUN void flush()
 {
   WritableDatabase  *db;
   db = (WritableDatabase*)THIS->object_data->database;
 
   try
   {
     db->flush();
   }
   catch(Xapian::DatabaseCorruptError &e)
   {
     Pike_error("DatabaseCorruptError\n");
   }
   catch(Xapian::DatabaseLockError &e)
   {
     Pike_error("DatabaseLockError\n");
   }
   catch(Xapian::DatabaseError &e)
   {
     Pike_error("DatabaseError\n");
   }
 }
 
 /*  WriteableDatabase.int add_document(object document) */
 /*! @decl int add_document(object document)
  *!
  *!  
  *! @param document
  *!  
 * !
  *! @returns
  *!  
  *!
  */
 PIKEFUN int add_document(object document)
 {
   WritableDatabase  *db;
   Document * doc;
   docid id;
 
   struct Document_struct * od;
 
   db = (WritableDatabase*)THIS->object_data->database;
   od = OBJ2_DOCUMENT(document);
 
   if(!od) Pike_error("Not a Document!\n");
 
   doc = od->object_data->document;
 
   try
   {
     id = db->add_document(*doc);
   }
   catch(Xapian::DatabaseCorruptError &e)
   {
     Pike_error("DatabaseCorruptError\n");
   }
   catch(Xapian::DatabaseError &e)
   {
     Pike_error("DatabaseError\n");
   }
   catch(Xapian::InvalidArgumentError &e)
   {
     //printf("%s\n",e.get_msg().c_str());
     Pike_error("InvalidArgumentError\n");
   }
   pop_n_elems(args);
   push_int(id);  
 }
 
 
 /*  WriteableDatabase.void replace_document(int did, object document) */
 /*! @decl void replace_document(int did, object document)
  *!
  *!  
  *! @param did
  *!  
 * !
  *! @param document
  *!  
 * !
  *!
  */
 PIKEFUN void replace_document(int did, object document)
 {
   WritableDatabase  *db;
   Document * doc;
   docid id;
 
   struct Document_struct * od;
 
   db = (WritableDatabase*)THIS->object_data->database;
   od = OBJ2_DOCUMENT(document);
 
   if(!od) Pike_error("Not a Document!\n");
 
   doc = od->object_data->document;
 
   try
   {
     db->replace_document((unsigned int)did, *doc);
   }
   catch(Xapian::DatabaseCorruptError &e)
   {
     Pike_error("DatabaseCorruptError\n");
   }
   catch(Xapian::DatabaseError &e)
   {
     Pike_error("DatabaseError\n");
   }
 
   pop_n_elems(args);
 }
 
 /*  WriteableDatabase.void replace_document(string term, object document) */
 /*! @decl void replace_document(string term, object document)
  *!
  *!  
  *! @param term
  *!  
 * !
  *! @param document
  *!  
 * !
  *!
  */
 PIKEFUN void replace_document(string term, object document)
 {
   WritableDatabase  *db;
   Document * doc;
   docid id;
   string str;
   struct Document_struct * od;
 
   db = (WritableDatabase*)THIS->object_data->database;
   od = OBJ2_DOCUMENT(document);
 
   if(!od) Pike_error("Not a Document!\n");
 
 
   doc = od->object_data->document;
 
   try
   {
     const string str((const char *)term->str, (size_t)term->len);
     db->replace_document(str, *doc);
   }
   catch(Xapian::DatabaseCorruptError &e)
   {
     Pike_error("DatabaseCorruptError\n");
   }
   catch(Xapian::DatabaseError &e)
   {
     Pike_error("DatabaseError\n");
   }
 
   pop_n_elems(args);
 }
 
 /*  WriteableDatabase.void delete_document(string unique_term) */
 /*! @decl void delete_document(string unique_term)
  *!
  *!  
  *! @param unique_term
  *!  
 * !
  *!
  */
 PIKEFUN void delete_document(string unique_term)
 {
   WritableDatabase  *db;
   db = (WritableDatabase*)THIS->object_data->database;
   const string str((const char *)unique_term->str, (size_t)unique_term->len);
   pop_n_elems(args);
 
   try
   {
     db->delete_document(str);
   }
   catch(Xapian::DatabaseCorruptError &e)
   {
     Pike_error("DatabaseCorruptError\n");
   }
   catch(Xapian::DatabaseError &e)
   {
     Pike_error("DatabaseError\n");
   }
 
 }
 
 /*  WriteableDatabase.void delete_document(int did) */
 /*! @decl void delete_document(int did)
  *!
  *!  
  *! @param did
  *!  
 * !
  *!
  */
 PIKEFUN void delete_document(int did)
 {
   WritableDatabase  *db;
   db = (WritableDatabase*)THIS->object_data->database;
 
   try
   {
     db->delete_document((docid)did);
   }
   catch(Xapian::DatabaseCorruptError &e)
   {
     pop_n_elems(args);
     Pike_error("DatabaseCorruptError\n");
   }
   catch(Xapian::DatabaseError &e)
   {
     pop_n_elems(args);
     Pike_error("DatabaseError\n");
   }
 
 }
 
 
 /*  WriteableDatabase.void begin_transaction(int flushed) */
 /*! @decl void begin_transaction(int flushed)
  *!
  *!  
  *! @param flushed
  *!  
 * !
  *!
  */
 PIKEFUN void begin_transaction(int flushed)
 {
   WritableDatabase  *db;
   db = (WritableDatabase*)THIS->object_data->database;
 
   try
   {
     db->begin_transaction((bool)flushed);
   }
   catch(Xapian::InvalidOperationError &e)
   {
     pop_n_elems(args);
     Pike_error("InvalidOperationError\n");
   }
   catch(Xapian::UnimplementedError &e)
   {
     pop_n_elems(args);
     Pike_error("UnimplementedError\n");
   }
 
 }
 
 /*  WriteableDatabase.void commit_transaction() */
 /*! @decl void commit_transaction()
  *!
  *!  
  *!
  */
 PIKEFUN void commit_transaction()
 {
   WritableDatabase  *db;
   db = (WritableDatabase*)THIS->object_data->database;
 
   try
   {
     db->commit_transaction();
   }
   catch(Xapian::InvalidOperationError &e)
   {
     Pike_error("InvalidOperationError\n");
   }
   catch(Xapian::DatabaseCorruptError &e)
   {
     Pike_error("DatabaseCorruptError\n");
   }
   catch(Xapian::DatabaseError &e)
   {
     Pike_error("DatabaseError\n");
   }
   catch(Xapian::UnimplementedError &e)
   {
     Pike_error("UnimplementedError\n");
   }
 
 }
 
 
 /*  WriteableDatabase.void cancel_transaction() */
 /*! @decl void cancel_transaction()
  *!
  *!  
  *!
  */
 PIKEFUN void cancel_transaction()
 {
   WritableDatabase  *db;
   db = (WritableDatabase*)THIS->object_data->database;
 
   try
   {
     db->cancel_transaction();
   }
   catch(Xapian::InvalidOperationError &e)
   {
     Pike_error("InvalidOperationError\n");
   }
   catch(Xapian::DatabaseCorruptError &e)
   {
     Pike_error("DatabaseCorruptError\n");
   }
   catch(Xapian::DatabaseError &e)
   {
     Pike_error("DatabaseError\n");
   }
   catch(Xapian::UnimplementedError &e)
   {
     Pike_error("UnimplementedError\n");
   }
 
 }
 
 /*  WriteableDatabase.string get_description() */
 /*! @decl string get_description()
  *!
  *!  
  *! @returns
  *!  
  *!
  */
 PIKEFUN string get_description()
 {
   WritableDatabase  *db;
   db = (WritableDatabase*)THIS->object_data->database;
 
   string str = db->get_description();
 
   push_text(str.c_str());
 }
 
 PIKEFUN string _sprintf(int conversion_type, mapping params)
 {
   WritableDatabase  *db;
   if(THIS && THIS->object_data && conversion_type == 'O')
   {
     db = (WritableDatabase*)THIS->object_data->database;
 
     string str = db->get_description();
     pop_n_elems(args);
     push_text(str.c_str());
   }
   else
   {
     pop_n_elems(args);
     push_int(0);
   }
 }
 
 
 }
 
 /*!  @endclass
 */
 
 
 /*! @class QueryParser
 */
 
 PIKECLASS QueryParser
 {
 CVAR XAPIAN_QUERYPARSER_OBJECT_DATA   *object_data;
 
 /*  QueryParser.void create() */
 /*! @decl void create()
  *!
  *!  
  *!
  */
 PIKEFUN void create()
 {
   QueryParser * parser = new QueryParser();
 
   THIS->object_data->parser = parser;
 }
 
 /*! @decl string get_corrected_query_string()
  *!
  */
 PIKEFUN string get_corrected_query_string()
 {
   QueryParser * parser;
 
   parser = THIS->object_data->parser;
   string nstr = parser->get_corrected_query_string();
 
   pop_n_elems(args);
 
   push_text(nstr.c_str());
 }
 
 /*  QueryParser.void set_stemmer(object stemmer) */
 /*! @decl void set_stemmer(object stemmer)
  *!
  *!  
  *! @param stemmer
  *!  
 * !
  *!
  */
 PIKEFUN void set_stemmer(object stemmer)
 {
   QueryParser * parser;
   Stem * s;
 
   parser = THIS->object_data->parser;
   s = OBJ2_STEM(stemmer)->object_data->stem; 
   parser->set_stemmer((const Stem)*s);
 
   pop_n_elems(args);
 }
 
 /*  QueryParser.void set_stopper(object stopper) */
 /*! @decl void set_stopper(object stopper)
  *!
  *!  
  *! @param stopper
  *!  
 * !
  *!
  */
 PIKEFUN void set_stopper(object stopper)
 {
   QueryParser * parser;
   Stopper * s;
 
   parser = THIS->object_data->parser;
   s = OBJ2_STOPPER(stopper)->object_data->stopper; 
   parser->set_stopper((const Stopper*)s);
 
   pop_n_elems(args);
 }
 
 /*  QueryParser.void set_database(object database) */
 /*! @decl void set_database(object database)
  *!
  *!  
  *! @param database
  *!  
  *!
  *!
  */
 PIKEFUN void set_database(object database)
 {
   QueryParser * parser;
   Database * d;
 
   parser = THIS->object_data->parser;
   d = OBJ2_DATABASE(database)->object_data->database; 
   parser->set_database((const Database)*d);
 
   pop_n_elems(args);
 }
 
 /*  QueryParser.void set_default_op(int op) */
 /*! @decl void set_default_op(int op)
  *!
  *!  
  *! @param op
  *!  
 * !
  *!
  */
 PIKEFUN void set_default_op(int op)
 {
   QueryParser * parser;
 
   parser = THIS->object_data->parser;
 
   parser->set_default_op((Query::op)op);
   pop_n_elems(args);
 }
 
 
 /*! @decl void set_stemming_strategy(int strat)
  *! Set the stemming strategy.
  *!
  *! This controls how the query parser will apply the stemming algorithm. 
  *! The default value is STEM_NONE. The possible values are:
  *! 
  *!   * STEM_NONE: Don't perform any stemming.
  *!
  *!   * STEM_SOME: Search for stemmed forms of terms except for those 
  *!  which start with a capital letter, or are followed by certain 
  *! characters (currently: (/@<>=*[{" ), or are used with operators which 
  *! need positional information. Stemmed terms are prefixed with 'Z'.
  *!
  *!   * STEM_ALL: Search for stemmed forms of all words (note: no 'Z' 
  *! prefix is added).
  *!
  *! Note that the stemming algorithm is only applied to words in 
  *! probabilistic fields - boolean filter terms are never stemmed.
  *! 
  */
 PIKEFUN void set_stemming_strategy(int strat)
 {
   QueryParser * parser;
 
   parser = THIS->object_data->parser;
 
   parser->set_stemming_strategy((Xapian::QueryParser::stem_strategy)strat);
   pop_n_elems(args);
 }
 
 /*  QueryParser.object parse_query(string query, int flags) */
 /*! @decl object parse_query(string query, int flags)
  *!
  *!  
  *! @param query
  *!  
 * !
  *! @param flags
  *!  
 * !
  *! @returns
  *!  
  *!
  */
 PIKEFUN object parse_query(string query, int flags)
 {
   Query q;
   Query * q1;
   QueryParser *parser;
   struct object *o;
   parser = THIS->object_data->parser;
 
   string str((const char *)query->str, (size_t)query->len);
 
   q = parser->parse_query(str, flags);
 
   q1 = new Query(q);  
 
   o = fast_clone_object(Query_program);
   if(!o) Pike_error("unable to clone the query program.\n");
   if(!q1) Pike_error("unable to parse the query.\n");
   OBJ2_QUERY(o)->object_data->query = q1;
   pop_n_elems(args);
   push_object(o);
 }
 
 /*  QueryParser.void add_prefix(string field, string prefix) */
 /*! @decl void add_prefix(string field, string prefix)
  *!
  *!  
  *! @param field
  *!  
 * !
  *! @param prefix
  *!  
 * !
  *!
  */
 PIKEFUN void add_prefix(string field, string prefix)
 {
   QueryParser *parser;
   parser = THIS->object_data->parser;
   
   string f((const char *)field->str, (size_t)field->len);
   string p((const char *)prefix->str, (size_t)prefix->len);
 
   parser->add_prefix(f, p);
   pop_n_elems(args);
 }
 
 /*  QueryParser.void add_boolean_prefix(string field, string prefix) */
 /*! @decl void add_boolean_prefix(string field, string prefix)
  *!
  *!  
  *! @param field
  *!  
 * !
  *! @param prefix
  *!  
 * !
  *!
  */
 PIKEFUN void add_boolean_prefix(string field, string prefix)
 {
   QueryParser *parser;
   parser = THIS->object_data->parser;
   
   string f((const char *)field->str, (size_t)field->len);
   string p((const char *)prefix->str, (size_t)prefix->len);
 
   parser->add_boolean_prefix(f, p);
   pop_n_elems(args);
 }
 
 /*  QueryParser.string get_description() */
 /*! @decl string get_description()
  *!
  *!  
  *! @returns
  *!  
  *!
  */
 PIKEFUN string get_description()
 {
   QueryParser *parser;
   parser = THIS->object_data->parser;
 
   string str = parser->get_description();
 
   push_text(str.c_str());
 }
 
 PIKEFUN string _sprintf(int conversion_type, mapping params)
 {
   QueryParser  *query;
   if(THIS && THIS->object_data && conversion_type == 'O')
   {
     query = THIS->object_data->parser;
 
     string str = query->get_description();
     pop_n_elems(args);
     push_text(str.c_str());
   }
   else
   {
     pop_n_elems(args);
     push_int(0);
   }
 }
 
 INIT
 {
     XAPIAN_QUERYPARSER_OBJECT_DATA * dta = 
 	(XAPIAN_QUERYPARSER_OBJECT_DATA*)malloc(sizeof(XAPIAN_QUERYPARSER_OBJECT_DATA));
     if (!dta)
         Pike_error("init_sample: Out of memory!\n");
 
     dta->parser = NULL;
     THIS->object_data = dta;
 }
 
 EXIT 
 {
   if(THIS->object_data)
   {
     QueryParser  *parser;
     parser = THIS->object_data->parser;
     if(parser) delete parser;
     free(THIS->object_data);
   }
 }
 
 EXTRA
 {
   QueryParser::feature_flag flag;
   int sflag;
 
   flag = QueryParser::FLAG_BOOLEAN;
   add_integer_constant("FLAG_BOOLEAN", flag, 0);
   flag = QueryParser::FLAG_PHRASE;
   add_integer_constant("FLAG_PHRASE", flag, 0);
   flag = QueryParser::FLAG_LOVEHATE;
   add_integer_constant("FLAG_LOVEHATE", flag, 0);
   flag = QueryParser::FLAG_BOOLEAN_ANY_CASE;
   add_integer_constant("FLAG_BOOLEAN_ANY_CASE", flag, 0);
   flag = QueryParser::FLAG_WILDCARD;
   add_integer_constant("FLAG_WILDCARD", flag, 0);
   flag = QueryParser::FLAG_SPELLING_CORRECTION;
   add_integer_constant("FLAG_SPELLING_CORRECTION", flag, 0);
 
   flag = QueryParser::FLAG_PURE_NOT;
   add_integer_constant("FLAG_PURE_NOT", flag, 0);
   flag = QueryParser::FLAG_PARTIAL;
   add_integer_constant("FLAG_PARTIAL", flag, 0);
   flag = QueryParser::FLAG_SYNONYM;
   add_integer_constant("FLAG_SYNONYM", flag, 0);
   flag = QueryParser::FLAG_AUTO_SYNONYMS;
   add_integer_constant("FLAG_AUTO_SYNONYMS", flag, 0);
 
 /*
   flag = QueryParser::FLAG_MULTIWORD_SYNONYMS;
   add_integer_constant("FLAG_MULTIWORD_SYNONYMS", flag, 0);
 */
 
   sflag = QueryParser::STEM_NONE;
   add_integer_constant("STEM_NONE", sflag, 0);
   sflag = QueryParser::STEM_SOME;
   add_integer_constant("STEM_SOME", sflag, 0);
   sflag = QueryParser::STEM_ALL;
   add_integer_constant("STEM_ALL", sflag, 0);
 }
 
 }
 
 /*!  @endclass
 */
 
 
 /*! @class Enquire
 */
 
 PIKECLASS Enquire
 {
 
 CVAR XAPIAN_ENQUIRE_OBJECT_DATA   *object_data;
 
 
 /*  Enquire.void create(object database) */
 /*! @decl void create(object database)
  *!
  *!  
  *! @param database
  *!  
 * !
  *!
  */
 PIKEFUN void create(object database)
 {
   try
   {
     Database * db;
     db = OBJ2_DATABASE(database)->object_data->database;
 
     Enquire * enquire = new Enquire(*db);
 
     pop_n_elems(args);
 
     THIS->object_data->enquire = enquire;
   }
 
   catch(...) 
   {
     Pike_error("an error occurred!\n");
   }
 }
 
 /*  Enquire.void set_weighting_scheme(object weight) */
 /*! @decl void set_weighting_scheme(object weight)
  *!
  *!  
  *! @param weight
  *!  
 * !
  *!
  */
 PIKEFUN void set_weighting_scheme(object weight)
 {
   Enquire * e = THIS->object_data->enquire;
   Weight * w = (OBJ2_WEIGHT(weight)->object_data->weight);
 
   e->set_weighting_scheme(*w);
   pop_n_elems(args);  
 }
 
 /*  Enquire.void set_query(object query, int termcount) */
 /*! @decl void set_query(object query, int termcount)
  *!
  *!  
  *! @param query
  *!  
 * !
  *! @param termcount
  *!  
 * !
  *!
  */
 PIKEFUN void set_query(object query, int termcount)
 {
   Query * q;
   Enquire  *enquire;
   enquire = THIS->object_data->enquire;
 
   q = OBJ2_QUERY(query)->object_data->query;
 
   enquire->set_query(*q, (Xapian::termcount)termcount);
   pop_n_elems(args);  
 }
 
 /*  Enquire.void set_cutoff(int percent_cutoff, float weight_cutoff) */
 /*! @decl void set_cutoff(int percent_cutoff, float weight_cutoff)
  *!
  *!  
  *! @param percent_cutoff
  *!  
 * !
  *! @param weight_cutoff
  *!  
 * !
  *!
  */
 PIKEFUN void set_cutoff(int percent_cutoff, float weight_cutoff)
 {
   Enquire  *enquire;
   enquire = THIS->object_data->enquire;
 
   enquire->set_cutoff((percent)percent_cutoff, (weight)weight_cutoff);
   pop_n_elems(args);  
 }
 
 /*  Enquire.void set_docid_order(int docid_order) */
 /*! @decl void set_docid_order(int docid_order)
  *!
  *!  
  *! @param docid_order
  *!  
 * !
  *!
  */
 PIKEFUN void set_docid_order(int docid_order)
 {
   Enquire  *enquire;
   enquire = THIS->object_data->enquire;
 
   enquire->set_docid_order((Xapian::Enquire::docid_order)docid_order);
   pop_n_elems(args);  
 }
 
 /*  Enquire.void set_collapse_key(int collapse_key) */
 /*! @decl void set_collapse_key(int collapse_key)
  *!
  *!  
  *! @param collapse_key
  *!  
 * !
  *!
  */
 PIKEFUN void set_collapse_key(int collapse_key)
 {
   Enquire  *enquire;
   enquire = THIS->object_data->enquire;
 
   enquire->set_collapse_key((valueno)collapse_key);
   pop_n_elems(args);  
 }
 
 /*  Enquire.void set_sort_by_relevance_then_value(int sort_key, int ascending) */
 /*! @decl void set_sort_by_relevance_then_value(int sort_key, int ascending)
  *!
  *!  
  *! @param sort_key
  *!  
 * !
  *! @param ascending
  *!  
 * !
  *!
  */
 PIKEFUN void set_sort_by_relevance_then_value(int sort_key, int ascending)
 {
   Enquire  *enquire;
   enquire = THIS->object_data->enquire;
 
   enquire->set_sort_by_relevance_then_value((valueno)sort_key, ascending?true:false);
   pop_n_elems(args);  
 }
 
 /*  Enquire.void set_sort_by_value_then_relevance(int sort_key, int ascending) */
 /*! @decl void set_sort_by_value_then_relevance(int sort_key, int ascending)
  *!
  *!  
  *! @param sort_key
  *!  
 * !
  *! @param ascending
  *!  
 * !
  *!
  */
 PIKEFUN void set_sort_by_value_then_relevance(int sort_key, int ascending)
 {
   Enquire  *enquire;
   enquire = THIS->object_data->enquire;
 
   enquire->set_sort_by_value_then_relevance((valueno)sort_key, ascending?true:false);
   pop_n_elems(args);  
 }
 
 /*  Enquire.void set_sort_value(int sort_key, int ascending) */
 /*! @decl void set_sort_value(int sort_key, int ascending)
  *!
  *!  
  *! @param sort_key
  *!  
 * !
  *! @param ascending
  *!  
 * !
  *!
  */
 PIKEFUN void set_sort_value(int sort_key, int ascending)
 {
   Enquire  *enquire;
   enquire = THIS->object_data->enquire;
 
   enquire->set_sort_by_value((valueno)sort_key, ascending?true:false);
   pop_n_elems(args);  
 }
 
 /*  Enquire.void set_sort_by_relevence() */
 /*! @decl void set_sort_by_relevence()
  *!
  *!  
  *!
  */
 PIKEFUN void set_sort_by_relevence()
 {
   Enquire  *enquire;
   enquire = THIS->object_data->enquire;
 
   enquire->set_sort_by_relevance();
 }
 
 
 /*  Enquire.object get_query() */
 /*! @decl object get_query()
  *!
  *!  
  *! @returns
  *!  
  *!
  */
 PIKEFUN object get_query()
 {
   Enquire  *enquire;
   Query q;
   Query * q2;
   struct object* r;
   enquire = THIS->object_data->enquire;
 
   q = enquire->get_query();  
 
   q2 = new Query(q);  
 
   r = fast_clone_object(Query_program);
 
   OBJ2_QUERY(r)->object_data->query = q2;
 
   push_object(r);
 }
 
 /*  Enquire.object get_mset(int first, int maxitems, object rset, function|void mdecider) */
 /*! @decl object get_mset(int first, int maxitems, object rset, function|void mdecider)
  *!
  *!  
  *! @param first
  *!  
 * !
  *! @param maxitems
  *!  
 * !
  *! @param rset
  *!  
 * !
  *! @returns
  *!  
  *!
  */
 PIKEFUN object get_mset(int first, int maxitems, object rset)
 {
   Enquire  *enquire;
   enquire = THIS->object_data->enquire;
   MSet mset;
   MSet * mset1;
   struct object * o;
   RSet * rseto;
 
   rseto = OBJ2_RSET(rset)->object_data->rset;
 
   try
   {
     mset = enquire->get_mset((doccount)first, (doccount)maxitems, 
             rseto, 0);
 
   }
   catch(InvalidArgumentError &e)
   {
     pop_n_elems(args);
     Pike_error("InvalidArgumentError\n");
   }  
 
   pop_n_elems(args);
 
   o = fast_clone_object(MSet_program);
   mset1 = new MSet(mset);
   OBJ2_MSET(o)->object_data->mset = mset1;
 
   push_object(o);
 
 
 }
 
 PIKEFUN object get_mset(int first, int maxitems, object rset, function mdecider)
 {
   Enquire  *enquire;
   enquire = THIS->object_data->enquire;
   MSet mset;
   MSet * mset1;
   struct object * o;
   RSet * rseto;
   PikeMatchDeciderProxy * md;
 
   rseto = OBJ2_RSET(rset)->object_data->rset;
   
   md = new PikeMatchDeciderProxy(mdecider);
 
   try
   {
     mset = enquire->get_mset((doccount)first, (doccount)maxitems, 
             rseto, md);
 
   }
   catch(InvalidArgumentError &e)
   {
     pop_n_elems(args);
     Pike_error("InvalidArgumentError\n");
   }  
 
   pop_n_elems(args);
 
   o = fast_clone_object(MSet_program);
   mset1 = new MSet(mset);
   OBJ2_MSET(o)->object_data->mset = mset1;
 
   push_object(o);
 
 }
 
 /*  Enquire.object get_mset(int first, int maxitems, int checkatleast) */
 /*! @decl object get_mset(int first, int maxitems, int checkatleast)
  *!
  *!  
  *! @param first
  *!  
 * !
  *! @param maxitems
  *!  
 * !
  *! @param checkatleast
  *!  
 * !
  *! @returns
  *!  
  *!
  */
 PIKEFUN object get_mset(int first, int maxitems, int checkatleast)
 {
   Enquire  *enquire;
   enquire = THIS->object_data->enquire;
   MSet mset;
   MSet * mset1;
   struct object * o;
 
   try
   {
     mset = enquire->get_mset((doccount)first, (doccount)maxitems, 
            (doccount)checkatleast);
 
   }
   catch(InvalidArgumentError &e)
   {
     pop_n_elems(args);
     Pike_error("InvalidArgumentError\n");
   }  
 
   pop_n_elems(args);
 
   o = fast_clone_object(MSet_program);
   mset1 = new MSet(mset);
   OBJ2_MSET(o)->object_data->mset = mset1;
 
   push_object(o);
 }
 
 
 /*  Enquire.object get_eset(int maxitems, object rset, function|void edecider) */
 /*! @decl object get_eset(int maxitems, object rset, function|void edecider)
  *!
  *!  
  *! @param maxitems
  *!  
 * !
  *! @param rset
  *!  
 * !
  *! @param edecider
  *!  
 * !
  *! @returns
  *!  
  *!
  */
 PIKEFUN object get_eset(int maxitems, object rset)
 {
   Enquire  *enquire;
   enquire = THIS->object_data->enquire;
   ESet eset;
   ESet * eset1;
   RSet * rseto;
   struct object * o;
 
   rseto = OBJ2_RSET(rset)->object_data->rset;
  
   try
   {
     eset = enquire->get_eset((termcount)maxitems, *rseto, 0);
 
   }
   catch(InvalidArgumentError &e)
   {
     pop_n_elems(args);
     Pike_error("InvalidArgumentError\n");
   }  
 
   pop_n_elems(args);
 
   o = fast_clone_object(ESet_program);
   eset1 = new ESet(eset);
   OBJ2_ESET(o)->object_data->eset = eset1;
 
   push_object(o);
 }
 
 PIKEFUN object get_eset(int maxitems, object rset, function edecider)
 {
   Enquire  *enquire;
   enquire = THIS->object_data->enquire;
   ESet eset;
   ESet * eset1;
   RSet * rseto;
   struct object * o;
   PikeExpandDeciderProxy * ed;
 
   ed = new PikeExpandDeciderProxy(edecider);
 
   rseto = OBJ2_RSET(rset)->object_data->rset;
  
   try
   {
     eset = enquire->get_eset((termcount)maxitems, *rseto, ed);
 
   }
   catch(InvalidArgumentError &e)
   {
     pop_n_elems(args);
     Pike_error("InvalidArgumentError\n");
   }  
 
   pop_n_elems(args);
 
   o = fast_clone_object(ESet_program);
   eset1 = new ESet(eset);
   OBJ2_ESET(o)->object_data->eset = eset1;
 
   push_object(o);
 }
 
 /*  Enquire.object get_eset(int maxitems, object rset, int flags, float k, function|void edecider) */
 /*! @decl object get_eset(int maxitems, object rset, int flags, float k, function|void edecider)
  *!
  *!  
  *! @param maxitems
  *!  
 * !
  *! @param rset
  *!  
 * !
  *! @param flags
  *!  
 * !
  *! @param k
  *!  
 * !
  *! @param edecider
  *!  
 * !
  *! @returns
  *!  
  *!
  */
 PIKEFUN object get_eset(int maxitems, object rset, int flags, float k, function edecider)
 {
   Enquire  *enquire;
   enquire = THIS->object_data->enquire;
   ESet eset;
   ESet * eset1;
   RSet * rseto;
   struct object * o;
   PikeExpandDeciderProxy * ed;
 
   ed = new PikeExpandDeciderProxy(edecider);
 
   rseto = OBJ2_RSET(rset)->object_data->rset;
  
   try
   {
     eset = enquire->get_eset((termcount)maxitems, *rseto, (int)flags, (double)k, ed);
 
   }
   catch(InvalidArgumentError &e)
   {
     pop_n_elems(args);
     Pike_error("InvalidArgumentError\n");
   }  
 
   pop_n_elems(args);
 
   o = fast_clone_object(ESet_program);
   eset1 = new ESet(eset);
   OBJ2_ESET(o)->object_data->eset = eset1;
 
   push_object(o);
 }
 
 PIKEFUN object get_eset(int maxitems, object rset, int flags, float k)
 {
   Enquire  *enquire;
   enquire = THIS->object_data->enquire;
   ESet eset;
   ESet * eset1;
   RSet * rseto;
   struct object * o;
 
   rseto = OBJ2_RSET(rset)->object_data->rset;
  
   try
   {
     eset = enquire->get_eset((termcount)maxitems, *rseto, (int)flags, (double)k, 0);
 
   }
   catch(InvalidArgumentError &e)
   {
     pop_n_elems(args);
     Pike_error("InvalidArgumentError\n");
   }  
 
   pop_n_elems(args);
 
   o = fast_clone_object(ESet_program);
   eset1 = new ESet(eset);
   OBJ2_ESET(o)->object_data->eset = eset1;
 
   push_object(o);
 }
 
 /*! @decl object get_matching_terms(int docid)
  *!
  *! @returns
  *!   a @[TermIterator] object which can also be passed to @[foreach]()
  */
 PIKEFUN object get_matching_terms(int docid)
 {
   TermIterator ti;
   TermIterator * ti2;
   struct object * o;
 
   Enquire  *enquire;
   enquire = THIS->object_data->enquire;
 
 
   ti = enquire->get_matching_terms_begin(docid);
   ti2 = new TermIterator(ti);
 
   o = fast_clone_object(TermIterator_program);
 
   OBJ2_TERMITERATOR(o)->object_data->termi = ti2;
   OBJ2_TERMITERATOR(o)->tie = new TermIterator(enquire->get_matching_terms_end(docid));
 
   push_object(o);    
 
 }
 
 /*  Enquire.string get_description() */
 /*! @decl string get_description()
  *!
  *!  
  *! @returns
  *!  
  *!
  */
 PIKEFUN string get_description()
 {
   Enquire  *enquire;
   enquire = THIS->object_data->enquire;
 
   string str = enquire->get_description();
 
   push_text(str.c_str());
 }
 
 PIKEFUN string _sprintf(int conversion_type, mapping params)
 {
   Enquire  *enquire;
   if(THIS && THIS->object_data && conversion_type == 'O')
   {
     enquire = THIS->object_data->enquire;
 
     string str = enquire->get_description();
     pop_n_elems(args);
     push_text(str.c_str());
   }
   else
   {
     pop_n_elems(args);
     push_int(0);
   }
 }
 
 
 INIT
 {
     XAPIAN_ENQUIRE_OBJECT_DATA * dta = 
 	(XAPIAN_ENQUIRE_OBJECT_DATA*)malloc(sizeof(XAPIAN_ENQUIRE_OBJECT_DATA));
     if (!dta)
         Pike_error("init_sample: Out of memory!\n");
 
     dta->enquire = NULL;
     THIS->object_data = dta;
 }
 
 EXIT 
 {
   if(THIS->object_data)
   {
     Enquire  *enquire;
     enquire = THIS->object_data->enquire;
     // if(enquire) delete enquire;
     free(THIS->object_data);
   }
 }
 
 EXTRA
 {
   add_integer_constant("ASCENDING", Enquire::ASCENDING, 0);
   add_integer_constant("DESCENDING", Enquire::DESCENDING, 0);
   add_integer_constant("DONT_CARE", Enquire::DONT_CARE, 0);
 }
 
 }
 
 
 INIT
 {
 }
 EXIT
 {
 }
 EXTRA
 {
 /*! @decl constant DB_CREATE_OR_OPEN 
  *! @decl constant DB_CREATE
  *! @decl constant DB_CREATE_OR_OVERWRITE
  *! @decl constant DB_OPEN
  *! @decl constant BAD_VALUENO
  */
 add_integer_constant("DB_CREATE_OR_OPEN", DB_CREATE_OR_OPEN, 0);
 add_integer_constant("DB_CREATE", DB_CREATE, 0);
 add_integer_constant("DB_CREATE_OR_OVERWRITE", DB_CREATE_OR_OVERWRITE, 0);
 add_integer_constant("DB_OPEN", DB_OPEN, 0);
 add_integer_constant("BAD_VALUENO", BAD_VALUENO, 0);
 }
 
 /*!  @endclass
  */
 
+
+/*! @class TermGenerator
+*/
+PIKECLASS TermGenerator
+{
+CVAR XAPIAN_TERMGENERATOR_OBJECT_DATA   *object_data;
+
+
+PIKEFUN int set_flags(int flags, int mask)
+{
+  TermGenerator * termgenerator;
+  termgenerator = (TermGenerator*)THIS->object_data->termgenerator;
+
+  TermGenerator::flags f;
+  TermGenerator::flags m;
+
+  f = (TermGenerator::flags)flags;
+  m = (TermGenerator::flags)mask;
+
+  termgenerator->set_flags(f, m);
+
+  pop_n_elems(args);
+}
+
+/*  TermGenerator.void set_document(object document) */
+/*! @decl void set_document(object document)
+ *!
+ *!  
+ *! @param document
+ *!  
+* !
+ *! @returns
+ *!  
+ *!
+ */
+PIKEFUN void set_document(object document)
+{
+  TermGenerator * termgenerator;
+  Document * doc;
+  docid id;
+
+  struct Document_struct * od;
+
+  termgenerator = (TermGenerator*)THIS->object_data->termgenerator;
+  od = OBJ2_DOCUMENT(document);
+
+  if(!od) Pike_error("Not a Document!\n");
+
+  doc = od->object_data->document;
+
+  try
+  {
+    termgenerator->set_document(*doc);
+  }
+  catch(Xapian::DatabaseCorruptError &e)
+  {
+    Pike_error("DatabaseCorruptError\n");
+  }
+  catch(Xapian::DatabaseError &e)
+  {
+    Pike_error("DatabaseError\n");
+  }
+  catch(Xapian::InvalidArgumentError &e)
+  {
+    //printf("%s\n",e.get_msg().c_str());
+    Pike_error("InvalidArgumentError\n");
+  }
+  pop_n_elems(args);
+}
+
+  PIKEFUN object get_document()
+  {
+    TermGenerator * termgenerator;
+    Document doc;
+    Document *doc2;
+    struct object * o;
+    try {
+    termgenerator = (TermGenerator*)THIS->object_data->termgenerator;
+    doc = termgenerator->get_document();    
+    doc2 = new Document(doc);
+
+    o = fast_clone_object(Document_program);
+    OBJ2_DOCUMENT(o)->object_data->document = doc2;
+
+    push_object(o);
+  }
+  catch(RangeError &e)
+  {
+    pop_n_elems(args);
+    Pike_error("RangeError\n");
+  }
+
+  }
+
+/*  TermGenerator.void set_stemmer(object stemmer) */
+/*! @decl void set_stemmer(object stemmer)
+ *!
+ *!  
+ *! @param stemmer
+ *!  
+* !
+ *!
+ */
+PIKEFUN void set_stemmer(object stemmer)
+{
+  TermGenerator * termgenerator;
+  Stem * s;
+
+  termgenerator = THIS->object_data->termgenerator;
+  s = OBJ2_STEM(stemmer)->object_data->stem; 
+  termgenerator->set_stemmer((const Stem)*s);
+
+  pop_n_elems(args);
+}
+
+/*  TermGenerator.void set_stopper(object stopper) */
+/*! @decl void set_stopper(object stopper)
+ *!
+ *!  
+ *! @param stopper
+ *!  
+* !
+ *!
+ */
+PIKEFUN void set_stopper(object stopper)
+{
+  TermGenerator * termgenerator;
+  Stopper * s;
+
+  termgenerator = THIS->object_data->termgenerator;
+  s = OBJ2_STOPPER(stopper)->object_data->stopper; 
+  termgenerator->set_stopper((const Stopper*)s);
+
+  pop_n_elems(args);
+}
+
+/*  TermGenerator.void set_database(object database) */
+/*! @decl void set_database(object database)
+ *!
+ *!  
+ *! @param database
+ *!  
+ *!
+ *!
+ */
+PIKEFUN void set_database(object database)
+{
+  TermGenerator * termgenerator;
+  Database * d;
+
+  termgenerator = THIS->object_data->termgenerator;
+  d = OBJ2_DATABASE(database)->object_data->database; 
+
+  termgenerator->set_database((const Xapian::WritableDatabase&)*d);
+
+  pop_n_elems(args);
+}
+
+
+
+INIT
+{
+    XAPIAN_TERMGENERATOR_OBJECT_DATA * dta = 
+	(XAPIAN_TERMGENERATOR_OBJECT_DATA*)malloc(sizeof(XAPIAN_TERMGENERATOR_OBJECT_DATA));
+    if (!dta)
+        Pike_error("init_sample: Out of memory!\n");
+
+    dta->termgenerator = NULL;
+    THIS->object_data = dta;
+}
+
+/*  Weight.void destroy() */
+/*! @decl void destroy()
+ *!
+ *!  
+ *!
+ */
+PIKEFUN void destroy()
+{
+
+    TermGenerator * termgenerator;
+    termgenerator = THIS->object_data->termgenerator;
+
+    if(termgenerator) 
+    {
+     delete termgenerator;
+    }
+
+}
+
+EXIT 
+{
+  if(THIS->object_data)
+  {
+
+    TermGenerator  *termgenerator;
+    termgenerator = THIS->object_data->termgenerator;
+//    printf("shutting down!\n");
+    free(THIS->object_data);
+  }
+}
+
+}
+
+/*!  @endclass
+*/
+
+
 /*! @endmodule
  */
 
 /*! @endmodule
  */