home *** CD-ROM | disk | FTP | other *** search
/ The UNIX CD Bookshelf / OREILLY_TUCB_UNIX_CD.iso / upt / examples / SOURCES / GLIMPSE / GLI40SRC.Z / GLI40SRC / glimpse-4.0.src / main.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-11-23  |  120.7 KB  |  3,574 lines

  1. /* Copyright (c) 1994 Sun Wu, Udi Manber, Burra Gopal.  All Rights Reserved. */
  2. /* bgopal: (1993-4) redesigned/rewritten using agrep's library interface */
  3. #include <sys/param.h>
  4. #include <errno.h>
  5. #include "glimpse.h"
  6. #include "defs.h"
  7. #include <fcntl.h>
  8. #include "checkfile.h"
  9. #include <sys/types.h>
  10. #include <sys/stat.h>
  11. #include <sys/time.h>
  12. #include <sys/file.h>    /* for flock definition */
  13. #if    ISO_CHAR_SET
  14. #include <locale.h>    /* support for 8bit character set */
  15. #endif
  16.  
  17. #define CLIENTSERVER    1
  18. #define USE_MSGHDR    0
  19. #define USE_UNIXDOMAIN    0
  20. #define DEBUG    0
  21.  
  22. #define DEF_SERV_PORT    2001
  23. #define MIN_SERV_PORT    1024
  24. #define MAX_SERV_PORT    30000
  25. #define SERVER_QUEUE_SIZE    10    /* number of requests to buffer up while processing one request = 5 */
  26.  
  27. /* Borrowed from C-Lib */
  28. extern char **environ;
  29. extern int errno;
  30.  
  31. #if    CLIENTSERVER
  32. #include "communicate.c"
  33. #endif    /*CLIENTSERVER*/
  34.  
  35. /* For client-server protocol */
  36. CHAR    *SERV_HOST = NULL;
  37. int    SERV_PORT;
  38. char    glimpse_reqbuf[MAX_ARGS*MAX_NAME_LEN];
  39. extern int glimpse_clientdied;    /* set if signal received about dead socket: need agrep variable so that exec() can return quickly */
  40. int    glimpse_reinitialize = 0;
  41.  
  42. /* Borrowed from agrep.c */
  43. extern int D_length;        /* global variable in agrep */
  44. extern int D;            /* global variable in agrep */
  45. extern int pattern_index;
  46. /* These are used for byte level index search */
  47. extern CHAR CurrentFileName[MAX_LINE_LEN];
  48. extern int SetCurrentFileName;
  49. extern int CurrentByteOffset;
  50. extern int SetCurrentByteOffset;
  51. extern long CurrentFileTime;
  52. extern int SetCurrentFileTime;
  53. extern int execfd;
  54. extern int  agrep_initialfd;
  55. extern CHAR *agrep_inbuffer;
  56. extern int  agrep_inlen;
  57. extern int  agrep_inpointer;
  58. extern FILE *agrep_finalfp;
  59. extern CHAR *agrep_outbuffer;
  60. extern int  agrep_outlen;
  61. extern int  agrep_outpointer;
  62. extern int glimpse_call;    /* prevent agrep from printing out its usage */
  63. extern int glimpse_isserver;    /* prevent agrep from asking for user input */
  64. int    first_search = 1;    /* intra/interaction in process_query() and glimpse_search() */
  65. #if    ISSERVER
  66. int    RemoteFiles = 0;    /* Are the files present locally or remotely? If on, then -NQ is automatically added to all search options for each query */
  67. #endif
  68.  
  69. /* Borrowed from index/io.c */
  70. extern int InfoAfterFilename;
  71. extern int OneFilePerBlock;
  72. extern int StructuredIndex;
  73. extern unsigned int *dest_index_set;
  74. extern unsigned char *dest_index_buf;
  75. extern unsigned int *src_index_set;
  76. extern unsigned char *src_index_buf;
  77. extern unsigned char *merge_index_buf;
  78. extern int mask_int[32];
  79. extern int indexable_char[256];
  80. int test_indexable_char[256];
  81. extern int p_table[MAX_PARTITION];
  82. extern int GMAX_WORD_SIZE;
  83. extern int IndexNumber;        /* used in getword() */
  84. extern int InterpretSpecial;    /* used to "not-split" agrep-regexps */
  85. extern int UseFilters;        /* defined in build_in.c, used for filtering routines in io.c */
  86. extern int ByteLevelIndex;
  87. extern int RecordLevelIndex;
  88. extern int rdelim_len;
  89. extern char rdelim[MAX_LINE_LEN];
  90. extern char old_rdelim[MAX_LINE_LEN];
  91. extern int file_num;
  92. extern int REAL_PARTITION, REAL_INDEX_BUF, MAX_ALL_INDEX, FILEMASK_SIZE;
  93.  
  94. /* Borrowed from get_filename.c */
  95. extern int bigbuffer_size;
  96. extern char *bigbuffer;
  97. extern char *outputbuffer;
  98.  
  99. /* OPTIONS/FLAGS */
  100. int    veryfast = 0;
  101. int    CONTACT_SERVER = 0;    /* Should client try to call server at all or just process query on its own? */
  102. int    NOBYTELEVEL = 0;    /* Some cases where we cannot do byte level fast-search: ALWAYS 0 if !ByteLevelIndex */
  103. int    OPTIMIZEBYTELEVEL = 0;    /* Some cases where we don't want to do byte level search since number of files is small */
  104. int    GCONSTANT = 0;        /* should pattern be taken as-is or parsed? */
  105. int    GLIMITOUTPUT = 0;    /* max no. of output lines: 0=>infinity=default=nolimit */
  106. int    GLIMITTOTALFILE = 0;    /* max no. of files to match: 0=>infinity=default=nolimit */
  107. int    GLIMITPERFILE = 0;    /* not used in glimpse */
  108. int    GBESTMATCH = 0;        /* Should I change -B to -# where # = no. of errors? */
  109. int    GRECURSIVE = 0;
  110. int    GNOPROMPT = 0;
  111. int    GBYTECOUNT = 0;
  112. int    GPRINTFILENUMBER = 0;
  113. int    GPRINTFILETIME = 0;
  114. int    GOUTTAIL = 0;
  115. int    GFILENAMEONLY = 0;    /* how to do it if it is an and expression in structured queries */
  116. int    GNOFILENAME=0;
  117. int    GPRINTNONEXISTENTFILE = 0; /* if filename is not there in index, then at least let user know its name */
  118. int    MATCHFILE = 0;
  119. int    PRINTATTR = 0;
  120. int    PRINTINDEXLINE = 0;
  121. int    Pat_as_is=0;
  122. int    Only_first=0;        /* Do index search only */
  123. int    PRINTAPPXFILEMATCH=0;    /* Print places in file where match occurs: useful with -b only to analyse the index */
  124. int    GCOUNT=0;        /* print number of matches rather than actual matches: used only when PRINTAPPX = 1 */
  125. int    HINTSFROMUSER=0;    /* The user gives the hints about where we should search (result of adding -EQNgy) */
  126. int    WHOLEFILESCOPE=0;    /* used only when foundattr is NOT set: otherwise, scope is whole file anyway */
  127. int    foundattr=0;        /* set in split.c -- != 0 only when StructuredIndex AND query is structured */
  128. int    foundnot=0;        /* set in split.c -- != 0 only when the not operator (~) is present in the pattern */
  129. int    FILENAMESINFILE=0;    /* whether the user is providing an explicit list of filenames to be searched for pattern (if absent, then means all files) */
  130. int    BITFIELDFILE=0;        /* Based on contribution From ada@mail2.umu.se Fri Jul 12 01:56 MST 1996; Christer Holgersson, Sen. SysNet Mgr, Umea University/SUNET, Sweden */
  131. int    BITFIELDOFFSET=0;
  132. int    BITFIELDLENGTH=0;
  133. int    BITFIELDENDIAN=0;
  134. int    GNumDays = 0;        /* whether the user wants files modified within these many days before creating the index: only >0 makes sense */
  135.  
  136. /* structured queries */
  137. CHAR    ***attr_vals;        /* matrix of char pointers: row=max #of attributes, col=max possible values */
  138. CHAR    **attr_found;        /* did the expression corr. to each value in attr_vals match? */
  139. ParseTree *GParse;        /* what kind of expression corr. to attr are we looking for */
  140.  
  141. /* arbitrary booleans */
  142. ParseTree terminals[MAXNUM_PAT];    /* parse tree's terminal node pointers pt. to elements of this array; also used outside */ 
  143. char    matched_terminals[MAXNUM_PAT];    /* ...[i] is 1 if i'th terminal matched: used in filter_output and eval_tree */
  144. int    num_terminals;        /* number of terminal patterns */
  145. int    ComplexBoolean=0;    /* 1 if we need to use parse trees and the eval function */
  146.  
  147. /* index search */
  148. CHAR    *pat_list[MAXNUM_PAT];    /* complete words within global pattern */
  149. int    pat_lens[MAXNUM_PAT];    /* their lengths */
  150. int    pat_attr[MAXNUM_PAT];    /* set of attributes */
  151. int    is_mgrep_pat[MAXNUM_PAT];
  152. int    mgrep_pat_index[MAXNUM_PAT];
  153. int    num_mgrep_pat;
  154. CHAR    pat_buf[(MAXNUM_PAT + 2)*MAXPAT];
  155. int    pat_ptr = 0;
  156. extern char INDEX_DIR[MAX_LINE_LEN];
  157. char    *TEMP_DIR = NULL;    /* directory to store glimpse temporary files, usually /tmp unless -T is specified */
  158. char    indexnumberbuf[256];    /* to read in first few lines of the index */
  159. char    *index_argv[MAX_ARGS];
  160. int    index_argc = 0;
  161. int    bestmatcherrors=0;    /* set during index search, used later on */
  162. int    patindex; 
  163. int    patbufpos = -1;
  164. char    tempfile[MAX_NAME_LEN];
  165. char    *filenames_file = NULL;
  166. char    *bitfield_file = NULL;
  167.  
  168. /* agrep search */
  169. char    *agrep_argv[MAX_ARGS];
  170. int     agrep_argc = 0;
  171. CHAR    *FileOpt;        /* the option list after -F */
  172. int    fileopt_length;
  173. CHAR    GPattern[MAXPAT];
  174. int    GM;
  175. CHAR    APattern[MAXPAT];
  176. int    AM;
  177. CHAR    GD_pattern[MAXPAT];
  178. int    GD_length;
  179. CHAR    **GTextfiles;
  180. CHAR    **GTextfilenames;
  181. int    *GFileIndex;
  182. int    GNumfiles;
  183. int    GNumpartitions;
  184. CHAR    GProgname[MAXNAME];
  185.  
  186. /* persistent file descriptors */
  187. #if    BG_DEBUG
  188. FILE *debug;             /* file descriptor for debugging output */
  189. #endif    /*BG_DEBUG*/
  190. FILE    *timesfp = NULL;
  191. FILE    *timesindexfp = NULL;
  192. FILE    *indexfp = NULL;    /* glimpse index */
  193. FILE    *partfp = NULL;        /* glimpse partitions */
  194. FILE    *minifp = NULL;        /* glimpse turbo */
  195. FILE    *nullfp = NULL;        /* to discard output: agrep -s doesn't work properly */
  196. int    svstdin = 0, svstdout = 1, svstderr = 2;
  197. static int one = 1;        /* to set socket option so that glimpseserver releases socket after death */
  198.  
  199. /* Index manipulation */
  200. struct offsets **src_offset_table;
  201. struct offsets **multi_dest_offset_table[MAXNUM_PAT];
  202. unsigned int *multi_dest_index_set[MAXNUM_PAT];
  203. extern free_list();
  204. struct stat index_stat_buf, file_stat_buf;
  205. int timesindexsize = 0;
  206. int last_Y_filenumber = 0;
  207.  
  208. /* Direct agrep access for bytelevel-indices */
  209. extern int COUNT, INVERSE, TCOMPRESSED, NOFILENAME, POST_FILTER, OUTTAIL, BYTECOUNT, SILENT, NEW_FILE,
  210.     LIMITOUTPUT, LIMITPERFILE, LIMITTOTALFILE, PRINTRECORD, DELIMITER, SILENT, FILENAMEONLY, num_of_matched, prev_num_of_matched, FILEOUT;
  211. CHAR    matched_region[MAX_REGION_LIMIT*2 + MAXPATT*2];
  212. int    RegionLimit=DEFAULT_REGION_LIMIT;
  213.  
  214. /* Returns number of matched records/lines. Uses agrep's options to output stuff nicely; never called with RecordLevelIndex set */
  215. int
  216. glimpse_search(AM, APattern, GD_length, GD_pattern, realfilename, filename, fileindex, src_offset_table, outfp)
  217.     int        AM;
  218.     unsigned char    APattern[];
  219.     int        GD_length;
  220.     unsigned char    GD_pattern[];
  221.     char        *realfilename;
  222.     char        *filename;
  223.     int        fileindex;
  224.     struct offsets    *src_offset_table[];
  225.     FILE        *outfp;
  226. {
  227.     FILE        *infp;
  228.     char        sig[SIGNATURE_LEN];
  229.     struct offsets    **p1, *tp1;
  230.     CHAR        *text, *curtextend, *curtextbegin, c;
  231.     int        times;
  232.     int        num, ret, totalret = 0;
  233.     int        prevoffset = 0, begininterval = 0, endinterval = -1;
  234.     CHAR        *beginregionptr = 0, *endregionptr = 0;
  235.     int        beginpage = 0, endpage = -1;
  236.     static int    MAXTIMES, MAXPGTIMES, pagesize;
  237.     static int    first_time = 1;
  238.  
  239.     /*
  240.      * If can't open file for read, quit
  241.      * For each offset for that file:
  242.      *    seek to that point
  243.      *    go back until delimiter, go forward until delimiter, output it: MAX_REGION_LIMIT is 16K on either side.
  244.      *    read in units of RegionLimit
  245.      *    before outputting matched record, use options to put prefixes (or use memagrep which does everything?)
  246.      * Algorithm changed: don't read same page in twice.
  247.      */
  248.  
  249.     if (first_time) {
  250.         pagesize = DISKBLOCKSIZE;
  251.         MAXTIMES = ((MAX_REGION_LIMIT / RegionLimit) > 1) ? (MAX_REGION_LIMIT / RegionLimit) : 1;
  252.         MAXPGTIMES = ((MAX_REGION_LIMIT / pagesize) > 1) ? (MAX_REGION_LIMIT / pagesize) : 1;
  253.         first_time = 0;
  254.     }
  255.     /* Safety: must end/begin with delim */
  256.     memcpy(matched_region, GD_pattern, GD_length);
  257.     memcpy(matched_region+MAXPATT+2*MAX_REGION_LIMIT, GD_pattern, GD_length);
  258.     text = &matched_region[MAX_REGION_LIMIT+MAXPATT];
  259.  
  260.     if ((infp = my_fopen(filename, "r")) == NULL) return 0;
  261.     NEW_FILE = ON;
  262. #if    0
  263.     /* Cannot search in .CZ files since offset computations will be incorrect */
  264.     TCOMPRESSED = ON;
  265.     if (!tuncompressible_filename(file_list[i], strlen(file_list[i]))) TCOMPRESSED = OFF;
  266.     num_read = fread(sig, 1, SIGNATURE_LEN, infp);
  267.     if ((TCOMPRESSED == ON) && tuncompressible(sig, num_read)) {
  268.         EASYSEARCH = sig[SIGNATURE_LEN-1];
  269.         if (!EASYSEARCH) {
  270.             fprintf(stderr, "not compressed for easy-search: can miss some matches in: %s\n", CurrentFileName);    /* not filename!!! */
  271.         }
  272.     }
  273.     else TCOMPRESSED = OFF;
  274. #endif    /*0*/
  275.  
  276.     p1 = &src_offset_table[fileindex];
  277.     while (*p1 != NULL) {
  278.         if ( (begininterval <= (*p1)->offset) && (endinterval > (*p1)->offset) ) {    /* already covered this area */
  279. #if    DEBUG
  280.             printf("ignoring %d in [%d,%d]\n", (*p1)->offset, begininterval, endinterval);
  281. #endif    /*DEBUG*/
  282.             tp1 = *p1;
  283.             *p1 = (*p1)->next;
  284.             my_free(tp1, sizeof(struct offsets));
  285.             continue;
  286.         }
  287.  
  288.         TCOMPRESSED = OFF;
  289. #if    1
  290.         if ( (beginpage <= (*p1)->offset) && (endpage >= (*p1)->offset) && (text + ((*p1)->offset - prevoffset) + GD_length < endregionptr)) {
  291.             /* beginregionptr = curtextend - GD_length;    /* prevent next curtextbegin to go behind previous curtextend (!) */
  292.             text += ((*p1)->offset - prevoffset);
  293.             prevoffset = (*p1)->offset;
  294.             if (!((curtextend = forward_delimiter(text, endregionptr, GD_pattern, GD_length, 1)) < endregionptr))
  295.                 goto fresh_read;
  296.             if (!((curtextbegin = backward_delimiter(text, beginregionptr, GD_pattern, GD_length, 0)) > beginregionptr))
  297.                 goto fresh_read;
  298.         }
  299.         else { /* NOT within an area already read: must read another page: if record overlapps page, might read page twice: no time to fix */
  300.         fresh_read:
  301.             prevoffset = (*p1)->offset;
  302.             text = &matched_region[MAX_REGION_LIMIT+MAXPATT];    /* middle: points to occurrence of pattern */
  303.             endpage = beginpage = ((*p1)->offset / pagesize) * pagesize;
  304.             /* endpage = (((*p1)->offset + pagesize) / pagesize) * pagesize */
  305.             endregionptr = beginregionptr = text - ((*p1)->offset - beginpage);    /* overlay physical place starting from this logical point */
  306.             /* endregionptr = text + (endpage - (*p1)->offset); */
  307.             curtextbegin = curtextend = text;
  308.             times = 0;
  309.             while (times < MAXPGTIMES) {
  310.                 fseek(infp, endpage, 0);
  311.                 num = (&matched_region[MAX_REGION_LIMIT*2+MAXPATT] - endregionptr < pagesize) ? (&matched_region[MAX_REGION_LIMIT*2+MAXPATT] - endregionptr) : pagesize;
  312.                 if ((num = fread(endregionptr, 1, num, infp)) <= 0) break;
  313.                 endpage += num;
  314.                 endregionptr += num;
  315.                 if (endregionptr <= text) {
  316.                     curtextend = text;    /* error in value of offset: file was modified and offsets no longer true: your RISK! */
  317.                     break;
  318.                 }
  319.                 if (((curtextend = forward_delimiter(text, endregionptr, GD_pattern, GD_length, 1)) < endregionptr) ||
  320.                     (endregionptr >= &matched_region[MAX_REGION_LIMIT*2 + MAXPATT])) break;
  321.                 times ++;
  322.             }
  323.             times = 0;
  324.             while (times < MAXPGTIMES) {    /* I have already read the initial page since endpage is beginpage initially */
  325.                 if ((curtextbegin = backward_delimiter(text, beginregionptr, GD_pattern, GD_length, 0)) > beginregionptr) break;
  326.                 if (beginpage > 0) {
  327.                     if (beginregionptr - pagesize < &matched_region[MAXPATT]) {
  328.                         if ((num = beginregionptr - &matched_region[MAXPATT]) <= 0) break;
  329.                     }
  330.                     else num = pagesize;
  331.                     beginpage -= num;
  332.                     beginregionptr -= num;
  333.                 }
  334.                 else break;
  335.                 times ++;
  336.                 fseek(infp, beginpage, 0);
  337.                 fread(beginregionptr, 1, num, infp);
  338.             }
  339.         }
  340. #else    /*1*/
  341.         /* Find forward delimiter (including delimiter) */
  342.         times = 0;
  343.         fseek(infp, (*p1)->offset, 0);
  344.         while (times < MAXTIMES) {
  345.             if ((num = fread(text+RegionLimit*times, 1, RegionLimit, infp)) > 0)
  346.                 curtextend = forward_delimiter(text, text+RegionLimit*times+num, GD_pattern, GD_length, 1);
  347.             if ((curtextend < text+RegionLimit*times+num) || (num < RegionLimit)) break;
  348.             times ++;
  349.         }
  350.         /* Find backward delimiter (including delimiter) */
  351.         times = 0;
  352.         while (times < MAXTIMES) {
  353.             num = ((*p1)->offset - RegionLimit*(times+1)) > 0 ? ((*p1)->offset - RegionLimit*(times+1)) : 0;
  354.             fseek(infp, num, 0);
  355.             if (num > 0) {
  356.                 fread(text-RegionLimit*(times+1), 1, RegionLimit, infp);
  357.                 curtextbegin = backward_delimiter(text, text-RegionLimit*(times+1), GD_pattern, GD_length, 0);
  358.             }
  359.             else {
  360.                 fread(text-RegionLimit*times-(*p1)->offset, 1, (*p1)->offset, infp);
  361.                 curtextbegin = backward_delimiter(text, text-RegionLimit*times-(*p1)->offset, GD_pattern, GD_length, 0);
  362.             }
  363.             if ((num <= 0) || (curtextbegin > text-RegionLimit*(times+1))) break;
  364.             times ++;
  365.         }
  366. #endif    /*1*/
  367.  
  368.         /* set interval and delete the entry */
  369.         begininterval = (*p1)->offset - (text - curtextbegin);
  370.         endinterval = (*p1)->offset + (curtextend - text); 
  371.  
  372.         if (strncmp(curtextbegin, GD_pattern, GD_length)) {
  373.             /* always pass enclosing delimiters to agrep; since we have seen text before curtextbegin + we have space, we can overwrite */
  374.             memcpy(curtextbegin - GD_length, GD_pattern, GD_length);
  375.             curtextbegin -= GD_length;
  376.         }
  377. #if    DEBUG
  378.         c = *curtextend;
  379.         *curtextend = '\0';
  380.         printf("%s [%d < %d < %d], text = %d: %s\n", CurrentFileName, begininterval, (*p1)->offset, endinterval, text, curtextbegin);
  381.         *curtextend = c;
  382. #endif    /*DEBUG*/
  383.  
  384.         tp1 = *p1;
  385.         *p1 = (*p1)->next;
  386.         my_free(tp1, sizeof(struct offsets));
  387.         if (curtextend <= curtextbegin) continue;    /* error in offsets/delims */
  388.  
  389.         /*
  390.          * Don't call memagrep since that is heavy weight. Call exec
  391.          * directly after doing agrep_search()'s preprocessing here.
  392.          * PS: can add agrep variable not to do delim search if called from here
  393.          * since that prevents unnecessarily scanning the buffer for the 2nd time.
  394.          */
  395.         CurrentByteOffset = begininterval+1;
  396.         SetCurrentByteOffset = 1;
  397.         first_search = 1;
  398.         if (first_search) {
  399.             if ((ret = memagrep_search(AM, APattern, curtextend-curtextbegin, curtextbegin, 0, outfp)) > 0)
  400.                 totalret ++; /* += ret */
  401.              else if ((ret < 0) && (errno == AGREP_ERROR)) {
  402.                 fclose(infp);
  403.                 return -1;
  404.             }
  405.             first_search = 0;
  406.         }
  407.         else {    /* All agrep globals are properly set: has a bug because agrep's globals aren't properly reinitialized without agrep_search :-( */
  408.             agrep_finalfp = (FILE *)outfp;
  409.             agrep_outlen = 0;
  410.             agrep_outbuffer = NULL;
  411.             agrep_outpointer = 0;
  412.             execfd = agrep_initialfd = -1;
  413.             agrep_inbuffer = curtextbegin;
  414.             agrep_inlen = curtextend - curtextbegin;
  415.             agrep_inpointer = 0;
  416.             if ((ret = exec(-1, NULL)) > 0)
  417.                 totalret ++; /* += ret; */
  418.              else if ((ret < 0) && (errno == AGREP_ERROR)) {
  419.                 fclose(infp);
  420.                 return -1;
  421.             }
  422.         }
  423.  
  424.         if (((LIMITOUTPUT > 0) && (LIMITOUTPUT <= num_of_matched)) ||
  425.             ((LIMITPERFILE > 0) && (LIMITPERFILE <= num_of_matched - prev_num_of_matched))) break;    /* done */
  426.         if ((totalret > 0) && FILENAMEONLY) break;
  427.     } /* while *p1 != NULL */
  428.  
  429.     SetCurrentByteOffset = 0;
  430.     fclose(infp);
  431.     if (totalret > 0) {    /* dirty solution: must handle part of agrep here */
  432.         if (COUNT && !FILEOUT && !SILENT) {
  433.             if(!NOFILENAME) fprintf(outfp, "%s: %d\n", CurrentFileName, totalret);
  434.             else fprintf(outfp, "%d\n", totalret);
  435.         }
  436.         else if (FILEOUT) {
  437.             file_out(realfilename);
  438.         }
  439.     }
  440.     return totalret;
  441. }
  442.  
  443. /* Sets lastfilenumber that needs to be searched: rest must be discarded */
  444. int
  445. process_Y_option(num_files, num_days, fp)
  446.     int    num_files, num_days;
  447.     FILE    *fp;
  448. {
  449.     CHAR    arrayend[4];
  450.  
  451.     if ((num_days <= 0) || (fp == NULL) || (timesindexsize <= 0)) return 0;
  452.     last_Y_filenumber = num_files;
  453.     if (num_days * sizeof(int) >= timesindexsize) return 0;    /* everything will be within so many days */
  454.     if (fseek(fp, num_days*sizeof(int), 0) == -1) return -1;
  455.     fread(arrayend, 1, 4, fp);
  456.     if ((last_Y_filenumber = (arrayend[0] << 24) | (arrayend[1] << 16) | (arrayend[2] << 8) | arrayend[3]) > num_files) last_Y_filenumber = num_files;
  457.     if (last_Y_filenumber == 0) {
  458.         last_Y_filenumber = 1;
  459.         printf("Warning: no files modified in the last %d days were found in the index.\nSearching only the most recently modified file...\n", num_days);
  460.     }
  461.     return 0;
  462. }
  463.  
  464. read_index(indexdir)
  465. char    indexdir[MAXNAME];
  466. {
  467.     char    *home;
  468.     char    s[MAXNAME];
  469.     int    ret;
  470.  
  471.     if (indexdir[0] == '\0') {
  472.         if ((home = (char *)getenv("HOME")) == NULL) {
  473.             getcwd(indexdir, MAXNAME-1);
  474.             fprintf(stderr, "using working-directory '%s' to locate index\n", indexdir);
  475.         }
  476.         else strncpy(indexdir, home, MAXNAME);
  477.     }
  478.     ret = chdir(indexdir);
  479.     if (getcwd(INDEX_DIR, MAXNAME-1) == NULL) strcpy(INDEX_DIR, indexdir);
  480.     if (ret < 0) {
  481.         fprintf(stderr, "using working-directory '%s' to locate index\n", INDEX_DIR);
  482.     }
  483.  
  484.     sprintf(s, "%s", INDEX_FILE);
  485.     indexfp = fopen(s, "r");
  486.     if(indexfp == NULL) {
  487.         fprintf(stderr, "can't open glimpse index-file %s/%s\n", INDEX_DIR, INDEX_FILE);
  488.         fprintf(stderr, "(use -H to give an index-directory or run 'glimpseindex' to make an index)\n");
  489.         return -1;
  490.     }
  491.     if (stat(s, &index_stat_buf) == -1) {
  492.         fprintf(stderr, "can't stat %s/%s\n", INDEX_DIR, s);
  493.         fclose(indexfp);
  494.         return -1;
  495.     }
  496.  
  497.     sprintf(s, "%s", P_TABLE);
  498.     partfp = fopen(s, "r");
  499.     if(partfp == NULL) {
  500.         fprintf(stderr, "can't open glimpse partition-table %s/%s\n", INDEX_DIR, P_TABLE);
  501.         fprintf(stderr, "(use -H to specify an index-directory or run glimpseindex to make an index)\n");
  502.         fclose(indexfp);
  503.         return -1;
  504.     }
  505.  
  506.     sprintf(s, "%s", DEF_TIME_FILE);
  507.     timesfp = fopen(s, "r");
  508.  
  509.     sprintf(s, "%s.index", DEF_TIME_FILE);
  510.     timesindexfp = fopen(s, "r");
  511.     if (timesindexfp != NULL) {
  512.         struct stat st;
  513.         fstat(fileno(timesindexfp), &st);
  514.         timesindexsize = st.st_size;
  515.     }
  516.  
  517.     /* Get options */
  518. #if    BG_DEBUG
  519.     debug = fopen(DEBUG_FILE, "w+");
  520.     if(debug == NULL) {
  521.         fprintf(stderr, "can't open file %s/%s, errno=%d\n", INDEX_DIR, DEBUG_FILE, errno);
  522.         return(-1);
  523.     }
  524. #endif    /*BG_DEBUG*/
  525.     fgets(indexnumberbuf, 256, indexfp);
  526.     if(strstr(indexnumberbuf, "1234567890")) IndexNumber = ON;
  527.     else IndexNumber = OFF;
  528.     fscanf(indexfp, "%%%d\n", &OneFilePerBlock);
  529.     if (OneFilePerBlock < 0) {
  530.         ByteLevelIndex = ON;
  531.         OneFilePerBlock = -OneFilePerBlock;
  532.     }
  533.     else if (OneFilePerBlock == 0) {
  534.         GNumpartitions = get_table(P_TABLE, p_table, MAX_PARTITION, 0);
  535.     }
  536.     fscanf(indexfp, "%%%d%s\n", &StructuredIndex, old_rdelim);
  537.     /* Set WHOLEFILESCOPE for do-it-yourself request processing at client */
  538.     WHOLEFILESCOPE = 1;
  539.     if (StructuredIndex <= 0) {
  540.         if (StructuredIndex == -2) {
  541.             RecordLevelIndex = 1;
  542.             strcpy(rdelim, old_rdelim);
  543.             rdelim_len = strlen(rdelim);
  544.             preprocess_delimiter(rdelim, rdelim_len, rdelim, &rdelim_len);
  545.         }
  546.         WHOLEFILESCOPE = 0;
  547.         StructuredIndex = 0;
  548.         PRINTATTR = 0;    /* doesn't make sense: must not go into filter_output */
  549.     }
  550.     else if (-1 == (StructuredIndex = attr_load_names(ATTRIBUTE_FILE))) {
  551.         fprintf(stderr, "error in reading attribute file %s/%s\n", INDEX_DIR, ATTRIBUTE_FILE);
  552.         return(-1);
  553.     }
  554. #if    BG_DEBUG
  555.     fprintf(debug, "buf = %s OneFilePerBlock=%d StructuredIndex=%d\n", indexnumberbuf, OneFilePerBlock, StructuredIndex);
  556. #endif    /*BG_DEBUG*/
  557.     sprintf(s, "%s", MINI_FILE);
  558.     minifp = fopen(s, "r");
  559.     /* if (minifp==NULL && OneFilePerBlock) fprintf(stderr, "Can't open for reading: %s/%s --- cannot do very fast search\n", INDEX_DIR, MINI_FILE); */
  560.     if (OneFilePerBlock && glimpse_isserver && (minifp != NULL)) read_mini(indexfp, minifp);
  561.     read_filenames();
  562.  
  563.     /* Once IndexNumber info is available */
  564.     set_indexable_char(indexable_char);
  565.     set_indexable_char(test_indexable_char);
  566.     set_special_char(indexable_char);
  567.     return 0;
  568. }
  569.  
  570. #define CLEANUP \
  571. {\
  572.     int    q, k;\
  573.     if (timesfp != NULL) fclose(timesfp);\
  574.     if (timesindexfp != NULL) fclose(timesindexfp);\
  575.     if (indexfp != NULL) fclose(indexfp);\
  576.     if (partfp != NULL) fclose(partfp);\
  577.     if (minifp != NULL) fclose(minifp);\
  578.     if (nullfp != NULL) fclose(nullfp);\
  579.     indexfp = partfp = minifp = nullfp = NULL;\
  580.     if (ByteLevelIndex) {\
  581.         if (src_offset_table != NULL) for (k=0; k<OneFilePerBlock; k++) {\
  582.             free_list(&src_offset_table[k]);\
  583.         }\
  584.         for (q=0; q<MAXNUM_PAT; q++) {\
  585.             if (multi_dest_offset_table[q] != NULL) for (k=0; k<OneFilePerBlock; k++) {\
  586.             free_list(&multi_dest_offset_table[q][k]);\
  587.             }\
  588.         }\
  589.     }\
  590.     if (StructuredIndex) {\
  591.         attr_free_table();\
  592.     }\
  593.     destroy_filename_hashtable();\
  594.     my_free(SERV_HOST, MAXNAME);\
  595. }
  596.  
  597. /* Called whenever we get SIGUSR2/SIGHUP (at the end of process_query()) */
  598. reinitialize_server(argc, argv)
  599.     int    argc;
  600.     char    **argv;
  601. {
  602.     int    i, fd;
  603.     CLEANUP;
  604. #if    0
  605.     init_filename_hashtable();
  606.     region_initialize();
  607.     indexfp = partfp = minifp = nullfp = NULL;
  608.     if ((nullfp = fopen("/dev/null", "w")) == NULL) {
  609.         return(-1);
  610.     }
  611.     src_offset_table = NULL;
  612.     for (i=0; i<MAXNUM_PAT; i++) multi_dest_offset_table[i] = NULL;
  613.     if (-1 == read_index(INDEX_DIR)) return(-1);
  614. #if    0
  615. #ifndef    LOCK_UN
  616. #define LOCK_UN    8
  617. #endif
  618.     if ((fd = open(INDEX_DIR, O_RDONLY)) == -1) return -1;
  619.     flock(fd, LOCK_UN);
  620.     close(fd);
  621. #endif
  622.     return 0;
  623. #else
  624.     return execve(argv[0], argv, environ);
  625. #endif
  626. }
  627.  
  628. /* MUST CARE IF PIPE/SOCKET IS BROKEN! ALSO SIGUSR1 (hardy@cs.colorado.edu) => QUIT CURRENT REQUEST. */
  629. int ignore_signal[32] = {    0,
  630.             0, 0, 1, 1, 1, 1, 1, 1,    /* all the tracing stuff: since default action is to dump core */
  631.             0, 0, 0, 0, 0, 0, 0, 0,
  632.             0, 0, 0, 0, 0, 0, 0, 0,
  633.             0, 0, 0, 0, 1, 0, 0 };    /* resource lost: since default action is to dump core */
  634.  
  635. /* S.t. sockets don't persist: they sometimes have a bad habit of doing so */
  636. void
  637. cleanup()
  638. {
  639.     int    i;
  640.  
  641.     /* ^C in the middle of a client call */
  642.     if (svstderr != 2) {
  643.         close(2);
  644.         dup(svstderr);
  645.     }
  646.     fprintf(stderr, "server cleaning up...\n");
  647.     CLEANUP;
  648.     for (i=0; i<64; i++) close(i);
  649.     exit(3);
  650. }
  651.  
  652. void reinitialize(s)
  653. int s;
  654. {
  655.     /* To force main-while loop call reinitialize_server() after do_select() */
  656.     glimpse_reinitialize = 1;
  657. #ifdef __svr4__
  658.     /* Solaris 2.3 insists that you reset the signal handler */
  659.     (void)signal(s, reinitialize);
  660. #endif
  661. }
  662.  
  663. #define QUITREQUESTMSG "glimpseserver: aborting request...\n"
  664. /* S.t. one request doesn't keep server occupied too long, when client already quits */
  665. void quitrequest(s)
  666. int s;
  667. {
  668.     /*
  669.      * Don't write onto stderr, since 2 is duped to sockfd => can cause recursive signal!
  670.      * Also, don't print error message more than once for quitting one request. The
  671.      * server receives signals for EVERY write it attempts when it finds a match: I could
  672.      * not find a way to prevent it, but agrep/bitap.c/fill_buf() was fixed to limit it.
  673.      * -- bg on 16th Feb 1995
  674.      */
  675.     if (!glimpse_clientdied && (s != SIGUSR1))    /* USR1 is a "friendly" cleanup message */
  676.         write(svstderr, QUITREQUESTMSG, strlen(QUITREQUESTMSG));
  677.  
  678.     glimpse_clientdied = 1;
  679. #ifdef __svr4__
  680.     /* Solaris 2.3 insists that you reset the signal handler */
  681.     (void)signal(s, quitrequest);
  682. #endif
  683. }
  684.  
  685. /* The client receives this signal when an output/input pipe is broken, etc. It simply exits from the current request */
  686. void exitrequest()
  687. {
  688.     glimpse_clientdied = 1;
  689. }
  690.  
  691. main(argc, argv)
  692. int argc;
  693. char *argv[];
  694. {
  695.     int    ret, tried = 0;
  696.     char    indexdir[MAXNAME];
  697.     char    **oldargv = argv;
  698.     int    oldargc = argc;
  699. #if    CLIENTSERVER
  700.     int    sockfd, newsockfd, clilen, len, clpid;
  701.     int    clout;
  702. #if    USE_UNIXDOMAIN
  703.     struct sockaddr_un cli_addr, serv_addr;
  704. #else    /*USE_UNIXDOMAIN*/
  705.     struct sockaddr_in cli_addr, serv_addr;
  706.     struct hostent *hp;
  707. #endif    /*USE_UNIXDOMAIN*/
  708.     int    cli_len;
  709.     int    clargc;
  710.     char    **clargv;
  711.     int    clstdin, clstdout, clstderr;
  712.     int    i;
  713.     char    array[4];
  714.     char    *p, c;
  715. #endif    /*CLIENTSERVER*/
  716.     int    quitwhile;
  717.  
  718. #if    ISO_CHAR_SET
  719.     setlocale(LC_ALL,"");       /* support for 8bit character set: ew@senate.be, Henrik.Martin@eua.ericsson.se */
  720. #endif
  721. #if    CLIENTSERVER && ISSERVER
  722.     glimpse_isserver = 1;    /* I am the server */
  723. #else    /*CLIENTSERVER && ISSERVER*/
  724.     if (argc <= 1) {
  725.         usage();    /* Client nees at least 1 argument */
  726.         exit(1);
  727.     }
  728. #endif    /*CLIENTSERVER && ISSERVER*/
  729.  
  730. #define RETURNMAIN(val)\
  731. {\
  732.     CLEANUP;\
  733.     if (val < 0) exit (1);\
  734.     else exit (0);\
  735. }
  736.  
  737.     SERV_HOST = (CHAR *)my_malloc(MAXNAME);
  738. #if    !SYSCALLTESTING
  739.     /* once-only initialization */
  740.     init_filename_hashtable();
  741.     src_offset_table = NULL;
  742.     for (i=0; i<MAXNUM_PAT; i++) multi_dest_offset_table[i] = NULL;
  743. #endif
  744.     gethostname(SERV_HOST, MAXNAME - 2);
  745.     SERV_PORT = DEF_SERV_PORT;
  746.     srand(getpid());
  747.     umask(077);
  748.     strcpy(&GProgname[0], argv[0]);
  749. #if    !SYSCALLTESTING
  750.     region_initialize();
  751. #endif
  752.     indexfp = partfp = minifp = nullfp = NULL;
  753.     if ((nullfp = fopen("/dev/null", "w")) == NULL) {
  754.         fprintf(stderr, "%s: cannot open for writing: /dev/null, errno=%d\n", argv[0], errno);
  755.         RETURNMAIN(-1);
  756.     }
  757.     InterpretSpecial = ON;
  758.     GMAX_WORD_SIZE = MAXPAT;
  759.  
  760. #if    CLIENTSERVER
  761. #if    !ISSERVER
  762.     /* Install signal handlers so that glimpse doesn't continue to run when pipes get broken, etc. */
  763.     if (((void (*)())-1 == signal(SIGPIPE, exitrequest))
  764. #ifndef    SCO
  765.         || ((void (*)())-1 == signal(SIGURG, exitrequest))
  766. #endif
  767.     )
  768.     {
  769.         /* Check for return values here since they ensure reliability */
  770.         fprintf(stderr, "glimpse: Unable to install signal-handlers.\n");
  771.         RETURNMAIN(-1);
  772.     }
  773.  
  774.     /* Check if client has too many arguments: then it is surely running as agrep since I have < half those options! */
  775.     if (argc > MAX_ARGS) goto doityourself;
  776. #endif    /*!ISSERVER*/
  777.  
  778. #if    !SYSCALLTESTING
  779.     while((--argc > 0) && (*++argv)[0] == '-' ) {
  780.         p = argv[0] + 1;    /* ptr to first character after '-' */
  781.         c = *(argv[0]+1);
  782.         quitwhile = OFF;
  783.         while (!quitwhile && (*p != '\0')) {
  784.             c = *p;
  785.             switch(c) {
  786.             /* Look for -H option at server (only one that makes sense); if client has a -H, then it goes to doityourself */
  787.             case 'H' :
  788.                 if (*(p + 1) == '\0') {/* space after - option */
  789.                     if (argc <= 1) {
  790.                         fprintf(stderr, "%s: a directory name must follow the -H option\n", GProgname);
  791.                         RETURNMAIN(usageS());
  792.                     }
  793.                     argv ++;
  794.                     strcpy(indexdir, argv[0]);
  795.                     argc --;
  796.                 }
  797.                 else {
  798.                     strcpy(indexdir, p+1);
  799.                 }
  800.                 quitwhile = ON;
  801.                 break;
  802.  
  803.             /* Recognized by both client and server */
  804.             case 'J' :
  805.                 if (*(p + 1) == '\0') {/* space after - option */
  806.                     if (argc <= 1) {
  807.                         fprintf(stderr, "%s: the server host name must follow the -J option\n", GProgname);
  808. #if    ISSERVER
  809.                         RETURNMAIN(usageS());
  810. #else    /*ISSERVER*/
  811.                         RETURNMAIN(usage());
  812. #endif    /*ISSERVER*/
  813.                     }
  814.                     argv ++;
  815.                     strcpy(SERV_HOST, argv[0]);
  816.                     argc --;
  817.                 }
  818.                 else {
  819.                     strcpy(SERV_HOST, p+1);
  820.                 }
  821.                 quitwhile = ON;
  822.                 break;
  823.  
  824.             /* Recognized by both client and server */
  825.             case 'K' :
  826.                 if (*(p + 1) == '\0') {/* space after - option */
  827.                     if (argc <= 1) {
  828.                         fprintf(stderr, "%s: the server port must follow the -C option\n", GProgname);
  829. #if    ISSERVER
  830.                         RETURNMAIN(usageS());
  831. #else    /*ISSERVER*/
  832.                         RETURNMAIN(usage());
  833. #endif    /*ISSERVER*/
  834.                     }
  835.                     argv ++;
  836.                     SERV_PORT = atoi(argv[0]);
  837.                     argc --;
  838.                 }
  839.                 else {
  840.                     SERV_PORT = atoi(p+1);
  841.                 }
  842.                 if ((SERV_PORT < MIN_SERV_PORT) || (SERV_PORT > MAX_SERV_PORT)) {
  843.                     fprintf(stderr, "Bad server port %d: must be in [%d, %d]: using default %d\n",
  844.                         SERV_PORT, MIN_SERV_PORT, MAX_SERV_PORT, DEF_SERV_PORT);
  845.                     SERV_PORT = DEF_SERV_PORT;
  846.                 }
  847.                 quitwhile = ON;
  848.                 break;
  849.  
  850. #if    ISSERVER
  851. #if    SFS_COMPAT
  852.             case 'R' :
  853.                 RemoteFiles = ON;
  854.                 break;
  855.  
  856.             case 'Z' :
  857.                 /* No op */
  858.                 break;
  859. #endif
  860.             /* server cannot recognize any other option */
  861.             default :
  862.                 fprintf(stderr, "%s: server cannot recognize option: '%s'\n", GProgname, p);
  863.                 RETURNMAIN(usageS());
  864. #else    /*ISSERVER*/
  865.  
  866.             /* These have 1 argument each, so must do quitwhile */
  867.             case 'd' :
  868.             case 'e' :
  869.             case 'f' :
  870.             case 'k' :
  871.             case 'D' :
  872.             case 'F' : 
  873.             case 'I' :
  874.             case 'L' :
  875.             case 'R' :
  876.             case 'S' :
  877.             case 'T' :
  878.             case 'Y' :
  879.             case 'p' :
  880.                 if (argv[0][2] == '\0') {/* space after - option */
  881.                     if(argc <= 1) {
  882.                         fprintf(stderr, "%s: the '-%c' option must have an argument\n", GProgname, c);
  883.                         RETURNMAIN(usage());
  884.                     }
  885.                     argv++;
  886.                     argc--;
  887.                 }
  888.                 quitwhile = ON;
  889.                 break;
  890.  
  891.             /* These are illegal */
  892.             case 'm' :
  893.             case 'v' :
  894.                 fprintf(stderr, "%s: illegal option: '-%c'\n", GProgname, c);
  895.                 RETURNMAIN(usage());
  896.  
  897.             /* They can't be patterns and filenames since they start with a -, these don't have arguments */
  898.             case '!' :
  899.             case 'a' :
  900.             case 'b' :
  901.             case 'c' :
  902.             case 'h' :
  903.             case 'i' :
  904.             case 'j' :
  905.             case 'l' :
  906.             case 'n' :
  907.             case 'o' :
  908.             case 'q' :
  909.             case 'r' :
  910.             case 's' :
  911.             case 't' :
  912.             case 'u' :
  913.             case 'g' :
  914.             case 'w' :
  915.             case 'x' :
  916.             case 'y' :
  917.             case 'z' :
  918.             case 'A' :
  919.             case 'B' :
  920.             case 'E' :
  921.             case 'G' :
  922.             case 'M' :
  923.             case 'N' :
  924.             case 'O' :
  925.             case 'P' :
  926.             case 'Q' :
  927.             case 'U' :
  928.             case 'W' :
  929.             case 'X' :
  930.             case 'Z' :
  931.                 break;
  932.  
  933.             case 'C':
  934.                 CONTACT_SERVER = 1;
  935.                 break;
  936.  
  937.             case 'V' :
  938.                 printf("\nThis is glimpse version %s, %s.\n\n", GLIMPSE_VERSION, GLIMPSE_DATE);
  939.                 RETURNMAIN(0);
  940.  
  941.             default :
  942.                 if (isdigit(c)) quitwhile = ON;
  943.                 else {
  944.                     fprintf(stderr, "%s: illegal option: '-%c'\n", GProgname, c);
  945.                     RETURNMAIN(usage());
  946.                 }
  947.                 break;
  948. #endif    /*ISSERVER*/
  949.             } /* switch(c) */
  950.             p ++;
  951.         }
  952.     }
  953. #else
  954.     CONTACT_SERVER = 1;
  955.     argc=0;
  956. #endif
  957.  
  958. #if    !ISSERVER
  959.     /* Next arg must be the pattern: Check if the user wants to run the client as agrep, or doesn't want to contact the server */
  960.     if ((argc > 1) || (!CONTACT_SERVER)) goto doityourself;
  961. #endif    /*!ISSERVER*/
  962.  
  963.     argv = oldargv;
  964.     argc = oldargc;
  965. #endif    /*CLIENTSERVER*/
  966.  
  967. #if    ISSERVER && CLIENTSERVER
  968.     if (-1 == read_index(indexdir)) RETURNMAIN(ret);
  969.  
  970.     /* Install signal handlers so that glimpseserver doesn't continue to run when sockets get broken, etc. */
  971.     for (i=0; i<32; i++)
  972.         if (ignore_signal[i]) signal(i, SIG_IGN);
  973.     signal(SIGHUP, cleanup);
  974.     signal(SIGINT, cleanup);
  975.     if (((void (*)())-1 == signal(SIGPIPE, quitrequest)) ||
  976.         ((void (*)())-1 == signal(SIGUSR1, quitrequest)) ||
  977. #ifndef    SCO
  978.         ((void (*)())-1 == signal(SIGURG, quitrequest)) ||
  979. #endif
  980.         ((void (*)())-1 == signal(SIGUSR2, reinitialize)) ||
  981.         ((void (*)())-1 == signal(SIGHUP, reinitialize))) {
  982.         /* Check for return values here since they ensure reliability */
  983.         fprintf(stderr, "glimpseserver: Unable to install signal-handlers.\n");
  984.         RETURNMAIN(-1);
  985.     }
  986.  
  987. #if    USE_UNIXDOMAIN
  988.     if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
  989.         fprintf(stderr, "server cannot open socket for communication.\n");
  990.         RETURNMAIN(-1);
  991.     }
  992.     unlink("/tmp/.glimpse_server");
  993.     memset((char *)&serv_addr, '\0', sizeof(serv_addr));
  994.     serv_addr.sun_family = AF_UNIX;
  995.     strcpy(serv_addr.sun_path, "/tmp/.glimpse_server");    /* < 108 ! */
  996.     len = strlen(serv_addr.sun_path) + sizeof(serv_addr.sun_family);
  997. #else    /*USE_UNIXDOMAIN*/
  998.     if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
  999.         perror("glimpseserver: Cannot create socket");
  1000.         RETURNMAIN(-1);
  1001.     }
  1002.     memset((char *)&serv_addr, '\0', sizeof(serv_addr));
  1003.         serv_addr.sin_family = AF_INET;
  1004.     serv_addr.sin_port = htons(SERV_PORT);
  1005. #if    0
  1006.     /* use host-names not internet style d.d.d.d notation */
  1007.     serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
  1008. #else
  1009.     /* 
  1010.      * We only want to accept connections from glimpse clients 
  1011.      * on the SERV_HOST, do not use INADDR_ANY!
  1012.      */
  1013.     if ((hp = gethostbyname(SERV_HOST)) == NULL) {
  1014.         perror("glimpseserver: Cannot resolve host");
  1015.         RETURNMAIN(-1);
  1016.     }
  1017.     memcpy((caddr_t)&serv_addr.sin_addr, hp->h_addr, hp->h_length);
  1018. #endif    /*0*/
  1019.     len = sizeof(serv_addr);
  1020. #endif    /*USE_UNIXDOMAIN*/
  1021.     /* test code for glimpse server, get it to realse socket when it dies: contribution by Sheldon Smoker <sheldon@thunder.tig.com> */
  1022.     if((setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,(char *)&one,sizeof(one))) == -1) {
  1023.         fprintf(stderr,"glimpseserver: could not set socket option\n");
  1024.         perror("setsockopt");
  1025.         exit(1);
  1026.     }
  1027.     /* end test code */
  1028.  
  1029.     if (bind(sockfd, (struct sockaddr *)&serv_addr, len) < 0) {
  1030.         perror("glimpseserver: Cannot bind to socket");
  1031.         RETURNMAIN(-1);
  1032.     }
  1033.     listen(sockfd, SERVER_QUEUE_SIZE);
  1034.  
  1035.     printf("glimpseserver: On-line (pid = %d, port = %d) waiting for request...\n", getpid(), SERV_PORT);
  1036.     fflush(stdout);    /* must fflush to print on server stdout */
  1037.     while (1) {
  1038.         /*
  1039.          *  Spin until sockfd is ready to do a non-blocking accept(2).
  1040.          *  We only wait for 15 seconds, because SunOS may
  1041.          *  swap us out if we block for 20 seconds or more.
  1042.          *  -- Courtesy: Darren Hardy, hardy@cs.colorado.edu
  1043.          */
  1044.         if ((ret = do_select(sockfd, 15)) == 0) {
  1045.             if ((errno == EINTR) && glimpse_reinitialize) {
  1046.                 glimpse_reinitialize = 0;
  1047.                 CLEANUP;
  1048.                 close(sockfd);
  1049.                 sleep(IC_PORTRELEASE);
  1050.                 reinitialize_server(oldargc, oldargv);
  1051.             }
  1052.             continue;
  1053.         }
  1054.         else if (ret != 1) continue;
  1055.  
  1056.         /* get parameters */
  1057.         ret = 0;
  1058.         clargc = 0;
  1059.         clargv = NULL;
  1060.         cli_len = sizeof(cli_addr);
  1061.         if ((newsockfd = accept(sockfd, &cli_addr, &cli_len)) < 0) continue;
  1062.         if (getreq(newsockfd, glimpse_reqbuf, &clstdin, &clstdout, &clstderr, &clargc, &clargv, &clpid) < 0) {
  1063.             ret = -1;
  1064. #if    DEBUG
  1065.             printf("getreq errno: %d\n", errno);
  1066. #endif    /*DEBUG*/
  1067.             goto end_process;
  1068.         }
  1069.  
  1070. #if    DEBUG
  1071.         printf("server processing request on %x\n", newsockfd);
  1072. #endif    /*DEBUG*/
  1073.         /*
  1074.          * Server doesn't wait for response, no point using
  1075.         svstdin = dup(0);
  1076.         close(0);
  1077.         dup(clstdin);
  1078.         close(clstdin);
  1079.          */
  1080.         /*
  1081.          * This is wrong since clstderr == clstdout!
  1082.         svstdout = dup(1);
  1083.         close(1);
  1084.         dup(clstdout);
  1085.         close(clstdout);
  1086.         svstderr = dup(2);
  1087.         close(2);
  1088.         dup(clstderr);
  1089.         close(clstderr);
  1090.         */
  1091.         svstdout = dup(1);
  1092.         svstderr = dup(2);
  1093.         close(1);
  1094.         close(2);
  1095.         dup(clstdout);
  1096.         dup(clstderr);
  1097.         close(clstdout);
  1098.         close(clstderr);
  1099.  
  1100.                         /*
  1101.              * IMPORTANT: Unbuffered I/O to the client!
  1102.                          * Done for Harvest since partial results might be
  1103.                          * needed and fflush will not flush partial results
  1104.                          * to the client if we type ^C and kill it: it puts
  1105.                          * them into /dev/null. This way, output is unbuffered
  1106.                          * and the client sees at least some results if killed.
  1107.                          */
  1108.                         setbuf(stdout, NULL);
  1109.                         setbuf(stderr, NULL);
  1110.  
  1111.             glimpse_call = 0;
  1112.             glimpse_clientdied = 0;
  1113.             ret = process_query(clargc, clargv, newsockfd);
  1114.         /*
  1115.          * Server doesn't wait for response, no point using
  1116.         close(0);
  1117.         dup(svstdin);
  1118.         close(svstdin);
  1119.         svstdin = 0;
  1120.          */
  1121.         if (glimpse_clientdied) {
  1122.             /*
  1123.              * This code is *ONLY* used as a safety net now.  
  1124.              * The old problem was that users would see portions 
  1125.              * of previous (and usually) unrelated queries!
  1126.              * glimpseserver now uses unbuffered I/O to the
  1127.              * client so all previous fwrite's to now are
  1128.              * gone.  But since this is such a nasty problem
  1129.              * we flush stdout to /dev/null just in case.
  1130.              */
  1131.             clout = open("/dev/null", O_WRONLY);
  1132.             close(1);
  1133.             dup(clout);
  1134.             close(clout);
  1135.             fflush(stdout);
  1136.         } 
  1137.  
  1138.         /* Restore svstdout and svstdout to stdout/stderr */
  1139.         close(1);
  1140.         dup(svstdout);
  1141.         close(svstdout);
  1142.         svstdout = 1;
  1143.         close(2);
  1144.         dup(svstderr);
  1145.         close(svstderr);
  1146.         svstderr = 2;
  1147.  
  1148.     end_process:
  1149. #if    USE_MSGHDR
  1150.         /* send reply and cleanup */
  1151.         array[0] = (ret & 0xff000000) >> 24;
  1152.         array[1] = (ret & 0xff0000) >> 16;
  1153.         array[2] = (ret & 0xff00) >> 8;
  1154.         array[3] = (ret & 0xff);
  1155.         writen(newsockfd, array, 4);
  1156. #endif    /*USE_MSGHDR*/
  1157. #if    DEBUG
  1158.         write(1, "done\n", 5);
  1159. #endif    /*DEBUG*/
  1160.         for (i=0; i<clargc; i++)
  1161.             if (clargv[i] != NULL) my_free(clargv[i], 0);
  1162.         if (clargv != NULL) my_free(clargv, 0);
  1163.         close(newsockfd);    /* if !USE_MSGHDR, client directly reads from socket and writes onto stdout until EOF */
  1164.     }
  1165. #else    /*ISSERVER && CLIENTSERVER*/
  1166.  
  1167. #if    CLIENTSERVER
  1168. trynewsocket:
  1169. #if    USE_UNIXDOMAIN
  1170.     if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
  1171.         perror("socket");
  1172.         goto doityourself;
  1173.     }
  1174.     memset((char *)&serv_addr, '\0', sizeof(serv_addr));
  1175.     serv_addr.sun_family = AF_UNIX;
  1176.     strcpy(serv_addr.sun_path, "/tmp/.glimpse_server");    /* < 108 ! */
  1177.     len = strlen(serv_addr.sun_path) + sizeof(serv_addr.sun_family);
  1178. #else    /*USE_UNIXDOMAIN*/
  1179.     if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
  1180.         perror("socket");
  1181.         goto doityourself;
  1182.     }
  1183.     serv_addr.sin_family = AF_INET;
  1184.     serv_addr.sin_port = htons(SERV_PORT);
  1185. #if    0
  1186.     /* use host-names not internet style d.d.d.d notation */
  1187.     serv_addr.sin__addr.s_addr = inet_addr(SERV_HOST);
  1188. #else    /*0*/
  1189.     if ((hp = gethostbyname(SERV_HOST)) == NULL) {
  1190.         fprintf(stderr, "gethostbyname (%s) failed\n", SERV_HOST);
  1191.         goto doityourself;
  1192.     }
  1193.     memcpy((caddr_t)&serv_addr.sin_addr, hp->h_addr, hp->h_length);
  1194. #endif    /*0*/
  1195.     len = sizeof(serv_addr);
  1196. #endif    /*USE_UNIXDOMAIN*/
  1197.  
  1198.     if (connect(sockfd, (struct sockaddr *)&serv_addr, len) < 0) {
  1199.                 char errbuf[4096];
  1200.                 sprintf(errbuf, "glimpse: Cannot contact glimpseserver: %s, port %d:", SERV_HOST, SERV_PORT);
  1201.                 perror(errbuf);
  1202.         /* perror(SERV_HOST); */
  1203. #if    DEBUG
  1204.         printf("connect errno: %d\n", errno);
  1205. #endif    /*DEBUG*/
  1206.         close(sockfd);
  1207.         if ((errno == ECONNREFUSED) && (tried < 4)) {
  1208.             tried ++;
  1209.             goto trynewsocket;
  1210.         }
  1211.         goto doityourself;
  1212.     }
  1213.  
  1214.     if (sendreq(sockfd, glimpse_reqbuf, fileno(stdin), fileno(stdout), fileno(stderr), argc, argv, getpid()) < 0) {
  1215.         perror("sendreq");
  1216. #if    DEBUG
  1217.         printf("sendreq errno: %d\n", errno);
  1218. #endif    /*DEBUG*/
  1219.         close(sockfd);
  1220.         goto doityourself;
  1221.     }
  1222.  
  1223. #if    USE_MSGHDR
  1224.     if (readn(sockfd, array, 4) != 4) {
  1225.         close(sockfd);
  1226.         goto doityourself;
  1227.     }
  1228.     ret = (array[0] << 24) + (array[1] << 16) + (array[2] << 8) + array[3];
  1229. #else    /*USE_MSGHDR*/
  1230. {
  1231.     /* 
  1232.      *  Dump everything the server writes into the socket onto 
  1233.      *  stdout until EOF/error.  Do this in a way so that *everything*
  1234.      *  the server sends is dumped to stdout by the client.  The
  1235.      *  client might die suddenly via ^C or SIGTERM, but we still
  1236.      *  want the results.
  1237.      */
  1238.     char tmpbuf[1024];
  1239.     int n;
  1240.  
  1241.     while ((n = read(sockfd, tmpbuf, 1024)) > 0) {
  1242.         write(fileno(stdout), tmpbuf, n);
  1243.     }
  1244. }
  1245. #endif    /*USE_MSGHDR*/
  1246.  
  1247.     close(sockfd);
  1248.     RETURNMAIN(ret);
  1249.  
  1250. doityourself:
  1251. #if    DEBUG
  1252.     printf("doing it myself :-(\n");
  1253. #endif    /*DEBUG*/
  1254. #endif    /*CLIENTSERVER*/
  1255.     setbuf(stdout, NULL);    /* Unbuffered I/O to always get every result */
  1256.     setbuf(stderr, NULL);
  1257.     glimpse_call = 0;
  1258.     glimpse_clientdied = 0;
  1259.     ret = process_query(oldargc, oldargv, fileno(stdin));
  1260.     RETURNMAIN(ret);
  1261. #endif    /*ISSERVER && CLIENTSERVER*/
  1262. }
  1263.  
  1264. process_query(argc, argv, newsockfd)
  1265. int argc; 
  1266. char *argv[];
  1267. int newsockfd;
  1268. {
  1269.     int    searchpercent;
  1270.     int    num_blocks;
  1271.     int    num_read;
  1272.     int    i, j;
  1273.     int    iii; /* Udi */
  1274.     int    jjj;
  1275.     char    c;
  1276.     char    *p;
  1277.     int    ret;
  1278.     int    jj;
  1279.     int    quitwhile;
  1280.     char    indexdir[MAX_LINE_LEN];
  1281.     char    temp_filenames_file[MAX_LINE_LEN];
  1282.     char    temp_bitfield_file[MAX_LINE_LEN];
  1283.     char    TEMP_FILE[MAX_LINE_LEN];
  1284.     char    temp_file[MAX_LINE_LEN];
  1285.     int    oldargc = argc;
  1286.     char    **oldargv = argv;
  1287.     CHAR    dummypat[MAX_PAT];
  1288.     int    dummylen=0;
  1289.     int    my_M_index, my_P_index, my_b_index, my_A_index, my_l_index = -1, my_B_index = -1;
  1290.     char    **outname;
  1291.     int    gnum_of_matched = 0;
  1292.     int    gprev_num_of_matched = 0;
  1293.     int    gfiles_matched = 0;
  1294.     int    foundpat = 0;
  1295.     int    wholefilescope=0;
  1296.     int    nobytelevelmustbeon=0;
  1297.     long    get_file_time();
  1298.  
  1299.     if ((argc <= 0) || (argv == NULL)) {
  1300.         errno = EINVAL;
  1301.         return -1;
  1302.     }
  1303. /*
  1304.  * Macro to destroy EVERYTHING before return since we might want to make this a
  1305.  * library function later on: convention is that after destroy, objects are made
  1306.  * NULL throughout the source code, and are all set to NULL at initialization time.
  1307.  * DO agrep_argv, index_argv and FileOpt my_malloc/my_free optimizations later.
  1308.  * my_free calls have 2nd parameter = 0 if the size is not easily determinable.
  1309.  */
  1310. #define RETURN(val) \
  1311. {\
  1312.     int    q,k;\
  1313. \
  1314.     first_search = 0;\
  1315.     for (k=0; k<MAX_ARGS; k++) {\
  1316.         if (agrep_argv[k] != NULL) my_free(agrep_argv[k], 0);\
  1317.         if (index_argv[k] != NULL) my_free(index_argv[k], 0);\
  1318.         agrep_argv[k] = index_argv[k] = NULL;\
  1319.     }\
  1320.     if (FileOpt != NULL) my_free(FileOpt, MAXFILEOPT);\
  1321.     FileOpt = NULL;\
  1322.     for (k=0; k<MAXNUM_PAT; k++) {\
  1323.         if (pat_list[k] != NULL) my_free(pat_list[k], 0);\
  1324.         pat_list[k] = NULL;\
  1325.     }\
  1326.     sprintf(tempfile, "%s/.glimpse_tmp.%d", TEMP_DIR, getpid());\
  1327.     unlink(tempfile);\
  1328.     sprintf(outname[0], "%s/.glimpse_apply.%d", TEMP_DIR, getpid());\
  1329.     unlink(outname[0]);\
  1330.     my_free(outname[0], 0);\
  1331.     my_free(outname, 0);\
  1332.     my_free(TEMP_DIR, MAX_LINE_LEN);\
  1333.     my_free(filenames_file, MAX_LINE_LEN);\
  1334.     my_free(bitfield_file, MAX_LINE_LEN);\
  1335. \
  1336.     if (ByteLevelIndex) {\
  1337.         if (src_offset_table != NULL) for (k=0; k<OneFilePerBlock; k++) {\
  1338.             free_list(&src_offset_table[k]);\
  1339.         }\
  1340.         /* Don't make src_offset_table itself NULL: it will be bzero-d below if !NULL */\
  1341.         for (q=0; q<MAXNUM_PAT; q++) {\
  1342.             if (multi_dest_offset_table[q] != NULL) for (k=0; k<OneFilePerBlock; k++) {\
  1343.             free_list(&multi_dest_offset_table[q][k]);\
  1344.             }\
  1345.             /* Don't make multi_dest_offset_table[q] itself NULL: it will be bzero-d below if !NULL */\
  1346.         }\
  1347.     }\
  1348.     for (k=0; k<num_terminals;k++)\
  1349.         free(terminals[k].data.leaf.value);\
  1350.     if (ComplexBoolean) destroy_tree(&GParse);\
  1351.     for (k=0; k<GNumfiles; k++) {\
  1352.         my_free(GTextfiles[k], 0);\
  1353.         GTextfiles[k] = NULL;\
  1354.     }\
  1355.     /* Don't free the GTextfiles buffer itself since it is allocated once in get_filename.c */\
  1356.     return (val);\
  1357. }
  1358.  
  1359.     /*
  1360.      * Initialize
  1361.      */
  1362.     strcpy(&GProgname[0], argv[0]);
  1363.     if (argc <= 1) return(usage());
  1364.     filenames_file = (char *)my_malloc(MAX_LINE_LEN);
  1365.     bitfield_file = (char *)my_malloc(MAX_LINE_LEN);
  1366.     TEMP_DIR = (char *)my_malloc(MAX_LINE_LEN);
  1367.     strcpy(TEMP_DIR, "/tmp");
  1368.     D_length = 0;
  1369.     D = 0;
  1370.     pattern_index = 0;
  1371.     first_search = 1;
  1372.     outname  = (char **)my_malloc(sizeof(char *));
  1373.     outname[0] = (char *)my_malloc(MAX_LINE_LEN);
  1374.     NOBYTELEVEL = 0;
  1375.     OPTIMIZEBYTELEVEL = 0;
  1376.     GCONSTANT = 0;
  1377.     GLIMITOUTPUT = 0;
  1378.     GLIMITTOTALFILE = 0;
  1379.     GBESTMATCH = 0;
  1380.     GRECURSIVE = 0;
  1381.     GNOPROMPT = 0;
  1382.     GBYTECOUNT = 0;
  1383.     GPRINTFILENUMBER = 0;
  1384.     GPRINTFILETIME = 0;
  1385.     GOUTTAIL = 2;    /* stupid fix, but works */
  1386.     GFILENAMEONLY = 0;
  1387.     GNOFILENAME = 0;
  1388.     GPRINTNONEXISTENTFILE = 0;
  1389.     MATCHFILE = 0;
  1390.     PRINTATTR = 0;
  1391.     PRINTINDEXLINE = 0;
  1392.     Pat_as_is=0;
  1393.     Only_first = 0;
  1394.     PRINTAPPXFILEMATCH = 0;
  1395.     GCOUNT = 0;
  1396.     HINTSFROMUSER = 0;
  1397.     FILENAMESINFILE=0;
  1398.     BITFIELDFILE=0;
  1399.     BITFIELDOFFSET=0;
  1400.     BITFIELDLENGTH=0;
  1401.     BITFIELDENDIAN=0;
  1402.     GNumDays = 0;
  1403.     foundattr = 0;
  1404.     foundnot = 0;
  1405.     ComplexBoolean = 0;
  1406.     bestmatcherrors = 0;
  1407.     patbufpos = -1;
  1408.     RegionLimit=DEFAULT_REGION_LIMIT;
  1409.     strcpy(GD_pattern, "\n");
  1410.     GD_length = strlen(GD_pattern);
  1411.     indexdir[0] = '\0';
  1412.     memset(index_argv, '\0', sizeof(char *) * MAX_ARGS);
  1413.     index_argc = 0;
  1414.     memset(agrep_argv, '\0', sizeof(char *) * MAX_ARGS);
  1415.     agrep_argc = 0;
  1416.     FileOpt = NULL;
  1417.     fileopt_length = 0;
  1418.     memset(pat_list, '\0', sizeof(char *) * MAXNUM_PAT);
  1419.     memset(pat_attr, '\0', sizeof(int) * MAXNUM_PAT);
  1420.     for (i=0; i<MAX_ARGS; i++)
  1421.         index_argv[i] = (char *)my_malloc(MaxNameLength + 2);
  1422.     memset(is_mgrep_pat, '\0', sizeof(int) * MAXNUM_PAT);
  1423.     memset(mgrep_pat_index, '\0', sizeof(int) *MAXNUM_PAT);
  1424.     num_mgrep_pat = 0;
  1425.     memset(pat_buf, '\0', (MAXNUM_PAT + 2)*MAXPAT);
  1426.     pat_ptr = 0;
  1427.     sprintf(tempfile, "%s/.glimpse_tmp.%d", TEMP_DIR, getpid());
  1428.     /* Set WHOLEFILESCOPE for per-request processing at server */
  1429.     if (StructuredIndex) WHOLEFILESCOPE = 1;
  1430.     else WHOLEFILESCOPE = 0;
  1431.     timesindexsize = 0;
  1432.     last_Y_filenumber = 0;
  1433.  
  1434.     if (argc > MAX_ARGS) {
  1435. #if    ISSERVER
  1436.     fprintf(stderr, "too many arguments %d obtained on server!\n", argc);
  1437. #endif    /*ISSERVER*/
  1438.         i = fileagrep(oldargc, oldargv, 0, stdout);
  1439.         RETURN(i);
  1440.     }
  1441.  
  1442.     /*
  1443.      * Process what options you can, then call fileagrep_init() to set
  1444.      * options in agrep and get the pattern. Then, call fileagrep_search().
  1445.      * Begin by copying options into agrep_argv assuming glimpse was not
  1446.      * called as agrep (optimistic :-).
  1447.      */
  1448.  
  1449.     agrep_argc = 0;
  1450.     for (i=0; i<MAX_ARGS; i++) agrep_argv[i] = NULL;
  1451.     agrep_argv[agrep_argc] = (char *)my_malloc(strlen(argv[0]) + 2);
  1452.     strcpy(agrep_argv[agrep_argc], argv[0]);    /* copy the name of the program anyway */
  1453.     agrep_argc ++;
  1454.  
  1455.     /* In glimpse, you should never output filenames with zero matches */
  1456.     if (agrep_argc + 1 >= MAX_ARGS) {
  1457.         fprintf(stderr, "%s: too many options!\n", GProgname);
  1458.         RETURN(usage());
  1459.     }
  1460.     agrep_argv[agrep_argc] = (char *)my_malloc(sizeof(char *));
  1461.     agrep_argv[agrep_argc][0] = '-';
  1462.     agrep_argv[agrep_argc][1] = 'z';
  1463.     agrep_argv[agrep_argc][2] = '\0';
  1464.     agrep_argc ++;
  1465.  
  1466.     /* In glimpse, you should always print pattern when using mgrep (user can't do -f or -m)! */
  1467.     if (agrep_argc + 1 >= MAX_ARGS) {
  1468.         fprintf(stderr, "%s: too many options!\n", GProgname);
  1469.         RETURN(usage());
  1470.     }
  1471.     agrep_argv[agrep_argc] = (char *)my_malloc(sizeof(char *));
  1472.     agrep_argv[agrep_argc][0] = '-';
  1473.     agrep_argv[agrep_argc][1] = 'P';
  1474.     agrep_argv[agrep_argc][2] = '\0';
  1475.     my_P_index = agrep_argc;
  1476.     agrep_argc ++;
  1477.  
  1478.     /* In glimpse, you should always output multiple when doing mgrep */
  1479.     if (agrep_argc + 1 >= MAX_ARGS) {
  1480.         fprintf(stderr, "%s: too many options!\n", GProgname);
  1481.         RETURN(usage());
  1482.     }
  1483.     agrep_argv[agrep_argc] = (char *)my_malloc(sizeof(char *));
  1484.     agrep_argv[agrep_argc][0] = '-';
  1485.     agrep_argv[agrep_argc][1] = 'M';
  1486.     agrep_argv[agrep_argc][2] = '\0';
  1487.     my_M_index = agrep_argc;
  1488.     agrep_argc ++;
  1489.  
  1490.     /* In glimpse, you should print the byte offset if there is a structured query */
  1491.     if (agrep_argc + 1 >= MAX_ARGS) {
  1492.         fprintf(stderr, "%s: too many options!\n", GProgname);
  1493.         RETURN(usage());
  1494.     }
  1495.     agrep_argv[agrep_argc] = (char *)my_malloc(sizeof(char *));
  1496.     agrep_argv[agrep_argc][0] = '-';
  1497.     agrep_argv[agrep_argc][1] = 'b';
  1498.     agrep_argv[agrep_argc][2] = '\0';
  1499.     my_b_index = agrep_argc;
  1500.     agrep_argc ++;
  1501.  
  1502.     /* In glimpse, you should always have space for doing -m if required */
  1503.     if (agrep_argc + 2 >= MAX_ARGS) {
  1504.         fprintf(stderr, "%s: too many options!\n", GProgname);
  1505.         RETURN(usage());
  1506.     }
  1507.     agrep_argv[agrep_argc] = (char *)my_malloc(sizeof(char *));
  1508.     agrep_argv[agrep_argc][0] = '-';
  1509.     agrep_argv[agrep_argc][1] = 'm';
  1510.     agrep_argv[agrep_argc][2] = '\0';
  1511.     agrep_argc ++;
  1512.     agrep_argv[agrep_argc] = (char *)my_malloc(2);    /* no op */
  1513.     agrep_argv[agrep_argc][0] = '\0';
  1514.     agrep_argc ++;
  1515.  
  1516.     /* Add -A option to print filenames as default */
  1517.     if (agrep_argc + 1 >= MAX_ARGS) {
  1518.         fprintf(stderr, "%s: too many options!\n", GProgname);
  1519.         RETURN(usage());
  1520.     }
  1521.     agrep_argv[agrep_argc] = (char *)my_malloc(sizeof(char *));
  1522.     agrep_argv[agrep_argc][0] = '-';
  1523.     agrep_argv[agrep_argc][1] = 'A';
  1524.     agrep_argv[agrep_argc][2] = '\0';
  1525.     my_A_index = agrep_argc;
  1526.     agrep_argc ++;
  1527.  
  1528.     while((agrep_argc < MAX_ARGS) && (--argc > 0) && (*++argv)[0] == '-' ) {
  1529.         p = argv[0] + 1;    /* ptr to first character after '-' */
  1530.         c = *(argv[0]+1);
  1531.         quitwhile = OFF;
  1532.         while (!quitwhile && (*p != '\0')) {
  1533.             c = *p;
  1534.             switch(c) {
  1535.             case 'F' : 
  1536.                 MATCHFILE = ON;
  1537.                 FileOpt = (CHAR *)my_malloc(MAXFILEOPT);
  1538.                 if (*(p + 1) == '\0') {/* space after - option */
  1539.                     if(argc <= 1) {
  1540.                         fprintf(stderr, "%s: a file pattern must follow the -F option\n", GProgname);
  1541.                         RETURN(usage());
  1542.                     }
  1543.                     argv++;
  1544.                     if ((dummylen = strlen(argv[0])) > MAXFILEOPT) {
  1545.                         fprintf(stderr, "%s: -F option list too long\n", GProgname);
  1546.                         RETURN(usage());
  1547.                     }
  1548.                     strcpy(FileOpt, argv[0]);
  1549.                     argc--;
  1550.                 } else {
  1551.                     if ((dummylen = strlen(p+1)) > MAXFILEOPT) {
  1552.                         fprintf(stderr, "%s: -F option list too long\n", GProgname);
  1553.                         RETURN(usage());
  1554.                     }
  1555.                     strcpy(FileOpt, p+1);
  1556.                 } /* else */
  1557.                 quitwhile = ON;
  1558.                 break;
  1559.  
  1560.             /* search the index only and output the number of blocks */
  1561.             case 'N' :
  1562.                 Only_first = ON;
  1563.                 break ;
  1564.  
  1565.             /* also keep track of the matches in each file */
  1566.             case 'Q' :
  1567.                 PRINTAPPXFILEMATCH = ON;
  1568.                 break ;
  1569.  
  1570.             case 'U' :
  1571.                 InfoAfterFilename = ON;
  1572.                 break;
  1573.             
  1574.             case '!' :
  1575.                 HINTSFROMUSER = ON;
  1576.                 break;
  1577.  
  1578.             /* go to home directory to find the index: even if server overwrites indexdir here, it won't overwrite INDEX_DIR until read_index() */
  1579.             case 'H' :
  1580.                 if (*(p + 1) == '\0') {/* space after - option */
  1581.                     if (argc <= 1) {
  1582.                         fprintf(stderr, "%s: a directory name must follow the -H option\n", GProgname);
  1583.                         RETURN(usage());
  1584.                     }
  1585.                     argv ++;
  1586. #if    !ISSERVER
  1587.                     strcpy(indexdir, argv[0]);
  1588. #endif    /*!ISSERVER*/
  1589.                     argc --;
  1590.                 }
  1591. #if    !ISSERVER
  1592.                 else {
  1593.                     strcpy(indexdir, p+1);
  1594.                 }
  1595.                 agrep_argv[agrep_argc] = (char *)my_malloc(4);
  1596.                 strcpy(agrep_argv[agrep_argc], "-H");
  1597.                 agrep_argc ++;
  1598.                 agrep_argv[agrep_argc] = (char *)my_malloc(strlen(indexdir) + 2);
  1599.                 strcpy(agrep_argv[agrep_argc], indexdir);
  1600.                 agrep_argc ++;
  1601. #endif    /*!ISSERVER*/
  1602.                 quitwhile = ON;
  1603.                 break;
  1604.  
  1605. #if    ISSERVER && SFS_COMPAT
  1606.             /* INDEX_DIR will be already set since this is the server, so we can direclty xfer the .glimpse_* files */
  1607.             case '.' :
  1608.                 strcpy(TEMP_FILE, INDEX_DIR);
  1609.                 strcpy(temp_file, ".");
  1610.                 strcat(TEMP_FILE, "/.");
  1611.                 if (*(p + 1) == '\0') {/* space after - option */
  1612.                     if (argc <= 1) {
  1613.                         fprintf(stderr, "%s: a file name must follow the -. option\n", GProgname);
  1614.                         RETURN(usage());
  1615.                     }
  1616.                     argv ++;
  1617.                     strcat(TEMP_FILE, argv[0]);
  1618.                     strcat(temp_file, argv[0]);
  1619.                     argc --;
  1620.                 }
  1621.                 else {
  1622.                     strcat(TEMP_FILE, p+1);
  1623.                     strcat(temp_file, p+1);
  1624.                 }
  1625.                 if (!strcmp(temp_file, INDEX_FILE) || !strcmp(temp_file, FILTER_FILE) ||
  1626.                     !strcmp(temp_file, ATTRIBUTE_FILE) || !strcmp(temp_file, MINI_FILE) ||
  1627.                     !strcmp(temp_file, P_TABLE) || !strcmp(temp_file, PROHIBIT_LIST) ||
  1628.                     !strcmp(temp_file, INCLUDE_LIST) || !strcmp(temp_file, NAME_LIST) ||
  1629.                     !strcmp(temp_file, NAME_LIST_INDEX) || !strcmp(temp_file, NAME_HASH) ||
  1630.                     !strcmp(temp_file, NAME_HASH_INDEX) || !strcmp(temp_file, DEF_STAT_FILE) ||
  1631.                     !strcmp(temp_file, DEF_MESSAGE_FILE) || !strcmp(temp_file, DEF_TIME_FILE)) {
  1632.                     if ((ret = open(TEMP_FILE, O_RDONLY, 0)) <= 0) RETURN(ret);
  1633.                     while ((num_read = read(ret, matched_region, MAX_REGION_LIMIT*2)) > 0) {
  1634.                         write(1 /* NOT TO newsockfd since that was got by a syscall!!! */, matched_region, num_read);
  1635.                     }
  1636.                     close(ret);
  1637.                 }
  1638.                 quitwhile = ON;
  1639.                 RETURN(0);
  1640. #endif    /* ISSERVER */
  1641.  
  1642.             /* go to temp directory to create temp files */
  1643.             case 'T' :
  1644.                 if (*(p + 1) == '\0') {/* space after - option */
  1645.                     if (argc <= 1) {
  1646.                         fprintf(stderr, "%s: a directory name must follow the -T option\n", GProgname);
  1647.                         RETURN(usage());
  1648.                     }
  1649.                     argv ++;
  1650.                     strcpy(TEMP_DIR, argv[0]);
  1651.                     argc --;
  1652.                 }
  1653.                 else {
  1654.                     strcpy(TEMP_DIR, p+1);
  1655.                 }
  1656.                 sprintf(tempfile, "%s/.glimpse_tmp.%d", TEMP_DIR, getpid());
  1657.                 quitwhile = ON;
  1658.                 break;
  1659.  
  1660.             /* To get files within some number of days before indexing was done */
  1661.             case 'Y':
  1662.                 if (*(p + 1) == '\0') {/* space after - option */
  1663.                     if (argc <= 1) {
  1664.                         fprintf(stderr, "%s: the number of days must follow the -Y option\n", GProgname);
  1665.                         RETURN(usage());
  1666.                     }
  1667.                     argv ++;
  1668.                     GNumDays = atoi(argv[0]);
  1669.                     argc --;
  1670.                 }
  1671.                 else {
  1672.                     GNumDays = atoi(p+1);
  1673.                 }
  1674.                 if (GNumDays <= 0) {
  1675.                     fprintf(stderr, "%s: the number of days %d must be > 0\n", GProgname, GNumDays);
  1676.                     RETURN(usage());
  1677.                 }
  1678.                 quitwhile = ON;
  1679.                 break;
  1680.  
  1681.             case 'R' :
  1682.                 if (*(p + 1) == '\0') {/* space after - option */
  1683.                     if (argc <= 1) {
  1684.                         fprintf(stderr, "%s: the record size must follow the -R option\n", GProgname);
  1685.                         RETURN(usage());
  1686.                     }
  1687.                     argv ++;
  1688.                     RegionLimit = atoi(argv[0]);
  1689.                     argc --;
  1690.                 }
  1691.                 else {
  1692.                     RegionLimit = atoi(p+1);
  1693.                 }
  1694.                 if ((RegionLimit <= 0) || (RegionLimit > MAX_REGION_LIMIT)) {
  1695.                     fprintf(stderr, "Bad record size %d: must be in [%d, %d]: using default %d\n",
  1696.                         RegionLimit, 1, MAX_REGION_LIMIT, DEFAULT_REGION_LIMIT);
  1697.                     RegionLimit = DEFAULT_REGION_LIMIT;
  1698.                 }
  1699.                 quitwhile = ON;
  1700.                 break;
  1701.  
  1702.             /* doesn't matter if we overwrite the value in the client since the same value would have been picked up in main() anyway */
  1703.             case 'J' :
  1704.                 if (*(p + 1) == '\0') {/* space after - option */
  1705.                     if (argc <= 1) {
  1706.                         fprintf(stderr, "%s: the server host name must follow the -J option\n", GProgname);
  1707.                         RETURNMAIN(usageS());
  1708.                     }
  1709.                     argv ++;
  1710. #if    !ISSERVER
  1711.                     strcpy(SERV_HOST, argv[0]);
  1712. #endif    /*!ISSERVER*/
  1713.                     argc --;
  1714.                 }
  1715. #if    !ISSERVER
  1716.                 else {
  1717.                     strcpy(SERV_HOST, p+1);
  1718.                 }
  1719. #endif    /*!ISSERVER*/
  1720.                 quitwhile = ON;
  1721.                 break;
  1722.  
  1723.             /* doesn't matter if we overwrite the value in the client since the same value would have been picked up in main() anyway */
  1724.             case 'K' :
  1725.                 if (*(p + 1) == '\0') {/* space after - option */
  1726.                     if (argc <= 1) {
  1727.                         fprintf(stderr, "%s: the server port must follow the -C option\n", GProgname);
  1728.                         RETURN(usage());
  1729.                     }
  1730.                     argv ++;
  1731. #if    !ISSERVER
  1732.                     SERV_PORT = atoi(argv[0]);
  1733. #endif    /*!ISSERVER*/
  1734.                     argc --;
  1735.                 }
  1736. #if    !ISSERVER
  1737.                 else {
  1738.                     SERV_PORT = atoi(p+1);
  1739.                 }
  1740.                 if ((SERV_PORT < MIN_SERV_PORT) || (SERV_PORT > MAX_SERV_PORT)) {
  1741.                     fprintf(stderr, "Bad server port %d: must be in [%d, %d]: using default %d\n",
  1742.                         SERV_PORT, MIN_SERV_PORT, MAX_SERV_PORT, DEF_SERV_PORT);
  1743.                     SERV_PORT = DEF_SERV_PORT;
  1744.                 }
  1745. #endif    /*!ISSERVER*/
  1746.                 quitwhile = ON;
  1747.                 break;
  1748.  
  1749.             /* Based on contribution From ada@mail2.umu.se Fri Jul 12 01:56 MST 1996; Christer Holgersson, Sen. SysNet Mgr, Umea University/SUNET, Sweden */
  1750.             /* the bit-mask corresponding to the set of filenames within which the pattern should be searched is explicitly provided in a filename (absolute path name) */
  1751.             case 'p' :
  1752.                 if (*(p + 1) == '\0') {/* space after - option */
  1753.                     if (argc <= 1) {
  1754.                         fprintf(stderr, "%s: the bitfield file [and an offset/length/endian separated by :] must follow the -p option\n", GProgname);
  1755.                         RETURN(usage());
  1756.                     }
  1757.                     argv ++;
  1758.                     strcpy(bitfield_file, argv[0]);
  1759.                     argc --;
  1760.                 }
  1761.                 else {
  1762.                     strcpy(bitfield_file, p+1);
  1763.                 }
  1764.                 /* Find offset and length into bitfield file */
  1765.                 {
  1766.                     int iiii = 0;
  1767.  
  1768.                     BITFIELDOFFSET=0;
  1769.                     BITFIELDLENGTH=0;
  1770.                     BITFIELDENDIAN=0;
  1771.                     iiii = 0;
  1772.                     while (bitfield_file[iiii] != '\0') {
  1773.                         if (bitfield_file[iiii] == '\\') {
  1774.                             iiii ++;
  1775.                             if (bitfield_file[iiii] == '\0') break;
  1776.                             if (bitfield_file[iiii] == ':') {
  1777.                                 strcpy(&bitfield_file[iiii-1], &bitfield_file[iiii]);
  1778.                             }
  1779.                             else iiii ++;
  1780.                             continue;
  1781.                         }
  1782.                         if (bitfield_file[iiii] == ':') {
  1783.                             bitfield_file[iiii] = '\0';
  1784.                             sscanf(&bitfield_file[iiii+1], "%d:%d:%d", &BITFIELDOFFSET, &BITFIELDLENGTH, &BITFIELDENDIAN);
  1785.                             if ((BITFIELDOFFSET < 0) || (BITFIELDLENGTH < 0) || (BITFIELDENDIAN < 0)) {
  1786.                                 fprintf(stderr, "Wrong offset %d or length %d or endian %d of bitfield file\n", BITFIELDOFFSET, BITFIELDLENGTH, BITFIELDENDIAN);
  1787.                                 RETURN(usage());
  1788.                             }
  1789.                             break;
  1790.                         }
  1791.                         iiii++;
  1792.                     }
  1793. #if    BG_DEBUG
  1794.                     fprintf(debug, "BITFIELD %s : %d : %d : %d\n", BITFIELDFILE, BITFIELDOFFSET, BITFIELDLENGTH, BITFIELDENDIAN);
  1795. #endif
  1796.                 }
  1797.                 if (bitfield_file[0] != '/') {
  1798.                     getcwd(temp_bitfield_file, MAX_LINE_LEN-1);
  1799.                     strcat(temp_bitfield_file, "/");
  1800.                     strcat(temp_bitfield_file, bitfield_file);
  1801.                     strcpy(bitfield_file, temp_bitfield_file);
  1802.                 }
  1803.                 BITFIELDFILE = 1;
  1804.                 quitwhile = ON;
  1805.                 break;
  1806.  
  1807.             /* the set of filenames within which the pattern should be searched is explicitly provided in a filename (absolute path name) */
  1808.             case 'f' :
  1809.                 if (*(p + 1) == '\0') {/* space after - option */
  1810.                     if (argc <= 1) {
  1811.                         fprintf(stderr, "%s: the filenames file must follow the -f option\n", GProgname);
  1812.                         RETURN(usage());
  1813.                     }
  1814.                     argv ++;
  1815.                     strcpy(filenames_file, argv[0]);
  1816.                     argc --;
  1817.                 }
  1818.                 else {
  1819.                     strcpy(filenames_file, p+1);
  1820.                 }
  1821.                 if (filenames_file[0] != '/') {
  1822.                     getcwd(temp_filenames_file, MAX_LINE_LEN-1);
  1823.                     strcat(temp_filenames_file, "/");
  1824.                     strcat(temp_filenames_file, filenames_file);
  1825.                     strcpy(filenames_file, temp_filenames_file);
  1826.                 }
  1827.                 FILENAMESINFILE = 1;
  1828.                 quitwhile = ON;
  1829.                 break;
  1830.  
  1831.             case 'C' :
  1832.                 CONTACT_SERVER = 1;
  1833.                 break;
  1834.  
  1835.             case 'a' :
  1836.                 PRINTATTR = 1;
  1837.                 break;
  1838.  
  1839.             case 'E':
  1840.                 PRINTINDEXLINE = 1;
  1841.                 break;
  1842.  
  1843.             case 'W':
  1844.                 wholefilescope = 1;
  1845.                 break;
  1846.  
  1847.             case 'z' :
  1848.                 UseFilters = 1;
  1849.                 break;
  1850.  
  1851.             case 'r' :
  1852.                 GRECURSIVE = 1;
  1853.                 break;
  1854.  
  1855.             case 'V' :
  1856.                 printf("\nThis is glimpse version %s, %s.\n\n", GLIMPSE_VERSION, GLIMPSE_DATE);
  1857.                 RETURN(0);
  1858.  
  1859.             /* Must let 'm' fall thru to default once multipatterns are done in agrep */
  1860.             case 'm' :
  1861.             case 'v' :
  1862.                 fprintf(stderr, "%s: illegal option: '-%c'\n", GProgname, c);
  1863.                 RETURN(usage());
  1864.  
  1865.             case 'I' :
  1866.             case 'D' :
  1867.             case 'S' :
  1868.                 /* There is no space after these options */
  1869.                 agrep_argv[agrep_argc] = (char *)my_malloc(strlen(argv[0]) + 2);
  1870.                 agrep_argv[agrep_argc][0] = '-';
  1871.                 strcpy(agrep_argv[agrep_argc] + 1, p);
  1872.                 agrep_argc ++;
  1873.                 quitwhile = ON;
  1874.                 break;
  1875.  
  1876.             case 'l':
  1877.                 GFILENAMEONLY = 1;
  1878.                 my_l_index = agrep_argc;
  1879.                 agrep_argv[agrep_argc] = (char *)my_malloc(4);
  1880.                 agrep_argv[agrep_argc][0] =  '-';
  1881.                 agrep_argv[agrep_argc][1] = c;
  1882.                 agrep_argv[agrep_argc][2] = '\0';
  1883.                 agrep_argc ++;
  1884.                 break;
  1885.  
  1886.             /*
  1887.              * Copy the set of options for agrep: put them in separate argvs
  1888.              * even if they are together after one '-' (easier to process).
  1889.              * These are agrep options which glimpse has to peek into.
  1890.              */
  1891.             default:
  1892.                 agrep_argv[agrep_argc] = (char *)my_malloc(16);
  1893.                 agrep_argv[agrep_argc][0] =  '-';
  1894.                 agrep_argv[agrep_argc][1] = c;
  1895.                 agrep_argv[agrep_argc][2] = '\0';
  1896.                 agrep_argc ++;
  1897.  
  1898.                 if (c == 'n') {
  1899.                     nobytelevelmustbeon=1;
  1900.                 }
  1901.                 else if (c == 'X') GPRINTNONEXISTENTFILE = 1;
  1902.                 else if (c == 'j') GPRINTFILETIME = 1;
  1903.                 else if (c == 'b') GBYTECOUNT = 1;
  1904.                 else if (c == 'g') GPRINTFILENUMBER = 1;
  1905.                 else if (c == 't') GOUTTAIL = 1;
  1906.                 else if (c == 'y') GNOPROMPT = 1;
  1907.                 else if (c == 'h') GNOFILENAME = 1;
  1908.                 else if (c == 'c') GCOUNT = 1;
  1909.                 else if (c == 'B') {
  1910.                     GBESTMATCH = 1;
  1911.                     my_B_index = agrep_argc - 1;
  1912.                 }
  1913.                 /* the following options are followed by a parameter */
  1914.                 else if ((c == 'e') || (c == 'd') || (c == 'L') || (c == 'k')) {
  1915.                     if (*(p + 1) == '\0') {/* space after - option */
  1916.                         if(argc <= 1) {
  1917.                             fprintf(stderr, "%s: the '-%c' option must have an argument\n", GProgname, c);
  1918.                             RETURN(usage());
  1919.                         }
  1920.                         argv++;
  1921.                         if ( (c == 'd') && ((D_length = strlen(argv[0])) > MAX_NAME_SIZE) ) {
  1922.                             fprintf(stderr, "%s: delimiter pattern too long (has > %d chars)\n", GProgname, MAX_NAME_SIZE);
  1923.                             RETURN(usage());
  1924.                             /* Should this be RegionLimit if ByteLevelIndex? */
  1925.                         }
  1926.                         else if (c == 'L') {
  1927.                             GLIMITOUTPUT = GLIMITTOTALFILE = GLIMITPERFILE = 0;
  1928.                             sscanf(argv[0], "%d:%d:%d", &GLIMITOUTPUT, &GLIMITTOTALFILE, &GLIMITPERFILE);
  1929.                             if ((GLIMITOUTPUT < 0) || (GLIMITTOTALFILE < 0) || (GLIMITPERFILE < 0)) {
  1930.                                 fprintf(stderr, "%s: invalid output limit %s\n", GProgname, argv[0]);
  1931.                                 RETURN(usage());
  1932.                             }
  1933.                         }
  1934.                         agrep_argv[agrep_argc] = (char *)my_malloc(strlen(argv[0]) + 2);
  1935.                         strcpy(agrep_argv[agrep_argc], argv[0]);
  1936.                         if (c == 'd') {
  1937.                             preprocess_delimiter(argv[0], D_length, GD_pattern, &GD_length);
  1938.                             if (GOUTTAIL == 2) GOUTTAIL = 0;
  1939.                             /* Should this be RegionLimit if ByteLevelIndex? */
  1940.                         }
  1941.                         if (c == 'k') GCONSTANT = 1;
  1942.                         argc--;
  1943.                     } else {
  1944.                         if ( (c == 'd') && ((D_length = strlen(p+1)) > MAX_NAME_SIZE) ) {
  1945.                             fprintf(stderr, "%s: delimiter pattern too long (has > %d chars)\n", GProgname, MAX_NAME_SIZE);
  1946.                             RETURN(usage());
  1947.                             /* Should this be RegionLimit if ByteLevelIndex? */
  1948.                         }
  1949.                         else if (c == 'L') {
  1950.                             GLIMITOUTPUT = GLIMITTOTALFILE = GLIMITPERFILE = 0;
  1951.                             sscanf(p+1, "%d:%d:%d", &GLIMITOUTPUT, &GLIMITTOTALFILE, &GLIMITPERFILE);
  1952.                             if ((GLIMITOUTPUT < 0) || (GLIMITTOTALFILE < 0) || (GLIMITPERFILE < 0)) {
  1953.                                 fprintf(stderr, "%s: invalid output limit %s\n", GProgname, p+1);
  1954.                                 RETURN(usage());
  1955.                             }
  1956.                         }
  1957.                         agrep_argv[agrep_argc] = (char *)my_malloc(strlen(p+1) + 2);
  1958.                         strcpy(agrep_argv[agrep_argc], p+1);
  1959.                         if (c == 'd') {
  1960.                             preprocess_delimiter(p+1, D_length-2, GD_pattern, &GD_length);
  1961.                             if (GOUTTAIL == 2) GOUTTAIL = 0;
  1962.                             /* Should this be RegionLimit if ByteLevelIndex? */
  1963.                         }
  1964.                         if (c == 'k') GCONSTANT = 1;
  1965.                     }
  1966.                     agrep_argc ++;
  1967. #if    DEBUG
  1968.                     fprintf(stderr, "%d = %s\n", agrep_argc, agrep_argv[agrep_argc - 1]);
  1969. #endif    /*DEBUG*/
  1970.                     quitwhile = ON;
  1971.                     if ((c == 'e') || (c == 'k')) foundpat = 1;
  1972.                 }
  1973.                 /* else it is something that glimpse doesn't know and agrep needs to look at */
  1974.  
  1975.                 break;    /* from default: */
  1976.  
  1977.             } /* switch(c) */
  1978.             p ++;
  1979.         }
  1980.     } /* while (--argc > 0 && (*++argv)[0] == '-') */
  1981.  
  1982. /* exitloop: */
  1983.     if ((GBESTMATCH == ON) && (MATCHFILE == ON) && (Only_first == ON))
  1984.         fprintf(stderr, "%s: Warning: the number of matches may be incorrect when -B is used with -F.\n", HARVEST_PREFIX);
  1985.  
  1986.     if (GOUTTAIL) GOUTTAIL = 1;
  1987.  
  1988.     if (GNOFILENAME) {
  1989.         agrep_argv[my_A_index][1] = 'Z';    /* ignore the -A option */
  1990.     }
  1991.  
  1992. #if    ISSERVER
  1993.     if (RemoteFiles) {    /* force -NQ so that won't start looking for files! */
  1994.         Only_first = ON;
  1995.         PRINTAPPXFILEMATCH = ON;
  1996.     }
  1997. #endif
  1998.  
  1999.     if (argc > 0) {
  2000.         /* copy the rest of the options the pattern and the filenames if any verbatim */
  2001.         for (i=0; i<argc; i++) {
  2002.             if (agrep_argc >= MAX_ARGS) break;
  2003.             agrep_argv[agrep_argc] = (char *)my_malloc(strlen(argv[0]) + 2);
  2004.             strcpy(agrep_argv[agrep_argc], argv[0]);
  2005.             agrep_argc ++;
  2006.             argv ++; }
  2007.         if (!foundpat) argc --;
  2008.     }
  2009.  
  2010. #if    0
  2011.     for (j=0; j<agrep_argc; j++) printf("agrep_argv[%d] = %s\n", j, agrep_argv[j]);
  2012.     printf("argc = %d\n", argc);
  2013. #endif    /*0*/
  2014.  
  2015.     /*
  2016.      * Now perform the search by first looking at the index
  2017.      * and obtaining the files to search; and then search
  2018.      * them and output the result. If argc > 0, glimpse
  2019.      * runs as agrep: otherwise, it searches index, etc.
  2020.      */
  2021.  
  2022.     if (argc <= 0) {
  2023.         if (RecordLevelIndex) {    /* based on work done for robint@zedcor.com Robin Thomas, Art Today, Tucson, AZ */
  2024.             /*
  2025.             if ((D_length > 0) && strcmp(GD_pattern, rdelim)) {
  2026.                 fprintf(stderr, "Index created for delimiter `%s': cannot search with delimiter `%s'\n", rdelim, GD_pattern);
  2027.                 RETURN(-1);
  2028.             }
  2029.             SHOULD I HAVE THIS CHECK? MAYBE GD_pattern is a SUBSTRING OF rdelim??? But this is safest thing to do... robint@zedcor.com
  2030.             */
  2031.             RegionLimit = 0;    /* region is EXACTLY the same record number, not a portion of a file within some offset+length */
  2032.         }
  2033.         glimpse_call = 1;
  2034.         /* Initialize some data structures, read the index */
  2035.         if (GRECURSIVE == 1) {
  2036.             fprintf(stderr, "illegal option: '-r'\n");
  2037.             RETURN(usage());
  2038.         }
  2039.         num_terminals = 0;
  2040.         GParse = NULL;
  2041.         memset(terminals, '\0', sizeof(ParseTree) * MAXNUM_PAT);
  2042. #if    !ISSERVER
  2043.         if (-1 == read_index(indexdir)) RETURN(-1);
  2044. #endif    /*!ISSERVER*/
  2045.  
  2046. /*
  2047. This handles the -n option with ByteLevelIndex: disabled as of now, else should go into file search...
  2048. */
  2049.         if (nobytelevelmustbeon && (ByteLevelIndex && !RecordLevelIndex)) {    /* with RecordLevelIndex, we'll do search, so don't set NOBYTELEVEL */
  2050.             /* fprintf(stderr, "Warning: -n option used with byte-level index: must SEARCH the files\n"); */
  2051.             NOBYTELEVEL=ON;
  2052.         }
  2053.  
  2054.         WHOLEFILESCOPE = (WHOLEFILESCOPE || wholefilescope);
  2055.  
  2056.         if (ByteLevelIndex) {
  2057.             /* Must zero them here in addition to index search so that RETURN macro runs correctly */
  2058.             if ((src_offset_table == NULL) &&
  2059.                 ((src_offset_table = (struct offsets **)my_malloc(sizeof(struct offsets *) * OneFilePerBlock)) == NULL)) exit(2);
  2060.             memset(src_offset_table, '\0', sizeof(struct offsets *) * OneFilePerBlock);
  2061.             for (i=0; i<MAXNUM_PAT; i++) {
  2062.                 if ((multi_dest_offset_table[i] == NULL) &&
  2063.                     ((multi_dest_offset_table[i] = (struct offsets **)my_malloc(sizeof(struct offsets *) * OneFilePerBlock)) == NULL)) exit(2);
  2064.                 memset(multi_dest_offset_table[i], '\0', sizeof(struct offsets *) * OneFilePerBlock);
  2065.             }
  2066.         }
  2067.         read_filters(INDEX_DIR, UseFilters);
  2068.  
  2069.         if (glimpse_clientdied) RETURN(0);
  2070.         /* Now initialize agrep, set the options and get the actual pattern into GPattern */
  2071.         if ((GM = fileagrep_init(agrep_argc, agrep_argv, MAXPAT, GPattern)) <= 0) {
  2072.             /* this printf need not be there: agrep prints messages if error */
  2073.             fprintf(stderr, "%s: error in options or arguments to `agrep'\n", HARVEST_PREFIX);
  2074.             RETURN(usage());
  2075.         }
  2076.         patindex = pattern_index;
  2077.         for (j=0; j<GM; j++) {
  2078.             if (GPattern[j] == '\\') j++;
  2079.             else if (test_indexable_char[GPattern[j]]) break;
  2080.         }
  2081.         if (j >= GM) {
  2082.             fprintf(stderr, "%s: pattern '%s' has no characters that were indexed: glimpse cannot search for it\n", HARVEST_PREFIX, GPattern);
  2083.             for (j=0; j<GM; j++) {
  2084.                 if (GPattern[j] == '\\') j++;
  2085.                 else if (isdigit(GPattern[j])) break;
  2086.             }
  2087.             if (j < GM) {
  2088.                 fprintf(stderr, "\t(to search for numbers, make the index using 'glimpseindex -n ...')\n");
  2089.             }
  2090.             RETURN(-1);
  2091.         }
  2092.  
  2093.         /* Split GPattern into individual boolean terms */
  2094.         if (GCONSTANT) {
  2095.             strcpy(APattern, GPattern);
  2096.             GParse = NULL;
  2097.             ComplexBoolean = 0;
  2098.             terminals[0].op = 0;
  2099.             terminals[0].type = LEAF;
  2100.             terminals[0].terminalindex = 0;
  2101.             terminals[0].data.leaf.attribute = 0;
  2102.             terminals[0].data.leaf.value = (CHAR *)malloc(GM + 1);
  2103.             strcpy(terminals[0].data.leaf.value, GPattern);
  2104.             num_terminals = 1;
  2105.         }
  2106.         else if (split_pattern(GPattern, GM, APattern, terminals, &num_terminals, &GParse, StructuredIndex) <= 0) RETURN(-1);
  2107. #if    BG_DEBUG
  2108.         fprintf(debug, "GPattern = %s, APattern = %s, num_terminals = %d\n", GPattern, APattern, num_terminals);
  2109. #endif    /*BG_DEBUG*/
  2110.  
  2111.         /* Set scope for booleans */
  2112.         if (foundnot && !wholefilescope) {
  2113.             fprintf(stderr, "To use the NOT (~) operation, you must use whole file scope (-W) for booleans.\n");
  2114.             RETURN(usage())
  2115.         }
  2116.         if (foundattr) WHOLEFILESCOPE = 1;    /* makes no sense to search attribute=value expressions without WHOLEFILESCOPE */
  2117.         else if (!ComplexBoolean && !PRINTATTR && !((long)GParse & AND_EXP)) WHOLEFILESCOPE = 0;    /* ORs can be done without WHOLEFILESCOPE */
  2118.         if (WHOLEFILESCOPE <= 0) agrep_argv[my_b_index][1] = 'Z';
  2119. /*
  2120.         if (!ComplexBoolean && ((long)GParse & AND_EXP) && (my_l_index != -1)) agrep_argv[my_l_index][1] = 'Z';
  2121. */
  2122.         if ((ComplexBoolean || ((long)GParse & AND_EXP)) && (my_l_index != -1)) agrep_argv[my_l_index][1] = 'Z';
  2123.  
  2124.         /* Now re-initialize agrep_argv with APattern instead of GPattern */
  2125.         my_free(agrep_argv[patindex], 0);
  2126.         AM=strlen(APattern);
  2127.         agrep_argv[patindex] = (char *)my_malloc(AM + 2);
  2128.         strcpy(agrep_argv[patindex], APattern);
  2129.  
  2130.         if (HINTSFROMUSER) {
  2131.             int    num=0, x, y, i, j;
  2132.             char    temp[MAX_NAME_SIZE+2];
  2133.             struct offsets *o, *tailo, *heado;
  2134.  
  2135.             while(1) {
  2136.                 if ((num = readline(newsockfd, dest_index_buf, REAL_INDEX_BUF)) <= 0) {
  2137.                     fprintf(stderr, "Input format error with -U option\n");
  2138.                     RETURN(-1);
  2139.                 }
  2140.                 dest_index_buf[num+1] = '\n';
  2141.                 if (!strncmp(dest_index_buf, "BEGIN", strlen("BEGIN"))) break;
  2142.             }
  2143.             sscanf(&dest_index_buf[strlen("BEGIN")], "%d%d%d", &bestmatcherrors, &NOBYTELEVEL, &OPTIMIZEBYTELEVEL);
  2144.             /* printf("BEGIN %d %d %d\n", bestmatcherrors, NOBYTELEVEL, OPTIMIZEBYTELEVEL);    */
  2145.             num = readline(newsockfd, dest_index_buf, REAL_INDEX_BUF);
  2146.             while (num > 0) {
  2147.                 dest_index_buf[num+1] = '\n';
  2148.                 if (!strncmp(dest_index_buf, "END", strlen("END"))) break;
  2149.                 i = j = 0;
  2150.                 while ((j<MAX_NAME_SIZE) && (dest_index_buf[i] != ' ') && (dest_index_buf[i] != '[') && (dest_index_buf[i] != '\n'))
  2151.                     temp[j++] = dest_index_buf[i++];
  2152.                 temp[j] = '\0';
  2153.                 x = atoi(temp);
  2154.                 GFileIndex[GNumfiles] = x;
  2155.                 if (x == file_num - 1) {
  2156.                     bigbuffer[bigbuffer_size] = '\0';
  2157.                     GTextfiles[GNumfiles++] = (CHAR *)strdup(GTextfilenames[x]);
  2158.                     bigbuffer[bigbuffer_size] = '\n';
  2159.                 }
  2160.                 else {
  2161.                     *(GTextfilenames[x+1] - 1) = '\0';
  2162.                     GTextfiles[GNumfiles++] = (CHAR *)strdup(GTextfilenames[x]);
  2163.                     *(GTextfilenames[x+1] - 1) = '\n';
  2164.                 }
  2165.                 /* printf("%d %s [", x, GTextfiles[GNumfiles-1]); */
  2166.                 src_index_set[block2index(x)] |= block2mask(x);
  2167.                 if (ByteLevelIndex && !NOBYTELEVEL) {    /* NOBYTELEVEL is 0 here with RecordLevelIndex */
  2168.                     heado = tailo = NULL;
  2169.                 onemorey:
  2170.                     j = 0;
  2171.                     while ((j<MAX_NAME_SIZE) && ((dest_index_buf[i] == ' ') || (dest_index_buf[i] == '['))) i++;
  2172.                     while ((j<MAX_NAME_SIZE) && (dest_index_buf[i] != ' ') && (dest_index_buf[i] != '\n') && (dest_index_buf[i] != ']'))
  2173.                         temp[j++] = dest_index_buf[i++];
  2174.                     temp[j] = '\0';
  2175.                     y = atoi(temp);
  2176.                     /* printf(" %d", y); */
  2177.                     o = (struct offsets *)my_malloc(sizeof(struct offsets));
  2178.                     o->offset = y;
  2179.                     o->next = NULL;
  2180.                     o->sign = o->done = 0;
  2181.                     if (heado == NULL) {
  2182.                         heado = o;
  2183.                         tailo = o;
  2184.                     }
  2185.                     else {
  2186.                         tailo->next = o;
  2187.                         tailo = o;
  2188.                     }
  2189.                     if (dest_index_buf[i] == ' ') goto onemorey;
  2190.                     src_offset_table[x] = heado;
  2191.                 }
  2192.                 /* printf("]\n"); */
  2193.                 num = readline(newsockfd, dest_index_buf, REAL_INDEX_BUF);
  2194.             }
  2195.             goto search_files;
  2196.         }
  2197.  
  2198.         /*
  2199.          * Copy the agrep-options that are relevant to index search into
  2200.          * index_argv (see man-pages for which options are relevant).
  2201.          * Also, adjust patindex whenever options are skipped over.
  2202.          * NOTE: agrep_argv does NOT contain two options after one '-'.
  2203.          */
  2204.         index_argc = 0;
  2205.         for (j=0; j<agrep_argc; j++) {
  2206.             if (agrep_argv[j][0] == '-') {
  2207.                 if ((agrep_argv[j][1] == 'c') || (agrep_argv[j][1] == 'h') || (agrep_argv[j][1] == 'l') || (agrep_argv[j][1] == 'n') ||
  2208.                     (agrep_argv[j][1] == 's') || (agrep_argv[j][1] == 't') || (agrep_argv[j][1] == 'G') || (agrep_argv[j][1] == 'O') ||
  2209.                     (agrep_argv[j][1] == 'b') || (agrep_argv[j][1] == 'i') || (agrep_argv[j][1] == 'u') || (agrep_argv[j][1] == 'g') ||
  2210.                     (agrep_argv[j][1] == 'E') || (agrep_argv[j][1] == 'Z') || (agrep_argv[j][1] == 'j') || (agrep_argv[j][1] == 'X')) {
  2211.                     patindex --;
  2212.                     continue;
  2213.                 }
  2214.                 if ((agrep_argv[j][1] == 'd') || (agrep_argv[j][1] == 'L')) {    /* skip over the argument too */
  2215.                     j++;
  2216.                     patindex -= 2;
  2217.                     continue;
  2218.                 }
  2219.                 if ((agrep_argv[j][1] == 'e') || (agrep_argv[j][1] == 'm')) {
  2220.                     strcpy(index_argv[index_argc], agrep_argv[j]);
  2221.                     index_argc ++; j++;
  2222.                     strcpy(index_argv[index_argc], agrep_argv[j]);
  2223.                     if (agrep_argv[j-1][1] == 'm') patbufpos = index_argc;    /* where to put the patbuf if fast-boolean by mgrep() */
  2224.                     index_argc ++;
  2225.                 }
  2226.                 else {    /* No arguments: just copy THAT option: maybe, change some options */
  2227.                     strcpy(index_argv[index_argc], agrep_argv[j]);
  2228.                     if (agrep_argv[j][1] == 'A') index_argv[index_argc][1] = 'h';
  2229.                     else if (agrep_argv[j][1] == 'x') index_argv[index_argc][1] = 'w';
  2230.                     index_argc++;
  2231.                 }
  2232.             }
  2233.             else {    /* This is either the pattern itself or a filename */
  2234.                 strcpy(index_argv[index_argc], agrep_argv[j]);
  2235.                 index_argc++;
  2236.             }
  2237.         }
  2238.         sprintf(index_argv[index_argc], "%s", INDEX_FILE);
  2239.         index_argc ++;
  2240. #if    0
  2241.         for (j=0; j<index_argc; j++) printf("index_argv[%d] = %s\n", j, index_argv[j]);
  2242.         printf("patindex = %d\n", patindex);
  2243. #endif    /*0*/
  2244.  
  2245.         /* process -Y option BEFORE search_index() so that get_set() doesn't even have to collect data for very old files */
  2246.         ret = process_Y_option(file_num, GNumDays, timesindexfp);
  2247.  
  2248.         /* Search the index and process index-search-only options; Worry about file-pattern */
  2249.         ret = search_index(GParse);
  2250.         if ((ret <= 0) && (!OneFilePerBlock || (src_index_set[REAL_PARTITION - 1] != 1))) RETURN(-1);    /* previously was: if ret < 0 then return... */
  2251.         num_blocks=0;
  2252.         if (OneFilePerBlock) {
  2253.             if (ByteLevelIndex || RecordLevelIndex) {
  2254.             for(iii=0; iii<OneFilePerBlock; iii++) {
  2255.                 if (src_offset_table[iii] != NULL) num_blocks ++;
  2256.             }
  2257.             /* printf("num_blocks = %d\n", num_blocks); */
  2258.             }
  2259.             if (src_index_set[REAL_PARTITION - 1] == 1) {
  2260.                 num_blocks = OneFilePerBlock;
  2261.                 for(iii=0; iii<round(OneFilePerBlock, 8*sizeof(int)) - 1; iii++) {
  2262.                     src_index_set[iii] = 0xffffffff;
  2263.                 }
  2264.                 src_index_set[i] = 0;
  2265.                 for (jjj=0; jjj<8*sizeof(int); jjj++) {
  2266.                     if (iii*8*sizeof(int) + jjj >= OneFilePerBlock) break;
  2267.                     src_index_set[iii] |= mask_int[jjj];
  2268.                 }
  2269.             }
  2270.             else for(iii=0; iii<round(OneFilePerBlock, 8*sizeof(int)); iii++) {
  2271.                 if (src_index_set[iii] == 0) continue;
  2272.                 for (jjj=0; jjj < 8*sizeof(int); jjj++)
  2273.                     if (src_index_set[iii] & mask_int[jjj])
  2274.                         if (!ByteLevelIndex || NOBYTELEVEL) {    /* was if (!RecordLevelIndex) ZZZZZZZZZZZZZZZZZZZZZZZZZZ */
  2275.                             num_blocks ++;
  2276.                         }
  2277.                         else {
  2278.                             if (src_offset_table[iii*8*sizeof(int) + jjj] != NULL)
  2279.                                 num_blocks ++;
  2280.                             else src_index_set[iii] &= ~mask_int[jjj];
  2281.                         }
  2282.             }
  2283.             if (num_blocks > OneFilePerBlock) num_blocks = OneFilePerBlock;    /* roundoff */
  2284.         }
  2285.         else {
  2286.             for (iii=0; iii<MAX_PARTITION; iii++)
  2287.                 if (src_index_set[iii]) num_blocks++;
  2288.         }
  2289.         if (num_blocks <= 0) RETURN (0);
  2290.         if ((src_index_set[REAL_PARTITION - 1] == 1) && !Only_first && !OPTIMIZEBYTELEVEL) {
  2291.             fprintf(stderr, "Warning: pattern has words present in the stop-list: must SEARCH the files\n");
  2292.         }
  2293.         if (RecordLevelIndex && GFILENAMEONLY && veryfast && (src_index_set[REAL_PARTITION - 1] != 1)) Only_first = 1;
  2294.         /* if just the NOBYTELEVEL flag is set, then it is an optimization which glimpse does and user need not be warned */
  2295. #if    DEBUG
  2296.         fprintf(stderr, "--> search=%d optimize=%d times=%d all=%d blocks=%d len=%d pat=%s scope=%d\n",
  2297.             NOBYTELEVEL, OPTIMIZEBYTELEVEL, src_index_set[REAL_PARTITION - 2], src_index_set[REAL_PARTITION - 1], num_blocks, strlen(APattern), APattern, WHOLEFILESCOPE);
  2298. #endif    /*DEBUG*/
  2299.  
  2300.         /* Based on contribution From ada@mail2.umu.se Fri Jul 12 01:56 MST 1996; Christer Holgersson, Sen. SysNet Mgr, Umea University/SUNET, Sweden */
  2301.         if (BITFIELDFILE) {
  2302.             int i, len = -1, nextchar;
  2303.             FILE    *fp;
  2304.             fp = fopen(bitfield_file, "r");
  2305.             if (fp != NULL) {
  2306.                 if (BITFIELDENDIAN >= 2) {    /* is a BIG-ENDIAN 4B integer list of indexes of files in .glimpse_filenames (sparse set) */
  2307.                     if (BITFIELDLENGTH == 0) BITFIELDLENGTH = file_num;
  2308.                     if (BITFIELDOFFSET > 0) fseek(fp, BITFIELDOFFSET, (long)0);
  2309.                     if (OneFilePerBlock) {
  2310.                         for (i=0; i<round(file_num, 8*sizeof(int)); i++)
  2311.                             multi_dest_index_set[0][i] = 0;
  2312.                     }
  2313.                     else {
  2314.                         for (i=0; i<MAX_PARTITION; i++)
  2315.                             multi_dest_index_set[0][i] = 0;
  2316.                     }
  2317.                     i = -1;
  2318.                     while ((nextchar = getc(fp)) != EOF) {
  2319.                         nextchar = nextchar & 0xff;
  2320.                         i = nextchar << 24;
  2321.                         if ((nextchar = getc(fp)) == EOF) break;
  2322.                         nextchar = nextchar & 0xff;
  2323.                         i |= nextchar << 16;
  2324.                         if ((nextchar = getc(fp)) == EOF) break;
  2325.                         nextchar = nextchar & 0xff;
  2326.                         i |= nextchar << 8;
  2327.                         if ((nextchar = getc(fp)) == EOF) break;
  2328.                         nextchar = nextchar & 0xff;
  2329.                         i |= nextchar;
  2330.  
  2331.                         if (OneFilePerBlock) {
  2332.                             if (i < file_num) multi_dest_index_set[0][block2index(i)] |= mask_int[i%(8*sizeof(int))];
  2333.                         }
  2334.                         else {
  2335.                             if (i < MAX_PARTITION) multi_dest_index_set[0][i] = 1;
  2336.                         }
  2337.                     }
  2338.                     fclose(fp);
  2339.                     if (i == -1) {
  2340.                         fprintf(stderr, "Error in reading %d bytes from offset %d in bitfield file %s ... ignoring it\n", BITFIELDOFFSET, BITFIELDLENGTH, BITFIELDFILE);
  2341.                         /* ignore index_file */
  2342.                     }
  2343.                     else {    /* intersect files in index_file with those that were obtained after pattern search */
  2344.                         if (OneFilePerBlock) {
  2345.                             for (i=0; i<round(file_num, 8*sizeof(int)); i++)
  2346.                                 src_index_set[i] &= multi_dest_index_set[0][i];
  2347.                         }
  2348.                         else {
  2349.                             for (i=0; i<MAX_PARTITION; i++)
  2350.                                 src_index_set[i] &= multi_dest_index_set[0][i];
  2351.                         }
  2352.                     }
  2353.                 }
  2354.                 else {
  2355.                     if (BITFIELDLENGTH == 0) BITFIELDLENGTH = sizeof(int)*REAL_PARTITION /* sizeof(int)*FILEMASK_SIZE */;
  2356.                     if (BITFIELDOFFSET > 0) fseek(fp, BITFIELDOFFSET, (long)0);
  2357.                     if (OneFilePerBlock) {
  2358.                         for (i=0; i<round(file_num, 8*sizeof(int)); i++)
  2359.                             multi_dest_index_set[0][i] = 0;
  2360.                     }
  2361.                     else {
  2362.                         for (i=0; i<MAX_PARTITION; i++)
  2363.                             multi_dest_index_set[0][i] = 0;
  2364.                     }
  2365.                     i = 0;
  2366.                     while ((i < BITFIELDLENGTH) && (nextchar = getc(fp)) != EOF) {
  2367.                         nextchar = nextchar & 0xff;
  2368.                         if (OneFilePerBlock) {
  2369.                             if (BITFIELDENDIAN == 1) {    /* little-endian: little end of integer was dumped first in bitfield_file */
  2370.                                 multi_dest_index_set[0][i/4] |= (nextchar << (8*(i%4)));
  2371.                             }
  2372.                             else if (BITFIELDENDIAN == 0) {    /* big-endian: big end of integer is first was dumped first in bitfield_file */
  2373.                                 multi_dest_index_set[0][i/4] |= (nextchar << (8*(4-1-(i%4))));
  2374.                             }
  2375.                         }
  2376.                         else {
  2377.                             if (i < MAX_PARTITION) {    /* interpretation of "bit" changes without OneFilePerBlock */
  2378.                                 multi_dest_index_set[0][i] = (nextchar != 0) ? 1 : 0;
  2379.                             }
  2380.                             else break;    /* BITFIELDLENGTH, by above definition, is always > MAX_PARTITION: see io.c */
  2381.                         }
  2382.                         i++;
  2383.                     }
  2384.                     fclose(fp);
  2385.                     if (i <= 0) {
  2386.                         fprintf(stderr, "Error in reading %d bytes from offset %d in bitfield file %s ... ignoring it\n", BITFIELDOFFSET, BITFIELDLENGTH, BITFIELDFILE);
  2387.                         /* ignore bitfield_file */
  2388.                     }
  2389.                     else {    /* intersect files in bitfield_file with those that were obtained after pattern search */
  2390.                         if (OneFilePerBlock) {
  2391.                             for (i=0; i<round(file_num, 8*sizeof(int)); i++)
  2392.                                 src_index_set[i] &= multi_dest_index_set[0][i];
  2393.                         }
  2394.                         else {
  2395.                             for (i=0; i<MAX_PARTITION; i++)
  2396.                                 src_index_set[i] &= multi_dest_index_set[0][i];
  2397.                         }
  2398.                     }
  2399.                 }
  2400.             }
  2401.         }
  2402.  
  2403.         if (FILENAMESINFILE) mask_filenames(src_index_set, filenames_file, file_num, num_blocks);    /* keep only those files that are in filenames_file */
  2404.         if (BITFIELDFILE || FILENAMESINFILE) {
  2405.             num_blocks=0;
  2406.             if (OneFilePerBlock) {
  2407.                 for(iii=0; iii<round(OneFilePerBlock, 8*sizeof(int)); iii++) {
  2408.                     if (src_index_set[iii] == 0) continue;
  2409.                     for (jjj=0; jjj < 8*sizeof(int); jjj++)
  2410.                         if (src_index_set[iii] & mask_int[jjj])
  2411.                             if (!ByteLevelIndex || NOBYTELEVEL) {    /* was if (!RecordLevelIndex) ZZZZZZZZZZZZZZZZZZZZZZZZZZ */
  2412.                                 num_blocks ++;
  2413.                             }
  2414.                             else {
  2415.                                 if (src_offset_table[iii*8*sizeof(int) + jjj] != NULL)
  2416.                                     num_blocks ++;
  2417.                                 else src_index_set[iii] &= ~mask_int[jjj];
  2418.                             }
  2419.                 }
  2420.                 if (num_blocks > OneFilePerBlock) num_blocks = OneFilePerBlock;    /* roundoff */
  2421.             }
  2422.             else {
  2423.                 for (iii=0; iii<MAX_PARTITION; iii++)
  2424.                     if (src_index_set[iii]) num_blocks++;
  2425.             }
  2426.             if (num_blocks <= 0) RETURN (0);
  2427.         }
  2428.  
  2429.         dummypat[0] = '\0';
  2430.         if (!MATCHFILE)    {    /* the argc,argv don't matter */
  2431.             get_filenames(src_index_set, 0, NULL, dummylen, dummypat, file_num);
  2432.  
  2433.             if (Only_first) { /* search the index only */
  2434.                 fprintf(stderr, "There are matches to %d out of %d %s\n", num_blocks, (OneFilePerBlock > 0) ? OneFilePerBlock : GNumpartitions, (OneFilePerBlock > 0) ? "files" : "blocks");
  2435.                 if (num_blocks > 0) {
  2436.                     char    cc[8];
  2437.                     cc[0] = 'y';
  2438. #if    !ISSERVER
  2439.                     if (!GNOPROMPT) {
  2440.                         fprintf(stderr, "Do you want to see the file names? (y/n)");
  2441.                         fgets(cc, 4, stdin);
  2442.                     }
  2443. #endif    /*!ISSERVER*/
  2444.                     if (!SILENT && (cc[0] == 'y')) {
  2445.                         if (PRINTAPPXFILEMATCH && Only_first && GPRINTFILENUMBER) {
  2446.                             printf("BEGIN %d %d %d\n", bestmatcherrors, NOBYTELEVEL, OPTIMIZEBYTELEVEL);
  2447.                         }
  2448.                         for (jjj=0; jjj<GNumfiles; jjj++) {
  2449.                             if ((GLIMITOUTPUT > 0) && (jjj >= GLIMITOUTPUT)) break;
  2450.                             if (ByteLevelIndex && !NOBYTELEVEL && (src_index_set[REAL_PARTITION - 1] != 1) && (src_offset_table[GFileIndex[jjj]] == NULL)) continue;    /* was if (RecordLevelIndex ...) ZZZZZZZZZZZZZZZZZZZZZZ */
  2451.                             if (GPRINTFILENUMBER) printf("%d", GFileIndex[jjj]);
  2452.                             else printf("%s", GTextfiles[jjj]);
  2453.                             if (PRINTAPPXFILEMATCH) {
  2454.                                 if (GCOUNT) {
  2455.                                 int n = 0;
  2456.                                 printf(": ");
  2457.                                 if (ByteLevelIndex && (src_offset_table != NULL)) {
  2458.                                     struct offsets  *p1 = src_offset_table[GFileIndex[jjj]];
  2459.                                     while (p1 != NULL) {
  2460.                                         n ++;
  2461.                                         p1 = p1->next;
  2462.                                     }
  2463.                                 }
  2464.                                 else n = 1;    /* there is atleast 1 match */
  2465.                                 printf("%d", n);
  2466.                                 }
  2467.                                 else {
  2468.                                 printf(" [");
  2469.                                 if (ByteLevelIndex && (src_offset_table != NULL)) {
  2470.                                     struct offsets  *p1 = src_offset_table[GFileIndex[jjj]];
  2471.                                     while (p1 != NULL) {
  2472.                                         printf(" %d", p1->offset);
  2473.                                         p1 = p1->next;
  2474.                                     }
  2475.                                 }
  2476.                                 printf("]");
  2477.                                 }
  2478.                             }
  2479.                             printf("\n");
  2480.                         }
  2481.                         if (PRINTAPPXFILEMATCH && Only_first && GPRINTFILENUMBER) {
  2482.                             printf("END\n");
  2483.                         }
  2484.                     }
  2485.                 }
  2486.                 RETURN(0);
  2487.             } /* end of Only_first */
  2488.             if (!OneFilePerBlock) searchpercent = num_blocks*100/GNumpartitions;
  2489.             else searchpercent = num_blocks * 100 / OneFilePerBlock;
  2490. #if    BG_DEBUG
  2491.             fprintf(debug, "searchpercent = %d, num_blocks = %d\n", searchpercent, num_blocks);
  2492. #endif    /*BG_DEBUG*/
  2493. #if    !ISSERVER
  2494.             if (!GNOPROMPT && (searchpercent > MAX_SEARCH_PERCENT)) {
  2495.                 char    cc[8];
  2496.                 cc[0] = 'y';
  2497.                 fprintf(stderr, "Your query may search about %d%% of the total space! Continue? (y/n)", searchpercent); 
  2498.                 fgets(cc, 4, stdin);
  2499.                 if (cc[0] != 'y') RETURN(0);
  2500.             }
  2501.             if (ByteLevelIndex && !RecordLevelIndex && (searchpercent > DEF_MAX_INDEX_PERCENT)) NOBYTELEVEL = 1;    /* with RecordLevelIndex, I don't just want to stop collecting offsets just because searchpercent > .... */
  2502. #endif    /*!ISSERVER*/
  2503.         } /* end of !MATCHFILE */
  2504.         else {    /* set up the right options for -F in index_argv/index_argc itself since they will no longer be used */
  2505.             index_argc=0;
  2506.             strcpy(index_argv[0], GProgname);
  2507.  
  2508.             /* adding the -h option, which is safer for -F */
  2509.             index_argc ++;
  2510.             index_argv[index_argc][0] =  '-';
  2511.             index_argv[index_argc][1] = 'h';
  2512.             index_argv[index_argc][2] = '\0';
  2513.             index_argc ++;
  2514.  
  2515.             /* new code: bgopal, Feb/8/94: deleted udi's code here */
  2516.             j = 0;
  2517.             while (FileOpt[j] == '-') {
  2518.                 j++;
  2519.                 while ((FileOpt[j] != ' ') && (FileOpt[j] != '\0') && (FileOpt[j] != '\n')) {
  2520.                     if (j >= MAX_ARGS - 1) {
  2521.                         fprintf(stderr, "%s: too many options after -F: %s\n", GProgname, FileOpt);
  2522.                         RETURN(usage());
  2523.                     }
  2524.                     index_argv[index_argc][0] =  '-';
  2525.                     index_argv[index_argc][1] = FileOpt[j];
  2526.                     index_argv[index_argc][2] = '\0';
  2527.                     index_argc ++;
  2528.                     j++;
  2529.                 }
  2530.                 if ((FileOpt[j] == '\0') || (FileOpt[j] == '\n')) break;
  2531.                 if ((FileOpt[j] == ' ') && (FileOpt[j-1] == '-')) {
  2532.                     fprintf(stderr, "%s: illegal option: '-' after -F\n", GProgname);
  2533.                     RETURN(usage());
  2534.                 }
  2535.                 else if (FileOpt[j] == ' ') while(FileOpt[j] == ' ') j++;
  2536.             }
  2537.             while(FileOpt[j] == ' ') j++;
  2538.  
  2539.             fileopt_length = strlen(FileOpt);
  2540.             strncpy(index_argv[index_argc],FileOpt+j,fileopt_length-j);
  2541.             index_argv[index_argc][fileopt_length-j] = '\0';
  2542.             index_argc++;
  2543.             my_free(FileOpt, MAXFILEOPT);
  2544.             FileOpt = NULL;
  2545.  
  2546. #if    BG_DEBUG
  2547.             fprintf(debug, "pattern to check with -F = %s\n",index_argv[index_argc-1]);
  2548. #endif    /*BG_DEBUG*/
  2549. #if    DEBUG
  2550.             fprintf(stderr, "-F : ");
  2551.             for (jj=0; jj < index_argc; jj++) 
  2552.                 fprintf(stderr, " %s ",index_argv[jj]);
  2553.             fprintf(stderr, "\n");
  2554. #endif    /*DEBUG*/
  2555.             fflush(stdout);
  2556.             get_filenames(src_index_set, index_argc, index_argv, dummylen, dummypat, file_num);
  2557.  
  2558.             /* Assume #files per partitions is appx constant */
  2559.             if (OneFilePerBlock) num_blocks = GNumfiles;
  2560.             else num_blocks = GNumfiles * GNumpartitions / p_table[GNumpartitions - 1];
  2561.             if (Only_first) { /* search the index only */
  2562.                 fprintf(stderr, "There are matches to %d out of %d %s\n", num_blocks, (OneFilePerBlock > 0) ? OneFilePerBlock : GNumpartitions, (OneFilePerBlock > 0) ? "files" : "blocks");
  2563.                 if (num_blocks > 0) {
  2564.                     char    cc[8];
  2565.                     cc[0] = 'y';
  2566. #if    !ISSERVER
  2567.                     if (!GNOPROMPT) {
  2568.                         fprintf(stderr, "Do you want to see the file names? (y/n)");
  2569.                         fgets(cc, 4, stdin);
  2570.                     }
  2571. #endif    /*!ISSERVER*/
  2572.                     if (!SILENT && (cc[0] == 'y')) {
  2573.                         if (PRINTAPPXFILEMATCH && Only_first && GPRINTFILENUMBER) {
  2574.                             printf("BEGIN %d %d %d\n", bestmatcherrors, NOBYTELEVEL, OPTIMIZEBYTELEVEL);
  2575.                         }
  2576.                         for (jjj=0; jjj<GNumfiles; jjj++) {
  2577.                             if ((GLIMITOUTPUT > 0) && (jjj >= GLIMITOUTPUT)) break;
  2578.                             if (ByteLevelIndex && !NOBYTELEVEL && (src_index_set[REAL_PARTITION - 1] != 1) && (src_offset_table[GFileIndex[jjj]] == NULL)) continue;    /* was if (RecordLevelIndex ...) ZZZZZZZZZZZZZZZZZZZZZZ */
  2579.                             if (GPRINTFILENUMBER) printf("%d", GFileIndex[jjj]);
  2580.                             else printf("%s", GTextfiles[jjj]);
  2581.                             if (PRINTAPPXFILEMATCH) {
  2582.                                 if (GCOUNT) {
  2583.                                 int n = 0;
  2584.                                 printf(": ");
  2585.                                 if (ByteLevelIndex && (src_offset_table != NULL)) {
  2586.                                     struct offsets  *p1 = src_offset_table[GFileIndex[jjj]];
  2587.                                     while (p1 != NULL) {
  2588.                                         n ++;
  2589.                                         p1 = p1->next;
  2590.                                     }
  2591.                                 }
  2592.                                 else n = 1;    /* there is atleast 1 match */
  2593.                                 printf("%d", n);
  2594.                                 }
  2595.                                 else {
  2596.                                 printf("[");
  2597.                                 if (ByteLevelIndex && (src_offset_table != NULL)) {
  2598.                                     struct offsets  *p1 = src_offset_table[GFileIndex[jjj]];
  2599.                                     while (p1 != NULL) {
  2600.                                         printf(" %d", p1->offset);
  2601.                                         p1 = p1->next;
  2602.                                     }
  2603.                                 }
  2604.                                 printf("]");
  2605.                                 }
  2606.                             }
  2607.                             printf("\n");
  2608.                         }
  2609.                         if (PRINTAPPXFILEMATCH && Only_first && GPRINTFILENUMBER) {
  2610.                             printf("END\n");
  2611.                         }
  2612.                     }
  2613.                 }
  2614.                 RETURN(0);
  2615.             } /* end of Only_first */
  2616.             if (OneFilePerBlock) searchpercent = GNumfiles * 100 / OneFilePerBlock;
  2617.             else searchpercent = GNumfiles * 100 / p_table[GNumpartitions - 1];
  2618. #if    BG_DEBUG
  2619.             fprintf(debug, "searchpercent = %d, num_files = %d\n", searchpercent, p_table[GNumpartitions - 1]);
  2620. #endif    /*BG_DEBUG*/
  2621. #if    !ISSERVER
  2622.             if (!GNOPROMPT && (searchpercent > MAX_SEARCH_PERCENT)) {
  2623.                 char    cc[8];
  2624.                 cc[0] = 'y';
  2625.                 fprintf(stderr, "Your query may search about %d%% of the total space! Continue? (y/n)", searchpercent); 
  2626.                 fgets(cc, 4, stdin);
  2627.                 if (cc[0] != 'y') RETURN(0);
  2628.             }
  2629.             if (ByteLevelIndex && !RecordLevelIndex && (searchpercent > DEF_MAX_INDEX_PERCENT)) NOBYTELEVEL = 1;    /* with RecordLevelIndex, I don't just want to stop collecting offsets just because searchpercent > .... */
  2630. #endif    /*!ISSERVER*/
  2631.         }
  2632.  
  2633.         /* At this point, I have the set of files to search */
  2634.  
  2635.     search_files:
  2636.         /* Replace -B by the number of errors if best-match */
  2637.         if (GBESTMATCH && (my_B_index >= 0)) {
  2638.             sprintf(&agrep_argv[my_B_index][1], "%d", bestmatcherrors);
  2639. #if    BG_DEBUG
  2640.             fprintf(debug, "Changing -B to -%d\n", bestmatcherrors);
  2641. #endif    /*BG_DEBUG*/
  2642.         }
  2643.         agrep_argv[my_M_index][1] = 'Z';
  2644.         agrep_argv[my_P_index][1] = 'Z';
  2645. #if    0
  2646.         for (iii=0; iii<agrep_argc; iii++) fprintf(stdout, "'%s' ", agrep_argv[iii]);
  2647.         fprintf(stdout, "\n");
  2648. #endif
  2649. /*
  2650.         if (!ComplexBoolean && ((long)GParse & AND_EXP) && (my_l_index != -1) && !WHOLEFILESCOPE) agrep_argv[my_l_index][1] = 'l';
  2651. */
  2652.         if ((ComplexBoolean || ((long)GParse & AND_EXP)) && (my_l_index != -1) && !WHOLEFILESCOPE) agrep_argv[my_l_index][1] = 'l';
  2653.  
  2654.         if (GNumfiles <= 0) RETURN(0);
  2655.         if (glimpse_clientdied) RETURN(0);
  2656.         /* must reinitialize since the above agrep calls for index-search ruined the real options: it is required EVEN IF ByteLevelIndex */
  2657.         AM = fileagrep_init(agrep_argc, agrep_argv, MAXPAT, APattern);
  2658.         /* do actual search with postfiltering if structured query */
  2659.         if (WHOLEFILESCOPE <= 0) {
  2660.             if (!UseFilters) {
  2661.                 if (!ByteLevelIndex || RecordLevelIndex || NOBYTELEVEL) {
  2662.                     for (i=0; i<GNumfiles; i++) {
  2663.                         /* if (RecordLevelIndex && (src_offset_table[GFileIndex[i]] == NULL)) continue; */
  2664.                         gprev_num_of_matched = gnum_of_matched;
  2665.                         SetCurrentFileName = 1;
  2666.                         if (GPRINTFILENUMBER) sprintf(CurrentFileName, "%d", GFileIndex[i]);
  2667.                         else strcpy(CurrentFileName, GTextfiles[i]);
  2668.                         if (GPRINTFILETIME) {
  2669.                             SetCurrentFileTime = 1;
  2670.                             CurrentFileTime = get_file_time(timesfp, NULL, GTextfiles[i], GFileIndex[i]);
  2671.                         }
  2672.                         if ((ret = fileagrep_search(AM, APattern, 1, >extfiles[i], 0, stdout)) > 0) {
  2673.                             gnum_of_matched += ret;
  2674.                             gfiles_matched ++;
  2675.                         }
  2676.                         SetCurrentFileName = 0;
  2677.                         if (GPRINTFILETIME) SetCurrentFileTime = 0;
  2678.                         if (GLIMITOUTPUT > 0) {
  2679.                             if (GLIMITOUTPUT <= gnum_of_matched) break;
  2680.                             LIMITOUTPUT = GLIMITOUTPUT - gnum_of_matched;
  2681.                         }
  2682.                         if (GLIMITTOTALFILE > 0) {
  2683.                             if (GLIMITTOTALFILE <= gfiles_matched) break;
  2684.                             LIMITTOTALFILE = GLIMITTOTALFILE - gfiles_matched;
  2685.                         }
  2686.                          if ((ret < 0) && (errno == AGREP_ERROR)) break;
  2687.                         if (glimpse_clientdied) break;
  2688.                         fflush(stdout);
  2689.                     }
  2690.                 }
  2691.                 else {
  2692.                     for (i=0; i<GNumfiles; i++) {
  2693.                         gprev_num_of_matched = gnum_of_matched;
  2694.                         SetCurrentFileName = 1;
  2695.                         if (GPRINTFILENUMBER) sprintf(CurrentFileName, "%d", GFileIndex[i]);
  2696.                         else strcpy(CurrentFileName, GTextfiles[i]);
  2697.                         if (my_stat(GTextfiles[i], &file_stat_buf) == -1) {
  2698.                             if (GPRINTNONEXISTENTFILE) printf("%s\n", CurrentFileName);
  2699.                             continue;
  2700.                         }
  2701.                         if (GPRINTFILETIME) {
  2702.                             SetCurrentFileTime = 1;
  2703.                             CurrentFileTime = get_file_time(timesfp, &file_stat_buf, GTextfiles[i], GFileIndex[i]);
  2704.                         }
  2705.                         if (file_stat_buf.st_mtime > index_stat_buf.st_mtime) {
  2706.                             /* fprintf(stderr, "Warning: file modified after indexing: must SEARCH %s\n", CurrentFileName); */
  2707.                             free_list(&src_offset_table[GFileIndex[i]]);
  2708.                             first_search = 1;
  2709.                             if ((ret = fileagrep_search(AM, APattern, 1, >extfiles[i], 0, stdout)) > 0) {
  2710.                                 gnum_of_matched += ret;
  2711.                                 gfiles_matched ++;
  2712.                             }
  2713.                         }
  2714.                         else if ((ret = glimpse_search(AM, APattern, GD_length, GD_pattern, GTextfiles[i], GTextfiles[i], GFileIndex[i], src_offset_table, stdout)) > 0) {
  2715.                             gnum_of_matched += ret;
  2716.                             gfiles_matched ++;
  2717.                         }
  2718.                         SetCurrentFileName = 0;
  2719.                         if (GPRINTFILETIME) SetCurrentFileTime = 0;
  2720.                         if (GLIMITOUTPUT > 0) {
  2721.                             if (GLIMITOUTPUT <= gnum_of_matched) break;
  2722.                             LIMITOUTPUT = GLIMITOUTPUT - gnum_of_matched;
  2723.                         }
  2724.                         if (GLIMITTOTALFILE > 0) {
  2725.                             if (GLIMITTOTALFILE <= gfiles_matched) break;
  2726.                             LIMITTOTALFILE = GLIMITTOTALFILE - gfiles_matched;
  2727.                         }
  2728.                          if ((ret < 0) && (errno == AGREP_ERROR)) break;
  2729.                         if (glimpse_clientdied) break;
  2730.                         fflush(stdout);
  2731.                     }
  2732.                 }
  2733.             } /* end of !UseFilters */
  2734.             else {
  2735.                 sprintf(outname[0], "%s/.glimpse_apply.%d", TEMP_DIR, getpid());
  2736.                 for (i=0; i<GNumfiles; i++) {
  2737.                     /* if (RecordLevelIndex && (src_offset_table[GFileIndex[i]] == NULL)) continue; */
  2738.                     if (apply_filter(GTextfiles[i], outname[0]) == 1) {
  2739.                         gprev_num_of_matched = gnum_of_matched;
  2740.                         SetCurrentFileName = 1;
  2741.                         if (GPRINTFILENUMBER) sprintf(CurrentFileName, "%d", GFileIndex[i]);
  2742.                         else strcpy(CurrentFileName, GTextfiles[i]);
  2743.                         if (my_stat(GTextfiles[i], &file_stat_buf) == -1) {
  2744.                             if (GPRINTNONEXISTENTFILE) printf("%s\n", CurrentFileName);
  2745.                             continue;
  2746.                         }
  2747.                         if (GPRINTFILETIME) {
  2748.                             SetCurrentFileTime = 1;
  2749.                             CurrentFileTime = get_file_time(timesfp, &file_stat_buf, GTextfiles[i], GFileIndex[i]);
  2750.                         }
  2751.                         if (!ByteLevelIndex || RecordLevelIndex || NOBYTELEVEL || (file_stat_buf.st_mtime > index_stat_buf.st_mtime)) {
  2752.                             first_search = 1;
  2753.                             if ((ret = fileagrep_search(AM, APattern, 1, outname, 0, stdout)) > 0) {
  2754.                                 gnum_of_matched += ret;
  2755.                                 gfiles_matched ++;
  2756.                             }
  2757.                         }
  2758.                         else {
  2759.                             if (file_stat_buf.st_mtime > index_stat_buf.st_mtime) {
  2760.                                 /* fprintf(stderr, "Warning: file modified after indexing: must SEARCH %s\n", CurrentFileName); */
  2761.                                 free_list(&src_offset_table[GFileIndex[i]]);
  2762.                                 first_search = 1;
  2763.                                 if ((ret = fileagrep_search(AM, APattern, 1, outname, 0, stdout)) > 0) {
  2764.                                     gnum_of_matched += ret;
  2765.                                     gfiles_matched ++;
  2766.                                 }
  2767.                             }
  2768.                             else if ((ret = glimpse_search(AM, APattern, GD_length, GD_pattern, GTextfiles[i], outname[0], GFileIndex[i], src_offset_table, stdout)) > 0) {
  2769.                                 gfiles_matched ++;
  2770.                                 gnum_of_matched += ret;
  2771.                             }
  2772.                         }
  2773.                         unlink(outname[0]);
  2774.                         SetCurrentFileName = 0;
  2775.                         if (GPRINTFILETIME) SetCurrentFileTime = 0;
  2776.                     }
  2777.                     else {
  2778.                         if (!ByteLevelIndex || RecordLevelIndex || NOBYTELEVEL) {
  2779.                             first_search = 1;
  2780.                             if ((ret = fileagrep_search(AM, APattern, 1, >extfiles[i], 0, stdout)) > 0) {
  2781.                                 gnum_of_matched += ret;
  2782.                                 gfiles_matched ++;
  2783.                             }
  2784.                         }
  2785.                         else {
  2786.                             SetCurrentFileName = 1;
  2787.                             if (GPRINTFILENUMBER) sprintf(CurrentFileName, "%d", GFileIndex[i]);
  2788.                             else strcpy(CurrentFileName, GTextfiles[i]);
  2789.                             if (my_stat(GTextfiles[i], &file_stat_buf) == -1) {
  2790.                                 if (GPRINTNONEXISTENTFILE) printf("%s\n", CurrentFileName);
  2791.                                 continue;
  2792.                             }
  2793.                             if (GPRINTFILETIME) {
  2794.                                 SetCurrentFileTime = 1;
  2795.                                 CurrentFileTime = get_file_time(timesfp, &file_stat_buf, GTextfiles[i], GFileIndex[i]);
  2796.                             }
  2797.                             if (file_stat_buf.st_mtime > index_stat_buf.st_mtime) {
  2798.                                 /* fprintf(stderr, "Warning: file modified after indexing: must SEARCH %s\n", CurrentFileName); */
  2799.                                 free_list(&src_offset_table[GFileIndex[i]]);
  2800.                                 first_search = 1;
  2801.                                 if ((ret = fileagrep_search(AM, APattern, 1, >extfiles[i], 0, stdout)) > 0) {
  2802.                                     gnum_of_matched += ret;
  2803.                                     gfiles_matched ++;
  2804.                                 }
  2805.                             }
  2806.                             else if ((ret = glimpse_search(AM, APattern, GD_length, GD_pattern, GTextfiles[i], GTextfiles[i], GFileIndex[i], src_offset_table, stdout)) > 0) {
  2807.                                 gnum_of_matched += ret;
  2808.                                 gfiles_matched ++;
  2809.                             }
  2810.                             SetCurrentFileName = 0;
  2811.                             if (GPRINTFILETIME) SetCurrentFileTime = 0;
  2812.                         }
  2813.                     }
  2814.                     if (GLIMITOUTPUT > 0) {
  2815.                         if (GLIMITOUTPUT <= gnum_of_matched) break;
  2816.                         LIMITOUTPUT = GLIMITOUTPUT - gnum_of_matched;
  2817.                     }
  2818.                     if (GLIMITTOTALFILE > 0) {
  2819.                         if (GLIMITTOTALFILE <= gfiles_matched) break;
  2820.                         LIMITTOTALFILE = GLIMITTOTALFILE - gfiles_matched;
  2821.                     }
  2822.                      if ((ret < 0) && (errno == AGREP_ERROR)) break;
  2823.                     if (glimpse_clientdied) break;
  2824.                     fflush(stdout);
  2825.                 }
  2826.             }
  2827.         } /* end of WHOLEFILESCOPE <= 0 */
  2828.         else {
  2829.             FILE    *tmpfp = NULL;    /* to store structured query-search output */
  2830.             int    OLDFILENAMEONLY;/* don't use FILENAMEONLY for agrepping the stuff: handle it in filtering */
  2831.             int     OLDLIMITOUTPUT; /* don't use LIMITs for search: only for filtering=identify_region(): agrep NEVER changes these 3 */
  2832.             int    OLDLIMITPERFILE;
  2833.             int    OLDLIMITTOTALFILE;
  2834.             int    OLDPRINTRECORD;    /* don't use PRINTRECORD for search: only after filter_output() recognizes boolean in wholefilescope */
  2835.             int    OLDCOUNT;    /* don't use OLDCOUNT for search: only after filter_output() recognizes boolean in wholefilescope */
  2836.  
  2837.             if (!UseFilters) {
  2838.                 for (i=0; i<GNumfiles; i++) {
  2839.                     /* if (RecordLevelIndex && (src_offset_table[GFileIndex[i]] == NULL)) continue; */
  2840.                     OLDFILENAMEONLY = FILENAMEONLY;
  2841.                     FILENAMEONLY = 0;
  2842.                     OLDLIMITOUTPUT = LIMITOUTPUT;
  2843.                     LIMITOUTPUT = 0;
  2844.                     OLDLIMITPERFILE = LIMITPERFILE;
  2845.                     LIMITPERFILE = 0;
  2846.                     OLDLIMITTOTALFILE = LIMITTOTALFILE;
  2847.                     LIMITTOTALFILE = 0;
  2848.                     OLDPRINTRECORD = PRINTRECORD;
  2849.                     PRINTRECORD = 1;
  2850.                     OLDCOUNT = COUNT;
  2851.                     COUNT = 0;
  2852.                     gprev_num_of_matched = gnum_of_matched;
  2853.                     if ((tmpfp = fopen(tempfile, "w")) == NULL) {
  2854.                         fprintf(stderr, "%s: cannot open for writing: %s, errno=%d\n", GProgname, tempfile, errno);
  2855.                         RETURN(usage());
  2856.                     }
  2857.                     SetCurrentFileName = 1;
  2858.                     if (GPRINTFILENUMBER) sprintf(CurrentFileName, "%d", GFileIndex[i]);
  2859.                     else strcpy(CurrentFileName, GTextfiles[i]);
  2860.                     if (!ByteLevelIndex || RecordLevelIndex || NOBYTELEVEL) {
  2861.                         if (GPRINTFILETIME) {
  2862.                             SetCurrentFileTime = 1;
  2863.                             CurrentFileTime = get_file_time(timesfp, NULL, GTextfiles[i], GFileIndex[i]);
  2864.                         }
  2865.                         first_search = 1;
  2866.                         ret = fileagrep_search(AM, APattern, 1, >extfiles[i], 0, tmpfp);
  2867.                     }
  2868.                     else {
  2869.                         if (my_stat(GTextfiles[i], &file_stat_buf) == -1) {
  2870.                             if (GPRINTNONEXISTENTFILE) printf("%s\n", CurrentFileName);
  2871.                             fclose(tmpfp);
  2872.                             continue;
  2873.                         }
  2874.                         if (GPRINTFILETIME) {
  2875.                             SetCurrentFileTime = 1;
  2876.                             CurrentFileTime = get_file_time(timesfp, &file_stat_buf, GTextfiles[i], GFileIndex[i]);
  2877.                         }
  2878.                         if (file_stat_buf.st_mtime > index_stat_buf.st_mtime) {
  2879.                             /* fprintf(stderr, "Warning: file modified after indexing: must SEARCH %s\n", CurrentFileName); */
  2880.                             free_list(&src_offset_table[GFileIndex[i]]);
  2881.                             first_search = 1;
  2882.                             ret = fileagrep_search(AM, APattern, 1, >extfiles[i], 0, tmpfp);
  2883.                         }
  2884.                         else ret = glimpse_search(AM, APattern, GD_length, GD_pattern, GTextfiles[i], GTextfiles[i], GFileIndex[i], src_offset_table, tmpfp);
  2885.                     }
  2886.                     SetCurrentFileName = 0;
  2887.                     if (GPRINTFILETIME) SetCurrentFileTime = 0;
  2888.                     fflush(tmpfp);
  2889.                     fclose(tmpfp);
  2890.                     tmpfp = NULL;
  2891.                     if ((ret < 0) && (errno == AGREP_ERROR)) break;
  2892. #if    DEBUG
  2893.                     printf("done search\n");
  2894.                     fflush(stdout);
  2895. #endif    /*DEBUG*/
  2896.                     FILENAMEONLY = OLDFILENAMEONLY;
  2897.                     LIMITOUTPUT = OLDLIMITOUTPUT;
  2898.                     LIMITPERFILE = OLDLIMITPERFILE;
  2899.                     LIMITTOTALFILE = OLDLIMITTOTALFILE;
  2900.                     PRINTRECORD = OLDPRINTRECORD;
  2901.                     COUNT = OLDCOUNT;
  2902.                     ret = filter_output(GTextfiles[i], tempfile, GParse, GD_pattern, GD_length, GOUTTAIL, nullfp, StructuredIndex);
  2903.                     gnum_of_matched += (ret > 0) ? ret : 0;
  2904.                     gfiles_matched += (ret > 0) ? 1 : 0;
  2905.                     if (GLIMITOUTPUT > 0) {
  2906.                         if (GLIMITOUTPUT <= gnum_of_matched) break;
  2907.                         LIMITOUTPUT = GLIMITOUTPUT - gnum_of_matched;
  2908.                     }
  2909.                     if (GLIMITTOTALFILE > 0) {
  2910.                         if (GLIMITTOTALFILE <= gfiles_matched) break;
  2911.                         LIMITTOTALFILE = GLIMITTOTALFILE - gfiles_matched;
  2912.                     }
  2913.                     if (glimpse_clientdied) break;
  2914.                     fflush(stdout);
  2915.                 }
  2916.             }
  2917.             else {    /* we should try to apply the filter (we come here with -W -z, say) */
  2918.                 sprintf(outname[0], "%s/.glimpse_apply.%d", TEMP_DIR, getpid());
  2919.                 for (i=0; i<GNumfiles; i++) {
  2920.                     /* if (RecordLevelIndex && (src_offset_table[GFileIndex[i]] == NULL)) continue; */
  2921.                     OLDFILENAMEONLY = FILENAMEONLY;
  2922.                     FILENAMEONLY = 0;
  2923.                     OLDLIMITOUTPUT = LIMITOUTPUT;
  2924.                     LIMITOUTPUT = 0;
  2925.                     OLDLIMITPERFILE = LIMITPERFILE;
  2926.                     LIMITPERFILE = 0;
  2927.                     OLDLIMITTOTALFILE = LIMITTOTALFILE;
  2928.                     LIMITTOTALFILE = 0;
  2929.                     OLDPRINTRECORD = PRINTRECORD;
  2930.                     PRINTRECORD = 1;
  2931.                     OLDCOUNT = COUNT;
  2932.                     COUNT = 0;
  2933.                     gprev_num_of_matched = gnum_of_matched;
  2934.                     if ((tmpfp = fopen(tempfile, "w")) == NULL) {
  2935.                         fprintf(stderr, "%s: cannot open for writing: %s, errno=%d\n", GProgname, tempfile, errno);
  2936.                         RETURN(usage());
  2937.                     }
  2938.  
  2939.                     SetCurrentFileName = 1;
  2940.                     if (GPRINTFILENUMBER) sprintf(CurrentFileName, "%d", GFileIndex[i]);
  2941.                     else strcpy(CurrentFileName, GTextfiles[i]);
  2942.                     if (apply_filter(GTextfiles[i], outname[0]) == 1) {
  2943.                         if (my_stat(GTextfiles[i], &file_stat_buf) == -1) {
  2944.                             if (GPRINTNONEXISTENTFILE) printf("%s\n", CurrentFileName);
  2945.                             fclose(tmpfp);
  2946.                             continue;
  2947.                         }
  2948.                         if (GPRINTFILETIME) {
  2949.                             SetCurrentFileTime = 1;
  2950.                             CurrentFileTime = get_file_time(timesfp, &file_stat_buf, GTextfiles[i], GFileIndex[i]);
  2951.                         }
  2952.                         if (!ByteLevelIndex || RecordLevelIndex || NOBYTELEVEL || (file_stat_buf.st_mtime > index_stat_buf.st_mtime)) {
  2953.                             first_search = 1;
  2954.                             ret = fileagrep_search(AM, APattern, 1, outname, 0, tmpfp);
  2955.                         }
  2956.                         else {
  2957.                             if (file_stat_buf.st_mtime > index_stat_buf.st_mtime) {
  2958.                                 /* fprintf(stderr, "Warning: file modified after indexing: must SEARCH %s\n", CurrentFileName); */
  2959.                                 free_list(&src_offset_table[GFileIndex[i]]);
  2960.                                 first_search = 1;
  2961.                                 ret = fileagrep_search(AM, APattern, 1, outname, 0, tmpfp);
  2962.                             }
  2963.                             else ret = glimpse_search(AM, APattern, GD_length, GD_pattern, GTextfiles[i], outname[0], GFileIndex[i], src_offset_table, tmpfp);
  2964.                         }
  2965.                         unlink(outname[0]);
  2966.                     }
  2967.                     else {
  2968.                         if (!ByteLevelIndex || RecordLevelIndex || NOBYTELEVEL) {
  2969.                             if (GPRINTFILETIME) {
  2970.                                 SetCurrentFileTime = 1;
  2971.                                 CurrentFileTime = get_file_time(timesfp, NULL, GTextfiles[i], GFileIndex[i]);
  2972.                             }
  2973.                             first_search = 1;
  2974.                             ret = fileagrep_search(AM, APattern, 1, >extfiles[i], 0, tmpfp);
  2975.                         }
  2976.                         else {
  2977.                             if (my_stat(GTextfiles[i], &file_stat_buf) == -1) {
  2978.                                 if (GPRINTNONEXISTENTFILE) printf("%s\n", CurrentFileName);
  2979.                                 fclose(tmpfp);
  2980.                                 continue;
  2981.                             }
  2982.                             if (GPRINTFILETIME) {
  2983.                                 SetCurrentFileTime = 1;
  2984.                                 CurrentFileTime = get_file_time(timesfp, &file_stat_buf, GTextfiles[i], GFileIndex[i]);
  2985.                             }
  2986.                             if (file_stat_buf.st_mtime > index_stat_buf.st_mtime) {
  2987.                                 /* fprintf(stderr, "Warning: file modified after indexing: must SEARCH %s\n", CurrentFileName); */
  2988.                                 free_list(&src_offset_table[GFileIndex[i]]);
  2989.                                 first_search = 1;
  2990.                                 ret = fileagrep_search(AM, APattern, 1, >extfiles[i], 0, tmpfp);
  2991.                             }
  2992.                             else ret = glimpse_search(AM, APattern, GD_length, GD_pattern, GTextfiles[i], GTextfiles[i], GFileIndex[i], src_offset_table, tmpfp);
  2993.                         }
  2994.                     }
  2995.                     SetCurrentFileName = 0;
  2996.                     if (GPRINTFILETIME) SetCurrentFileTime = 0;
  2997.                     fflush(tmpfp);
  2998.                     fclose(tmpfp);
  2999.                     tmpfp = NULL;
  3000.                     if ((ret < 0) && (errno == AGREP_ERROR)) break;
  3001. #if    DEBUG
  3002.                     printf("done search\n");
  3003.                     fflush(stdout);
  3004. #endif    /*DEBUG*/
  3005.                     FILENAMEONLY = OLDFILENAMEONLY;
  3006.                     LIMITOUTPUT = OLDLIMITOUTPUT;
  3007.                     LIMITPERFILE = OLDLIMITPERFILE;
  3008.                     LIMITTOTALFILE = OLDLIMITTOTALFILE;
  3009.                     PRINTRECORD = OLDPRINTRECORD;
  3010.                     COUNT = OLDCOUNT;
  3011.                     ret = filter_output(GTextfiles[i], tempfile, GParse, GD_pattern, GD_length, GOUTTAIL, nullfp, StructuredIndex);
  3012.                     gnum_of_matched += (ret > 0) ? ret : 0;
  3013.                     gfiles_matched += (ret > 0) ? 1 : 0;
  3014.                     if (GLIMITOUTPUT > 0) {
  3015.                         if (GLIMITOUTPUT <= gnum_of_matched) break;
  3016.                         LIMITOUTPUT = GLIMITOUTPUT - gnum_of_matched;
  3017.                     }
  3018.                     if (GLIMITTOTALFILE > 0) {
  3019.                         if (GLIMITTOTALFILE <= gfiles_matched) break;
  3020.                         LIMITTOTALFILE = GLIMITTOTALFILE - gfiles_matched;
  3021.                     }
  3022.                     if (glimpse_clientdied) break;
  3023.                     fflush(stdout);
  3024.                 }
  3025.             }
  3026.         }
  3027.         if (errno == AGREP_ERROR) {
  3028.             fprintf(stderr, "%s: error in options or arguments to `agrep'\n", HARVEST_PREFIX);
  3029.         }
  3030.  
  3031.         RETURN(0);
  3032.     }
  3033.     else { /* argc > 0: simply call agrep */
  3034. #if    DEBUG
  3035.         for (i=0; i<agrep_argc; i++)
  3036.             printf("agrep_argv[%d] = %s\n", i, agrep_argv[i]);
  3037. #endif    /*DEBUG*/
  3038.         i = fileagrep(oldargc, oldargv, 0, stdout);
  3039.         RETURN(i);
  3040.     }
  3041. }
  3042. /* end of process_query() */
  3043.  
  3044. /*
  3045.  * Simple function to remove the non-existent files from the set of
  3046.  * files passed onto agrep for search. These are the files which got
  3047.  * DELETED after the index was built (but a fresh index was NOT built).
  3048.  * Redundant since agrep opens them anyway and stat is as bad as open.
  3049.  */
  3050. int
  3051. purge_filenames(filenames, num)
  3052.     CHAR    **filenames;
  3053.     int    num;
  3054. {
  3055.     struct stat    buf;
  3056.     int        i, j;
  3057.     int        newnum = num;
  3058.     int        ret;
  3059.  
  3060.     for (i=0; i<newnum; i++) {
  3061.         if (-1 == (ret = my_stat(filenames[i], &buf))) {
  3062. #if    BG_DEBUG
  3063.             fprintf(debug, "stat on %s = %d\n", filenames[i], ret);
  3064. #endif    /*BG_DEBUG*/
  3065.             my_free(filenames[i], 0);
  3066.             for (j=i; j<newnum-1; j++)
  3067.                 filenames[j] = filenames[j+1];
  3068.             filenames[j] = NULL;
  3069.             newnum --;
  3070.             i--;    /* to counter the ++ on top */
  3071.         }
  3072.     }
  3073.  
  3074. #if    BG_DEBUG
  3075.     fprintf(debug, "Old numfiles=%d\tNew numfiles=%d\n", num, newnum);
  3076.     for (i=0; i<newnum; i++)
  3077.         fprintf(debug, "file %d = %s\n", i, filenames[i]);
  3078. #endif    /*BG_DEBUG*/
  3079.     return newnum;
  3080. }
  3081.  
  3082. CHAR filter_buf[BLOCKSIZE + MAXPAT*2];
  3083.  
  3084. /* returns #of bytes stripped off */
  3085. int getbyteoff(buf, pbyteoff)
  3086.     CHAR    *buf;
  3087.     int    *pbyteoff;
  3088. {
  3089.     CHAR    temp[32];
  3090.     int    i = 0;
  3091.  
  3092.     while (isdigit(*buf) && (i<32)) temp[i++] = *buf++;
  3093.     if ((*buf != '=') || (*(buf + 1) != ' ')) return -1;
  3094.     temp[i] = '\0';
  3095.     *pbyteoff = atoi(temp);
  3096.     return i+2;
  3097. }
  3098.  
  3099. /*
  3100.  * Filter the output in infile:
  3101.  *
  3102.  * -- get the matched line/record-s using GD_pattern, GD_length and GOUTAIL
  3103.  * -- call identify regions using matched line/record's byte offset
  3104.  * -- collect patterns corr. to that attribute into a new pattern (in split_pat itself)
  3105.  * -- see if one of them matches that line/record using memagrep
  3106.  * -- if so, output that line/record onto stdout
  3107.  */
  3108.  /* May have to change name to reflect the fact that it does booleans too */
  3109. int
  3110. filter_output(infile, outfile, GParse, GD_pattern, GD_length, GOUTTAIL, nullfp, num_attr)
  3111.     char    *infile;
  3112.     char    *outfile;
  3113.     ParseTree *GParse;
  3114.     CHAR    GD_pattern[];
  3115.     int    GD_length[];
  3116.     int    GOUTTAIL;
  3117.     FILE    *nullfp;
  3118.     int    num_attr;
  3119. {
  3120.     FILE    *outfp;
  3121.     FILE    *displayfp = NULL;
  3122.     FILE    *storefp = NULL;
  3123.     int    num_read, total_read = 0;
  3124.     int    residue = 0;
  3125.     int    byteoff;
  3126.     int    attribute;
  3127.     int    i, ii;    /* i is forloop index, ii is booleaneval index */
  3128.     CHAR    *final_end;
  3129.     CHAR    *current_end;
  3130.     CHAR    *current_begin;
  3131.     CHAR    *previous_begin;
  3132.     int    skiplen;
  3133.     char    s[MAX_LINE_LEN];
  3134.     CHAR    c1, c2;
  3135.     int    printed, numprinted = 0;    /* returns number of printed records if successful in matching the pattern in the object infile */
  3136.     char    *attrname;
  3137.     int    success = 0;    /* do we print the stored output or not */
  3138.     int    count = 0;
  3139.     int    OLDLIMITOUTPUT = 0, OLDLIMITPERFILE = 0, OLDLIMITTOTALFILE = 0;
  3140.  
  3141. #if    BG_DEBUG
  3142.     printf("INFILE=%s\n", infile);
  3143.     printf("OUTFILE\n");
  3144.     sprintf(s, "exec cat %s\n", outfile);
  3145.     system(s);
  3146.     printf("OUTFILEDONE\n");
  3147. #endif    /*BG_DEBUG*/
  3148.     if ((outfp = fopen(outfile, "r")) == NULL) return 0;
  3149.     if (StructuredIndex && (-1 == region_create(infile))) {
  3150.         fclose(outfp);
  3151.         return 0;
  3152.     }
  3153.     if (ComplexBoolean || ((long)GParse & AND_EXP)) {
  3154.         sprintf(s, "%s/.glimpse_storeoutput.%d", TEMP_DIR, getpid());
  3155.         if ((displayfp = storefp = fopen(s, "w")) == NULL) {
  3156.             if (StructuredIndex) region_destroy();
  3157.             fclose(outfp);
  3158.             return 0;
  3159.         }
  3160.     }
  3161.     else {
  3162.         displayfp = stdout;
  3163.         /* cannot come to filter_output in this case unless -a! */
  3164.     }
  3165.     memset(matched_terminals, '\0', num_terminals);
  3166.  
  3167.     while ( ( (num_read = fread(filter_buf + residue, 1, BLOCKSIZE - residue, outfp)) > 0) || (residue > 0)) {
  3168.         total_read += num_read;
  3169.         if (num_read <= 0) {
  3170.             final_end = filter_buf + residue;
  3171.             num_read = residue;
  3172.             residue = 0;
  3173.         }
  3174.         else {
  3175.             num_read += residue;
  3176.             final_end = (CHAR *)backward_delimiter(filter_buf + num_read, filter_buf, GD_pattern, GD_length, GOUTTAIL);
  3177.             residue = filter_buf + num_read - final_end;
  3178.         }
  3179. #if    DEBUG
  3180.         fprintf(stderr, "filter_buf=%x final_end=%x residue=%x last_chars=%c%c%c num_read=%x\n",
  3181.             filter_buf, final_end, residue, *(final_end-2), *(final_end-1), *(final_end), num_read);
  3182. #endif    /*DEBUG*/
  3183.  
  3184.         current_begin = previous_begin = filter_buf;
  3185. #if    1
  3186.         current_end = (CHAR *)forward_delimiter(filter_buf, filter_buf + num_read, GD_pattern, GD_length, GOUTTAIL);    /* skip over prefixes like filename */
  3187.         if (!GOUTTAIL) current_end = (CHAR *)forward_delimiter((long)current_end + GD_length, final_end, GD_pattern, GD_length, GOUTTAIL);
  3188. #else    /*1*/
  3189.         current_end = (CHAR *)forward_delimiter(filter_buf+1, final_end, GD_pattern, GD_length, GOUTTAIL);
  3190.  
  3191. #endif    /*1*/
  3192.  
  3193. #if    DEBUG
  3194.         fprintf(stderr, "current_begin=%x current_end=%x\n", current_begin, current_end);
  3195. #endif    /*DEBUG*/
  3196.  
  3197.         while (current_end <= final_end) {
  3198.             previous_begin = current_begin;
  3199.             /* look for %d= */
  3200.             byteoff = -1;
  3201.             while (current_begin < current_end) {
  3202.                 if (isdigit(*current_begin)) {
  3203.                     skiplen = getbyteoff(current_begin, &byteoff);
  3204. #if    BG_DEBUG
  3205.                     fprintf(debug, "byteoff=%d skiplen=%d\n", byteoff, skiplen);
  3206. #endif    /*BG_DEBUG*/
  3207.                     if ((skiplen < 0) || (byteoff < 0)) {
  3208.                         current_begin ++;
  3209.                         continue;
  3210.                     }
  3211.                     else break;
  3212.                 }
  3213.                 else current_begin ++;
  3214.             }
  3215. #if    DEBUG
  3216.             printf("current_begin=%x current_end=%x final_end=%x residue=%x num_read=%x\n", current_begin, current_end, final_end, residue, num_read);
  3217. #endif    /*DEBUG*/
  3218.  
  3219. #if    DEBUG
  3220.             printf("byteoff=%d skiplen=%d\n", byteoff, skiplen);
  3221. #endif    /*DEBUG*/
  3222.             if ((skiplen < 0) || (byteoff < 0)) {    /* output the whole line as it is: there is nothing to strip (e.g., -l) */
  3223. #if    0
  3224.                 /* This is an error: -l is now handled completely inside filter_output --> agrep won't processes it when -W */
  3225.                 if (!SILENT) fwrite(previous_begin, 1, current_end-previous_begin, displayfp);
  3226.                 numprinted ++;
  3227. #endif
  3228.             }
  3229.             else if ( (num_attr <= 0) || (((attribute = region_identify(byteoff, 0)) < num_attr) && (attribute >= 0)) ) {
  3230.                 /* prefix is from previous_begin to current_begin. Skip skiplen from current_begin. Rest until current_end is valid output */
  3231.                 if (num_attr <= 0) attribute = 0;
  3232. #if    BG_DEBUG
  3233.                 fprintf(debug, "region@%d=%d\n", byteoff, attribute);
  3234. #endif    /*BG_DEBUG*/
  3235.                 c1 = *(current_begin + skiplen - 1);
  3236.                 c2 = *(current_end + 1);
  3237.                 printed = 0;
  3238.  
  3239.                 for (i=0; i<num_terminals; i++) {
  3240. #if    0
  3241.                     printf("--> already_matched[%d] = %d, going to look at '%s'\n", i, matched_terminals[i], terminals[i].data.leaf.value);
  3242. #endif
  3243.                     if (matched_terminals[i] && (GFILENAMEONLY || FILEOUT || printed || ((LIMITOUTPUT > 0) && (numprinted >= LIMITOUTPUT)) || ((LIMITPERFILE > 0) && (numprinted >= LIMITPERFILE)))) continue;
  3244.                     if ((terminals[i].data.leaf.attribute == 0)  || ((int)(terminals[i].data.leaf.attribute) == attribute)) {
  3245.                         *(current_begin + skiplen - 1) = '\n';
  3246.                         *(current_end + 1) = '\n';
  3247.                         OLDLIMITOUTPUT = LIMITOUTPUT;
  3248.                         LIMITOUTPUT = 0;
  3249.                         OLDLIMITPERFILE = LIMITPERFILE;
  3250.                         LIMITPERFILE = 0;
  3251.                         OLDLIMITTOTALFILE = LIMITTOTALFILE;
  3252.                         LIMITTOTALFILE = 0;
  3253.                         if (memagrep_search(    strlen(terminals[i].data.leaf.value), terminals[i].data.leaf.value,
  3254.                                     current_end - current_begin - skiplen + 1, current_begin + skiplen - 1,
  3255.                                     0, nullfp) > 0) {
  3256.                             LIMITOUTPUT = OLDLIMITOUTPUT;
  3257.                             LIMITPERFILE = OLDLIMITPERFILE;
  3258.                             LIMITTOTALFILE = OLDLIMITTOTALFILE;
  3259.  
  3260. #if    0
  3261.                             *(current_end + 1) = '\0';
  3262.                             printf("--> search succeeded for %s in %s\n", terminals[i].data.leaf.value, previous_begin);
  3263. #endif    /*0*/
  3264.                             *(current_begin + skiplen - 1) = c1;
  3265.                             *(current_end + 1) = c2;
  3266.                             matched_terminals[i] = 1;    /* must reevaluate/set since don't know if it should be printed */
  3267.  
  3268.                             if (!(((LIMITOUTPUT > 0) && (numprinted >= LIMITOUTPUT)) ||
  3269.                                   ((LIMITPERFILE > 0) && (numprinted >= LIMITPERFILE))) && !printed) {    /* see if it was useful later */
  3270.                                 if (!COUNT && !FILEOUT && !SILENT) {
  3271.                                 fwrite(previous_begin, 1, current_begin - previous_begin, displayfp);
  3272.                                 if (PRINTATTR) fprintf(displayfp, "%s# ",
  3273.                                     (attrname = attr_id_to_name(attribute)) == NULL ? "(null)" : attrname);
  3274.                                 if (GBYTECOUNT) fprintf(displayfp, "%d= ", byteoff);
  3275.                                 if (PRINTRECORD) {
  3276.                                 fwrite(current_begin + skiplen, 1, current_end - current_begin - skiplen, displayfp);
  3277.                                 }
  3278.                                 else {
  3279.                                     if (*(current_begin + skiplen) == '@') {
  3280.                                         int    iii = 0;
  3281.                                         while (current_begin[skiplen + iii] != '}')
  3282.                                             fputc(current_begin[skiplen + iii++], displayfp);
  3283.                                         fputc('}', displayfp);
  3284.                                     }
  3285.                                     fputc('\n', displayfp);
  3286.                                 }
  3287.                                 }
  3288.                                 printed = 1;
  3289.                                 numprinted ++;
  3290.                             }
  3291.                         }
  3292.                         else {
  3293.                             LIMITOUTPUT = OLDLIMITOUTPUT;
  3294.                             LIMITPERFILE = OLDLIMITPERFILE;
  3295.                             LIMITTOTALFILE = OLDLIMITTOTALFILE;
  3296. #if    0
  3297.                             *(current_end + 1) = '\0';
  3298.                             printf("--> search failed for %s in %s\n", terminals[i].data.leaf.value, previous_begin);
  3299. #endif    /*0*/
  3300.                             *(current_begin + skiplen - 1) = c1;
  3301.                             *(current_end + 1) = c2;
  3302.                         }
  3303.                     }
  3304.                 }
  3305.  
  3306.                 if (!success) {
  3307.                     if (ComplexBoolean) {
  3308.                         success = eval_tree(GParse, matched_terminals);
  3309.                     }
  3310.                     else {
  3311.                         if ((long)GParse & AND_EXP) {
  3312.                             success = 0;
  3313.                             for (ii=0; ii<num_terminals; ii++) {
  3314.                                 if (!matched_terminals[ii]) break;
  3315.                             }
  3316.                             if (ii >= num_terminals) success = 1;
  3317.                         }
  3318.                         else {
  3319.                             success = 0;
  3320.                             /* cannot come to filter_output in this case unless -a! */
  3321.                         }
  3322.                     }
  3323.                 }
  3324.  
  3325.                 /* optimize options that do not need all the matched lines */
  3326.                 if (success) {
  3327.                     if (GFILENAMEONLY) {
  3328.                         if (GPRINTFILETIME) {    /* from bug fix message by  Dr Jaime Prilusky lsprilus@weizmann.weizmann.ac.il jaimep@terminator.pdb.bnl.gov */
  3329.                             if (!SILENT) fprintf(stdout, "%s%s\n", CurrentFileName, aprint_file_time(CurrentFileTime));
  3330.                         }
  3331.                         else {
  3332.                             if (!SILENT) fprintf(stdout, "%s\n", CurrentFileName);
  3333.                         }
  3334.                         if (storefp != NULL) fclose(storefp); /* don't bother to flush! */
  3335.                         storefp = NULL;
  3336.                         goto unlink_and_quit;
  3337.                     }
  3338.                     else if (FILEOUT) {
  3339.                         /* file_out(infile); */
  3340.                         if (storefp != NULL) fclose(storefp); /* don't bother to flush! */
  3341.                         storefp = NULL;
  3342.                         goto unlink_and_quit;
  3343.                     }
  3344.                 }
  3345.             }
  3346.             if (success && (((LIMITOUTPUT > 0) && (numprinted >= LIMITOUTPUT)) || ((LIMITPERFILE > 0) && (numprinted >= LIMITPERFILE)))) goto double_break;
  3347.             if (glimpse_clientdied) goto double_break;
  3348.             if (current_end >= final_end) break;
  3349.             current_begin = current_end;
  3350.             if (!GOUTTAIL) current_end = (CHAR *)forward_delimiter((long)current_end + GD_length, final_end, GD_pattern, GD_length, GOUTTAIL);
  3351.             else current_end = (CHAR *)forward_delimiter(current_end, final_end, GD_pattern, GD_length, GOUTTAIL);
  3352. #if    DEBUG
  3353.         fprintf(stderr, "current_begin=%x current_end=%x\n", current_begin, current_end);
  3354. #endif    /*DEBUG*/
  3355.         }
  3356.         if (residue > 0) {
  3357.             memcpy(filter_buf, final_end, residue);
  3358.             memcpy(filter_buf+residue, GD_pattern, GD_length);
  3359.         }
  3360.     }
  3361.  
  3362. double_break:
  3363.     /* Come here on normal exit or when the current agrep-output is no longer of any use */
  3364.     if (!success && (total_read > 0)) {
  3365.         if (ComplexBoolean) {
  3366.             success = eval_tree(GParse, matched_terminals);
  3367.         }
  3368.         else {
  3369.             if ((long)GParse & AND_EXP) {
  3370.                 success = 0;
  3371.                 for (ii=0; ii<num_terminals; ii++) {
  3372.                     if (!matched_terminals[ii]) break;
  3373.                 }
  3374.                 if (ii >= num_terminals) success = 1;
  3375.             }
  3376.             else {
  3377.                 success = 0;
  3378.                 /* cannot come to filter_output in this case unless -a! */
  3379.             }
  3380.         }
  3381.     }
  3382.  
  3383.     /* Print the temporary output onto stdout if search was successful; unlink the temprorary file */
  3384.     if (success) {
  3385.         if (GFILENAMEONLY) {    /* all other output options are useless since they all deal with the MATCHED line */
  3386.             if (GPRINTFILETIME) {    /* from bug fix message by  Dr Jaime Prilusky lsprilus@weizmann.weizmann.ac.il jaimep@terminator.pdb.bnl.gov */
  3387.                 if (!SILENT) fprintf(stdout, "%s%s\n", CurrentFileName, aprint_file_time(CurrentFileTime));
  3388.             }
  3389.             else {
  3390.                 if (!SILENT) fprintf(stdout, "%s\n", CurrentFileName);
  3391.             }
  3392.             if (!SILENT) fprintf(stdout, "%s\n", CurrentFileName);
  3393.             if (storefp != NULL) fclose(storefp); /* don't bother to flush! */
  3394.             storefp = NULL;
  3395.         }
  3396.         else if (COUNT && !FILEOUT) {
  3397.             if (!SILENT) {
  3398.                 if(!NOFILENAME) fprintf(stdout, "%s: %d\n", CurrentFileName, numprinted);
  3399.                 else fprintf(stdout, "%d\n", numprinted);
  3400.             }
  3401.             if (storefp != NULL) fclose(storefp); /* don't bother to flush! */
  3402.             storefp = NULL;
  3403.         }
  3404.         else if (FILEOUT) {
  3405.             /* file_out(infile); */
  3406.             if (storefp != NULL) fclose(storefp); /* don't bother to flush! */
  3407.             storefp = NULL;
  3408.         }
  3409.         else if (storefp != NULL) {
  3410.             fflush(storefp);
  3411.             fclose(storefp);
  3412. #if    DEBUG
  3413.             printf("STOREOUTPUT\n");
  3414.             sprintf(s, "exec cat %s/.glimpse_storeoutput.%d\n", TEMP_DIR, getpid());
  3415.             system(s);
  3416. #endif    /*DEBUG*/
  3417.             sprintf(s, "%s/.glimpse_storeoutput.%d", TEMP_DIR, getpid());
  3418.             if ((storefp = fopen(s, "r")) != NULL) {
  3419.                 if (!SILENT) while (fgets(s, MAX_LINE_LEN, storefp) != NULL) fputs(s, stdout);
  3420.                 fclose(storefp);
  3421.             }
  3422.             storefp = NULL;
  3423.         }
  3424.     }
  3425.     else {
  3426.         if (storefp != NULL) fclose(storefp); /* else don't bother to flush */
  3427.     }
  3428.  
  3429. unlink_and_quit:
  3430.     sprintf(s, "%s/.glimpse_storeoutput.%d", TEMP_DIR, getpid());
  3431.     unlink(s);
  3432.  
  3433.     if (StructuredIndex) region_destroy();
  3434.     fclose(outfp);
  3435.  
  3436.     if (GFILENAMEONLY) {
  3437.         if (numprinted > 0) return 1;
  3438.         else return 0;
  3439.     }
  3440.     else if (ComplexBoolean || ((long)GParse & AND_EXP)) {
  3441.         if (success) return numprinted;
  3442.         else return 0;
  3443.     } else {    /* must be -a */
  3444.         return numprinted;
  3445.     }
  3446. }
  3447.  
  3448. usage()
  3449. {
  3450.     fprintf(stderr, "\nThis is glimpse version %s, %s.\n\n", GLIMPSE_VERSION, GLIMPSE_DATE);
  3451.     fprintf(stderr, "usage:  %s [-#abceghijklnprstwxyBCDEGIMNPQSVWZ] [-d DEL] [-f FILE] [-F PAT] [-H DIR] [-J HOST] [-K PORT] [-L X[:Y:Z]] [-R X] [-T DIR] [-Y D] pattern [files]", GProgname);
  3452.     fprintf(stderr, "\n");
  3453.     fprintf(stderr, "List of options (see %s for more details):\n", GLIMPSE_URL);
  3454.     fprintf(stderr, "\n");
  3455.  
  3456.     fprintf(stderr, "-#: find matches with at most # errors\n");
  3457.     fprintf(stderr, "-a: print attribute names (useful only for Harvest SOIF format)\n");
  3458.     fprintf(stderr, "-b: print the byte offset of the record from the beginning of the file\n");
  3459.     fprintf(stderr, "-B: best match mode: find the closest matches to the pattern\n");
  3460.     fprintf(stderr, "-c: output the number of matched records\n");
  3461.     fprintf(stderr, "-C: send queries to glimpseserver\n");
  3462.     fprintf(stderr, "-d DEL: define record delimiter DEL\n");
  3463.     fprintf(stderr, "-D x: adjust the cost of deletions to x\n");
  3464.     fprintf(stderr, "-e: for patterns starting with -\n");
  3465.     fprintf(stderr, "-E: print matching lines as they appear in the index (useful in -EQNg)\n");
  3466.     fprintf(stderr, "-f FILE: restrict the search to files whose names appear in FILE\n");
  3467.     fprintf(stderr, "-F PAT: restrict the search to files matching PAT\n");
  3468.     fprintf(stderr, "-g: print the file number (in the index)\n");
  3469.     fprintf(stderr, "-G: output the (whole) files that contain a match\n");
  3470.     fprintf(stderr, "-h: do not output file names before matched record\n");
  3471.     fprintf(stderr, "-H DIR: the glimpse index is located in directory DIR\n");
  3472.     fprintf(stderr, "-i: case-insensitive search, e.g., 'a' = 'A'\n");
  3473.     fprintf(stderr, "-I x: adjust the cost of insertions to x\n");
  3474.     fprintf(stderr, "-j: output file modification dates (if -t was used for the indexing)\n");
  3475.     fprintf(stderr, "-J HOST: send queries to glimpseserver at HOST\n");
  3476.     fprintf(stderr, "-k: use the pattern as is (no meta characters)\n");
  3477.     fprintf(stderr, "-K PORT: send queries to glimpseserver at TCP port number PORT\n");
  3478.     fprintf(stderr, "-l: output only the names of files that contain a match\n");
  3479.     fprintf(stderr, "-L X[:Y:Z]: limit the output to X records [Y files, Z matches per file]\n");
  3480.     fprintf(stderr, "-n: output record prefixed by record number\n");
  3481.     fprintf(stderr, "-N: search only the index (may not be precise for some queries) \n");
  3482.     fprintf(stderr, "-o: delimiter is output at the beginning of the matched record\n");
  3483.     fprintf(stderr, "-O: file names are printed only once per file\n");
  3484.     fprintf(stderr, "-p FILE:off:len:endian: restrict the search to the files whose names\n\tare specified as a bit-field OR sparse-set in FILE\n");
  3485.     fprintf(stderr, "-P: print the pattern that matched before the matched record\n");
  3486.     fprintf(stderr, "-q: print the offsets of the beginning and end of each matched record\n");
  3487.     fprintf(stderr, "-Q: (with -N) print offsets of matches from (only the large) index\n");
  3488.     fprintf(stderr, "-r: (used only for agrep) - recursive search\n");
  3489.     fprintf(stderr, "-R X: set the maximum size of a record to X\n");
  3490.     fprintf(stderr, "-s: display nothing except error messages\n");
  3491.     fprintf(stderr, "-S x: adjust the cost of substitutions to x\n");
  3492.     fprintf(stderr, "-t DEL: like -d, except that the delimiter DEL appears at the end \n");
  3493.     fprintf(stderr, "-T DIR: temporary files are put in directory DIR (instead of /tmp)\n");
  3494.     fprintf(stderr, "-u: do not output matched records (useful in -qbug)\n");
  3495.     fprintf(stderr, "-U: interpret .glimpse_filenames when -U / -X option is used in glimpseindex\n");
  3496.     fprintf(stderr, "-v: (works ONLY for agrep) - output all records that do not contain a match\n");
  3497.     fprintf(stderr, "-V: print the current version of glimpse\n");
  3498.     fprintf(stderr, "-w: pattern has to match as a word, e.g., 'win' will not match 'wind'\n");
  3499.     fprintf(stderr, "-W: the scope of Booleans is the whole file (except for structured queries)\n");
  3500.     fprintf(stderr, "-x: the pattern must match the whole line\n");
  3501.     fprintf(stderr, "-X: if an indexed file that matches 'pattern' doesn't exist, print its name\n");
  3502.     fprintf(stderr, "-y: no prompt\n");
  3503.     fprintf(stderr, "-Y D: output only matches in files that were updated in the last D days\n");
  3504.     fprintf(stderr, "-z: customizable filtering using the .glimpse_filters file\n");
  3505.     fprintf(stderr, "-Z: no op\n");
  3506.     fprintf(stderr, "\n");
  3507.  
  3508.     fprintf(stderr, "For questions about glimpse, please contact: `%s'\n", GLIMPSE_EMAIL);
  3509.  
  3510.     return -1;    /* useful if we make glimpse into a library */
  3511.  
  3512. /*
  3513.  * Undocumented Option Combinations for SFS (like RPC calls)
  3514.  *    print file number of match instead of file name: -g
  3515.  *    print enclosing offsets of matched record: -q
  3516.  *    NOT print matched record: -u
  3517.  * E.G. USAGE: -qbug (b prints offset of pattern: can also use -lg or -Ng)
  3518.  *    look only at index: -E
  3519.  *    look at matched offsets in files as seen in index (w/o searching): -QN
  3520.  * E.G. USAGE: -EQNgy
  3521.  *    read the -EQNg or just -QNg output from stdin and perform actual search w/o
  3522.  *    searching the index (take hints from user): -U
  3523.  * NOTE: can't use U unless QNg are all used together (e.g., BEGIN/END won't be printed)
  3524.  */
  3525. }
  3526.  
  3527. usageS()
  3528. {
  3529.     fprintf(stderr, "\nThis is glimpse server version %s, %s.\n\n", GLIMPSE_VERSION, GLIMPSE_DATE);
  3530.     fprintf(stderr, "usage:  %s [-H DIR] [-J HOST] [-K PORT]", GProgname);
  3531.     fprintf(stderr, "\n");
  3532.     fprintf(stderr, "-H DIR: the glimpse index is located in directory DIR\n");
  3533.     fprintf(stderr, "-J HOST: the host name (string) clients must use / server runs on\n");
  3534.     fprintf(stderr, "-K PORT: the port (short integer) clients must use / server runs on\n");
  3535.     fprintf(stderr, "\n");
  3536.     fprintf(stderr, "For questions about glimpse, please contact `%s'\n", GLIMPSE_EMAIL);
  3537.  
  3538.     return -1;    /* useful if we make glimpse into a library */
  3539. }
  3540.  
  3541. #if    CLIENTSERVER
  3542. /*
  3543.  *  do_select() - based on select_loop() from the Harvest Broker.
  3544.  *  -- Courtesy: Darren Hardy, hardy@cs.colorado.edu
  3545.  */
  3546. int do_select(sock, sec)
  3547. int sock;        /* the socket to wait for */
  3548. int sec;        /* the number of seconds to wait */
  3549. {
  3550.     struct timeval to;
  3551.     fd_set qready;
  3552.     int err;
  3553.  
  3554.     if (sock < 0 || sec < 0)
  3555.         return 0;
  3556.  
  3557.     FD_ZERO(&qready);
  3558.     FD_SET(sock, &qready);
  3559.     to.tv_sec = sec;
  3560.     to.tv_usec = 0;
  3561.     if ((err = select(sock + 1, &qready, NULL, NULL, &to)) < 0) {
  3562.         if (errno == EINTR)
  3563.             return 0;
  3564.         perror("select");
  3565.         return -1;
  3566.     }
  3567.     if (err == 0)
  3568.         return 0;
  3569.  
  3570.     /* If there's someone waiting to get it, let them through */
  3571.     return (FD_ISSET(sock, &qready) ? 1 : 0);
  3572. }
  3573. #endif    /* CLIENTSERVER */
  3574.