xref: /titanic_50/usr/src/lib/libast/common/misc/fastfind.c (revision 3e14f97f673e8a630f076077de35afdd43dc1587)
1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin *                                                                      *
3da2e3ebdSchin *               This software is part of the ast package               *
4*3e14f97fSRoger A. Faulkner *          Copyright (c) 1985-2010 AT&T Intellectual Property          *
5da2e3ebdSchin *                      and is licensed under the                       *
6da2e3ebdSchin *                  Common Public License, Version 1.0                  *
77c2fbfb3SApril Chin *                    by AT&T Intellectual Property                     *
8da2e3ebdSchin *                                                                      *
9da2e3ebdSchin *                A copy of the License is available at                 *
10da2e3ebdSchin *            http://www.opensource.org/licenses/cpl1.0.txt             *
11da2e3ebdSchin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12da2e3ebdSchin *                                                                      *
13da2e3ebdSchin *              Information and Software Systems Research               *
14da2e3ebdSchin *                            AT&T Research                             *
15da2e3ebdSchin *                           Florham Park NJ                            *
16da2e3ebdSchin *                                                                      *
17da2e3ebdSchin *                 Glenn Fowler <gsf@research.att.com>                  *
18da2e3ebdSchin *                  David Korn <dgk@research.att.com>                   *
19da2e3ebdSchin *                   Phong Vo <kpv@research.att.com>                    *
20da2e3ebdSchin *                                                                      *
21da2e3ebdSchin ***********************************************************************/
22da2e3ebdSchin #pragma prototyped
23da2e3ebdSchin /*
24da2e3ebdSchin  * original code
25da2e3ebdSchin  *
26da2e3ebdSchin  *  	James A. Woods, Informatics General Corporation,
27da2e3ebdSchin  *	NASA Ames Research Center, 6/81.
28da2e3ebdSchin  *	Usenix ;login:, February/March, 1983, p. 8.
29da2e3ebdSchin  *
30da2e3ebdSchin  * discipline/method interface
31da2e3ebdSchin  *
32da2e3ebdSchin  *	Glenn Fowler
33da2e3ebdSchin  *	AT&T Research
34da2e3ebdSchin  *	modified from the original BSD source
35da2e3ebdSchin  *
36da2e3ebdSchin  * 'fastfind' scans a file list for the full pathname of a file
37da2e3ebdSchin  * given only a piece of the name.  The list is processed with
38da2e3ebdSchin  * with "front-compression" and bigram coding.  Front compression reduces
39da2e3ebdSchin  * space by a factor of 4-5, bigram coding by a further 20-25%.
40da2e3ebdSchin  *
41da2e3ebdSchin  * there are 4 methods:
42da2e3ebdSchin  *
43da2e3ebdSchin  *	FF_old	original with 7 bit bigram encoding (no magic)
44da2e3ebdSchin  *	FF_gnu	8 bit clean front compression (FF_gnu_magic)
45da2e3ebdSchin  *	FF_dir	FF_gnu with sfgetl/sfputl and trailing / on dirs (FF_dir_magic)
46da2e3ebdSchin  *	FF_typ	FF_dir with (mime) types (FF_typ_magic)
47da2e3ebdSchin  *
48da2e3ebdSchin  * the bigram encoding steals the eighth bit (that's why its FF_old)
49da2e3ebdSchin  * maybe one day we'll limit it to readonly:
50da2e3ebdSchin  *
51da2e3ebdSchin  * 0-2*FF_OFF	 likeliest differential counts + offset to make nonnegative
52da2e3ebdSchin  * FF_ESC	 4 byte big-endian out-of-range count+FF_OFF follows
53da2e3ebdSchin  * FF_MIN-FF_MAX ascii residue
54da2e3ebdSchin  * >=FF_MAX	 bigram codes
55da2e3ebdSchin  *
56da2e3ebdSchin  * a two-tiered string search technique is employed
57da2e3ebdSchin  *
58da2e3ebdSchin  * a metacharacter-free subpattern and partial pathname is matched
59da2e3ebdSchin  * backwards to avoid full expansion of the pathname list
60da2e3ebdSchin  *
61da2e3ebdSchin  * then the actual shell glob-style regular expression (if in this form)
62da2e3ebdSchin  * is matched against the candidate pathnames using the slower regexec()
63da2e3ebdSchin  *
64da2e3ebdSchin  * The original BSD code is covered by the BSD license:
65da2e3ebdSchin  *
66da2e3ebdSchin  * Copyright (c) 1985, 1993, 1999
67da2e3ebdSchin  *	The Regents of the University of California.  All rights reserved.
68da2e3ebdSchin  *
69da2e3ebdSchin  * Redistribution and use in source and binary forms, with or without
70da2e3ebdSchin  * modification, are permitted provided that the following conditions
71da2e3ebdSchin  * are met:
72da2e3ebdSchin  * 1. Redistributions of source code must retain the above copyright
73da2e3ebdSchin  *    notice, this list of conditions and the following disclaimer.
74da2e3ebdSchin  * 2. Redistributions in binary form must reproduce the above copyright
75da2e3ebdSchin  *    notice, this list of conditions and the following disclaimer in the
76da2e3ebdSchin  *    documentation and/or other materials provided with the distribution.
77da2e3ebdSchin  * 3. Neither the name of the University nor the names of its contributors
78da2e3ebdSchin  *    may be used to endorse or promote products derived from this software
79da2e3ebdSchin  *    without specific prior written permission.
80da2e3ebdSchin  *
81da2e3ebdSchin  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
82da2e3ebdSchin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
83da2e3ebdSchin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
84da2e3ebdSchin  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
85da2e3ebdSchin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
86da2e3ebdSchin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
87da2e3ebdSchin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
88da2e3ebdSchin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
89da2e3ebdSchin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
90da2e3ebdSchin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
91da2e3ebdSchin  * SUCH DAMAGE.
92da2e3ebdSchin  */
93da2e3ebdSchin 
94da2e3ebdSchin static const char id[] = "\n@(#)$Id: fastfind (AT&T Research) 2002-10-02 $\0\n";
95da2e3ebdSchin 
96da2e3ebdSchin static const char lib[] = "libast:fastfind";
97da2e3ebdSchin 
98da2e3ebdSchin #include "findlib.h"
99da2e3ebdSchin 
100da2e3ebdSchin #define FIND_MATCH	"*/(find|locate)/*"
101da2e3ebdSchin 
102da2e3ebdSchin /*
103da2e3ebdSchin  * this db could be anywhere
104da2e3ebdSchin  * findcodes[] directories are checked for findnames[i]
105da2e3ebdSchin  */
106da2e3ebdSchin 
107da2e3ebdSchin static char*		findcodes[] =
108da2e3ebdSchin {
109da2e3ebdSchin 	0,
110da2e3ebdSchin 	0,
111da2e3ebdSchin 	FIND_CODES,
112da2e3ebdSchin 	"/usr/local/share/lib",
113da2e3ebdSchin 	"/usr/local/lib",
114da2e3ebdSchin 	"/usr/share/lib",
115da2e3ebdSchin 	"/usr/lib",
116da2e3ebdSchin 	"/var/spool",
117da2e3ebdSchin 	"/usr/local/var",
118da2e3ebdSchin 	"/var/lib",
119da2e3ebdSchin 	"/var/lib/slocate",
120da2e3ebdSchin 	"/var/db",
121da2e3ebdSchin };
122da2e3ebdSchin 
123da2e3ebdSchin static char*		findnames[] =
124da2e3ebdSchin {
125da2e3ebdSchin 	"find/codes",
126da2e3ebdSchin 	"find/find.codes",
127da2e3ebdSchin 	"locate/locatedb",
128da2e3ebdSchin 	"locatedb",
129da2e3ebdSchin 	"locate.database",
130da2e3ebdSchin 	"slocate.db",
131da2e3ebdSchin };
132da2e3ebdSchin 
133da2e3ebdSchin /*
134da2e3ebdSchin  * convert t to lower case and drop leading x- and x- after /
135da2e3ebdSchin  * converted value copied to b of size n
136da2e3ebdSchin  */
137da2e3ebdSchin 
138da2e3ebdSchin char*
typefix(char * buf,size_t n,register const char * t)139da2e3ebdSchin typefix(char* buf, size_t n, register const char* t)
140da2e3ebdSchin {
141da2e3ebdSchin 	register int	c;
142da2e3ebdSchin 	register char*	b = buf;
143da2e3ebdSchin 
144da2e3ebdSchin 	if ((*t == 'x' || *t == 'X') && *(t + 1) == '-')
145da2e3ebdSchin 		t += 2;
146da2e3ebdSchin 	while (c = *t++)
147da2e3ebdSchin 	{
148da2e3ebdSchin 		if (isupper(c))
149da2e3ebdSchin 			c = tolower(c);
150da2e3ebdSchin 		if ((*b++ = c) == '/' && (*t == 'x' || *t == 'X') && *(t + 1) == '-')
151da2e3ebdSchin 			t += 2;
152da2e3ebdSchin 	}
153da2e3ebdSchin 	*b = 0;
154da2e3ebdSchin 	return buf;
155da2e3ebdSchin }
156da2e3ebdSchin 
157da2e3ebdSchin /*
158da2e3ebdSchin  * return a fastfind stream handle for pattern
159da2e3ebdSchin  */
160da2e3ebdSchin 
161da2e3ebdSchin Find_t*
findopen(const char * file,const char * pattern,const char * type,Finddisc_t * disc)162da2e3ebdSchin findopen(const char* file, const char* pattern, const char* type, Finddisc_t* disc)
163da2e3ebdSchin {
164da2e3ebdSchin 	register Find_t*	fp;
165da2e3ebdSchin 	register char*		p;
166da2e3ebdSchin 	register char*		s;
167da2e3ebdSchin 	register char*		b;
168da2e3ebdSchin 	register int		i;
169da2e3ebdSchin 	register int		j;
170da2e3ebdSchin 	char*			path;
171da2e3ebdSchin 	int			brace = 0;
172da2e3ebdSchin 	int			paren = 0;
173da2e3ebdSchin 	int			k;
174da2e3ebdSchin 	int			q;
175da2e3ebdSchin 	int			fd;
176da2e3ebdSchin 	int			uid;
177da2e3ebdSchin 	Vmalloc_t*		vm;
178da2e3ebdSchin 	Type_t*			tp;
179da2e3ebdSchin 	struct stat		st;
180da2e3ebdSchin 
181da2e3ebdSchin 
182da2e3ebdSchin 	if (!(vm = vmopen(Vmdcheap, Vmbest, 0)))
183da2e3ebdSchin 		goto nospace;
184da2e3ebdSchin 
185da2e3ebdSchin 	/*
186da2e3ebdSchin 	 * NOTE: searching for FIND_CODES would be much simpler if we
187da2e3ebdSchin 	 *       just stuck with our own, but we also support GNU
188da2e3ebdSchin 	 *	 locate codes and have to search for the one of a
189da2e3ebdSchin 	 *	 bazillion possible names for that file
190da2e3ebdSchin 	 */
191da2e3ebdSchin 
192da2e3ebdSchin 	if (!findcodes[1])
193da2e3ebdSchin 		findcodes[1] = getenv(FIND_CODES_ENV);
194da2e3ebdSchin 	if (disc->flags & FIND_GENERATE)
195da2e3ebdSchin 	{
196da2e3ebdSchin 		if (!(fp = (Find_t*)vmnewof(vm, 0, Find_t, 1, sizeof(Encode_t) - sizeof(Code_t))))
197da2e3ebdSchin 			goto nospace;
198da2e3ebdSchin 		fp->vm = vm;
199da2e3ebdSchin 		fp->id = lib;
200da2e3ebdSchin 		fp->disc = disc;
201da2e3ebdSchin 		fp->generate = 1;
202da2e3ebdSchin 		if (file && (!*file || streq(file, "-")))
203da2e3ebdSchin 			file = 0;
204da2e3ebdSchin 		uid = geteuid();
205da2e3ebdSchin 		j = (findcodes[0] = (char*)file) && *file == '/' ? 1 : elementsof(findcodes);
206da2e3ebdSchin 
207da2e3ebdSchin 		/*
208da2e3ebdSchin 		 * look for the codes file, but since it may not exist yet,
209da2e3ebdSchin 		 * also look for the containing directory if i<2 or if
210da2e3ebdSchin 		 * it is sufficiently qualified (FIND_MATCH)
211da2e3ebdSchin 		 */
212da2e3ebdSchin 
213da2e3ebdSchin 		for (i = 0; i < j; i++)
214da2e3ebdSchin 			if (path = findcodes[i])
215da2e3ebdSchin 			{
216da2e3ebdSchin 				if (*path == '/')
217da2e3ebdSchin 				{
218da2e3ebdSchin 					if (!stat(path, &st))
219da2e3ebdSchin 					{
220da2e3ebdSchin 						if (S_ISDIR(st.st_mode))
221da2e3ebdSchin 						{
222da2e3ebdSchin 							for (k = 0; k < elementsof(findnames); k++)
223da2e3ebdSchin 							{
224da2e3ebdSchin 								sfsprintf(fp->encode.file, sizeof(fp->encode.file), "%s/%s", path, findnames[k]);
225da2e3ebdSchin 								if (!eaccess(fp->encode.file, R_OK|W_OK))
226da2e3ebdSchin 								{
227da2e3ebdSchin 									path = fp->encode.file;
228da2e3ebdSchin 									break;
229da2e3ebdSchin 								}
230da2e3ebdSchin 								if (strchr(findnames[k], '/') && (b = strrchr(fp->encode.file, '/')))
231da2e3ebdSchin 								{
232da2e3ebdSchin 									*b = 0;
233da2e3ebdSchin 									if (!stat(fp->encode.file, &st) && st.st_uid == uid && (st.st_mode & S_IWUSR))
234da2e3ebdSchin 									{
235da2e3ebdSchin 										*b = '/';
236da2e3ebdSchin 										path = fp->encode.file;
237da2e3ebdSchin 										break;
238da2e3ebdSchin 									}
239da2e3ebdSchin 								}
240da2e3ebdSchin 							}
241da2e3ebdSchin 							if (k < elementsof(findnames))
242da2e3ebdSchin 								break;
243da2e3ebdSchin 						}
244da2e3ebdSchin 						else if (st.st_uid == uid && (st.st_mode & S_IWUSR))
245da2e3ebdSchin 						{
246da2e3ebdSchin 							sfsprintf(fp->encode.file, sizeof(fp->encode.file), "%s", path);
247da2e3ebdSchin 							path = fp->encode.file;
248da2e3ebdSchin 							break;
249da2e3ebdSchin 						}
250da2e3ebdSchin 					}
251da2e3ebdSchin 					else if (i < 2 || strmatch(path, FIND_MATCH))
252da2e3ebdSchin 					{
253da2e3ebdSchin 						sfsprintf(fp->encode.file, sizeof(fp->encode.file), "%s", path);
254da2e3ebdSchin 						if (b = strrchr(fp->encode.file, '/'))
255da2e3ebdSchin 						{
256da2e3ebdSchin 							*b = 0;
257da2e3ebdSchin 							if (!stat(fp->encode.file, &st) && st.st_uid == uid && (st.st_mode & S_IWUSR))
258da2e3ebdSchin 							{
259da2e3ebdSchin 								*b = '/';
260da2e3ebdSchin 								path = fp->encode.file;
261da2e3ebdSchin 								break;
262da2e3ebdSchin 							}
263da2e3ebdSchin 						}
264da2e3ebdSchin 					}
265da2e3ebdSchin 				}
266da2e3ebdSchin 				else if (pathpath(fp->encode.file, path, "", PATH_REGULAR|PATH_READ|PATH_WRITE))
267da2e3ebdSchin 				{
268da2e3ebdSchin 					path = fp->encode.file;
269da2e3ebdSchin 					break;
270da2e3ebdSchin 				}
271da2e3ebdSchin 				else if (b = strrchr(path, '/'))
272da2e3ebdSchin 				{
273da2e3ebdSchin 					sfsprintf(fp->encode.file, sizeof(fp->encode.file), "%-.*s", b - path, path);
274da2e3ebdSchin 					if (pathpath(fp->encode.temp, fp->encode.file, "", PATH_EXECUTE|PATH_READ|PATH_WRITE) &&
275da2e3ebdSchin 					    !stat(fp->encode.temp, &st) && st.st_uid == uid && (st.st_mode & S_IWUSR))
276da2e3ebdSchin 					{
277da2e3ebdSchin 						sfsprintf(fp->encode.file, sizeof(fp->encode.file), "%s%s", fp->encode.temp, b);
278da2e3ebdSchin 						path = fp->encode.file;
279da2e3ebdSchin 						break;
280da2e3ebdSchin 					}
281da2e3ebdSchin 				}
282da2e3ebdSchin 			}
283da2e3ebdSchin 		if (i >= j)
284da2e3ebdSchin 		{
285da2e3ebdSchin 			if (fp->disc->errorf)
286da2e3ebdSchin 				(*fp->disc->errorf)(fp, fp->disc, 2, "%s: cannot locate codes", file ? file : findcodes[2]);
287da2e3ebdSchin 			goto drop;
288da2e3ebdSchin 		}
289da2e3ebdSchin 		if (fp->disc->flags & FIND_OLD)
290da2e3ebdSchin 		{
291da2e3ebdSchin 			/*
292da2e3ebdSchin 			 * FF_old generates temp data that is read
293da2e3ebdSchin 			 * in a second pass to generate the real codes
294da2e3ebdSchin 			 */
295da2e3ebdSchin 
296da2e3ebdSchin 			fp->method = FF_old;
297da2e3ebdSchin 			if (!(fp->fp = sftmp(32 * PATH_MAX)))
298da2e3ebdSchin 			{
299da2e3ebdSchin 				if (fp->disc->errorf)
300da2e3ebdSchin 					(*fp->disc->errorf)(fp, fp->disc, ERROR_SYSTEM|2, "cannot create tmp file");
301da2e3ebdSchin 				goto drop;
302da2e3ebdSchin 			}
303da2e3ebdSchin 		}
304da2e3ebdSchin 		else
305da2e3ebdSchin 		{
306da2e3ebdSchin 			/*
307da2e3ebdSchin 			 * the rest generate into a temp file that
308da2e3ebdSchin 			 * is simply renamed on completion
309da2e3ebdSchin 			 */
310da2e3ebdSchin 
311da2e3ebdSchin 			if (s = strrchr(path, '/'))
312da2e3ebdSchin 			{
313da2e3ebdSchin 				*s = 0;
314da2e3ebdSchin 				p = path;
315da2e3ebdSchin 			}
316da2e3ebdSchin 			else
317da2e3ebdSchin 				p = ".";
318da2e3ebdSchin 			if (!pathtemp(fp->encode.temp, sizeof(fp->encode.temp), p, "ff", &fd))
319da2e3ebdSchin 			{
320da2e3ebdSchin 				if (fp->disc->errorf)
321da2e3ebdSchin 					(*fp->disc->errorf)(fp, fp->disc, ERROR_SYSTEM|2, "%s: cannot create tmp file in this directory", p ? p : ".");
322da2e3ebdSchin 				goto drop;
323da2e3ebdSchin 			}
324da2e3ebdSchin 			if (s)
325da2e3ebdSchin 				*s = '/';
326da2e3ebdSchin 			if (!(fp->fp = sfnew(NiL, NiL, (size_t)SF_UNBOUND, fd, SF_WRITE)))
327da2e3ebdSchin 			{
328da2e3ebdSchin 				if (fp->disc->errorf)
329da2e3ebdSchin 					(*fp->disc->errorf)(fp, fp->disc, ERROR_SYSTEM|2, "%s: cannot open tmp file", fp->encode.temp);
330da2e3ebdSchin 				close(fd);
331da2e3ebdSchin 				goto drop;
332da2e3ebdSchin 			}
333da2e3ebdSchin 			if (fp->disc->flags & FIND_TYPE)
334da2e3ebdSchin 			{
335da2e3ebdSchin 				fp->method = FF_typ;
336da2e3ebdSchin 				fp->encode.namedisc.key = offsetof(Type_t, name);
337da2e3ebdSchin 				fp->encode.namedisc.link = offsetof(Type_t, byname);
338da2e3ebdSchin 				fp->encode.indexdisc.key = offsetof(Type_t, index);
339da2e3ebdSchin 				fp->encode.indexdisc.size = sizeof(unsigned long);
340da2e3ebdSchin 				fp->encode.indexdisc.link = offsetof(Type_t, byindex);
341da2e3ebdSchin 				s = "system/dir";
342da2e3ebdSchin 				if (!(fp->encode.namedict = dtopen(&fp->encode.namedisc, Dttree)) || !(fp->encode.indexdict = dtopen(&fp->encode.indexdisc, Dttree)) || !(tp = newof(0, Type_t, 1, strlen(s) + 1)))
343da2e3ebdSchin 				{
344da2e3ebdSchin 					if (fp->encode.namedict)
345da2e3ebdSchin 						dtclose(fp->encode.namedict);
346da2e3ebdSchin 					if (fp->disc->errorf)
347da2e3ebdSchin 						(*fp->disc->errorf)(fp, fp->disc, 2, "cannot allocate type table");
348da2e3ebdSchin 					goto drop;
349da2e3ebdSchin 				}
350da2e3ebdSchin 
351da2e3ebdSchin 				/*
352da2e3ebdSchin 				 * type index 1 is always system/dir
353da2e3ebdSchin 				 */
354da2e3ebdSchin 
355da2e3ebdSchin 				tp->index = ++fp->types;
356da2e3ebdSchin 				strcpy(tp->name, s);
357da2e3ebdSchin 				dtinsert(fp->encode.namedict, tp);
358da2e3ebdSchin 				dtinsert(fp->encode.indexdict, tp);
359da2e3ebdSchin 			}
360da2e3ebdSchin 			else if (fp->disc->flags & FIND_GNU)
361da2e3ebdSchin 			{
362da2e3ebdSchin 				fp->method = FF_gnu;
363da2e3ebdSchin 				sfputc(fp->fp, 0);
364da2e3ebdSchin 				sfputr(fp->fp, FF_gnu_magic, 0);
365da2e3ebdSchin 			}
366da2e3ebdSchin 			else
367da2e3ebdSchin 			{
368da2e3ebdSchin 				fp->method = FF_dir;
369da2e3ebdSchin 				sfputc(fp->fp, 0);
370da2e3ebdSchin 				sfputr(fp->fp, FF_dir_magic, 0);
371da2e3ebdSchin 			}
372da2e3ebdSchin 		}
373da2e3ebdSchin 	}
374da2e3ebdSchin 	else
375da2e3ebdSchin 	{
376da2e3ebdSchin 		i = sizeof(Decode_t) + sizeof(Code_t);
377da2e3ebdSchin 		if (!pattern || !*pattern)
378da2e3ebdSchin 			pattern = "*";
379da2e3ebdSchin 		i += (j = 2 * (strlen(pattern) + 1));
380da2e3ebdSchin 		if (!(fp = (Find_t*)vmnewof(vm, 0, Find_t, 1, i)))
381da2e3ebdSchin 		{
382da2e3ebdSchin 			vmclose(vm);
383da2e3ebdSchin 			return 0;
384da2e3ebdSchin 		}
385da2e3ebdSchin 		fp->vm = vm;
386da2e3ebdSchin 		fp->id = lib;
387da2e3ebdSchin 		fp->disc = disc;
388da2e3ebdSchin 		if (disc->flags & FIND_ICASE)
389da2e3ebdSchin 			fp->decode.ignorecase = 1;
390da2e3ebdSchin 		j = (findcodes[0] = (char*)file) && *file == '/' ? 1 : elementsof(findcodes);
391da2e3ebdSchin 		for (i = 0; i < j; i++)
392da2e3ebdSchin 			if (path = findcodes[i])
393da2e3ebdSchin 			{
394da2e3ebdSchin 				if (*path == '/')
395da2e3ebdSchin 				{
396da2e3ebdSchin 					if (!stat(path, &st))
397da2e3ebdSchin 					{
398da2e3ebdSchin 						if (S_ISDIR(st.st_mode))
399da2e3ebdSchin 						{
400da2e3ebdSchin 							for (k = 0; k < elementsof(findnames); k++)
401da2e3ebdSchin 							{
402da2e3ebdSchin 								sfsprintf(fp->decode.path, sizeof(fp->decode.path), "%s/%s", path, findnames[k]);
403da2e3ebdSchin 								if (fp->fp = sfopen(NiL, fp->decode.path, "r"))
404da2e3ebdSchin 								{
405da2e3ebdSchin 									path = fp->decode.path;
406da2e3ebdSchin 									break;
407da2e3ebdSchin 								}
408da2e3ebdSchin 							}
409da2e3ebdSchin 							if (fp->fp)
410da2e3ebdSchin 								break;
411da2e3ebdSchin 						}
412da2e3ebdSchin 						else if (fp->fp = sfopen(NiL, path, "r"))
413da2e3ebdSchin 							break;
414da2e3ebdSchin 					}
415da2e3ebdSchin 				}
416da2e3ebdSchin 				else if ((path = pathpath(fp->decode.path, path, "", PATH_REGULAR|PATH_READ)) && (fp->fp = sfopen(NiL, path, "r")))
417da2e3ebdSchin 					break;
418da2e3ebdSchin 			}
419da2e3ebdSchin 		if (!fp->fp)
420da2e3ebdSchin 		{
421da2e3ebdSchin 			if (fp->disc->errorf)
422da2e3ebdSchin 				(*fp->disc->errorf)(fp, fp->disc, 2, "%s: cannot locate codes", file ? file : findcodes[2]);
423da2e3ebdSchin 			goto drop;
424da2e3ebdSchin 		}
425da2e3ebdSchin 		if (fstat(sffileno(fp->fp), &st))
426da2e3ebdSchin 		{
427da2e3ebdSchin 			if (fp->disc->errorf)
428da2e3ebdSchin 				(*fp->disc->errorf)(fp, fp->disc, 2, "%s: cannot stat codes", path);
429da2e3ebdSchin 			goto drop;
430da2e3ebdSchin 		}
431da2e3ebdSchin 		if (fp->secure = ((st.st_mode & (S_IRGRP|S_IROTH)) == S_IRGRP) && st.st_gid == getegid() && getegid() != getgid())
432da2e3ebdSchin 			setgid(getgid());
433da2e3ebdSchin 		fp->stamp = st.st_mtime;
434da2e3ebdSchin 		b = (s = fp->decode.temp) + 1;
435da2e3ebdSchin 		for (i = 0; i < elementsof(fp->decode.bigram1); i++)
436da2e3ebdSchin 		{
437da2e3ebdSchin 			if ((j = sfgetc(fp->fp)) == EOF)
438da2e3ebdSchin 				goto invalid;
439da2e3ebdSchin 			if (!(*s++ = fp->decode.bigram1[i] = j) && i)
440da2e3ebdSchin 			{
441da2e3ebdSchin 				i = -i;
442da2e3ebdSchin 				break;
443da2e3ebdSchin 			}
444da2e3ebdSchin 			if ((j = sfgetc(fp->fp)) == EOF)
445da2e3ebdSchin 				goto invalid;
446da2e3ebdSchin 			if (!(*s++ = fp->decode.bigram2[i] = j) && (i || fp->decode.bigram1[0] >= '0' && fp->decode.bigram1[0] <= '1'))
447da2e3ebdSchin 				break;
448da2e3ebdSchin 		}
449da2e3ebdSchin 		if (streq(b, FF_typ_magic))
450da2e3ebdSchin 		{
451da2e3ebdSchin 			if (type)
452da2e3ebdSchin 			{
453da2e3ebdSchin 				type = (const char*)typefix(fp->decode.bigram2, sizeof(fp->decode.bigram2), type);
454da2e3ebdSchin 				memset(fp->decode.bigram1, 0, sizeof(fp->decode.bigram1));
455da2e3ebdSchin 			}
456da2e3ebdSchin 			fp->method = FF_typ;
457da2e3ebdSchin 			for (j = 0, i = 1;; i++)
458da2e3ebdSchin 			{
459da2e3ebdSchin 				if (!(s = sfgetr(fp->fp, 0, 0)))
460da2e3ebdSchin 					goto invalid;
461da2e3ebdSchin 				if (!*s)
462da2e3ebdSchin 					break;
463da2e3ebdSchin 				if (type && strmatch(s, type))
464da2e3ebdSchin 				{
465da2e3ebdSchin 					FF_SET_TYPE(fp, i);
466da2e3ebdSchin 					j++;
467da2e3ebdSchin 				}
468da2e3ebdSchin 			}
469da2e3ebdSchin 			if (type && !j)
470da2e3ebdSchin 				goto drop;
471da2e3ebdSchin 			fp->types = j;
472da2e3ebdSchin 		}
473da2e3ebdSchin 		else if (streq(b, FF_dir_magic))
474da2e3ebdSchin 			fp->method = FF_dir;
475da2e3ebdSchin 		else if (streq(b, FF_gnu_magic))
476da2e3ebdSchin 			fp->method = FF_gnu;
477da2e3ebdSchin 		else if (!*b && *--b >= '0' && *b <= '1')
478da2e3ebdSchin 		{
479da2e3ebdSchin 			fp->method = FF_gnu;
480da2e3ebdSchin 			while (j = sfgetc(fp->fp))
481da2e3ebdSchin 			{
482da2e3ebdSchin 				if (j == EOF || fp->decode.count >= sizeof(fp->decode.path))
483da2e3ebdSchin 					goto invalid;
484da2e3ebdSchin 				fp->decode.path[fp->decode.count++] = j;
485da2e3ebdSchin 			}
486da2e3ebdSchin 		}
487da2e3ebdSchin 		else
488da2e3ebdSchin 		{
489da2e3ebdSchin 			fp->method = FF_old;
490da2e3ebdSchin 			if (i < 0)
491da2e3ebdSchin 			{
492da2e3ebdSchin 				if ((j = sfgetc(fp->fp)) == EOF)
493da2e3ebdSchin 					goto invalid;
494da2e3ebdSchin 				fp->decode.bigram2[i = -i] = j;
495da2e3ebdSchin 			}
496da2e3ebdSchin 			while (++i < elementsof(fp->decode.bigram1))
497da2e3ebdSchin 			{
498da2e3ebdSchin 				if ((j = sfgetc(fp->fp)) == EOF)
499da2e3ebdSchin 					goto invalid;
500da2e3ebdSchin 				fp->decode.bigram1[i] = j;
501da2e3ebdSchin 				if ((j = sfgetc(fp->fp)) == EOF)
502da2e3ebdSchin 					goto invalid;
503da2e3ebdSchin 				fp->decode.bigram2[i] = j;
504da2e3ebdSchin 			}
505da2e3ebdSchin 			if ((fp->decode.peek = sfgetc(fp->fp)) != FF_OFF)
506da2e3ebdSchin 				goto invalid;
507da2e3ebdSchin 		}
508da2e3ebdSchin 
509da2e3ebdSchin 		/*
510da2e3ebdSchin 		 * set up the physical dir table
511da2e3ebdSchin 		 */
512da2e3ebdSchin 
513da2e3ebdSchin 		if (disc->version >= 19980301L)
514da2e3ebdSchin 		{
515da2e3ebdSchin 			fp->verifyf = disc->verifyf;
516da2e3ebdSchin 			if (disc->dirs && *disc->dirs)
517da2e3ebdSchin 			{
518da2e3ebdSchin 				for (k = 0; disc->dirs[k]; k++);
519da2e3ebdSchin 				if (k == 1 && streq(disc->dirs[0], "/"))
520da2e3ebdSchin 					k = 0;
521da2e3ebdSchin 				if (k)
522da2e3ebdSchin 				{
523da2e3ebdSchin 					if (!(fp->dirs = vmnewof(fp->vm, 0, char*, 2 * k + 1, 0)))
524da2e3ebdSchin 						goto drop;
525da2e3ebdSchin 					if (!(fp->lens = vmnewof(fp->vm, 0, int, 2 * k, 0)))
526da2e3ebdSchin 						goto drop;
527da2e3ebdSchin 					p = 0;
528da2e3ebdSchin 					b = fp->decode.temp;
529da2e3ebdSchin 					j = fp->method == FF_old || fp->method == FF_gnu;
530da2e3ebdSchin 
531da2e3ebdSchin 					/*
532da2e3ebdSchin 					 * fill the dir list with logical and
533da2e3ebdSchin 					 * physical names since we don't know
534da2e3ebdSchin 					 * which way the db was encoded (it
535da2e3ebdSchin 					 * could be *both* ways)
536da2e3ebdSchin 					 */
537da2e3ebdSchin 
538da2e3ebdSchin 					for (i = q = 0; i < k; i++)
539da2e3ebdSchin 					{
540da2e3ebdSchin 						if (*(s = disc->dirs[i]) == '/')
541da2e3ebdSchin 							sfsprintf(b, sizeof(fp->decode.temp) - 1, "%s", s);
542da2e3ebdSchin 						else if (!p && !(p = getcwd(fp->decode.path, sizeof(fp->decode.path))))
543da2e3ebdSchin 							goto nospace;
544da2e3ebdSchin 						else
545da2e3ebdSchin 							sfsprintf(b, sizeof(fp->decode.temp) - 1, "%s/%s", p, s);
546da2e3ebdSchin 						s = pathcanon(b, 0);
547da2e3ebdSchin 						*s = '/';
548da2e3ebdSchin 						*(s + 1) = 0;
549da2e3ebdSchin 						if (!(fp->dirs[q] = vmstrdup(fp->vm, b)))
550da2e3ebdSchin 							goto nospace;
551da2e3ebdSchin 						if (j)
552da2e3ebdSchin 							(fp->dirs[q])[s - b] = 0;
553da2e3ebdSchin 						q++;
554da2e3ebdSchin 						*s = 0;
555da2e3ebdSchin 						s = pathcanon(b, PATH_PHYSICAL);
556da2e3ebdSchin 						*s = '/';
557da2e3ebdSchin 						*(s + 1) = 0;
558da2e3ebdSchin 						if (!strneq(b, fp->dirs[q - 1], s - b))
559da2e3ebdSchin 						{
560da2e3ebdSchin 							if (!(fp->dirs[q] = vmstrdup(fp->vm, b)))
561da2e3ebdSchin 								goto nospace;
562da2e3ebdSchin 							if (j)
563da2e3ebdSchin 								(fp->dirs[q])[s - b] = 0;
564da2e3ebdSchin 							q++;
565da2e3ebdSchin 						}
566da2e3ebdSchin 					}
567da2e3ebdSchin 					strsort(fp->dirs, q, strcasecmp);
568da2e3ebdSchin 					for (i = 0; i < q; i++)
569da2e3ebdSchin 						fp->lens[i] = strlen(fp->dirs[i]);
570da2e3ebdSchin 				}
571da2e3ebdSchin 			}
572da2e3ebdSchin 		}
573da2e3ebdSchin 		if (fp->verifyf || (disc->flags & FIND_VERIFY))
574da2e3ebdSchin 		{
575da2e3ebdSchin 			if (fp->method != FF_dir && fp->method != FF_typ)
576da2e3ebdSchin 			{
577da2e3ebdSchin 				if (fp->disc->errorf)
578da2e3ebdSchin 					(*fp->disc->errorf)(fp, fp->disc, 2, "%s: %s code format does not support directory verification", path, fp->method == FF_gnu ? FF_gnu_magic : "OLD-BIGRAM");
579da2e3ebdSchin 				goto drop;
580da2e3ebdSchin 			}
581da2e3ebdSchin 			fp->verify = 1;
582da2e3ebdSchin 		}
583da2e3ebdSchin 
584da2e3ebdSchin 		/*
585da2e3ebdSchin 		 * extract last glob-free subpattern in name for fast pre-match
586da2e3ebdSchin 		 * prepend 0 for backwards match
587da2e3ebdSchin 		 */
588da2e3ebdSchin 
589da2e3ebdSchin 		if (p = s = (char*)pattern)
590da2e3ebdSchin 		{
591da2e3ebdSchin 			b = fp->decode.pattern;
592da2e3ebdSchin 			for (;;)
593da2e3ebdSchin 			{
594da2e3ebdSchin 				switch (*b++ = *p++)
595da2e3ebdSchin 				{
596da2e3ebdSchin 				case 0:
597da2e3ebdSchin 					break;
598da2e3ebdSchin 				case '\\':
599da2e3ebdSchin 					s = p;
600da2e3ebdSchin 					if (!*p++)
601da2e3ebdSchin 						break;
602da2e3ebdSchin 					continue;
603da2e3ebdSchin 				case '[':
604da2e3ebdSchin 					if (!brace)
605da2e3ebdSchin 					{
606da2e3ebdSchin 						brace++;
607da2e3ebdSchin 						if (*p == ']')
608da2e3ebdSchin 							p++;
609da2e3ebdSchin 					}
610da2e3ebdSchin 					continue;
611da2e3ebdSchin 				case ']':
612da2e3ebdSchin 					if (brace)
613da2e3ebdSchin 					{
614da2e3ebdSchin 						brace--;
615da2e3ebdSchin 						s = p;
616da2e3ebdSchin 					}
617da2e3ebdSchin 					continue;
618da2e3ebdSchin 				case '(':
619da2e3ebdSchin 					if (!brace)
620da2e3ebdSchin 						paren++;
621da2e3ebdSchin 					continue;
622da2e3ebdSchin 				case ')':
623da2e3ebdSchin 					if (!brace && paren > 0 && !--paren)
624da2e3ebdSchin 						s = p;
625da2e3ebdSchin 					continue;
626da2e3ebdSchin 				case '|':
627da2e3ebdSchin 				case '&':
628da2e3ebdSchin 					if (!brace && !paren)
629da2e3ebdSchin 					{
630da2e3ebdSchin 						s = "";
631da2e3ebdSchin 						break;
632da2e3ebdSchin 					}
633da2e3ebdSchin 					continue;
634da2e3ebdSchin 				case '*':
635da2e3ebdSchin 				case '?':
636da2e3ebdSchin 					s = p;
637da2e3ebdSchin 					continue;
638da2e3ebdSchin 				default:
639da2e3ebdSchin 					continue;
640da2e3ebdSchin 				}
641da2e3ebdSchin 				break;
642da2e3ebdSchin 			}
643da2e3ebdSchin 			if (s != pattern && !streq(pattern, "*"))
644da2e3ebdSchin 			{
645da2e3ebdSchin 				fp->decode.match = 1;
646da2e3ebdSchin 				if (i = regcomp(&fp->decode.re, pattern, REG_SHELL|REG_AUGMENTED|(fp->decode.ignorecase?REG_ICASE:0)))
647da2e3ebdSchin 				{
648da2e3ebdSchin 					if (disc->errorf)
649da2e3ebdSchin 					{
650da2e3ebdSchin 						regerror(i, &fp->decode.re, fp->decode.temp, sizeof(fp->decode.temp));
651da2e3ebdSchin 						(*fp->disc->errorf)(fp, fp->disc, 2, "%s: %s", pattern, fp->decode.temp);
652da2e3ebdSchin 					}
653da2e3ebdSchin 					goto drop;
654da2e3ebdSchin 				}
655da2e3ebdSchin 			}
656da2e3ebdSchin 			if (*s)
657da2e3ebdSchin 			{
658da2e3ebdSchin 				*b++ = 0;
659da2e3ebdSchin 				while (i = *s++)
660da2e3ebdSchin 					*b++ = i;
661da2e3ebdSchin 				*b-- = 0;
662da2e3ebdSchin 				fp->decode.end = b;
663da2e3ebdSchin 				if (fp->decode.ignorecase)
664da2e3ebdSchin 					for (s = fp->decode.pattern; s <= b; s++)
665da2e3ebdSchin 						if (isupper(*s))
666da2e3ebdSchin 							*s = tolower(*s);
667da2e3ebdSchin 			}
668da2e3ebdSchin 		}
669da2e3ebdSchin 	}
670da2e3ebdSchin 	return fp;
671da2e3ebdSchin  nospace:
672da2e3ebdSchin 	if (disc->errorf)
673da2e3ebdSchin 		(*fp->disc->errorf)(fp, fp->disc, 2, "out of space");
674da2e3ebdSchin 	if (!vm)
675da2e3ebdSchin 		return 0;
676da2e3ebdSchin 	if (!fp)
677da2e3ebdSchin 	{
678da2e3ebdSchin 		vmclose(vm);
679da2e3ebdSchin 		return 0;
680da2e3ebdSchin 	}
681da2e3ebdSchin 	goto drop;
682da2e3ebdSchin  invalid:
683da2e3ebdSchin 	if (fp->disc->errorf)
684da2e3ebdSchin 		(*fp->disc->errorf)(fp, fp->disc, 2, "%s: invalid codes", path);
685da2e3ebdSchin  drop:
686da2e3ebdSchin 	if (!fp->generate && fp->decode.match)
687da2e3ebdSchin 		regfree(&fp->decode.re);
688da2e3ebdSchin 	if (fp->fp)
689da2e3ebdSchin 		sfclose(fp->fp);
690da2e3ebdSchin 	vmclose(fp->vm);
691da2e3ebdSchin 	return 0;
692da2e3ebdSchin }
693da2e3ebdSchin 
694da2e3ebdSchin /*
695da2e3ebdSchin  * return the next fastfind path
696da2e3ebdSchin  * 0 returned when list exhausted
697da2e3ebdSchin  */
698da2e3ebdSchin 
699da2e3ebdSchin char*
findread(register Find_t * fp)700da2e3ebdSchin findread(register Find_t* fp)
701da2e3ebdSchin {
702da2e3ebdSchin 	register char*		p;
703da2e3ebdSchin 	register char*		q;
704da2e3ebdSchin 	register char*		s;
705da2e3ebdSchin 	register char*		b;
706da2e3ebdSchin 	register char*		e;
707da2e3ebdSchin 	register int		c;
708da2e3ebdSchin 	register int		n;
709da2e3ebdSchin 	register int		m;
710da2e3ebdSchin 	int			ignorecase;
711da2e3ebdSchin 	int			t;
712da2e3ebdSchin 	unsigned char		w[4];
713da2e3ebdSchin 	struct stat		st;
714da2e3ebdSchin 
715da2e3ebdSchin 	if (fp->generate)
716da2e3ebdSchin 		return 0;
717da2e3ebdSchin 	if (fp->decode.restore)
718da2e3ebdSchin 	{
719da2e3ebdSchin 		*fp->decode.restore = '/';
720da2e3ebdSchin 		fp->decode.restore = 0;
721da2e3ebdSchin 	}
722da2e3ebdSchin 	ignorecase = fp->decode.ignorecase ? STR_ICASE : 0;
723da2e3ebdSchin 	c = fp->decode.peek;
724da2e3ebdSchin  next:
725da2e3ebdSchin 	for (;;)
726da2e3ebdSchin 	{
727da2e3ebdSchin 		switch (fp->method)
728da2e3ebdSchin 		{
729da2e3ebdSchin 		case FF_dir:
730da2e3ebdSchin 			t = 0;
731da2e3ebdSchin 			n = sfgetl(fp->fp);
732da2e3ebdSchin 			goto grab;
733da2e3ebdSchin 		case FF_gnu:
734da2e3ebdSchin 			if ((c = sfgetc(fp->fp)) == EOF)
735da2e3ebdSchin 				return 0;
736da2e3ebdSchin 			if (c == 0x80)
737da2e3ebdSchin 			{
738da2e3ebdSchin 				if ((c = sfgetc(fp->fp)) == EOF)
739da2e3ebdSchin 					return 0;
740da2e3ebdSchin 				n = c << 8;
741da2e3ebdSchin 				if ((c = sfgetc(fp->fp)) == EOF)
742da2e3ebdSchin 					return 0;
743da2e3ebdSchin 				n |= c;
744da2e3ebdSchin 				if (n & 0x8000)
745da2e3ebdSchin 					n = (n - 0xffff) - 1;
746da2e3ebdSchin 			}
747da2e3ebdSchin 			else if ((n = c) & 0x80)
748da2e3ebdSchin 				n = (n - 0xff) - 1;
749da2e3ebdSchin 			t = 0;
750da2e3ebdSchin 			goto grab;
751da2e3ebdSchin 		case FF_typ:
752da2e3ebdSchin 			t = sfgetu(fp->fp);
753da2e3ebdSchin 			n = sfgetl(fp->fp);
754da2e3ebdSchin 		grab:
755da2e3ebdSchin 			p = fp->decode.path + (fp->decode.count += n);
756da2e3ebdSchin 			do
757da2e3ebdSchin 			{
758da2e3ebdSchin 				if ((c = sfgetc(fp->fp)) == EOF)
759da2e3ebdSchin 					return 0;
760da2e3ebdSchin 			} while (*p++ = c);
761da2e3ebdSchin 			p -= 2;
762da2e3ebdSchin 			break;
763da2e3ebdSchin 		case FF_old:
764da2e3ebdSchin 			if (c == EOF)
765da2e3ebdSchin 			{
766da2e3ebdSchin 				fp->decode.peek = c;
767da2e3ebdSchin 				return 0;
768da2e3ebdSchin 			}
769da2e3ebdSchin 			if (c == FF_ESC)
770da2e3ebdSchin 			{
771da2e3ebdSchin 				if (sfread(fp->fp, w, sizeof(w)) != sizeof(w))
772da2e3ebdSchin 					return 0;
773da2e3ebdSchin 				if (fp->decode.swap >= 0)
774da2e3ebdSchin 				{
775da2e3ebdSchin 					c = (int32_t)((w[0] << 24) | (w[1] << 16) | (w[2] << 8) | w[3]);
776da2e3ebdSchin 					if (!fp->decode.swap)
777da2e3ebdSchin 					{
778da2e3ebdSchin 						/*
779da2e3ebdSchin 						 * the old format uses machine
780da2e3ebdSchin 						 * byte order; this test uses
781da2e3ebdSchin 						 * the smallest magnitude of
782da2e3ebdSchin 						 * both byte orders on the
783da2e3ebdSchin 						 * first encoded path motion
784da2e3ebdSchin 						 * to determine the original
785da2e3ebdSchin 						 * byte order
786da2e3ebdSchin 						 */
787da2e3ebdSchin 
788da2e3ebdSchin 						m = c;
789da2e3ebdSchin 						if (m < 0)
790da2e3ebdSchin 							m = -m;
791da2e3ebdSchin 						n = (int32_t)((w[3] << 24) | (w[2] << 16) | (w[1] << 8) | w[0]);
792da2e3ebdSchin 						if (n < 0)
793da2e3ebdSchin 							n = -n;
794da2e3ebdSchin 						if (m < n)
795da2e3ebdSchin 							fp->decode.swap = 1;
796da2e3ebdSchin 						else
797da2e3ebdSchin 						{
798da2e3ebdSchin 							fp->decode.swap = -1;
799da2e3ebdSchin 							c = (int32_t)((w[3] << 24) | (w[2] << 16) | (w[1] << 8) | w[0]);
800da2e3ebdSchin 						}
801da2e3ebdSchin 					}
802da2e3ebdSchin 				}
803da2e3ebdSchin 				else
804da2e3ebdSchin 					c = (int32_t)((w[3] << 24) | (w[2] << 16) | (w[1] << 8) | w[0]);
805da2e3ebdSchin 			}
806da2e3ebdSchin 			fp->decode.count += c - FF_OFF;
807da2e3ebdSchin 			for (p = fp->decode.path + fp->decode.count; (c = sfgetc(fp->fp)) > FF_ESC;)
808da2e3ebdSchin 				if (c & (1<<(CHAR_BIT-1)))
809da2e3ebdSchin 				{
810da2e3ebdSchin 					*p++ = fp->decode.bigram1[c & ((1<<(CHAR_BIT-1))-1)];
811da2e3ebdSchin 					*p++ = fp->decode.bigram2[c & ((1<<(CHAR_BIT-1))-1)];
812da2e3ebdSchin 				}
813da2e3ebdSchin 				else
814da2e3ebdSchin 					*p++ = c;
815da2e3ebdSchin 			*p-- = 0;
816da2e3ebdSchin 			t = 0;
817da2e3ebdSchin 			break;
818da2e3ebdSchin 		}
819da2e3ebdSchin 		b = fp->decode.path;
820da2e3ebdSchin 		if (fp->decode.found)
821da2e3ebdSchin 			fp->decode.found = 0;
822da2e3ebdSchin 		else
823da2e3ebdSchin 			b += fp->decode.count;
824da2e3ebdSchin 		if (fp->dirs)
825da2e3ebdSchin 			for (;;)
826da2e3ebdSchin 			{
827da2e3ebdSchin 				if (!*fp->dirs)
828da2e3ebdSchin 					return 0;
829da2e3ebdSchin 
830da2e3ebdSchin 				/*
831da2e3ebdSchin 				 * use the ordering and lengths to prune
832da2e3ebdSchin 				 * comparison function calls
833da2e3ebdSchin 				 * (*fp->dirs)[*fp->lens]=='/' if its
834da2e3ebdSchin 				 * already been matched
835da2e3ebdSchin 				 */
836da2e3ebdSchin 
837da2e3ebdSchin 				if ((n = p - fp->decode.path + 1) > (m = *fp->lens))
838da2e3ebdSchin 				{
839da2e3ebdSchin 					if (!(*fp->dirs)[m])
840da2e3ebdSchin 						goto next;
841da2e3ebdSchin 					if (!strncasecmp(*fp->dirs, fp->decode.path, m))
842da2e3ebdSchin 						break;
843da2e3ebdSchin 				}
844da2e3ebdSchin 				else if (n == m)
845da2e3ebdSchin 				{
846da2e3ebdSchin 					if (!(*fp->dirs)[m])
847da2e3ebdSchin 					{
848da2e3ebdSchin 						if (!(n = strcasecmp(*fp->dirs, fp->decode.path)) && (ignorecase || !strcmp(*fp->dirs, fp->decode.path)))
849da2e3ebdSchin 						{
850da2e3ebdSchin 							if (m > 0)
851da2e3ebdSchin 							{
852da2e3ebdSchin 								(*fp->dirs)[m] = '/';
853da2e3ebdSchin 								if ((*fp->dirs)[m - 1] != '/')
854da2e3ebdSchin 									(*fp->dirs)[++(*fp->lens)] = '/';
855da2e3ebdSchin 							}
856da2e3ebdSchin 							break;
857da2e3ebdSchin 						}
858da2e3ebdSchin 						if (n >= 0)
859da2e3ebdSchin 							goto next;
860da2e3ebdSchin 					}
861da2e3ebdSchin 				}
862da2e3ebdSchin 				else if (!(*fp->dirs)[m])
863da2e3ebdSchin 					goto next;
864da2e3ebdSchin 				fp->dirs++;
865da2e3ebdSchin 				fp->lens++;
866da2e3ebdSchin 			}
867da2e3ebdSchin 		if (fp->verify && (*p == '/' || t == 1))
868da2e3ebdSchin 		{
869da2e3ebdSchin 			if ((n = p - fp->decode.path))
870da2e3ebdSchin 				*p = 0;
871da2e3ebdSchin 			else
872da2e3ebdSchin 				n = 1;
873da2e3ebdSchin 			if (fp->verifyf)
874da2e3ebdSchin 				n = (*fp->verifyf)(fp, fp->decode.path, n, fp->disc);
875da2e3ebdSchin 			else if (stat(fp->decode.path, &st))
876da2e3ebdSchin 				n = -1;
877da2e3ebdSchin 			else if ((unsigned long)st.st_mtime > fp->stamp)
878da2e3ebdSchin 				n = 1;
879da2e3ebdSchin 			else
880da2e3ebdSchin 				n = 0;
881da2e3ebdSchin 			*p = '/';
882da2e3ebdSchin 
883da2e3ebdSchin 			/*
884da2e3ebdSchin 			 * n<0	skip this subtree
885da2e3ebdSchin 			 * n==0 keep as is
886da2e3ebdSchin 			 * n>0	read this dir now
887da2e3ebdSchin 			 */
888da2e3ebdSchin 
889da2e3ebdSchin 			/* NOT IMPLEMENTED YET */
890da2e3ebdSchin 		}
891da2e3ebdSchin 		if (FF_OK_TYPE(fp, t))
892da2e3ebdSchin 		{
893da2e3ebdSchin 			if (fp->decode.end)
894da2e3ebdSchin 			{
895da2e3ebdSchin 				if (*(s = p) == '/')
896da2e3ebdSchin 					s--;
897da2e3ebdSchin 				if (*fp->decode.pattern == '/' && b > fp->decode.path)
898da2e3ebdSchin 					b--;
899da2e3ebdSchin 				for (; s >= b; s--)
900da2e3ebdSchin 					if (*s == *fp->decode.end || ignorecase && tolower(*s) == *fp->decode.end)
901da2e3ebdSchin 					{
902da2e3ebdSchin 						if (ignorecase)
903da2e3ebdSchin 							for (e = fp->decode.end - 1, q = s - 1; *e && (*q == *e || tolower(*q) == *e); e--, q--);
904da2e3ebdSchin 						else
905da2e3ebdSchin 							for (e = fp->decode.end - 1, q = s - 1; *e && *q == *e; e--, q--);
906da2e3ebdSchin 						if (!*e)
907da2e3ebdSchin 						{
908da2e3ebdSchin 							fp->decode.found = 1;
909da2e3ebdSchin 							if (!fp->decode.match || strgrpmatch(fp->decode.path, fp->decode.pattern, NiL, 0, STR_MAXIMAL|STR_LEFT|STR_RIGHT|ignorecase))
910da2e3ebdSchin 							{
911da2e3ebdSchin 								fp->decode.peek = c;
912da2e3ebdSchin 								if (*p == '/')
913da2e3ebdSchin 									*(fp->decode.restore = p) = 0;
914da2e3ebdSchin 								if (!fp->secure || !access(fp->decode.path, F_OK))
915da2e3ebdSchin 									return fp->decode.path;
916da2e3ebdSchin 							}
917da2e3ebdSchin 							break;
918da2e3ebdSchin 						}
919da2e3ebdSchin 					}
920da2e3ebdSchin 			}
921da2e3ebdSchin 			else if (!fp->decode.match || !(n = regexec(&fp->decode.re, fp->decode.path, 0, NiL, 0)))
922da2e3ebdSchin 			{
923da2e3ebdSchin 				fp->decode.peek = c;
924da2e3ebdSchin 				if (*p == '/' && p > fp->decode.path)
925da2e3ebdSchin 					*(fp->decode.restore = p) = 0;
926da2e3ebdSchin 				if (!fp->secure || !access(fp->decode.path, F_OK))
927da2e3ebdSchin 					return fp->decode.path;
928da2e3ebdSchin 			}
929da2e3ebdSchin 			else if (n != REG_NOMATCH)
930da2e3ebdSchin 			{
931da2e3ebdSchin 				if (fp->disc->errorf)
932da2e3ebdSchin 				{
933da2e3ebdSchin 					regerror(n, &fp->decode.re, fp->decode.temp, sizeof(fp->decode.temp));
934da2e3ebdSchin 					(*fp->disc->errorf)(fp, fp->disc, 2, "%s: %s", fp->decode.pattern, fp->decode.temp);
935da2e3ebdSchin 				}
936da2e3ebdSchin 				return 0;
937da2e3ebdSchin 			}
938da2e3ebdSchin 		}
939da2e3ebdSchin 	}
940da2e3ebdSchin }
941da2e3ebdSchin 
942da2e3ebdSchin /*
943da2e3ebdSchin  * add path to the code table
944da2e3ebdSchin  * paths are assumed to be in sort order
945da2e3ebdSchin  */
946da2e3ebdSchin 
947da2e3ebdSchin int
findwrite(register Find_t * fp,const char * path,size_t len,const char * type)948da2e3ebdSchin findwrite(register Find_t* fp, const char* path, size_t len, const char* type)
949da2e3ebdSchin {
950da2e3ebdSchin 	register unsigned char*	s;
951da2e3ebdSchin 	register unsigned char*	e;
952da2e3ebdSchin 	register unsigned char*	p;
953da2e3ebdSchin 	register int		n;
954da2e3ebdSchin 	register int		d;
955da2e3ebdSchin 	register Type_t*	x;
956da2e3ebdSchin 	register unsigned long	u;
957da2e3ebdSchin 
958da2e3ebdSchin 	if (!fp->generate)
959da2e3ebdSchin 		return -1;
960da2e3ebdSchin 	if (type && fp->method == FF_dir)
961da2e3ebdSchin 	{
962da2e3ebdSchin 		len = sfsprintf(fp->encode.mark, sizeof(fp->encode.mark), "%-.*s/", len, path);
963da2e3ebdSchin 		path = fp->encode.mark;
964da2e3ebdSchin 	}
965da2e3ebdSchin 	s = (unsigned char*)path;
966da2e3ebdSchin 	if (len <= 0)
967da2e3ebdSchin 		len = strlen(path);
968da2e3ebdSchin 	if (len < sizeof(fp->encode.path))
969da2e3ebdSchin 		e = s + len++;
970da2e3ebdSchin 	else
971da2e3ebdSchin 	{
972da2e3ebdSchin 		len = sizeof(fp->encode.path) - 1;
973da2e3ebdSchin 		e = s + len;
974da2e3ebdSchin 	}
975da2e3ebdSchin 	p = (unsigned char*)fp->encode.path;
976da2e3ebdSchin 	while (s < e)
977da2e3ebdSchin 	{
978da2e3ebdSchin 		if (*s != *p++)
979da2e3ebdSchin 			break;
980da2e3ebdSchin 		s++;
981da2e3ebdSchin 	}
982da2e3ebdSchin 	n = s - (unsigned char*)path;
983da2e3ebdSchin 	switch (fp->method)
984da2e3ebdSchin 	{
985da2e3ebdSchin 	case FF_gnu:
986da2e3ebdSchin 		d = n - fp->encode.prefix;
987da2e3ebdSchin 		if (d >= -127 && d <= 127)
988da2e3ebdSchin 			sfputc(fp->fp, d & 0xff);
989da2e3ebdSchin 		else
990da2e3ebdSchin 		{
991da2e3ebdSchin 			sfputc(fp->fp, 0x80);
992da2e3ebdSchin 			sfputc(fp->fp, (d >> 8) & 0xff);
993da2e3ebdSchin 			sfputc(fp->fp, d & 0xff);
994da2e3ebdSchin 		}
995da2e3ebdSchin 		fp->encode.prefix = n;
996da2e3ebdSchin 		sfputr(fp->fp, (char*)s, 0);
997da2e3ebdSchin 		break;
998da2e3ebdSchin 	case FF_old:
999da2e3ebdSchin 		sfprintf(fp->fp, "%ld", n - fp->encode.prefix + FF_OFF);
1000da2e3ebdSchin 		fp->encode.prefix = n;
1001da2e3ebdSchin 		sfputc(fp->fp, ' ');
1002da2e3ebdSchin 		p = s;
1003da2e3ebdSchin 		while (s < e)
1004da2e3ebdSchin 		{
1005da2e3ebdSchin 			n = *s++;
1006da2e3ebdSchin 			if (s >= e)
1007da2e3ebdSchin 				break;
1008da2e3ebdSchin 			fp->encode.code[n][*s++]++;
1009da2e3ebdSchin 		}
1010da2e3ebdSchin 		while (p < e)
1011da2e3ebdSchin 		{
1012da2e3ebdSchin 			if ((n = *p++) < FF_MIN || n >= FF_MAX)
1013da2e3ebdSchin 				n = '?';
1014da2e3ebdSchin 			sfputc(fp->fp, n);
1015da2e3ebdSchin 		}
1016da2e3ebdSchin 		sfputc(fp->fp, 0);
1017da2e3ebdSchin 		break;
1018da2e3ebdSchin 	case FF_typ:
1019da2e3ebdSchin 		if (type)
1020da2e3ebdSchin 		{
1021da2e3ebdSchin 			type = (const char*)typefix((char*)fp->encode.bigram, sizeof(fp->encode.bigram), type);
1022da2e3ebdSchin 			if (x = (Type_t*)dtmatch(fp->encode.namedict, type))
1023da2e3ebdSchin 				u = x->index;
1024da2e3ebdSchin 			else if (!(x = newof(0, Type_t, 1, strlen(type) + 1)))
1025da2e3ebdSchin 				u = 0;
1026da2e3ebdSchin 			else
1027da2e3ebdSchin 			{
1028da2e3ebdSchin 				u = x->index = ++fp->types;
1029da2e3ebdSchin 				strcpy(x->name, type);
1030da2e3ebdSchin 				dtinsert(fp->encode.namedict, x);
1031da2e3ebdSchin 				dtinsert(fp->encode.indexdict, x);
1032da2e3ebdSchin 			}
1033da2e3ebdSchin 		}
1034da2e3ebdSchin 		else
1035da2e3ebdSchin 			u = 0;
1036da2e3ebdSchin 		sfputu(fp->fp, u);
1037da2e3ebdSchin 		/*FALLTHROUGH...*/
1038da2e3ebdSchin 	case FF_dir:
1039da2e3ebdSchin 		d = n - fp->encode.prefix;
1040da2e3ebdSchin 		sfputl(fp->fp, d);
1041da2e3ebdSchin 		fp->encode.prefix = n;
1042da2e3ebdSchin 		sfputr(fp->fp, (char*)s, 0);
1043da2e3ebdSchin 		break;
1044da2e3ebdSchin 	}
1045da2e3ebdSchin 	memcpy(fp->encode.path, path, len);
1046da2e3ebdSchin 	return 0;
1047da2e3ebdSchin }
1048da2e3ebdSchin 
1049da2e3ebdSchin /*
1050da2e3ebdSchin  * findsync() helper
1051da2e3ebdSchin  */
1052da2e3ebdSchin 
1053da2e3ebdSchin static int
finddone(register Find_t * fp)1054da2e3ebdSchin finddone(register Find_t* fp)
1055da2e3ebdSchin {
1056da2e3ebdSchin 	int	r;
1057da2e3ebdSchin 
1058da2e3ebdSchin 	if (sfsync(fp->fp))
1059da2e3ebdSchin 	{
1060da2e3ebdSchin 		if (fp->disc->errorf)
1061da2e3ebdSchin 			(*fp->disc->errorf)(fp, fp->disc, 2, "%s: write error [sfsync]", fp->encode.file);
1062da2e3ebdSchin 		return -1;
1063da2e3ebdSchin 	}
1064da2e3ebdSchin 	if (sferror(fp->fp))
1065da2e3ebdSchin 	{
1066da2e3ebdSchin 		if (fp->disc->errorf)
1067da2e3ebdSchin 			(*fp->disc->errorf)(fp, fp->disc, 2, "%s: write error [sferror]", fp->encode.file);
1068da2e3ebdSchin 		return -1;
1069da2e3ebdSchin 	}
1070da2e3ebdSchin 	r = sfclose(fp->fp);
1071da2e3ebdSchin 	fp->fp = 0;
1072da2e3ebdSchin 	if (r)
1073da2e3ebdSchin 	{
1074da2e3ebdSchin 		if (fp->disc->errorf)
1075da2e3ebdSchin 			(*fp->disc->errorf)(fp, fp->disc, 2, "%s: write error [sfclose]", fp->encode.file);
1076da2e3ebdSchin 		return -1;
1077da2e3ebdSchin 	}
1078da2e3ebdSchin 	return 0;
1079da2e3ebdSchin }
1080da2e3ebdSchin 
1081da2e3ebdSchin /*
1082da2e3ebdSchin  * finish the code table
1083da2e3ebdSchin  */
1084da2e3ebdSchin 
1085da2e3ebdSchin static int
findsync(register Find_t * fp)1086da2e3ebdSchin findsync(register Find_t* fp)
1087da2e3ebdSchin {
1088da2e3ebdSchin 	register char*		s;
1089da2e3ebdSchin 	register int		n;
1090da2e3ebdSchin 	register int		m;
1091da2e3ebdSchin 	register int		d;
1092da2e3ebdSchin 	register Type_t*	x;
1093da2e3ebdSchin 	char*			t;
1094da2e3ebdSchin 	int			b;
1095da2e3ebdSchin 	long			z;
1096da2e3ebdSchin 	Sfio_t*			sp;
1097da2e3ebdSchin 
1098da2e3ebdSchin 	switch (fp->method)
1099da2e3ebdSchin 	{
1100da2e3ebdSchin 	case FF_dir:
1101da2e3ebdSchin 	case FF_gnu:
1102da2e3ebdSchin 		/*
1103da2e3ebdSchin 		 * replace the real file with the temp file
1104da2e3ebdSchin 		 */
1105da2e3ebdSchin 
1106da2e3ebdSchin 		if (finddone(fp))
1107da2e3ebdSchin 			goto bad;
1108da2e3ebdSchin 		remove(fp->encode.file);
1109da2e3ebdSchin 		if (rename(fp->encode.temp, fp->encode.file))
1110da2e3ebdSchin 		{
1111da2e3ebdSchin 			if (fp->disc->errorf)
1112da2e3ebdSchin 				(*fp->disc->errorf)(fp, fp->disc, ERROR_SYSTEM|2, "%s: cannot rename from tmp file %s", fp->encode.file, fp->encode.temp);
1113da2e3ebdSchin 			remove(fp->encode.temp);
1114da2e3ebdSchin 			return -1;
1115da2e3ebdSchin 		}
1116da2e3ebdSchin 		break;
1117da2e3ebdSchin 	case FF_old:
1118da2e3ebdSchin 		/*
1119da2e3ebdSchin 		 * determine the top FF_MAX bigrams
1120da2e3ebdSchin 		 */
1121da2e3ebdSchin 
1122da2e3ebdSchin 		for (n = 0; n < FF_MAX; n++)
1123da2e3ebdSchin 			for (m = 0; m < FF_MAX; m++)
1124da2e3ebdSchin 				fp->encode.hits[fp->encode.code[n][m]]++;
1125da2e3ebdSchin 		fp->encode.hits[0] = 0;
1126da2e3ebdSchin 		m = 1;
1127da2e3ebdSchin 		for (n = USHRT_MAX; n >= 0; n--)
1128da2e3ebdSchin 			if (d = fp->encode.hits[n])
1129da2e3ebdSchin 			{
1130da2e3ebdSchin 				fp->encode.hits[n] = m;
1131da2e3ebdSchin 				if ((m += d) > FF_MAX)
1132da2e3ebdSchin 					break;
1133da2e3ebdSchin 			}
1134da2e3ebdSchin 		while (--n >= 0)
1135da2e3ebdSchin 			fp->encode.hits[n] = 0;
1136da2e3ebdSchin 		for (n = FF_MAX - 1; n >= 0; n--)
1137da2e3ebdSchin 			for (m = FF_MAX - 1; m >= 0; m--)
1138da2e3ebdSchin 				if (fp->encode.hits[fp->encode.code[n][m]])
1139da2e3ebdSchin 				{
1140da2e3ebdSchin 					d = fp->encode.code[n][m];
1141da2e3ebdSchin 					b = fp->encode.hits[d] - 1;
1142da2e3ebdSchin 					fp->encode.code[n][m] = b + FF_MAX;
1143da2e3ebdSchin 					if (fp->encode.hits[d]++ >= FF_MAX)
1144da2e3ebdSchin 						fp->encode.hits[d] = 0;
1145da2e3ebdSchin 					fp->encode.bigram[b *= 2] = n;
1146da2e3ebdSchin 					fp->encode.bigram[b + 1] = m;
1147da2e3ebdSchin 				}
1148da2e3ebdSchin 				else
1149da2e3ebdSchin 					fp->encode.code[n][m] = 0;
1150da2e3ebdSchin 
1151da2e3ebdSchin 		/*
1152da2e3ebdSchin 		 * commit the real file
1153da2e3ebdSchin 		 */
1154da2e3ebdSchin 
1155da2e3ebdSchin 		if (sfseek(fp->fp, (Sfoff_t)0, SEEK_SET))
1156da2e3ebdSchin 		{
1157da2e3ebdSchin 			if (fp->disc->errorf)
1158da2e3ebdSchin 				(*fp->disc->errorf)(fp, fp->disc, ERROR_SYSTEM|2, "cannot rewind tmp file");
1159da2e3ebdSchin 			return -1;
1160da2e3ebdSchin 		}
1161da2e3ebdSchin 		if (!(sp = sfopen(NiL, fp->encode.file, "w")))
1162da2e3ebdSchin 			goto badcreate;
1163da2e3ebdSchin 
1164da2e3ebdSchin 		/*
1165da2e3ebdSchin 		 * dump the bigrams
1166da2e3ebdSchin 		 */
1167da2e3ebdSchin 
1168da2e3ebdSchin 		sfwrite(sp, fp->encode.bigram, sizeof(fp->encode.bigram));
1169da2e3ebdSchin 
1170da2e3ebdSchin 		/*
1171da2e3ebdSchin 		 * encode the massaged paths
1172da2e3ebdSchin 		 */
1173da2e3ebdSchin 
1174da2e3ebdSchin 		while (s = sfgetr(fp->fp, 0, 0))
1175da2e3ebdSchin 		{
1176da2e3ebdSchin 			z = strtol(s, &t, 0);
1177da2e3ebdSchin 			s = t;
1178da2e3ebdSchin 			if (z < 0 || z > 2 * FF_OFF)
1179da2e3ebdSchin 			{
1180da2e3ebdSchin 				sfputc(sp, FF_ESC);
1181da2e3ebdSchin 				sfputc(sp, (z >> 24));
1182da2e3ebdSchin 				sfputc(sp, (z >> 16));
1183da2e3ebdSchin 				sfputc(sp, (z >> 8));
1184da2e3ebdSchin 				sfputc(sp, z);
1185da2e3ebdSchin 			}
1186da2e3ebdSchin 			else
1187da2e3ebdSchin 				sfputc(sp, z);
1188da2e3ebdSchin 			while (n = *s++)
1189da2e3ebdSchin 			{
1190da2e3ebdSchin 				if (!(m = *s++))
1191da2e3ebdSchin 				{
1192da2e3ebdSchin 					sfputc(sp, n);
1193da2e3ebdSchin 					break;
1194da2e3ebdSchin 				}
1195da2e3ebdSchin 				if (d = fp->encode.code[n][m])
1196da2e3ebdSchin 					sfputc(sp, d);
1197da2e3ebdSchin 				else
1198da2e3ebdSchin 				{
1199da2e3ebdSchin 					sfputc(sp, n);
1200da2e3ebdSchin 					sfputc(sp, m);
1201da2e3ebdSchin 				}
1202da2e3ebdSchin 			}
1203da2e3ebdSchin 		}
1204da2e3ebdSchin 		sfclose(fp->fp);
1205da2e3ebdSchin 		fp->fp = sp;
1206da2e3ebdSchin 		if (finddone(fp))
1207da2e3ebdSchin 			goto bad;
1208da2e3ebdSchin 		break;
1209da2e3ebdSchin 	case FF_typ:
1210da2e3ebdSchin 		if (finddone(fp))
1211da2e3ebdSchin 			goto bad;
1212da2e3ebdSchin 		if (!(fp->fp = sfopen(NiL, fp->encode.temp, "r")))
1213da2e3ebdSchin 		{
1214da2e3ebdSchin 			if (fp->disc->errorf)
1215da2e3ebdSchin 				(*fp->disc->errorf)(fp, fp->disc, ERROR_SYSTEM|2, "%s: cannot read tmp file", fp->encode.temp);
1216da2e3ebdSchin 			remove(fp->encode.temp);
1217da2e3ebdSchin 			return -1;
1218da2e3ebdSchin 		}
1219da2e3ebdSchin 
1220da2e3ebdSchin 		/*
1221da2e3ebdSchin 		 * commit the output file
1222da2e3ebdSchin 		 */
1223da2e3ebdSchin 
1224da2e3ebdSchin 		if (!(sp = sfopen(NiL, fp->encode.file, "w")))
1225da2e3ebdSchin 			goto badcreate;
1226da2e3ebdSchin 
1227da2e3ebdSchin 		/*
1228da2e3ebdSchin 		 * write the header magic
1229da2e3ebdSchin 		 */
1230da2e3ebdSchin 
1231da2e3ebdSchin 		sfputc(sp, 0);
1232da2e3ebdSchin 		sfputr(sp, FF_typ_magic, 0);
1233da2e3ebdSchin 
1234da2e3ebdSchin 		/*
1235da2e3ebdSchin 		 * write the type table in index order starting with 1
1236da2e3ebdSchin 		 */
1237da2e3ebdSchin 
1238da2e3ebdSchin 		for (x = (Type_t*)dtfirst(fp->encode.indexdict); x; x = (Type_t*)dtnext(fp->encode.indexdict, x))
1239da2e3ebdSchin 			sfputr(sp, x->name, 0);
1240da2e3ebdSchin 		sfputc(sp, 0);
1241da2e3ebdSchin 
1242da2e3ebdSchin 		/*
1243da2e3ebdSchin 		 * append the front compressed strings
1244da2e3ebdSchin 		 */
1245da2e3ebdSchin 
1246da2e3ebdSchin 		if (sfmove(fp->fp, sp, SF_UNBOUND, -1) < 0 || !sfeof(fp->fp))
1247da2e3ebdSchin 		{
1248da2e3ebdSchin 			sfclose(sp);
1249da2e3ebdSchin 			if (fp->disc->errorf)
1250da2e3ebdSchin 				(*fp->disc->errorf)(fp, fp->disc, 2, "%s: cannot append codes", fp->encode.file);
1251da2e3ebdSchin 			goto bad;
1252da2e3ebdSchin 		}
1253da2e3ebdSchin 		sfclose(fp->fp);
1254da2e3ebdSchin 		fp->fp = sp;
1255da2e3ebdSchin 		if (finddone(fp))
1256da2e3ebdSchin 			goto bad;
1257da2e3ebdSchin 		remove(fp->encode.temp);
1258da2e3ebdSchin 		break;
1259da2e3ebdSchin 	}
1260da2e3ebdSchin 	return 0;
1261da2e3ebdSchin  badcreate:
1262da2e3ebdSchin 	if (fp->disc->errorf)
1263da2e3ebdSchin 		(*fp->disc->errorf)(fp, fp->disc, 2, "%s: cannot write codes", fp->encode.file);
1264da2e3ebdSchin  bad:
1265da2e3ebdSchin 	if (fp->fp)
1266da2e3ebdSchin 	{
1267da2e3ebdSchin 		sfclose(fp->fp);
1268da2e3ebdSchin 		fp->fp = 0;
1269da2e3ebdSchin 	}
1270da2e3ebdSchin 	remove(fp->encode.temp);
1271da2e3ebdSchin 	return -1;
1272da2e3ebdSchin }
1273da2e3ebdSchin 
1274da2e3ebdSchin /*
1275da2e3ebdSchin  * close an open fastfind stream
1276da2e3ebdSchin  */
1277da2e3ebdSchin 
1278da2e3ebdSchin int
findclose(register Find_t * fp)1279da2e3ebdSchin findclose(register Find_t* fp)
1280da2e3ebdSchin {
1281da2e3ebdSchin 	int	n = 0;
1282da2e3ebdSchin 
1283da2e3ebdSchin 	if (!fp)
1284da2e3ebdSchin 		return -1;
1285da2e3ebdSchin 	if (fp->generate)
1286da2e3ebdSchin 	{
1287da2e3ebdSchin 		n = findsync(fp);
1288da2e3ebdSchin 		if (fp->encode.indexdict)
1289da2e3ebdSchin 			dtclose(fp->encode.indexdict);
1290da2e3ebdSchin 		if (fp->encode.namedict)
1291da2e3ebdSchin 			dtclose(fp->encode.namedict);
1292da2e3ebdSchin 	}
1293da2e3ebdSchin 	else
1294da2e3ebdSchin 	{
1295da2e3ebdSchin 		if (fp->decode.match)
1296da2e3ebdSchin 			regfree(&fp->decode.re);
1297da2e3ebdSchin 		n = 0;
1298da2e3ebdSchin 	}
1299da2e3ebdSchin 	if (fp->fp)
1300da2e3ebdSchin 		sfclose(fp->fp);
1301da2e3ebdSchin 	vmclose(fp->vm);
1302da2e3ebdSchin 	return n;
1303da2e3ebdSchin }
1304