home *** CD-ROM | disk | FTP | other *** search
/ Internet Publisher's Toolbox 1.0 / Image.iso / toolbox / ntserver / wtsource / waisinde.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-03-22  |  63.3 KB  |  1,681 lines

  1. /* WIDE AREA INFORMATION SERVER SOFTWARE:
  2.    No guarantees or restrictions.  See the readme file for the full standard
  3.    disclaimer.
  4.  
  5.    Brewster@think.com
  6. */
  7.  
  8. /* Copyright (c) CNIDR (see ../COPYRIGHT) */
  9.  
  10.  
  11. #ifndef lint
  12. static char *RCSid = "$Header: /archives/stelar/src/freeWAIS/freeWAIS-0.2/ir/RCS/waisindex.c,v 1.5 93/07/21 18:53:04 warnock Exp $";
  13. #endif
  14.  
  15. /*
  16.  * Building an index with a Unix shell interface.
  17.  *
  18.  * -brewster 6/90
  19.  */
  20.  
  21. /* Change log:
  22.  * added -stdio option from jik@athena.mit.edu
  23.  * $Log:    waisindex.c,v $
  24.  * Revision 1.5  93/07/21  18:53:04  warnock
  25.  * Renamed from irbuild.c
  26.  * Added STELAR-specific patches
  27.  *
  28.  * $Log: irbuild.c,v $
  29.  * Revision 1.8  1993/10/12  11:18:25  pfeifer
  30.  * Added stopword file for document style bibdb
  31.  * 
  32.  * Revision 1.1  93/07/19  16:30:22  warnock
  33.  * Initial revision
  34.  *
  35.  * Revision 1.7  1993/09/22  16:09:13  pfeifer
  36.  * What have i done ?
  37.  *
  38.  * Revision 1.4  93/07/01  19:40:31  warnock
  39.  * Added prototype for function double
  40.  *
  41.  * Revision 1.6  1993/06/04  10:23:15  pfeifer
  42.  * Pachtlevel BIBDB
  43.  * 
  44.  * Revision 1.3  93/02/16  17:07:49  freewais
  45.  *
  46.  * Revision 1.5  1993/06/02  18:29:00  pfeifer
  47.  * Added code for local formats
  48.  *
  49.  * Revision 1.4  1993/06/01  14:05:54  pfeifer
  50.  * Added code for soundex/phonix indexing and retrieval
  51.  *
  52.  * Revision 1.3  1993/02/16  17:07:49  freewais
  53.  * added AT&T patches for keyword list
  54.  * 
  55.  * Revision 1.2  1993/02/16  15:32:21  freewais
  56.  * added AT&T patch to write first 50 dictionary entries to
  57.  * src file
  58.  *
  59.  * Revision 1.1  1993/02/16  15:05:35  freewais
  60.  * Initial revision
  61.  *
  62.  * Revision 1.47  92/05/10  14:48:17  jonathan
  63.  * Updated for release.
  64.  * 
  65.  * Revision 1.46  92/05/08  10:03:17  jonathan
  66.  * Adjusted memory paramters.  It's closer...
  67.  * 
  68.  * Revision 1.45  92/05/06  17:26:46  jonathan
  69.  * Added switch for indexing contents, new user-specified type name, new type:
  70.  * filename, which only puts the name of the file in the header.
  71.  * 
  72.  * Revision 1.44  92/04/25  21:14:35  brewster
  73.  * added ziff
  74.  * 
  75.  * Revision 1.43  92/04/22  15:29:13  jonathan
  76.  * Added jargon to usage message.
  77.  * 
  78.  * Revision 1.42  92/04/01  17:08:50  jonathan
  79.  * Added FTP type.
  80.  * 
  81.  * Revision 1.41  92/03/25  18:49:39  jonathan
  82.  * Added log_level and log_file arguments.
  83.  * 
  84.  * Revision 1.40  92/03/22  18:38:14  brewster
  85.  * added objective C filter
  86.  * 
  87.  * Revision 1.39  92/03/20  11:02:44  jonathan
  88.  * Added code to handle switches for word_pairs and word_postition info.
  89.  * 
  90.  * Revision 1.38  92/03/17  07:34:32  jonathan
  91.  * Fixed spacing in usage message.
  92.  * 
  93.  * Revision 1.37  92/03/10  10:42:51  morris
  94.  * fixed small bug in command line argument handleing.  doesn't die if there
  95.  * are no args.
  96.  * 
  97.  * Revision 1.36  92/03/05  07:05:32  shen
  98.  * add cm grow percent and textsize to command line and init search engine
  99.  * 
  100.  * Revision 1.35  92/03/04  16:34:09  jonathan
  101.  * Set wais_pid from getpid().
  102.  * 
  103.  * Revision 1.34  92/02/20  09:49:37  jonathan
  104.  * Added bibtex and nhyp filters from S.P.vandeBurgt@research.ptt.nl.
  105.  * 
  106.  * Revision 1.33  92/02/17  14:21:08  jonathan
  107.  * Added switch to disable creation of catalog (-nocat).
  108.  * 
  109.  * Revision 1.32  92/02/17  12:41:55  jonathan
  110.  * Added RCSid.
  111.  * 
  112.  * Revision 1.31  92/02/17  12:41:01  jonathan
  113.  * Build catalog after completion of indexing.
  114.  * 
  115.  * Revision 1.30  92/02/12  13:22:53  jonathan
  116.  * Added "$Log" so RCS will put the log message in the header
  117.  * 
  118.  */
  119.  
  120. /* to do:
  121.  *   done: make incremental indexing not index things that are already index
  122.  *   add extra arg -register that will send in description of the server to 
  123.  *           the directory of servers.
  124.  *   done: create a source struct in the .src file
  125.  *   make it continuously index to keep itself uptodate.
  126.  *
  127.  */
  128.  
  129. #include <string.h>
  130. #include <sys/types.h>
  131. #ifndef WIN32
  132. #include <sys/param.h>
  133. #endif
  134. #include "irdirent.h"
  135. #include "cutil.h"
  136. #include "futil.h"
  137. #include "irfiles.h"
  138. #include "irtfiles.h"
  139. #include "panic.h"
  140. #include "ircfiles.h"
  141. #include "version.h"
  142. #include "irext.h"
  143. #include "stoplist.h"   /* dgg */
  144.  
  145. #ifdef WIN32
  146. #include <windows.h>
  147. #include <io.h>
  148. #include <fcntl.h>
  149. #define MAXPATHLEN 260
  150. int read_src_structure(char*,char**);
  151. int retreive_keywords(database*);
  152. #endif
  153.  
  154. #ifdef BIO
  155. #define INDEXER_DATE "2/16/93"
  156. #else
  157. #define INDEXER_DATE "2/16/93"
  158. #endif
  159. #define MAX_LINE_LENGTH 1000
  160.  
  161. extern char *keyword[50], *descript[1000];
  162. extern short nKeys, nDesLines;
  163. extern double compare();
  164.  
  165. /* for reporting errors, in WAIStation it is defined in CRetrievalApp.c */
  166.  
  167. extern boolean indexingForBeta;
  168.  
  169. void usage(command)
  170. char *command;
  171. { /* no args */
  172.   fprintf(stderr,"Usage: %s [-d index_filename]\n", command);
  173.   fprintf(stderr,"          [-a] /* adding to an existing index, otherwise it erases the index */\n");
  174.   fprintf(stderr,"          [-r] /* recursively index subdirectories */\n");
  175.   fprintf(stderr,"          [-mem mbytes] /* number of megabytes to run this in */\n");
  176.   fprintf(stderr,"          [-register] /* registers the database with the directory of servers.\n");
  177.   fprintf(stderr,"                         This should be done with care. */\n");
  178.   fprintf(stderr,"          [-export] /* uses short dbname and port 210 */\n");
  179.   fprintf(stderr,"          [-e [file]] /* set log output to file, or /dev/null if not specified */\n");
  180.   fprintf(stderr,"          [-l log_level] /* set log level.  0 means log nothing,\n");
  181.   fprintf(stderr,"                            10 [the default] means log everything */\n");
  182.   fprintf(stderr,"          [-v] /* print the version of the software */\n");
  183.   fprintf(stderr,"          [-filter process] /* use an external document parser */\n");
  184.   fprintf(stderr,"          [-stdin] /* read file names from stdin */\n");
  185.   fprintf(stderr,"          [-pos | -nopos] /* include (don't include - default) word position information /*\n");
  186.   fprintf(stderr,"          [-nopairs | -pairs] /* don't include (or include - default) word pairs /*\n");
  187.   fprintf(stderr,"          [-nocat] /* inhibit creation of catalog /*\n");
  188.   fprintf(stderr,"          [-contents] /* Index the contents: this is good for types that\n");
  189.   fprintf(stderr,"                         inhibit the indexing of the contents (like gif). /*\n");
  190.   fprintf(stderr,"          [-nocontents] /* Index only the filename, not the contents /*\n");
  191. #ifdef BIO
  192.   fprintf(stderr,"          [-stop stoplist_filename] /* file of common words to ignore */\n");
  193.   fprintf(stderr,"          [-delim delimiters] /* list of word delimiter symbols */\n");
  194. #endif 
  195.   fprintf(stderr,"          [-keywords \"<string>\"] /* Keywords to index for each document. */\n");
  196.   fprintf(stderr,"          [-keyword_file <filename>] /* File of keywords to index. */\n");
  197.  
  198.   fprintf(stderr,"          [-cmmem  mem%] /* percent of CM memory (CM code only) */\n");
  199.   fprintf(stderr,"          [-T  type] /* type becomes the \"TYPE\" of the document. */\n");
  200. /* multitype extensions */
  201.   fprintf(stderr,"          [-M  type,type] /* for multi-type documents. */\n");
  202. #ifdef WIN32
  203.   fprintf(stderr,"          [-x  filename,filename] /* ignore the filename(s). */\n");
  204. #endif
  205.   fprintf(stderr,"          [-t /* format of the file. if none then each file is a document */\n");
  206.   fprintf(stderr,"             text /* simple text files, this is the default */\n");
  207.   fprintf(stderr,"           | bibtex /* BibTeX / LaTeX format */\n");
  208.   fprintf(stderr,"           | bio /* biology abstract format */\n");
  209.   fprintf(stderr,"           | cmapp /* CM applications from Hypercard */\n");
  210.   fprintf(stderr,"           | dash /* entries separated by a row of dashes */\n");
  211.   fprintf(stderr,"           | dvi /* dvi format */\n");     
  212.   fprintf(stderr,"           | emacsinfo /* the GNU documentation system */\n");
  213.   fprintf(stderr,"           | first_line /* first line of file is headline */\n");
  214.   fprintf(stderr,"           | filename /* uses only the filename part of the pathname for the title */\n");
  215.   fprintf(stderr,"           | ftp /* special type for FTP files.  First line of file is headline */\n");
  216.   fprintf(stderr,"           | gif /* gif files, only indexes the filename */\n");
  217.   fprintf(stderr,"           | irg /* internet resource guide */\n");
  218.   fprintf(stderr,"           | jargon /* Jargon File 2.9.8 format*/\n");
  219.   fprintf(stderr,"           | listserv_digest /* standard internet mail digest format */\n");
  220.   fprintf(stderr,"           | mail_digest /* standard internet mail digest format */\n");
  221.   fprintf(stderr,"           | mail_or_rmail /* mail or rmail or both */\n");
  222.   fprintf(stderr,"           | medline /* medline format */\n");
  223.   fprintf(stderr,"           | mh_bboard /* MH bulletin board format */\n");
  224. #ifdef WIN32
  225.   fprintf(stderr,"           | ms_kbase /* MS Knowledge Base format */\n");
  226. #endif
  227.   fprintf(stderr,"           | netnews /* netnews format */\n");
  228.   fprintf(stderr,"           | nhyp /* ?:? hyper text format, Polytechnic of Central London */\n");
  229.   fprintf(stderr,"           | one_line /* each line is a document */\n");
  230.   fprintf(stderr,"           | para /* paragraphs separated by blank lines */\n");
  231.   fprintf(stderr,"           | pict /* pict files, only indexes the filename */\n");
  232.   fprintf(stderr,"           | ps /* postscript format */\n");
  233.   fprintf(stderr,"           | refer /* refer format */\n");
  234. #ifdef BIBDB
  235.   fprintf(stderr,"           | irlist           /* irlist mail or rmail or both */\n");  
  236.   fprintf(stderr,"           | formfeed         /* entries separated by a formfeed */\n");
  237.   fprintf(stderr,"           | bibdb            /* steve file entries separated by a formfeed */\n");
  238.   fprintf(stderr,"           | bibinf           /* bibinf entries separated by an empty line */\n");
  239. #endif
  240.   fprintf(stderr,"           | rn /* netnews saved by the [rt]?rn newsreader */\n");
  241.   fprintf(stderr,"           | server /* server structures for the dir of servers */\n");
  242. #ifdef NeXT
  243.   fprintf(stderr,"           | objc /* objective-C .h and .m files */\n");
  244. #endif /* def NeXT */
  245.   fprintf(stderr,"           | tiff /* tiff files, only indexes the filename */\n");
  246.   fprintf(stderr,"           | URL what-to-trim what-to-add /* URL */\n");
  247.   fprintf(stderr,"           | object /* a structured object*/\n");
  248.   fprintf(stderr,"           | inriadoc /* INRIA library catalog */\n");
  249.   fprintf(stderr,"           | paradoc /* INRIA library catalog para-mode */\n ");
  250.   fprintf(stderr,"           | fortran /* Fortran files,needs also -filter */\n");
  251.   fprintf(stderr,"           | mime /* Like mail */\n");
  252.  
  253. #ifdef BIO
  254.   fprintf(stderr,"           | genbank  /* GenBank flatfile format */\n");
  255.   fprintf(stderr,"           | embl     /* EMBL flatfile format */\n");
  256.   fprintf(stderr,"           | pir     /* PIR flatfile format */\n");
  257.   fprintf(stderr,"           | prositedoc /* Prosite protein doc format */\n");
  258.   fprintf(stderr,"           | prositedat /* Prosite protein dat format */\n");
  259.   fprintf(stderr,"           | biojournal /* Bio journal TOC on bionet.journals */\n");
  260.   fprintf(stderr,"           | redbook  /* Drosophila redbook text */\n");
  261.   fprintf(stderr,"           | flybase  /* Drosophila Ashburner data files */\n");
  262.   fprintf(stderr,"           | flystock  /* Drosophila stock lists */\n");
  263.   fprintf(stderr,"           | din      /* Drosophila Info. Newsletter */\n");
  264. #endif
  265. #ifdef SOUND
  266.   fprintf(stderr,"           | oneline_phonix   /* Phonebooks PHONIX */\n");
  267.   fprintf(stderr,"           | oneline_soundex  /* Phonebooks SOUNDEX */\n");
  268. #endif
  269. #ifdef AAS
  270.   fprintf(stderr,"           | AAS_abstract /* AAS meeting abstracts using AAS LaTeX macros */\n");
  271. #endif /* AAS */
  272. #ifdef STELAR
  273.   fprintf(stderr,"           | stelar /* stelar abstracts - third line is hl */\n");
  274. #endif /* STELAR */
  275. #ifdef HTML
  276.   fprintf(stderr,"           | html /* Hypertext Markup Language from WWW */\n");
  277. #endif /* HTML */
  278.   fprintf(stderr,"          ] filename filename ...\n");
  279. }
  280.  
  281. /* char *log_file_name = NULL; */
  282. FILE *logfile;
  283.  
  284. extern char* keywords;           /* used in irtfiles.c */
  285. extern char* keyword_filename;   /* used in irtfiles.c */
  286. #ifdef WIN32
  287. extern char ExcludeFiles[];      /* used in irtfiles.c */
  288. #endif
  289.  
  290. extern boolean index_contents;
  291.  
  292.  
  293. /* This is the MAIN for building an index.
  294.  */
  295. void
  296. main(argc, argv)
  297. int argc;
  298. char *argv[];
  299. {
  300.   database* db = NULL;
  301.   long argc_copy = argc;
  302.   char **argv_copy = argv;
  303.   char *next_argument;
  304.   char index_filename[1000];
  305.   boolean adding_to_existing_index = false;
  306.   boolean traverse_directory = false;
  307.   boolean word_positions = false;
  308.   boolean word_pairs = true;
  309.   long memory_to_use = -1;
  310.   long cm_mem_percent = 0;  /* default */
  311.   long grow_percent = 0;  /* default */
  312.   long text_size = 0;  /* default */
  313.   boolean check_for_text_file = false;
  314.   boolean register_database = false;
  315.   boolean export_database = false;
  316.   boolean read_files_from_stdin = false;
  317.   boolean make_catalog = true;
  318.   char data_filename[MAXPATHLEN];
  319.   char *typename = NULL;  /* this is what the user said */
  320.   long start_of_filenames;
  321.   long hashtable_size = 1L<<16;
  322.   long flush_after_n_words = 300000;
  323.   char *command_name;
  324.   char *filter_name = NULL;
  325.   FILE *filter_process_in = NULL;
  326.   FILE *filter_process_out = NULL;
  327. #ifdef WIN32
  328.   PROCESS_INFORMATION piProcInfo;
  329. #endif
  330.  
  331.  
  332.   dataopsrec    dataops;    
  333.   /*-------------   these go into dataops   
  334.   boolean (*separator_function)();
  335.   void (*header_function)();
  336.   void (*finish_header_function)();
  337.   long (*date_function)();
  338.   char *type = NULL;     
  339.   int minwordlen= 2;     
  340.   ---------------*/
  341.   
  342.         /* dgg -- put all of these separate, datatype-specific functions & params into a record! */
  343.   gDelimiters[0]= '\0'; /* <-- bombs ?? */
  344.   dataops.separator_function= NULL;
  345.   dataops.header_function= NULL;
  346.   dataops.date_function= NULL;
  347.   dataops.finish_header_function= NULL;
  348.   dataops.type= "TEXT";
  349.   dataops.indextype= NULL;
  350.   dataops.multitype=NULL;
  351.   dataops.addseparatorwords= false;
  352.   dataops.extraheaderweight= true;
  353.   dataops.repeat_weight= 1;
  354.   dataops.minwordlen= 2;
  355.   dataops.wordDelimiter= wordbreak_notalnum;
  356.   dataops.delimiters= gDelimiters;
  357.   wordDelimiter= wordbreak_notalnum;   
  358.  
  359.   /*------
  360.   separator_function = NULL; 
  361.   header_function = NULL;
  362.   date_function = NULL;
  363.   finish_header_function = NULL;
  364.   type = "TEXT";  
  365.   -------*/
  366.   typename = "Text"; 
  367.   
  368.  
  369.   next_argument = next_arg(&argc, &argv);
  370.   command_name = next_argument;
  371.  
  372.   logfile = stderr;
  373.  
  374. #ifdef WIN32
  375.   wais_pid = GetCurrentProcessId();
  376. #else
  377.   wais_pid = getpid();
  378. #endif
  379.  
  380.   if(0 == argc) {
  381.     usage(command_name);
  382.     exit(0);
  383.   }
  384.  
  385. #ifdef THINK_C
  386.   strcpy(index_filename, "wais:System Folder:wais-index:index");
  387. #else
  388.   strcpy(index_filename, "index"); /* in the current directory */
  389. #endif /* THINK_C */
  390.   stop_list_file("\0");     /* dgg */
  391.   
  392.   if(NULL == (next_argument = next_arg(&argc, &argv))){
  393.     fprintf(stderr,"No arguments specified\n");
  394.     exit(0);
  395.   }
  396.   while((next_argument != NULL) && '-' == next_argument[0]){
  397.     /* then we have an argument to process */
  398.     if((0 == strcmp("-i", next_argument)) || /* -i is for backcompatibility */
  399.        (0 == strcmp("-d", next_argument))){
  400.       if(NULL == (next_argument = next_arg(&argc, &argv))){
  401.     fprintf(stderr,"Expected filename for the index\n");
  402.     exit(0);
  403.         }
  404.       strcpy(index_filename, next_argument);
  405.       }
  406. #ifdef BIO      
  407.     else if (0 == strcmp("-stop", next_argument)){      /* dgg, stoplist file */
  408.       if (NULL == (next_argument = next_arg(&argc, &argv))){
  409.     fprintf(stderr,"Expected filename for the stoplist\n");
  410.     exit(0);
  411.         }
  412.       stop_list_file(next_argument);
  413.       } 
  414.     else if (0 == strcmp("-delim", next_argument)){     /* dgg, delimiters */
  415.       if (NULL == (next_argument = next_arg(&argc, &argv))){
  416.     fprintf(stderr,"Expected the delimiters argument\n");
  417.     exit(0);
  418.         }
  419.       strcpy(gDelimiters, next_argument);
  420.       dataops.wordDelimiter = wordbreak_user;
  421.       wordDelimiter = wordbreak_user;
  422.       printf("Delimiters used in index: %s\n\n",gDelimiters);
  423.       } 
  424. #endif
  425.  
  426.     else if(0 == strcmp("-a", next_argument)){
  427.       adding_to_existing_index = true;
  428.     }
  429.     else if(0 == strcmp("-r", next_argument)){
  430.       traverse_directory = true;
  431.     }
  432.     else if(0 == strcmp("-register", next_argument)){
  433.       register_database = true;
  434.     }
  435.     else if(0 == strcmp("-export", next_argument)){
  436.       export_database = true;
  437.     }
  438.     else if(0 == strcmp("-v", next_argument)){
  439.       fprintf(stderr,"%s: %s %s\n", command_name, VERSION, INDEXER_DATE);
  440. #ifdef WIN32
  441.       fprintf(stderr,"%s\n",VERWIN32);
  442.       if (argc_copy == 2)
  443.         exit(0);
  444. #endif
  445.     }
  446.     else if (0 == strcmp("-stdin", next_argument)) {
  447.       read_files_from_stdin = true;
  448.     }
  449.     else if (0 == strcmp("-nopos", next_argument)) {
  450.       word_positions = false;
  451.     }
  452.     else if (0 == strcmp("-pos", next_argument)) {
  453.       word_positions = true;
  454.     }
  455.     else if (0 == strcmp("-nopairs", next_argument)) {
  456.       word_pairs = false;
  457.     }
  458.     else if (0 == strcmp("-pairs", next_argument)) {
  459.       word_pairs = true;
  460.     }
  461.     else if (0 == strcmp("-nocat", next_argument)) {
  462.       make_catalog = false;
  463.     }
  464.     else if(0 == strcmp("-mem", next_argument)){
  465.       if(NULL == (next_argument = next_arg(&argc, &argv)))
  466.     panic("Expected a number for the amount of memory to use");
  467.       memory_to_use = atol(next_argument);
  468.       if(memory_to_use < 1)
  469.     panic("The -mem argument should not be less than 1");
  470.       if(memory_to_use > 200)
  471.     fprintf(stderr,"Warning: The -mem parameter was %ld Mbytes.  That is a large number of mega bytes in current machines\n", memory_to_use);
  472.     }
  473.     else if(0 == strcmp("-cmmem", next_argument)){
  474.       if(NULL == (next_argument = next_arg(&argc, &argv)))
  475.     panic("Expected a number (1-100) for percentage of memory to use");
  476.       cm_mem_percent = atol(next_argument);
  477.       if(cm_mem_percent < 1)
  478.     panic("The -cmmem argument should not be less than 1 and less than 100");
  479.       if(cm_mem_percent > 100)
  480.     panic("Warning: The -cmmem parameter was %ld%%. It should be between 1-100.", cm_mem_percent);
  481.     }
  482.        else if(0 == strcmp("-filter", next_argument)){
  483.        if(NULL == (next_argument = next_arg(&argc, &argv)))
  484.        panic("Expected the name of a program to use to find keywords");
  485.        filter_name=next_argument;
  486.     }
  487.     else if(0 == strcmp("-grow", next_argument)){
  488.       if(NULL == (next_argument = next_arg(&argc, &argv)))
  489.         panic("Expected a number (1-100) for database growing percentage");
  490.       grow_percent = atol(next_argument);
  491.       if(grow_percent < 1)
  492.         panic("The -grow argument should not be less than 1");
  493.     }
  494.     else if(0 == strcmp("-textsize", next_argument)){
  495.       if(NULL == (next_argument = next_arg(&argc, &argv)))
  496.         panic("Expected a number for text size in megabytes");
  497.       text_size = atol(next_argument);
  498.       if(text_size < 1)
  499.         panic("The -textsize argument should not be less than 1");
  500.     }
  501.     else if (0 == strcmp("-e", next_argument)) {
  502.       char *peek_argument = peek_arg(&argc, &argv);
  503. #ifdef WIN32
  504.       log_file_name = "NUL:"; /* default to NUL: */
  505. #else
  506.       log_file_name = "/dev/null"; /* default to /dev/null */
  507. #endif
  508.       if ((peek_argument != NULL) &&
  509.       ('-' != peek_argument[0])) {
  510.     log_file_name = next_arg(&argc, &argv);
  511.       }             /* end if (explicit log file) */
  512.     }               /* end if (-e) */
  513.     else if (0 == strcmp("-l", next_argument)) {
  514. #ifdef WIN32
  515.       char *pNextArg = next_arg(&argc, &argv);
  516.       if (pNextArg!=NULL) {
  517.         wais_log_level = atol(pNextArg);
  518.       } else {
  519.         panic("Expected a log-level argument");
  520.       }
  521. #else
  522.       wais_log_level = atol(next_arg(&argc, &argv));
  523. #endif
  524.     }               /* end if (-l) */
  525.     else if(0 == strcmp("-cm", next_argument)){
  526.       /* this is an undocumented argument to help use this to
  527.      front end the CM application */
  528.       indexingForBeta = true;
  529.     }
  530.     else if(0 == strcmp("-T", next_argument)){
  531.       /* This is a specification for a "Special" type.  The next argument
  532.      is the type name.  This will not index the body of the file. */
  533.       if(NULL == (next_argument = next_arg(&argc, &argv)))
  534.     panic("Expected a file type");
  535.       typename = next_argument;
  536.       dataops.type = next_argument;
  537.       fprintf(stderr,"waisindex: setting type to %s\n", next_argument);
  538.       dataops.finish_header_function = filename_finish_header_function;
  539.     }
  540.  
  541. /* multitype extensions */
  542. /* 
  543.    This is a specification for a multi-type document, the types should
  544.    be entered as a comma delimited list.  Note that this only defines
  545.    all the types available in the database, you also need to specify a
  546.    -t option so that the indexer knows how to parse the files. 
  547.    One of the limitations here is that each document must
  548.    be a file with the extension of the file being the document type, so
  549.    the document #### has a text file ####.TEXT and a jfif file
  550.    ####.JFIF, not real nice but needed.
  551.  
  552.    Note that this contains both the primary and secondary document
  553.    types, whereas dataops.type contains the primary type.
  554. */
  555.  
  556.     else if(0 == strcmp("-M", next_argument)){
  557.       if(NULL == (next_argument = next_arg(&argc, &argv)))
  558.     panic("Expected a multitype list");
  559.       dataops.multitype = next_argument;
  560.    }
  561.    
  562.     else if(0 == strcmp("-x", next_argument)){
  563.       if(NULL == (next_argument = next_arg(&argc, &argv)))
  564.     panic("Expected an excluded filename list");
  565.       strncpy(ExcludeFiles,next_argument,EXCLUDEFILENAMESLEN-2);
  566.       ExcludeFiles[strlen(ExcludeFiles)+2] = '\0';  /* Ensure double-null terminated */
  567.       strtok(ExcludeFiles,",");
  568.       while (strtok(NULL,",")!=NULL) /* Cycle until all tokens found */ ;
  569.       }
  570.      else if(0 == strcmp("-keywords", next_argument)){
  571.        if(NULL == (next_argument = next_arg(&argc, &argv)))
  572.     panic("Expected -keywords argument string");
  573.        keywords = next_argument;
  574.      }
  575.      else if(0 == strcmp("-keyword_file", next_argument)){
  576.        if(NULL == (next_argument = next_arg(&argc, &argv)))
  577.     panic("Expected -keyword_file filename");
  578.        keyword_filename = next_argument;
  579.     }
  580.  
  581.     else if(0 == strcmp("-contents", next_argument)){
  582.       index_contents = true;
  583.     }
  584.     else if(0 == strcmp("-nocontents", next_argument)){
  585.       index_contents = false;
  586.     }
  587.     else if(0 == strcmp("-t", next_argument)){
  588.       /* then we have a specialized file */
  589.       index_contents = true;
  590.       if(NULL == (next_argument = next_arg(&argc, &argv)))
  591.     panic("Expected a file type");
  592.       if(0 == strcmp("groliers", next_argument)){
  593.     typename = next_argument;
  594.     dataops.type ="TEXT";
  595.     dataops.separator_function = groliers_separator_function;
  596.     dataops.header_function = groliers_header_function;
  597.     dataops.finish_header_function = groliers_finish_header_function;
  598.       }
  599.  
  600. #ifdef BIO 
  601.        else if(0 == strcmp("genbank", next_argument)){/* dgg */
  602.     typename = next_argument;
  603.     dataops.type ="TEXT";
  604.     dataops.separator_function = genbank_separator_function;
  605.     dataops.header_function = genbank_header_function;
  606.     dataops.finish_header_function = genbank_finish_header_function;
  607.     dataops.date_function = genbank_date_function;
  608.     dataops.repeat_weight= 0;
  609.     dataops.addseparatorwords= true;
  610.     dataops.extraheaderweight= false;
  611.     dataops.minwordlen= 2;
  612.        }
  613.        else if(0 == strcmp("embl", next_argument)){/* dgg */
  614.     typename = next_argument;
  615.     dataops.type ="TEXT";
  616.     dataops.separator_function = embl_separator_function;
  617.     dataops.header_function = embl_header_function;
  618.     dataops.finish_header_function = embl_finish_header_function;
  619.     dataops.date_function = embl_date_function;
  620.     dataops.repeat_weight= 0;
  621.     dataops.addseparatorwords= true;
  622.     dataops.extraheaderweight= false;
  623.       }
  624.        else if(0 == strcmp("pir", next_argument)){/* dgg */
  625.     typename = next_argument;
  626.     dataops.type = "TEXT";
  627.     dataops.separator_function = pir_separator_function;
  628.     dataops.header_function = pir_header_function;
  629.     dataops.finish_header_function = pir_finish_header_function;
  630.     dataops.date_function = pir_date_function;
  631.     dataops.repeat_weight= 0;
  632.     dataops.addseparatorwords= true;
  633.     dataops.extraheaderweight= false;
  634.       }
  635.         else if(0 == strcmp("prositedoc", next_argument)){ /* dgg */
  636.          typename = next_argument;
  637.          dataops.type = "TEXT";
  638.          dataops.separator_function = prositedoc_separator_function;
  639.          dataops.header_function = prositedoc_header_function;
  640.          dataops.finish_header_function = prositedoc_finish_header_function;
  641.      dataops.repeat_weight= 0;
  642.     dataops.addseparatorwords= true;
  643.     dataops.extraheaderweight= false;
  644.        }
  645.        else if(0 == strcmp("prositedat", next_argument)){ /* dgg */
  646.          typename = next_argument;
  647.          dataops.type = "TEXT";
  648.          dataops.separator_function = prositedat_separator_function;
  649.          dataops.header_function = prositedat_header_function;
  650.          dataops.finish_header_function = prositedat_finish_header_function;
  651.      dataops.repeat_weight= 0;
  652.     dataops.addseparatorwords= true;
  653.     dataops.extraheaderweight= false;
  654.        }
  655.        else if(0 == strcmp("biojournal", next_argument)){ /* dgg */
  656.          typename = next_argument;
  657.          dataops.type = "TEXT";
  658.          dataops.separator_function = biojournal_separator_function;
  659.          dataops.header_function = biojournal_header_function;
  660.          dataops.finish_header_function = biojournal_finish_header_function;
  661.      dataops.repeat_weight= 0;
  662.     dataops.addseparatorwords= true;
  663.     dataops.extraheaderweight= false;
  664.        }
  665.  
  666.        else if(0 == strcmp("redbook", next_argument)){ /* dgg */
  667.     typename = next_argument;
  668.     dataops.type = "TEXT";
  669.     dataops.separator_function = redbook_separator_function;
  670.     dataops.header_function = redbook_header_function;
  671.     dataops.finish_header_function = redbook_finish_header_function;
  672.     dataops.repeat_weight= 0;
  673.     dataops.addseparatorwords= true;
  674.     dataops.extraheaderweight= false;
  675.         dataops.wordDelimiter= wordbreak_user; /* redbook_delimiter;  */
  676.         wordDelimiter= wordbreak_user; /* wordbreak_notgraph; */
  677.     dataops.minwordlen= 1;
  678.     if (gDelimiters[0] == '\0') strcpy( gDelimiters, "/{}()[]%-:#.~*\";,|");
  679.        }
  680.        else if(0 == strcmp("flybase", next_argument)){ /* dgg */
  681.     typename = next_argument;
  682.     dataops.type = "TEXT";
  683.     dataops.separator_function = flybase_separator_function;
  684.     dataops.header_function = flybase_header_function;
  685.     dataops.finish_header_function = flybase_finish_header_function;
  686.      dataops.repeat_weight= 0;
  687.     dataops.addseparatorwords= true;
  688.     dataops.extraheaderweight= false;
  689.         dataops.wordDelimiter= wordbreak_user; /* flybase_delimiter;  */
  690.         wordDelimiter= wordbreak_user; /* wordbreak_notgraph; */
  691.     dataops.minwordlen= 1;
  692.     if (gDelimiters[0] == '\0') strcpy( gDelimiters, "-/{}:.~*\";,|");
  693.     
  694.     /* flybase symbols
  695.       valid data ()$+-?;.\'
  696.       possible data and delimiter |;[]-?.~
  697.       delimiters 
  698.       solution to confusion: set possible delimiters as delimiters, and
  699.          permit literal searches with "..." or '...' enclosed strings.
  700.     */
  701.     
  702.        }
  703.       else if(0 == strcmp("flystock", next_argument)){  /* dgg */
  704.     typename = next_argument;
  705.     dataops.type = "TEXT";
  706.     dataops.separator_function = bio_separator_function;
  707.     dataops.header_function = bio_header_function;
  708.     dataops.finish_header_function = bio_finish_header_function;
  709.      dataops.repeat_weight= 0;
  710.     dataops.addseparatorwords= true;
  711.     dataops.extraheaderweight= false;
  712.         dataops.wordDelimiter= wordbreak_user; /* flybase_delimiter;  */
  713.         wordDelimiter= wordbreak_user; /* wordbreak_notgraph; */
  714.     dataops.minwordlen= 1;
  715.     if (gDelimiters[0] == '\0') strcpy( gDelimiters, "-/{}:.~*\";,|");
  716.  
  717.     /* flystock symbols
  718.       valid data []()/-;?+.{}
  719.       possible data and delimiter  =;.
  720.         ;. in text field is del, in data field is data
  721.       delimiters *";,
  722.       more delimiters (from matthewk)  - / {} :
  723.       
  724.       solution to confusion: set possible delimiters as delimiters, and
  725.          permit literal searches with "..." or '...' enclosed strings.
  726.       ! want some way to provide field names (report "stylesheet") with
  727.         searched/fetched records for flybase, flystock, other data files
  728.       ! want "keyword [field]" limited searches for some of this to make sense !
  729.     */
  730.       }
  731.  
  732.       else if(0 == strcmp("din", next_argument)){
  733.     typename = next_argument;
  734.     dataops.type = "TEXT";
  735.     dataops.separator_function = din_separator_function;
  736.     dataops.header_function = din_header_function;
  737.     dataops.finish_header_function = din_finish_header_function;
  738.       }
  739.  
  740. #endif 
  741.  
  742. #ifdef NeXT
  743.       else if(0 == strcmp("objc", next_argument)){
  744.     typename = next_argument;
  745.     dataops.type = "TEXT";
  746.     dataops.separator_function = wobjc_separator_function;
  747.     dataops.header_function = wobjc_header_function;
  748.     dataops.finish_header_function = wobjc_finish_header_function;
  749.       }
  750. #endif /* def NeXT */
  751.       else if(0 == strcmp("listserv_digest", next_argument)){
  752.     typename = next_argument;
  753.     dataops.type = "TEXT";
  754.     dataops.separator_function = listserv_digest_separator_function;
  755.     dataops.header_function = listserv_header_function;
  756.     dataops.date_function = listserv_date_function;
  757.     dataops.finish_header_function = listserv_finish_header_function;
  758.       }
  759. #ifdef AAS
  760.       else if(0 == strcmp("AAS_abstract", next_argument)){
  761.     typename = next_argument;
  762.     dataops.separator_function = aasab_separator_function;
  763.     dataops.header_function = aasab_header_function;
  764.     dataops.finish_header_function = aasab_finish_header_function;
  765.       }
  766. #endif /* AAS */
  767. #ifdef STELAR
  768.       else if(0==strcmp("stelar",next_argument)){
  769.         dataops.type="TEXT";
  770.         typename=next_argument;
  771.         dataops.separator_function=stelar_separator_function;
  772.         dataops.header_function=stelar_header_function;
  773.         dataops.finish_header_function=stelar_finish_header_function;
  774.       }
  775. #endif /* STELAR */
  776.       else if(0 == strcmp("mail", next_argument)){
  777.     typename = next_argument;
  778.     dataops.type = "TEXT";
  779.     dataops.separator_function = mail_separator_function;
  780.     dataops.header_function = mail_header_function;
  781.     dataops.date_function = mail_date_function;
  782.     dataops.finish_header_function = mail_finish_header_function;
  783.       }
  784.       else if(0 == strcmp("mail_or_rmail", next_argument)){
  785.     typename = next_argument;
  786.     dataops.type = "TEXT";
  787.     dataops.separator_function = mail_or_rmail_separator;
  788.     dataops.header_function = mail_header_function;
  789.     dataops.date_function = mail_date_function;
  790.     dataops.finish_header_function = mail_finish_header_function;
  791.       }
  792.       else if(0 == strcmp("mail_digest", next_argument)){
  793.     typename = next_argument;
  794.     dataops.type = "TEXT";
  795.     dataops.separator_function = mail_digest_separator_function;
  796.     dataops.header_function = mail_header_function;
  797.     dataops.date_function = mail_date_function;
  798.     dataops.finish_header_function = mail_finish_header_function;
  799.       }
  800.       else if(0 == strcmp("mh_bboard", next_argument)){
  801.     typename = next_argument;
  802.     dataops.type = "TEXT";
  803.     dataops.separator_function = mh_bboard_separator_function;
  804.     dataops.header_function = mail_header_function;
  805.     dataops.date_function = mail_date_function;
  806.     dataops.finish_header_function = mail_finish_header_function;
  807.       }
  808. #ifdef WIN32
  809.       else if(0 == strcmp("ms_kbase", next_argument)){
  810.     typename = next_argument;
  811.     dataops.type = "TEXT";
  812.     dataops.separator_function = NULL;
  813.     dataops.header_function = mskbase_header_function;
  814.     dataops.date_function = mskbase_date_function;
  815.     dataops.finish_header_function = mskbase_finish_header_function;
  816.       }
  817. #endif
  818.       else if(0 == strcmp("rmail", next_argument)){
  819.     typename = next_argument;
  820.     dataops.type = "TEXT";
  821.     dataops.separator_function = rmail_separator_function;
  822.     dataops.header_function = mail_header_function;
  823.     dataops.date_function = mail_date_function;
  824.     dataops.finish_header_function = mail_finish_header_function;
  825.       }
  826.       else if(0 == strcmp("netnews", next_argument)){
  827.     typename = next_argument;
  828.     dataops.type = "TEXT";
  829.     dataops.separator_function = NULL;
  830.     dataops.header_function = mail_header_function;
  831.     dataops.date_function = mail_date_function;
  832.     dataops.finish_header_function = mail_finish_header_function;
  833.       }
  834.       else if(0 == strcmp("rn", next_argument)){
  835.     typename = next_argument;
  836.     dataops.type = "TEXT";
  837.     dataops.separator_function = rn_separator_function;
  838.     dataops.header_function = mail_header_function;
  839.     dataops.date_function = mail_date_function;
  840.     dataops.finish_header_function = mail_finish_header_function;
  841.       }
  842. #ifdef BIBDB
  843.       else if(0 == strcmp("irlist", next_argument)){
  844.         typename = next_argument;
  845.         dataops.type = "TEXT";
  846.         dataops.separator_function = irlist_separator_function;
  847.         dataops.header_function = irlist_header_function;
  848.         dataops.date_function = irlist_date_function;
  849.         dataops.finish_header_function = mail_finish_header_function;
  850.       }
  851.       /* formfeed-separated items , Intro to Algorithms buglist, etc */
  852.       else if(0 == strcmp("formfeed", next_argument)){
  853.         typename = next_argument;
  854.         if (!dataops.type || (strlen(dataops.type)==0)) {
  855.           if (dataops.type)
  856.             fprintf(stderr, "irbuild: overwriting type %s\n", dataops.type);
  857.           dataops.type = "TEXT";
  858.         } else {
  859.           fprintf(stderr, "irbuild: using type %s\n", dataops.type);
  860.         }
  861.         dataops.separator_function = formfeed_separator_function;
  862.         dataops.header_function = dash_header_function;
  863.         dataops.finish_header_function = dash_finish_header_function;
  864.       }
  865.       /* formfeed-separated items , steve files */
  866.       else if(0 == strcmp("bibdb", next_argument)){
  867.         typename = next_argument;
  868.         if (!dataops.type || (strlen(dataops.type)==0)) {
  869.           if (dataops.type)
  870.             fprintf(stderr, "irbuild: overwriting type %s\n", dataops.type);
  871.           dataops.type = "TEXT";
  872.         } else {
  873.           fprintf(stderr, "irbuild: using type %s\n", dataops.type);
  874.           stop_list_file("bibdb.stop");
  875.         }
  876.         dataops.separator_function = bibdb_separator_function;
  877.         dataops.header_function = bibdb_header_function;
  878.         dataops.date_function = bibdb_date_function;
  879.         dataops.finish_header_function = bibdb_finish_header_function;
  880.       }
  881.       /* formfeed-separated items, bibinbf */
  882.       else if(0 == strcmp("bibinf", next_argument)){
  883.         typename = next_argument;
  884.         dataops.type = "TEXT";
  885.         dataops.separator_function = bibinf_separator_function;
  886.         dataops.header_function = bibinf_header_function;
  887. #ifdef SIMPLE_BIBINF
  888.         dataops.date_function = bibinf_date_function;
  889. #endif
  890.         dataops.finish_header_function = bibinf_finish_header_function;
  891.       }
  892. #endif
  893.       else if(0 == strcmp("emacsinfo", next_argument)){
  894.     typename = next_argument;
  895.     dataops.type = "TEXT";
  896.     dataops.separator_function = emacs_info_separator_function;
  897.     dataops.header_function = emacs_info_header_function;
  898.     dataops.finish_header_function = emacs_info_finish_header_function;
  899.       }
  900.       else if(0 == strcmp("catalog", next_argument)){
  901.     typename = next_argument;
  902.     dataops.type = "TEXT";
  903.     dataops.separator_function = catalog_separator_function;
  904.     dataops.header_function = catalog_header_function;
  905.     dataops.finish_header_function = catalog_finish_header_function;
  906.       }
  907.       else if(0 == strcmp("bio", next_argument)){
  908.     typename = next_argument;
  909.     dataops.type = "TEXT";
  910.     dataops.separator_function = bio_separator_function;
  911.     dataops.header_function = bio_header_function;
  912.     dataops.finish_header_function = bio_finish_header_function;
  913.       }
  914.       else if(0 == strcmp("cmapp", next_argument)){
  915.     typename = next_argument;
  916.     dataops.type = "TEXT";  
  917.     dataops.separator_function = cmapp_separator_function;
  918.     dataops.header_function = cmapp_header_function;
  919.     dataops.finish_header_function = cmapp_finish_header_function;
  920.       }
  921.       else if(0 == strcmp("ftp", next_argument)){
  922.     dataops.type = "TEXT-FTP";
  923.     typename = next_argument;
  924.     dataops.separator_function = first_line_separator_function;
  925.     dataops.header_function = first_line_header_function;
  926.     dataops.finish_header_function = first_line_finish_header_function;
  927.       }
  928.       else if(0 == strcmp("jargon", next_argument)){
  929.     typename = next_argument;
  930.     dataops.type = "TEXT";
  931.     dataops.separator_function = jargon_separator_function;
  932.     dataops.header_function = jargon_header_function;
  933.     dataops.finish_header_function = jargon_finish_header_function;
  934.       }
  935.       else if(0 == strcmp("server", next_argument)){
  936.     typename = next_argument;
  937.     dataops.type = "WSRC";
  938.     dataops.finish_header_function = filename_finish_header_function;
  939.       }
  940.       else if(0 == strcmp("text", next_argument)){
  941.     dataops.type = "TEXT";
  942.     typename = next_argument;
  943.     check_for_text_file = true;
  944.       }
  945.       else if(0 == strcmp("filename", next_argument)){
  946.     dataops.type = "TEXT";
  947.     typename = next_argument;
  948.     dataops.finish_header_function = filename_finish_header_function;
  949.       }
  950. #if 0      /* html format */
  951.       else if(0 == strcmp("html", next_argument)){
  952.         dataops.type = "HTML";
  953.         typename = next_argument;
  954.         dataops.separator_function = html_separator_function;
  955.         dataops.header_function = html_header_function;
  956.         dataops.finish_header_function = html_finish_header_function;
  957.       }
  958. #endif
  959.       else if(0 == strcmp("irg", next_argument)){
  960.     typename = next_argument;
  961.     dataops.type = "TEXT";
  962.     dataops.separator_function = irg_separator_function;
  963.     dataops.header_function = irg_header_function;
  964.     dataops.finish_header_function = irg_finish_header_function;
  965.       }
  966.       /* dash-separated items , Intro to Algorithms buglist, etc */
  967.       else if(0 == strcmp("dash", next_argument)){
  968.     dataops.type = "TEXT";
  969.     typename = next_argument;
  970.     dataops.separator_function = dash_separator_function;
  971.     dataops.header_function = dash_header_function;
  972.     dataops.finish_header_function = dash_finish_header_function;
  973.       }
  974.       /* one_line-separated items */
  975.       else if(0 == strcmp("one_line", next_argument)){
  976.     dataops.type = "TEXT";
  977.     typename = next_argument;
  978.     dataops.separator_function = one_line_separator_function;
  979.     dataops.header_function = one_line_header_function;
  980.     dataops.finish_header_function = one_line_finish_header_function;
  981.       }
  982.       /* blank line-separated items (paragraphs) */
  983.       else if(0 == strcmp("para", next_argument)){
  984.     dataops.type = "TEXT";
  985.     typename = next_argument;
  986.     dataops.separator_function = para_separator_function;
  987.     dataops.header_function = para_header_function;
  988.     dataops.finish_header_function = para_finish_header_function;
  989.       }
  990.       /* seeker items */
  991.       else if(0 == strcmp("seeker", next_argument)){
  992.     dataops.type = "TEXT";
  993.     typename = next_argument;
  994.     dataops.separator_function = seeker_separator_function;
  995.     dataops.header_function = seeker_header_function;
  996.     dataops.finish_header_function = seeker_finish_header_function;
  997.       }
  998.       /* medline format */
  999.       else if(0 == strcmp("medline", next_argument)){
  1000.     dataops.type = "TEXT";
  1001.     typename = next_argument;
  1002.     dataops.separator_function = medline_separator_function;
  1003.     dataops.header_function = medline_header_function;
  1004.     dataops.finish_header_function = medline_finish_header_function;
  1005.       }
  1006.       /* refer format */
  1007.       else if(0 == strcmp("refer", next_argument)){
  1008.     dataops.type = "TEXT";
  1009.     typename = next_argument;
  1010.     dataops.separator_function = refer_separator_function;
  1011.     dataops.header_function = refer_header_function;
  1012.     dataops.finish_header_function = refer_finish_header_function;
  1013.       }
  1014.       /* first_line format */
  1015.       else if(0 == strcmp("first_line", next_argument)){
  1016.     dataops.type = "TEXT";
  1017.     typename = next_argument;
  1018.     dataops.separator_function = first_line_separator_function;
  1019.     dataops.header_function = first_line_header_function;
  1020.     dataops.finish_header_function = first_line_finish_header_function;
  1021.       }
  1022.       /* rlin items */
  1023.       else if(0 == strcmp("rlin", next_argument)){
  1024.     dataops.type = "TEXT";
  1025.     typename = next_argument;
  1026.     dataops.separator_function = rlin_separator_function;
  1027.     dataops.header_function = rlin_header_function;
  1028.     dataops.finish_header_function = rlin_finish_header_function;
  1029.       }
  1030.       else if(0 == strcmp("dvi", next_argument)){
  1031.     typename = next_argument;
  1032.     dataops.type = "DVI";
  1033.     dataops.finish_header_function = filename_finish_header_function;
  1034.       }
  1035.       else if(0 == strcmp("ps", next_argument)){
  1036.     typename = next_argument;
  1037.     dataops.type = "PS";
  1038.     dataops.finish_header_function = filename_finish_header_function;
  1039.       }
  1040.       else if(0 == strcmp("pict", next_argument)){
  1041.     typename = next_argument;
  1042.     dataops.type = "PICT";  
  1043.     dataops.finish_header_function = filename_finish_header_function;
  1044.     index_contents = false;
  1045.       }
  1046.       else if(0 == strcmp("gif", next_argument)){
  1047.     typename = next_argument;
  1048.     dataops.type = "GIF";   
  1049.     dataops.finish_header_function = filename_finish_header_function;
  1050.     index_contents = false;
  1051.       }
  1052.       else if(0 == strcmp("tiff", next_argument)){
  1053.     typename = next_argument;
  1054.     dataops.type = "TIFF";  
  1055.     dataops.finish_header_function = filename_finish_header_function;
  1056.     index_contents = false;
  1057.       }
  1058.       else if(0== strcmp("object", next_argument)) {
  1059.         dataops.type = "OBJECT";
  1060.         typename = next_argument;
  1061.       }
  1062.       else if(0 == strcmp("inriadoc", next_argument)){
  1063.         typename = next_argument;
  1064.         dataops.type = "TEXT";
  1065.         dataops.separator_function = NULL;
  1066.         dataops.header_function = inriadoc_header_function;
  1067.         dataops.date_function = NULL;
  1068.         dataops.finish_header_function = inriadoc_finish_header_function;
  1069.       }
  1070.       else if(0 == strcmp("fortran", next_argument)){
  1071.         typename = next_argument;
  1072.         dataops.type = "FORTRAN";
  1073.       }
  1074.       else if(0 == strcmp("paradoc", next_argument)){
  1075.         typename = next_argument;
  1076.         dataops.type = "TEXT";
  1077.         dataops.separator_function = para_separator_function;
  1078.         dataops.header_function = inriadoc_header_function;
  1079.         dataops.date_function = NULL;
  1080.         dataops.finish_header_function = inriadoc_finish_header_function;
  1081.       }
  1082.       else if(0 == strcmp("mime", next_argument)){
  1083.         typename = next_argument;
  1084.         dataops.type = "MIME";
  1085.         dataops.separator_function = mail_separator_function;
  1086.         dataops.header_function = mail_header_function;
  1087.         dataops.date_function = mail_date_function;
  1088.         dataops.finish_header_function = mail_finish_header_function;
  1089.       }
  1090.       /* BibTeX items */
  1091.       else if(0 == strcmp("bibtex", next_argument)){
  1092.     dataops.type = "TEXT";
  1093.     typename = next_argument;
  1094.     dataops.separator_function = bibtex_separator_function;
  1095.     dataops.header_function = bibtex_header_function;
  1096.     dataops.finish_header_function = bibtex_finish_header_function;
  1097.       }
  1098.       /* ?:? seperated hypertext items */
  1099.       else if(0 == strcmp("nhyp", next_argument)){
  1100.     dataops.type = "TEXT";
  1101.     typename = next_argument;
  1102.     dataops.separator_function = nhyp_separator_function;
  1103.     dataops.header_function = nhyp_header_function;
  1104.     dataops.finish_header_function = nhyp_finish_header_function;
  1105.       }
  1106.       /* Uniform Resource Locators  - from Nat Torkington */
  1107.       else if(0 == strcmp("URL", next_argument)) {
  1108.         dataops.type = "URL";
  1109.         typename = next_argument;
  1110.         URL_trim = s_strdup(next_arg(&argc, &argv));
  1111.         URL_prefix = s_strdup(next_arg(&argc, &argv));
  1112.       }
  1113.       else if(0 == strcmp("ziff", next_argument)){
  1114.     dataops.type = "TEXT";
  1115.     typename = next_argument;
  1116.     dataops.separator_function = ziff_separator_function;
  1117.     dataops.header_function = ziff_header_function;
  1118.     dataops.finish_header_function = ziff_finish_header_function;
  1119.       }
  1120. #ifdef SOUND
  1121.       else if(0 == strcmp("oneline_soundex", next_argument)){
  1122.         dataops.indextype = "SOUNDEX";
  1123.         dataops.type = "TEXT";
  1124.         typename = next_argument;
  1125.         dataops.separator_function = one_line_separator_function;
  1126.         dataops.header_function = one_line_header_function;
  1127.         dataops.finish_header_function = one_line_finish_header_function;
  1128.       }
  1129.       else if(0 == strcmp("oneline_phonix", next_argument)){
  1130.         dataops.indextype = "PHONIX";
  1131.         dataops.type = "TEXT";
  1132.         typename = next_argument;
  1133.         dataops.separator_function = one_line_separator_function;
  1134.         dataops.header_function = one_line_header_function;
  1135.         dataops.finish_header_function = one_line_finish_header_function;
  1136.       }
  1137. #endif
  1138. #ifdef HTML                                                    
  1139.     /* HyperText Markup Lanugage (from World Wide Web) */        
  1140.       else if(0 == strcmp("html", next_argument)){             
  1141.     dataops.type = "HTML";                                       
  1142.     typename = next_argument;                                    
  1143.     dataops.separator_function = NULL;                           
  1144.     dataops.header_function = html_header_function;              
  1145.     dataops.finish_header_function = html_finish_header_function;
  1146.       }                                                        
  1147. #endif /* HTML */                                              
  1148.       else{
  1149.     panic("Don't recognize the '%s' type", next_argument);
  1150.       }
  1151.     }
  1152.     else{
  1153.       panic("Don't recognize the '%s' option", next_argument);
  1154.     }
  1155.     next_argument = next_arg(&argc, &argv);
  1156.     if (! (read_files_from_stdin || next_argument)) {
  1157.       fprintf(stderr,"No files specified\n");
  1158.       exit(0);
  1159.     }
  1160.   }
  1161.   start_of_filenames = argc_copy - argc - 1;
  1162.  
  1163.   /* check index */
  1164.   if(0 == strlen(pathname_name(index_filename))){
  1165.     waislog(WLOG_HIGH, WLOG_ERROR,
  1166.         "The pathname specified for the destination of the index files ('%s') should have a leaf filename without an extention rather than just a directory.",
  1167.         index_filename);
  1168.     exit(0);     
  1169.   }
  1170.  
  1171. #ifdef WIN32
  1172.   /* Check that we're on a partition supporting long file names */
  1173.   if (!CanCreateLongFileNames(index_filename)) {
  1174.     waislog(WLOG_HIGH, WLOG_ERROR,
  1175.         "The pathname specified for the destination of the index files ('%s') is inaccessible or does not support long filenames.",
  1176.         index_filename);
  1177.     exit(0);     
  1178.   }
  1179. #endif
  1180.     
  1181.   waislog(WLOG_MEDIUM, WLOG_INDEX, "Starting to build database %s",
  1182.       index_filename);
  1183.  
  1184.   if(0 != init_search_engine(index_filename, false, false, cm_mem_percent,
  1185.           text_size, grow_percent))
  1186.     panic("unable to initialize search engine");
  1187.  
  1188.   if(true == adding_to_existing_index){
  1189.     db = openDatabase(index_filename, false, false);
  1190.     if (db == NULL){ /* does not exist, create one */
  1191.       db = openDatabase(index_filename, true, false);
  1192.       if (db == NULL)
  1193.     panic("unable to open the database");
  1194.     }
  1195.   }
  1196.   else{
  1197.     db = openDatabase(index_filename, true, false);
  1198.     if (db == NULL)
  1199.       panic("unable to open the database");
  1200.   }
  1201.   
  1202. #ifdef BIO
  1203.     write_delimiters(gDelimiters, db);
  1204. #endif
  1205.  
  1206.   { /* set up the memory hashtable */
  1207.  
  1208.     if(memory_to_use < 0){ /* default */
  1209.       /* do nothing */
  1210.     }
  1211.     else if(memory_to_use <= 2){
  1212.       hashtable_size = 1L<<16;
  1213.       flush_after_n_words = 50000;
  1214.     }
  1215.  
  1216.     else if(memory_to_use <= 3){
  1217.       hashtable_size = 1L<<16;
  1218.       flush_after_n_words =850000;
  1219.     }
  1220.     else if(memory_to_use <= 4){
  1221.       hashtable_size = 1L<<16;
  1222.       flush_after_n_words = 110000;
  1223.     }
  1224.     else if(memory_to_use <= 5){
  1225.       hashtable_size = 1L<<16;
  1226.       flush_after_n_words = 150000;
  1227.     }
  1228.  
  1229.     else if(memory_to_use <= 10){
  1230.       /* shown to take about 6MB on a sun4, when it is dict limited */
  1231.       hashtable_size = 1L<<16;
  1232.       flush_after_n_words = 300000;
  1233.     }
  1234.     else if(memory_to_use <= 20){
  1235.       hashtable_size = 1L<<17;
  1236.       flush_after_n_words = 600000;
  1237.     }
  1238.     else{ /* over 20 Mbytes */
  1239.       hashtable_size = 1L<<18;
  1240.       flush_after_n_words = 1000000;
  1241.     }
  1242. /* Set up the filter process, if needed */
  1243.      /* We do this before initing the hash table to stop the fork copying a
  1244.         load of rubbish*/
  1245. #ifdef WIN32
  1246.    /* WIN32 Process is used here, how about thread? */
  1247.    if(filter_name) {
  1248.      HANDLE hChildStdinRd, hChildStdinWr, hChildStdinWrDup,
  1249.          hChildStdoutRd, hChildStdoutWr, hSaveStdin, hSaveStdout;
  1250.      SECURITY_ATTRIBUTES saAttr;
  1251.      BOOL fSuccess;
  1252.      STARTUPINFO siStartInfo;
  1253.      int fd;
  1254.  
  1255.      /* Set the bInheritHandle flag so pipe handles are inherited. */
  1256.  
  1257.      saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
  1258.      saAttr.bInheritHandle = TRUE;
  1259.      saAttr.lpSecurityDescriptor = NULL;
  1260.  
  1261.      /*
  1262.       * The steps for redirecting child's STDOUT:
  1263.       *     1.  Save current STDOUT, to be restored later.
  1264.       *     2.  Create anonymous pipe to be STDOUT for child.
  1265.       *     3.  Set STDOUT of parent to be write handle of pipe, so
  1266.       *         it is inherited by child.
  1267.       */
  1268.  
  1269.      /* Save the handle to the current STDOUT. */
  1270.  
  1271.      hSaveStdout = GetStdHandle(STD_OUTPUT_HANDLE);
  1272.  
  1273.      /* Create a pipe for the child's STDOUT. */
  1274.  
  1275.      if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0))
  1276.        panic("Stdout pipe creation failed\n");
  1277.  
  1278.      /* Set a write handle to the pipe to be STDOUT. */
  1279.  
  1280.      if (! SetStdHandle(STD_OUTPUT_HANDLE, hChildStdoutWr))
  1281.        panic("Redirecting STDOUT failed");
  1282.      /*
  1283.       * The steps for redirecting child's STDIN:
  1284.       *     1.  Save current STDIN, to be restored later.
  1285.       *     2.  Create anonymous pipe to be STDIN for child.
  1286.       *     3.  Set STDIN of parent to be read handle of pipe, so
  1287.       *         it is inherited by child.
  1288.       *     4.  Create a noninheritable duplicate of write handle,
  1289.       *         and close the inheritable write handle.
  1290.       */
  1291.  
  1292.      /* Save the handle to the current STDIN. */
  1293.  
  1294.      hSaveStdin = GetStdHandle(STD_INPUT_HANDLE);
  1295.      /* Create a pipe for the child's STDIN. */
  1296.  
  1297.      if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0))
  1298.        panic("Stdin pipe creation failed\n");
  1299.  
  1300.      /* Set a read handle to the pipe to be STDIN. */
  1301.  
  1302.      if (! SetStdHandle(STD_INPUT_HANDLE, hChildStdinRd))
  1303.        panic("Redirecting Stdin failed");
  1304.  
  1305.      /* 
  1306.       * Duplicate the write handle to the pipe, so it is not 
  1307.       * inherited. 
  1308.       */
  1309.  
  1310.      fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
  1311.          GetCurrentProcess(), &hChildStdinWrDup, 0,
  1312.          FALSE,       /* not inherited */
  1313.          DUPLICATE_SAME_ACCESS);
  1314.      if (!fSuccess)
  1315.        panic("DuplicateHandle failed");
  1316.  
  1317.      CloseHandle(hChildStdinWr);
  1318.  
  1319.      /* Set up members of STARTUPINFO structure. */
  1320.  
  1321.      siStartInfo.cb = sizeof(STARTUPINFO);
  1322.      siStartInfo.lpReserved = NULL;
  1323.      siStartInfo.lpReserved2 = NULL;
  1324.      siStartInfo.cbReserved2 = 0;
  1325.      siStartInfo.lpDesktop = NULL;
  1326.      siStartInfo.dwFlags = 0;
  1327.  
  1328.      /* Create the child process. */
  1329.  
  1330.      fSuccess = CreateProcess(NULL,
  1331.         filter_name,   /* command line                       */
  1332.         NULL,          /* process security attributes        */
  1333.         NULL,          /* primary thread security attributes */
  1334.         TRUE,          /* handles are inherited              */
  1335.         0,             /* creation flags                     */
  1336.         NULL,          /* use parent's environment           */
  1337.         NULL,          /* use parent's current directory     */
  1338.         &siStartInfo,  /* STARTUPINFO pointer                */
  1339.         &piProcInfo);  /* receives PROCESS_INFORMATION       */
  1340.  
  1341.      if (!fSuccess)
  1342.        panic("Create process failed");
  1343.  
  1344.      /* After process creation, restore the saved STDIN and STDOUT. */
  1345.  
  1346.      if (! SetStdHandle(STD_INPUT_HANDLE, hSaveStdin))
  1347.        panic("Re-redirecting Stdin failed\n");
  1348.  
  1349.      if (! SetStdHandle(STD_OUTPUT_HANDLE, hSaveStdout))
  1350.        panic("Re-redirecting Stdout failed\n");
  1351.  
  1352.      fd = _open_osfhandle((long)hChildStdinWrDup, _O_APPEND);
  1353.      if (fd < 0)
  1354.        panic("Convert Win32 Handle to filter_process_in failed\n");
  1355.      filter_process_in=_fdopen(fd,"wb");
  1356.      fd = _open_osfhandle((long)hChildStdoutRd, _O_RDONLY);
  1357.      if (fd < 0)
  1358.        panic("Convert Win32 Handle to filter_process_out failed\n");
  1359.      filter_process_out=_fdopen(fd,"rb");
  1360.      waislog(WLOG_LOW, WLOG_INDEX, "Filter %s started (%d)",filter_name,
  1361.                 piProcInfo.dwProcessId);
  1362.    }
  1363.  
  1364. #else
  1365.    if(filter_name) {
  1366.      int to_handles[2];
  1367.      int from_handles[2];
  1368.      int pid;
  1369.      extern int errno;
  1370.      if (pipe(to_handles) <0) {
  1371.        panic("can't open to pipe");
  1372.      }
  1373.      if (pipe(from_handles) <0) {
  1374.        panic("can't open from pipe");
  1375.      }
  1376.  
  1377.      if((pid = fork()) ==0) {
  1378.  
  1379.        /* child */
  1380.  
  1381.        close(0);
  1382.        close(1);
  1383.        close(2);
  1384.        dup(to_handles[0]);
  1385.        dup(from_handles[1]);         /* Set up standard input/output/error */
  1386.        dup(from_handles[1]);
  1387.        close(to_handles[0]);
  1388.        close(to_handles[1]);
  1389.        close(from_handles[0]);
  1390.        close(from_handles[1]);
  1391.  
  1392.        if(execl(filter_name,filter_name,NULL) == -1) {
  1393.        exit(errno);
  1394.        }
  1395.        /*NOTREACHED*/
  1396.  }    
  1397.      /* parent */
  1398.  
  1399.     if (pid <0) {
  1400.        panic("Couldn't fork");
  1401.      }
  1402.      close(to_handles[0]);
  1403.      close(from_handles[1]);
  1404.  
  1405.      filter_process_in=fdopen(to_handles[1],"w");
  1406.      filter_process_out=fdopen(from_handles[0],"r");
  1407.      waislog(WLOG_LOW, WLOG_INDEX, "Filter %s started (%d)",filter_name,pid);
  1408.    }
  1409. #endif /* WIN32 */
  1410.  
  1411.     init_add_word(db, hashtable_size, flush_after_n_words);
  1412.   }
  1413.  
  1414.   if (read_files_from_stdin) {
  1415.     if (0 != (next_argument = fgets(data_filename, MAXPATHLEN, stdin))) {
  1416.       int len = strlen(next_argument);
  1417.       if (next_argument[len-1] == '\n') {
  1418.     next_argument[len-1] = '\0';
  1419.       }
  1420.     }
  1421.   }
  1422.  
  1423.   while(NULL != next_argument){ /* the first filename is in next_argument already */
  1424.     if(directoryp(next_argument)){
  1425.       if(traverse_directory){
  1426.         index_directory(next_argument, &dataops, db,
  1427.                          check_for_text_file,
  1428.                          adding_to_existing_index,
  1429.                          word_positions, word_pairs,
  1430. #ifndef WIN32
  1431.                          filter_process_in,filter_process_out);
  1432. #else                         
  1433.                          "*.*", filter_process_in,filter_process_out);
  1434. #endif
  1435. /*       index_directory(next_argument,
  1436.                          separator_function,
  1437.                          header_function,
  1438.                          date_function,
  1439.                          finish_header_function,
  1440.                          type, db,
  1441.                          check_for_text_file,
  1442.                          adding_to_existing_index, 
  1443.                          word_positions, word_pairs, minwordlen); */
  1444.        }
  1445.      }
  1446. #ifdef WIN32
  1447.     else if ((strchr(next_argument,'*')!=NULL)||(strchr(next_argument,'?')!=NULL)) {
  1448.         /* Contains a wildcard */
  1449.         if (traverse_directory) {
  1450.             /* We're being asked to recursively index a directory tree looking for
  1451.                filenames which match the wildcarded pattern. */
  1452.             char *cp;
  1453.             char *cPath = next_argument;
  1454.  
  1455.             /* Split the argument into the directory and the wildcard mask */
  1456.             cp = strrchr(cPath,'\\');
  1457.             if (cp==NULL) {
  1458.                 /* No path */
  1459.                 cPath = ".";
  1460.                 cp = next_argument;
  1461.             } else {
  1462.                 /* Tie off path */
  1463.                 *cp++ = '\0';
  1464.                 /* File mask */
  1465.                 if (*cp=='\0') cp = "*.*";
  1466.             }
  1467.             /* Index the directory */
  1468.             index_directory(cPath, &dataops, db,
  1469.                 check_for_text_file,
  1470.                 adding_to_existing_index, 
  1471.                 word_positions, word_pairs, cp,
  1472.                 filter_process_in,filter_process_out);
  1473.  
  1474.         } else {
  1475.             /* Not recursive */
  1476.             HANDLE hSearch;
  1477.             WIN32_FIND_DATA ffd;
  1478.             char FileName[MAX_FILENAME_LEN+1];
  1479.             char *cp;
  1480.             hSearch = FindFirstFile(next_argument,&ffd);
  1481.             if (hSearch!=INVALID_HANDLE_VALUE) {
  1482.                 while (TRUE) {
  1483.                     if ((ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)==0) {
  1484.                         /* Index the file */
  1485.                         strncpy(FileName,next_argument,MAX_FILENAME_LEN);
  1486.                         cp = strrchr(FileName,'\\');
  1487.                         if (cp!=NULL) {
  1488.                             *(cp+1) = '\0';
  1489.                             strncat(FileName,ffd.cFileName,MAX_FILENAME_LEN);
  1490.                         } else {
  1491.                             strncpy(FileName,ffd.cFileName,MAX_FILENAME_LEN);
  1492.                         }
  1493.                         waislog(WLOG_MEDIUM, WLOG_INDEX, "Indexing file: %s", FileName);
  1494.                         index_text_file(FileName, &dataops, db, 
  1495.                             check_for_text_file, adding_to_existing_index,
  1496.                             word_positions, word_pairs,
  1497.                             filter_process_in,filter_process_out);
  1498.                     }
  1499.                     if (!FindNextFile(hSearch,&ffd)) break;
  1500.                 }
  1501.                 FindClose(hSearch);
  1502.             }
  1503.         }
  1504.     }
  1505. #endif
  1506.     else{           /* not a directory */
  1507.       waislog(WLOG_MEDIUM, WLOG_INDEX, 
  1508.           "Indexing file: %s", next_argument);
  1509.       index_text_file(next_argument, &dataops, db, 
  1510.                       check_for_text_file, adding_to_existing_index,
  1511.                       word_positions, word_pairs,
  1512.                       filter_process_in,filter_process_out);
  1513. /*      index_text_file(next_argument,
  1514.                       separator_function,
  1515.                       header_function,
  1516.                       date_function,
  1517.                       finish_header_function,
  1518.                       type, db, 
  1519.                       check_for_text_file, adding_to_existing_index,
  1520.                       word_positions, word_pairs, minwordlen); */
  1521.     }
  1522.     if (read_files_from_stdin) {
  1523.       if (0 != (next_argument = fgets(data_filename, MAXPATHLEN, stdin))) {
  1524.     int len = strlen(next_argument);
  1525.     if (next_argument[len-1] == '\n') {
  1526.       next_argument[len-1] = '\0';
  1527.     }
  1528.       }
  1529.     }
  1530.     else {
  1531.       next_argument = next_arg(&argc, &argv);
  1532.     }
  1533.   }
  1534.   finished_add_word(db);
  1535.   retreive_keywords(db);
  1536.   {
  1537.     char filename[MAX_FILENAME_LEN + 1];
  1538.     if(!probe_file(source_filename(filename, db))){
  1539.       char database_name[MAX_FILENAME_LEN];
  1540.       write_src_structure(source_filename(filename, db),
  1541.               export_database?pathname_name(index_filename):
  1542.                       truename(index_filename, database_name),
  1543.               typename,
  1544.               &argv_copy[start_of_filenames],
  1545.               argc_copy - start_of_filenames,
  1546.               export_database,
  1547.               210L);
  1548.     }else{
  1549.        char *oldkeys[50];
  1550.        short oldKeys;
  1551.        if ((oldKeys = read_src_structure(source_filename(filename, db),
  1552. oldkeys))) {
  1553.  
  1554.        if (compare(keyword, nKeys, oldkeys, oldKeys) > 0.1) {
  1555.          char database_name[MAX_FILENAME_LEN];
  1556.          waislog(WLOG_MEDIUM,WLOG_INDEX, 
  1557.     "Keyword comparison indicates significant change.");
  1558.          waislog(WLOG_MEDIUM,WLOG_INDEX, "Rewriting source description.");
  1559.          waislog(WLOG_MEDIUM,WLOG_INDEX, 
  1560. "New source description should be exported.");
  1561.          write_src_structure(source_filename(filename, db),
  1562.             export_database?pathname_name(index_filename):
  1563.                              truename(index_filename, database_name),
  1564.                              typename,
  1565.                              &argv_copy[start_of_filenames],
  1566.                              argc_copy - start_of_filenames,
  1567.             export_database, 210L);
  1568.        }
  1569.        } else {
  1570.        char database_name[MAX_FILENAME_LEN];
  1571.        waislog(WLOG_MEDIUM,WLOG_INDEX, "No keyword list found.");
  1572.        waislog(WLOG_MEDIUM,WLOG_INDEX, "Rewriting source description.");
  1573.        waislog(WLOG_MEDIUM,WLOG_INDEX, 
  1574. "New source description should be export ed.");
  1575.        write_src_structure(source_filename(filename, db),
  1576. export_database?pathname_name(index_filename):
  1577.                            truename(index_filename, database_name),
  1578.                            typename,
  1579.                            &argv_copy[start_of_filenames],
  1580.   argc_copy - start_of_filenames,
  1581.                        export_database,
  1582.                            210L);
  1583.        }
  1584. }
  1585.     /* write out a description of the server if appropriate */
  1586.     if(register_database){
  1587.       register_src_structure(source_filename(filename, db));
  1588.     }
  1589.   }
  1590.   if(make_catalog) build_catalog(db);
  1591.   closeDatabase(db);
  1592.   /* wait for filter process to die, if there was one*/
  1593.  
  1594.    if(filter_process_in) {
  1595.      fprintf(filter_process_in,"Q\n");
  1596.      fflush(filter_process_in);
  1597.      fclose(filter_process_out);
  1598.      fclose(filter_process_in);
  1599. #ifdef WIN32
  1600.      waislog(WLOG_LOW, WLOG_INDEX, "Filter %s Exited (%ld)",filter_name,
  1601.          WaitForSingleObject(piProcInfo.hProcess, INFINITE));
  1602. #else
  1603.      waislog(WLOG_LOW, WLOG_INDEX, "Filter %s Exited (%ld)",filter_name,wait(0L));
  1604. #endif
  1605.    }
  1606.  
  1607.   waislog(WLOG_MEDIUM, WLOG_INDEX, "Finished build");
  1608.   exit(0);
  1609. }
  1610.  
  1611. #ifdef WIN32
  1612. int
  1613. #endif
  1614.  read_src_structure(filename, output)
  1615.  char *filename;
  1616.  char *output[50];
  1617.  {
  1618.    FILE *source_stream = s_fopen(filename, "r");
  1619.    char line[MAX_LINE_LENGTH], *ptr;
  1620. #ifdef WIN32
  1621.    int keyflag = 0, linelen, index;
  1622. #else
  1623.    int keyflag = 0, linelen, i, index;
  1624. #endif
  1625.    int desflag = 0;
  1626.     int tmp;
  1627.  
  1628.    index = 0;
  1629.   while (fgets(line, MAX_LINE_LENGTH, source_stream)) {
  1630.      linelen = strlen(line);
  1631.      if (keyflag) {
  1632.        if (!strncmp("                  )", line, (linelen > 19) ? 19 : linelen))
  1633.     keyflag = 0;
  1634.        else {
  1635.     line[strlen(line)-1] = '\0'; /* get rid of trailing return */
  1636.     ptr = line;     /* parse keyword */
  1637.     while (*ptr == ' ')
  1638.       ptr++;
  1639.     output[index] = malloc(strlen(ptr)+1);
  1640.     strcpy(output[index], ptr);
  1641.     index++;
  1642.        }
  1643.      }
  1644.      if (!strncmp("   :keyword-list (", line, (linelen > 18) ? 18 : linelen))
  1645.        keyflag = 1;
  1646.      if (!strncmp("   :description", line, (linelen > 15) ? 15 : linelen))
  1647.        desflag = 1;
  1648.      if (desflag) {
  1649.     tmp=strlen(line)+1;
  1650.        descript[nDesLines] = malloc(tmp);
  1651.        strcpy(descript[nDesLines], line);
  1652.        nDesLines++;
  1653.        if (*line == '\"')
  1654.     desflag = 0;
  1655.      }
  1656.    }
  1657.     fclose(source_stream);
  1658.    return(index);
  1659.  }
  1660.  
  1661.  double compare(a, alen, b, blen)
  1662.  char *a[50], *b[50];
  1663.  short alen, blen;
  1664.  {
  1665.    int changes = 0;
  1666.    int i, j;
  1667.    for (i=0; i<alen; i++) {
  1668.      for (j=0; j<blen; j++)
  1669.        if (!strcmp(a[i], b[j]))
  1670.          break;
  1671.      if (j == blen)
  1672.        changes++;
  1673.    }
  1674. #ifdef WIN32
  1675.    if (alen==0) return 0.0;
  1676. #else
  1677.    printf("%d out of %d\n", changes, alen); /* info stuff */
  1678. #endif
  1679.    return((double) changes/alen);
  1680.  }
  1681.