xref: /netbsd-src/external/gpl2/groff/dist/src/libs/libbib/linear.cpp (revision 89a07cf815a29524268025a1139fac4c5190f765)
1*89a07cf8Schristos /*	$NetBSD: linear.cpp,v 1.1.1.1 2016/01/13 18:41:48 christos Exp $	*/
2*89a07cf8Schristos 
3*89a07cf8Schristos // -*- C++ -*-
4*89a07cf8Schristos /* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001
5*89a07cf8Schristos    Free Software Foundation, Inc.
6*89a07cf8Schristos      Written by James Clark (jjc@jclark.com)
7*89a07cf8Schristos 
8*89a07cf8Schristos This file is part of groff.
9*89a07cf8Schristos 
10*89a07cf8Schristos groff is free software; you can redistribute it and/or modify it under
11*89a07cf8Schristos the terms of the GNU General Public License as published by the Free
12*89a07cf8Schristos Software Foundation; either version 2, or (at your option) any later
13*89a07cf8Schristos version.
14*89a07cf8Schristos 
15*89a07cf8Schristos groff is distributed in the hope that it will be useful, but WITHOUT ANY
16*89a07cf8Schristos WARRANTY; without even the implied warranty of MERCHANTABILITY or
17*89a07cf8Schristos FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
18*89a07cf8Schristos for more details.
19*89a07cf8Schristos 
20*89a07cf8Schristos You should have received a copy of the GNU General Public License along
21*89a07cf8Schristos with groff; see the file COPYING.  If not, write to the Free Software
22*89a07cf8Schristos Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
23*89a07cf8Schristos 
24*89a07cf8Schristos #include "lib.h"
25*89a07cf8Schristos 
26*89a07cf8Schristos #include <stdlib.h>
27*89a07cf8Schristos #include <assert.h>
28*89a07cf8Schristos #include <errno.h>
29*89a07cf8Schristos 
30*89a07cf8Schristos #include "posix.h"
31*89a07cf8Schristos #include "errarg.h"
32*89a07cf8Schristos #include "error.h"
33*89a07cf8Schristos #include "cset.h"
34*89a07cf8Schristos #include "cmap.h"
35*89a07cf8Schristos #include "nonposix.h"
36*89a07cf8Schristos 
37*89a07cf8Schristos #include "refid.h"
38*89a07cf8Schristos #include "search.h"
39*89a07cf8Schristos 
40*89a07cf8Schristos class file_buffer {
41*89a07cf8Schristos   char *buffer;
42*89a07cf8Schristos   char *bufend;
43*89a07cf8Schristos public:
44*89a07cf8Schristos   file_buffer();
45*89a07cf8Schristos   ~file_buffer();
46*89a07cf8Schristos   int load(int fd, const char *filename);
47*89a07cf8Schristos   const char *get_start() const;
48*89a07cf8Schristos   const char *get_end() const;
49*89a07cf8Schristos };
50*89a07cf8Schristos 
51*89a07cf8Schristos typedef unsigned char uchar;
52*89a07cf8Schristos 
53*89a07cf8Schristos static uchar map[256];
54*89a07cf8Schristos static uchar inv_map[256][3];
55*89a07cf8Schristos 
56*89a07cf8Schristos struct map_init {
57*89a07cf8Schristos   map_init();
58*89a07cf8Schristos };
59*89a07cf8Schristos 
60*89a07cf8Schristos static map_init the_map_init;
61*89a07cf8Schristos 
map_init()62*89a07cf8Schristos map_init::map_init()
63*89a07cf8Schristos {
64*89a07cf8Schristos   int i;
65*89a07cf8Schristos   for (i = 0; i < 256; i++)
66*89a07cf8Schristos     map[i] = csalnum(i) ? cmlower(i) : '\0';
67*89a07cf8Schristos   for (i = 0; i < 256; i++) {
68*89a07cf8Schristos     if (cslower(i)) {
69*89a07cf8Schristos       inv_map[i][0] = i;
70*89a07cf8Schristos       inv_map[i][1] = cmupper(i);
71*89a07cf8Schristos       inv_map[i][2] = '\0';
72*89a07cf8Schristos     }
73*89a07cf8Schristos     else if (csdigit(i)) {
74*89a07cf8Schristos       inv_map[i][0] = i;
75*89a07cf8Schristos       inv_map[i][1] = 0;
76*89a07cf8Schristos     }
77*89a07cf8Schristos     else
78*89a07cf8Schristos       inv_map[i][0] = '\0';
79*89a07cf8Schristos   }
80*89a07cf8Schristos }
81*89a07cf8Schristos 
82*89a07cf8Schristos 
83*89a07cf8Schristos class bmpattern {
84*89a07cf8Schristos   char *pat;
85*89a07cf8Schristos   int len;
86*89a07cf8Schristos   int delta[256];
87*89a07cf8Schristos public:
88*89a07cf8Schristos   bmpattern(const char *pattern, int pattern_length);
89*89a07cf8Schristos   ~bmpattern();
90*89a07cf8Schristos   const char *search(const char *p, const char *end) const;
91*89a07cf8Schristos   int length() const;
92*89a07cf8Schristos };
93*89a07cf8Schristos 
bmpattern(const char * pattern,int pattern_length)94*89a07cf8Schristos bmpattern::bmpattern(const char *pattern, int pattern_length)
95*89a07cf8Schristos : len(pattern_length)
96*89a07cf8Schristos {
97*89a07cf8Schristos   pat = new char[len];
98*89a07cf8Schristos   int i;
99*89a07cf8Schristos   for (i = 0; i < len; i++)
100*89a07cf8Schristos     pat[i] = map[uchar(pattern[i])];
101*89a07cf8Schristos   for (i = 0; i < 256; i++)
102*89a07cf8Schristos     delta[i] = len;
103*89a07cf8Schristos   for (i = 0; i < len; i++)
104*89a07cf8Schristos     for (const unsigned char *inv = inv_map[uchar(pat[i])]; *inv; inv++)
105*89a07cf8Schristos       delta[*inv] = len - i - 1;
106*89a07cf8Schristos }
107*89a07cf8Schristos 
search(const char * buf,const char * end) const108*89a07cf8Schristos const char *bmpattern::search(const char *buf, const char *end) const
109*89a07cf8Schristos {
110*89a07cf8Schristos   int buflen = end - buf;
111*89a07cf8Schristos   if (len > buflen)
112*89a07cf8Schristos     return 0;
113*89a07cf8Schristos   const char *strend;
114*89a07cf8Schristos   if (buflen > len*4)
115*89a07cf8Schristos     strend = end - len*4;
116*89a07cf8Schristos   else
117*89a07cf8Schristos     strend = buf;
118*89a07cf8Schristos   const char *k = buf + len - 1;
119*89a07cf8Schristos   const int *del = delta;
120*89a07cf8Schristos   const char *pattern = pat;
121*89a07cf8Schristos   for (;;) {
122*89a07cf8Schristos     while (k < strend) {
123*89a07cf8Schristos       int t = del[uchar(*k)];
124*89a07cf8Schristos       if (!t)
125*89a07cf8Schristos 	break;
126*89a07cf8Schristos       k += t;
127*89a07cf8Schristos       k += del[uchar(*k)];
128*89a07cf8Schristos       k += del[uchar(*k)];
129*89a07cf8Schristos     }
130*89a07cf8Schristos     while (k < end && del[uchar(*k)] != 0)
131*89a07cf8Schristos       k++;
132*89a07cf8Schristos     if (k == end)
133*89a07cf8Schristos       break;
134*89a07cf8Schristos     int j = len - 1;
135*89a07cf8Schristos     const char *s = k;
136*89a07cf8Schristos     for (;;) {
137*89a07cf8Schristos       if (j == 0)
138*89a07cf8Schristos 	return s;
139*89a07cf8Schristos       if (map[uchar(*--s)] != uchar(pattern[--j]))
140*89a07cf8Schristos 	break;
141*89a07cf8Schristos     }
142*89a07cf8Schristos     k++;
143*89a07cf8Schristos   }
144*89a07cf8Schristos   return 0;
145*89a07cf8Schristos }
146*89a07cf8Schristos 
~bmpattern()147*89a07cf8Schristos bmpattern::~bmpattern()
148*89a07cf8Schristos {
149*89a07cf8Schristos   a_delete pat;
150*89a07cf8Schristos }
151*89a07cf8Schristos 
length() const152*89a07cf8Schristos inline int bmpattern::length() const
153*89a07cf8Schristos {
154*89a07cf8Schristos   return len;
155*89a07cf8Schristos }
156*89a07cf8Schristos 
157*89a07cf8Schristos 
158*89a07cf8Schristos static const char *find_end(const char *bufend, const char *p);
159*89a07cf8Schristos 
search_and_check(const bmpattern * key,const char * buf,const char * bufend,const char ** start) const160*89a07cf8Schristos const char *linear_searcher::search_and_check(const bmpattern *key,
161*89a07cf8Schristos   const char *buf, const char *bufend, const char **start) const
162*89a07cf8Schristos {
163*89a07cf8Schristos   assert(buf[-1] == '\n');
164*89a07cf8Schristos   assert(bufend[-1] == '\n');
165*89a07cf8Schristos   const char *ptr = buf;
166*89a07cf8Schristos   for (;;) {
167*89a07cf8Schristos     const char *found = key->search(ptr, bufend);
168*89a07cf8Schristos     if (!found)
169*89a07cf8Schristos       break;
170*89a07cf8Schristos     if (check_match(buf, bufend, found, key->length(), &ptr, start))
171*89a07cf8Schristos       return found;
172*89a07cf8Schristos   }
173*89a07cf8Schristos   return 0;
174*89a07cf8Schristos }
175*89a07cf8Schristos 
skip_field(const char * end,const char * p)176*89a07cf8Schristos static const char *skip_field(const char *end, const char *p)
177*89a07cf8Schristos {
178*89a07cf8Schristos   for (;;)
179*89a07cf8Schristos     if (*p++ == '\n') {
180*89a07cf8Schristos       if (p == end || *p == '%')
181*89a07cf8Schristos 	break;
182*89a07cf8Schristos       const char *q;
183*89a07cf8Schristos       for (q = p; *q == ' ' || *q == '\t'; q++)
184*89a07cf8Schristos 	;
185*89a07cf8Schristos       if (*q == '\n')
186*89a07cf8Schristos 	break;
187*89a07cf8Schristos       p = q + 1;
188*89a07cf8Schristos     }
189*89a07cf8Schristos   return p;
190*89a07cf8Schristos }
191*89a07cf8Schristos 
find_end(const char * bufend,const char * p)192*89a07cf8Schristos static const char *find_end(const char *bufend, const char *p)
193*89a07cf8Schristos {
194*89a07cf8Schristos   for (;;)
195*89a07cf8Schristos     if (*p++ == '\n') {
196*89a07cf8Schristos       if (p == bufend)
197*89a07cf8Schristos 	break;
198*89a07cf8Schristos       const char *q;
199*89a07cf8Schristos       for (q = p; *q == ' ' || *q == '\t'; q++)
200*89a07cf8Schristos 	;
201*89a07cf8Schristos       if (*q == '\n')
202*89a07cf8Schristos 	break;
203*89a07cf8Schristos       p = q + 1;
204*89a07cf8Schristos     }
205*89a07cf8Schristos   return p;
206*89a07cf8Schristos }
207*89a07cf8Schristos 
208*89a07cf8Schristos 
check_match(const char * buf,const char * bufend,const char * match,int matchlen,const char ** cont,const char ** start) const209*89a07cf8Schristos int linear_searcher::check_match(const char *buf, const char *bufend,
210*89a07cf8Schristos 				 const char *match, int matchlen,
211*89a07cf8Schristos 				 const char **cont, const char **start) const
212*89a07cf8Schristos {
213*89a07cf8Schristos   *cont = match + 1;
214*89a07cf8Schristos   // The user is required to supply only the first truncate_len characters
215*89a07cf8Schristos   // of the key.  If truncate_len <= 0, he must supply all the key.
216*89a07cf8Schristos   if ((truncate_len <= 0 || matchlen < truncate_len)
217*89a07cf8Schristos       && map[uchar(match[matchlen])] != '\0')
218*89a07cf8Schristos     return 0;
219*89a07cf8Schristos 
220*89a07cf8Schristos   // The character before the match must not be an alphanumeric
221*89a07cf8Schristos   // character (unless the alphanumeric character follows one or two
222*89a07cf8Schristos   // percent characters at the beginning of the line), nor must it be
223*89a07cf8Schristos   // a percent character at the beginning of a line, nor a percent
224*89a07cf8Schristos   // character following a percent character at the beginning of a
225*89a07cf8Schristos   // line.
226*89a07cf8Schristos 
227*89a07cf8Schristos   switch (match - buf) {
228*89a07cf8Schristos   case 0:
229*89a07cf8Schristos     break;
230*89a07cf8Schristos   case 1:
231*89a07cf8Schristos     if (match[-1] == '%' || map[uchar(match[-1])] != '\0')
232*89a07cf8Schristos       return 0;
233*89a07cf8Schristos     break;
234*89a07cf8Schristos   case 2:
235*89a07cf8Schristos     if (map[uchar(match[-1])] != '\0' && match[-2] != '%')
236*89a07cf8Schristos       return 0;
237*89a07cf8Schristos     if (match[-1] == '%'
238*89a07cf8Schristos 	&& (match[-2] == '\n' || match[-2] == '%'))
239*89a07cf8Schristos       return 0;
240*89a07cf8Schristos     break;
241*89a07cf8Schristos   default:
242*89a07cf8Schristos     if (map[uchar(match[-1])] != '\0'
243*89a07cf8Schristos 	&& !(match[-2] == '%'
244*89a07cf8Schristos 	     && (match[-3] == '\n'
245*89a07cf8Schristos 		 || (match[-3] == '%' && match[-4] == '\n'))))
246*89a07cf8Schristos       return 0;
247*89a07cf8Schristos     if (match[-1] == '%'
248*89a07cf8Schristos 	&& (match[-2] == '\n'
249*89a07cf8Schristos 	    || (match[-2] == '%' && match[-3] == '\n')))
250*89a07cf8Schristos       return 0;
251*89a07cf8Schristos   }
252*89a07cf8Schristos 
253*89a07cf8Schristos   const char *p = match;
254*89a07cf8Schristos   int had_percent = 0;
255*89a07cf8Schristos   for (;;) {
256*89a07cf8Schristos     if (*p == '\n') {
257*89a07cf8Schristos       if (!had_percent && p[1] == '%') {
258*89a07cf8Schristos 	if (p[2] != '\0' && strchr(ignore_fields, p[2]) != 0) {
259*89a07cf8Schristos 	  *cont = skip_field(bufend, match + matchlen);
260*89a07cf8Schristos 	  return 0;
261*89a07cf8Schristos 	}
262*89a07cf8Schristos 	if (!start)
263*89a07cf8Schristos 	  break;
264*89a07cf8Schristos 	had_percent = 1;
265*89a07cf8Schristos       }
266*89a07cf8Schristos       if (p <= buf) {
267*89a07cf8Schristos 	if (start)
268*89a07cf8Schristos 	  *start = p + 1;
269*89a07cf8Schristos 	return 1;
270*89a07cf8Schristos       }
271*89a07cf8Schristos       const char *q;
272*89a07cf8Schristos       for (q = p - 1; *q == ' ' || *q == '\t'; q--)
273*89a07cf8Schristos 	;
274*89a07cf8Schristos       if (*q == '\n') {
275*89a07cf8Schristos 	if (start)
276*89a07cf8Schristos 	  *start = p + 1;
277*89a07cf8Schristos 	break;
278*89a07cf8Schristos       }
279*89a07cf8Schristos       p = q;
280*89a07cf8Schristos     }
281*89a07cf8Schristos     p--;
282*89a07cf8Schristos   }
283*89a07cf8Schristos   return 1;
284*89a07cf8Schristos }
285*89a07cf8Schristos 
file_buffer()286*89a07cf8Schristos file_buffer::file_buffer()
287*89a07cf8Schristos : buffer(0), bufend(0)
288*89a07cf8Schristos {
289*89a07cf8Schristos }
290*89a07cf8Schristos 
~file_buffer()291*89a07cf8Schristos file_buffer::~file_buffer()
292*89a07cf8Schristos {
293*89a07cf8Schristos   a_delete buffer;
294*89a07cf8Schristos }
295*89a07cf8Schristos 
get_start() const296*89a07cf8Schristos const char *file_buffer::get_start() const
297*89a07cf8Schristos {
298*89a07cf8Schristos   return buffer ? buffer + 4 : 0;
299*89a07cf8Schristos }
300*89a07cf8Schristos 
get_end() const301*89a07cf8Schristos const char *file_buffer::get_end() const
302*89a07cf8Schristos {
303*89a07cf8Schristos   return bufend;
304*89a07cf8Schristos }
305*89a07cf8Schristos 
load(int fd,const char * filename)306*89a07cf8Schristos int file_buffer::load(int fd, const char *filename)
307*89a07cf8Schristos {
308*89a07cf8Schristos   struct stat sb;
309*89a07cf8Schristos   if (fstat(fd, &sb) < 0)
310*89a07cf8Schristos     error("can't fstat `%1': %2", filename, strerror(errno));
311*89a07cf8Schristos   else if (!S_ISREG(sb.st_mode))
312*89a07cf8Schristos     error("`%1' is not a regular file", filename);
313*89a07cf8Schristos   else {
314*89a07cf8Schristos     // We need one character extra at the beginning for an additional newline
315*89a07cf8Schristos     // used as a sentinel.  We get 4 instead so that the read buffer will be
316*89a07cf8Schristos     // word-aligned.  This seems to make the read slightly faster.  We also
317*89a07cf8Schristos     // need one character at the end also for an additional newline used as a
318*89a07cf8Schristos     // sentinel.
319*89a07cf8Schristos     int size = int(sb.st_size);
320*89a07cf8Schristos     buffer = new char[size + 4 + 1];
321*89a07cf8Schristos     int nread = read(fd, buffer + 4, size);
322*89a07cf8Schristos     if (nread < 0)
323*89a07cf8Schristos       error("error reading `%1': %2", filename, strerror(errno));
324*89a07cf8Schristos     else if (nread != size)
325*89a07cf8Schristos       error("size of `%1' decreased", filename);
326*89a07cf8Schristos     else {
327*89a07cf8Schristos       char c;
328*89a07cf8Schristos       nread = read(fd, &c, 1);
329*89a07cf8Schristos       if (nread != 0)
330*89a07cf8Schristos 	error("size of `%1' increased", filename);
331*89a07cf8Schristos       else if (memchr(buffer + 4, '\0', size < 1024 ? size : 1024) != 0)
332*89a07cf8Schristos 	error("database `%1' is a binary file", filename);
333*89a07cf8Schristos       else {
334*89a07cf8Schristos 	close(fd);
335*89a07cf8Schristos 	buffer[3] = '\n';
336*89a07cf8Schristos 	int sidx = 4, didx = 4;
337*89a07cf8Schristos 	for ( ; sidx < size + 4; sidx++, didx++)
338*89a07cf8Schristos 	  {
339*89a07cf8Schristos 	    if (buffer[sidx] == '\r')
340*89a07cf8Schristos 	      {
341*89a07cf8Schristos 		if (buffer[++sidx] != '\n')
342*89a07cf8Schristos 		  buffer[didx++] = '\r';
343*89a07cf8Schristos 		else
344*89a07cf8Schristos 		  size--;
345*89a07cf8Schristos 	      }
346*89a07cf8Schristos 	    if (sidx != didx)
347*89a07cf8Schristos 	      buffer[didx] = buffer[sidx];
348*89a07cf8Schristos 	  }
349*89a07cf8Schristos 	bufend = buffer + 4 + size;
350*89a07cf8Schristos 	if (bufend[-1] != '\n')
351*89a07cf8Schristos 	  *bufend++ = '\n';
352*89a07cf8Schristos 	return 1;
353*89a07cf8Schristos       }
354*89a07cf8Schristos     }
355*89a07cf8Schristos     a_delete buffer;
356*89a07cf8Schristos     buffer = 0;
357*89a07cf8Schristos   }
358*89a07cf8Schristos   close(fd);
359*89a07cf8Schristos   return 0;
360*89a07cf8Schristos }
361*89a07cf8Schristos 
linear_searcher(const char * query,int query_len,const char * ign,int trunc)362*89a07cf8Schristos linear_searcher::linear_searcher(const char *query, int query_len,
363*89a07cf8Schristos 				 const char *ign, int trunc)
364*89a07cf8Schristos : ignore_fields(ign), truncate_len(trunc), keys(0), nkeys(0)
365*89a07cf8Schristos {
366*89a07cf8Schristos   const char *query_end = query + query_len;
367*89a07cf8Schristos   int nk = 0;
368*89a07cf8Schristos   const char *p;
369*89a07cf8Schristos   for (p = query; p < query_end; p++)
370*89a07cf8Schristos     if (map[uchar(*p)] != '\0'
371*89a07cf8Schristos 	&& (p[1] == '\0' || map[uchar(p[1])] == '\0'))
372*89a07cf8Schristos       nk++;
373*89a07cf8Schristos   if (nk == 0)
374*89a07cf8Schristos     return;
375*89a07cf8Schristos   keys = new bmpattern*[nk];
376*89a07cf8Schristos   p = query;
377*89a07cf8Schristos   for (;;) {
378*89a07cf8Schristos     while (p < query_end && map[uchar(*p)] == '\0')
379*89a07cf8Schristos       p++;
380*89a07cf8Schristos     if (p == query_end)
381*89a07cf8Schristos       break;
382*89a07cf8Schristos     const char *start = p;
383*89a07cf8Schristos     while (p < query_end && map[uchar(*p)] != '\0')
384*89a07cf8Schristos       p++;
385*89a07cf8Schristos     keys[nkeys++] = new bmpattern(start, p - start);
386*89a07cf8Schristos   }
387*89a07cf8Schristos   assert(nkeys <= nk);
388*89a07cf8Schristos   if (nkeys == 0) {
389*89a07cf8Schristos     a_delete keys;
390*89a07cf8Schristos     keys = 0;
391*89a07cf8Schristos   }
392*89a07cf8Schristos }
393*89a07cf8Schristos 
~linear_searcher()394*89a07cf8Schristos linear_searcher::~linear_searcher()
395*89a07cf8Schristos {
396*89a07cf8Schristos   for (int i = 0; i < nkeys; i++)
397*89a07cf8Schristos     delete keys[i];
398*89a07cf8Schristos   a_delete keys;
399*89a07cf8Schristos }
400*89a07cf8Schristos 
search(const char * buffer,const char * bufend,const char ** startp,int * lengthp) const401*89a07cf8Schristos int linear_searcher::search(const char *buffer, const char *bufend,
402*89a07cf8Schristos 			    const char **startp, int *lengthp) const
403*89a07cf8Schristos {
404*89a07cf8Schristos   assert(bufend - buffer > 0);
405*89a07cf8Schristos   assert(buffer[-1] == '\n');
406*89a07cf8Schristos   assert(bufend[-1] == '\n');
407*89a07cf8Schristos   if (nkeys == 0)
408*89a07cf8Schristos     return 0;
409*89a07cf8Schristos   for (;;) {
410*89a07cf8Schristos     const char *refstart;
411*89a07cf8Schristos     const char *found = search_and_check(keys[0], buffer, bufend, &refstart);
412*89a07cf8Schristos     if (!found)
413*89a07cf8Schristos       break;
414*89a07cf8Schristos     const char *refend = find_end(bufend, found + keys[0]->length());
415*89a07cf8Schristos     int i;
416*89a07cf8Schristos     for (i = 1; i < nkeys; i++)
417*89a07cf8Schristos       if (!search_and_check(keys[i], refstart, refend))
418*89a07cf8Schristos 	break;
419*89a07cf8Schristos     if (i >= nkeys) {
420*89a07cf8Schristos       *startp = refstart;
421*89a07cf8Schristos       *lengthp = refend - refstart;
422*89a07cf8Schristos       return 1;
423*89a07cf8Schristos     }
424*89a07cf8Schristos     buffer = refend;
425*89a07cf8Schristos   }
426*89a07cf8Schristos   return 0;
427*89a07cf8Schristos }
428*89a07cf8Schristos 
429*89a07cf8Schristos class linear_search_item : public search_item {
430*89a07cf8Schristos   file_buffer fbuf;
431*89a07cf8Schristos public:
432*89a07cf8Schristos   linear_search_item(const char *filename, int fid);
433*89a07cf8Schristos   ~linear_search_item();
434*89a07cf8Schristos   int load(int fd);
435*89a07cf8Schristos   search_item_iterator *make_search_item_iterator(const char *);
436*89a07cf8Schristos   friend class linear_search_item_iterator;
437*89a07cf8Schristos };
438*89a07cf8Schristos 
439*89a07cf8Schristos class linear_search_item_iterator : public search_item_iterator {
440*89a07cf8Schristos   linear_search_item *lsi;
441*89a07cf8Schristos   int pos;
442*89a07cf8Schristos public:
443*89a07cf8Schristos   linear_search_item_iterator(linear_search_item *, const char *query);
444*89a07cf8Schristos   ~linear_search_item_iterator();
445*89a07cf8Schristos   int next(const linear_searcher &, const char **ptr, int *lenp,
446*89a07cf8Schristos 	   reference_id *ridp);
447*89a07cf8Schristos };
448*89a07cf8Schristos 
make_linear_search_item(int fd,const char * filename,int fid)449*89a07cf8Schristos search_item *make_linear_search_item(int fd, const char *filename, int fid)
450*89a07cf8Schristos {
451*89a07cf8Schristos   linear_search_item *item = new linear_search_item(filename, fid);
452*89a07cf8Schristos   if (!item->load(fd)) {
453*89a07cf8Schristos     delete item;
454*89a07cf8Schristos     return 0;
455*89a07cf8Schristos   }
456*89a07cf8Schristos   else
457*89a07cf8Schristos     return item;
458*89a07cf8Schristos }
459*89a07cf8Schristos 
linear_search_item(const char * filename,int fid)460*89a07cf8Schristos linear_search_item::linear_search_item(const char *filename, int fid)
461*89a07cf8Schristos : search_item(filename, fid)
462*89a07cf8Schristos {
463*89a07cf8Schristos }
464*89a07cf8Schristos 
~linear_search_item()465*89a07cf8Schristos linear_search_item::~linear_search_item()
466*89a07cf8Schristos {
467*89a07cf8Schristos }
468*89a07cf8Schristos 
load(int fd)469*89a07cf8Schristos int linear_search_item::load(int fd)
470*89a07cf8Schristos {
471*89a07cf8Schristos   return fbuf.load(fd, name);
472*89a07cf8Schristos }
473*89a07cf8Schristos 
make_search_item_iterator(const char * query)474*89a07cf8Schristos search_item_iterator *linear_search_item::make_search_item_iterator(
475*89a07cf8Schristos   const char *query)
476*89a07cf8Schristos {
477*89a07cf8Schristos   return new linear_search_item_iterator(this, query);
478*89a07cf8Schristos }
479*89a07cf8Schristos 
linear_search_item_iterator(linear_search_item * p,const char *)480*89a07cf8Schristos linear_search_item_iterator::linear_search_item_iterator(
481*89a07cf8Schristos   linear_search_item *p, const char *)
482*89a07cf8Schristos : lsi(p), pos(0)
483*89a07cf8Schristos {
484*89a07cf8Schristos }
485*89a07cf8Schristos 
~linear_search_item_iterator()486*89a07cf8Schristos linear_search_item_iterator::~linear_search_item_iterator()
487*89a07cf8Schristos {
488*89a07cf8Schristos }
489*89a07cf8Schristos 
next(const linear_searcher & searcher,const char ** startp,int * lengthp,reference_id * ridp)490*89a07cf8Schristos int linear_search_item_iterator::next(const linear_searcher &searcher,
491*89a07cf8Schristos 				      const char **startp, int *lengthp,
492*89a07cf8Schristos 				      reference_id *ridp)
493*89a07cf8Schristos {
494*89a07cf8Schristos   const char *bufstart = lsi->fbuf.get_start();
495*89a07cf8Schristos   const char *bufend = lsi->fbuf.get_end();
496*89a07cf8Schristos   const char *ptr = bufstart + pos;
497*89a07cf8Schristos   if (ptr < bufend && searcher.search(ptr, bufend, startp, lengthp)) {
498*89a07cf8Schristos     pos = *startp + *lengthp - bufstart;
499*89a07cf8Schristos     if (ridp)
500*89a07cf8Schristos       *ridp = reference_id(lsi->filename_id, *startp - bufstart);
501*89a07cf8Schristos     return 1;
502*89a07cf8Schristos   }
503*89a07cf8Schristos   else
504*89a07cf8Schristos     return 0;
505*89a07cf8Schristos }
506