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