1/***********************************************************************
2*                                                                      *
3*               This software is part of the ast package               *
4*          Copyright (c) 1985-2011 AT&T Intellectual Property          *
5*                      and is licensed under the                       *
6*                 Eclipse Public License, Version 1.0                  *
7*                    by AT&T Intellectual Property                     *
8*                                                                      *
9*                A copy of the License is available at                 *
10*          http://www.eclipse.org/org/documents/epl-v10.html           *
11*         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
12*                                                                      *
13*              Information and Software Systems Research               *
14*                            AT&T Research                             *
15*                           Florham Park NJ                            *
16*                                                                      *
17*                 Glenn Fowler <gsf@research.att.com>                  *
18*                  David Korn <dgk@research.att.com>                   *
19*                   Phong Vo <kpv@research.att.com>                    *
20*                                                                      *
21***********************************************************************/
22#pragma prototyped
23/*
24 * Glenn Fowler
25 * AT&T Research
26 *
27 * ftwalk on top of fts
28 */
29
30#include <ast.h>
31#include <ftwalk.h>
32
33static struct
34{
35	int	(*comparf)(Ftw_t*, Ftw_t*);
36} state;
37
38/*
39 * why does fts take FTSENT** instead of FTSENT*
40 */
41
42static int
43ftscompare(Ftw_t* const* pf1, Ftw_t* const* pf2)
44{
45	return (*state.comparf)(*pf1, *pf2);
46}
47
48/*
49 * the real thing -- well it used to be
50 */
51
52int
53ftwalk(const char* path, int (*userf)(Ftw_t*), int flags, int (*comparf)(Ftw_t*, Ftw_t*))
54{
55	register FTS*		f;
56	register FTSENT*	e;
57	register int		children;
58	register int		rv;
59	int			oi;
60	int			ns;
61	int			os;
62	int			nd;
63	FTSENT*			x;
64	FTSENT*			dd[2];
65
66	flags ^= FTS_ONEPATH;
67	if (flags & FTW_TWICE)
68		flags &= ~(FTS_NOPREORDER|FTS_NOPOSTORDER);
69	else if (flags & FTW_POST)
70		flags |= FTS_NOPREORDER;
71	else
72		flags |= FTS_NOPOSTORDER;
73	if (children = flags & FTW_CHILDREN)
74		flags |= FTS_SEEDOT;
75	state.comparf = comparf;
76	if (!(f = fts_open((char* const*)path, flags, comparf ? ftscompare : 0)))
77	{
78		if (!path || !(flags & FTS_ONEPATH) && !(path = (const char*)(*((char**)path))))
79			return -1;
80		ns = strlen(path) + 1;
81		if (!(e = newof(0, FTSENT, 1, ns)))
82			return -1;
83		e->fts_accpath = e->fts_name = e->fts_path = strcpy((char*)(e + 1), path);
84		e->fts_namelen = e->fts_pathlen = ns;
85		e->fts_info = FTS_NS;
86		e->parent = e;
87		e->parent->link = e;
88		rv = (*userf)((Ftw_t*)e);
89		free(e);
90		return rv;
91	}
92	rv = 0;
93	if (children && (e = fts_children(f, 0)))
94	{
95		nd = 0;
96		for (x = e; x; x = x->link)
97			if (x->info & FTS_DD)
98			{
99				x->statb = *x->fts_statp;
100				x->info &= ~FTS_DD;
101				dd[nd++] = x;
102				if (nd >= elementsof(dd))
103					break;
104			}
105		e->parent->link = e;
106		rv = (*userf)((Ftw_t*)e->parent);
107		e->parent->link = 0;
108		while (nd > 0)
109			dd[--nd]->info |= FTS_DD;
110		for (x = e; x; x = x->link)
111			if (!(x->info & FTS_D))
112				x->status = FTS_SKIP;
113	}
114	while (!rv && (e = fts_read(f)))
115	{
116		oi = e->info;
117		os = e->status;
118		ns = e->status = e->path == e->fts_accpath ? FTW_PATH : FTW_NAME;
119		nd = 0;
120		switch (e->info)
121		{
122		case FTS_D:
123		case FTS_DNX:
124			if (children)
125				for (x = fts_children(f, 0); x; x = x->link)
126					if (x->info & FTS_DD)
127					{
128						x->statb = *x->fts_statp;
129						x->info &= ~FTS_DD;
130						dd[nd++] = x;
131						if (nd >= elementsof(dd))
132							break;
133					}
134			break;
135		case FTS_DOT:
136			continue;
137		case FTS_ERR:
138			e->info = FTS_NS;
139			break;
140		case FTS_NSOK:
141			e->info = FTS_NSOK;
142			break;
143		case FTS_SLNONE:
144			e->info = FTS_SL;
145			break;
146		}
147		rv = (*userf)((Ftw_t*)e);
148		e->info = oi;
149		if (e->status == ns)
150			e->status = os;
151		while (nd > 0)
152			dd[--nd]->info |= FTS_DD;
153	}
154	fts_close(f);
155	return rv;
156}
157