xref: /illumos-gate/usr/src/contrib/ast/src/lib/libast/misc/ftwalk.c (revision b30d193948be5a7794d7ae3ba0ed9c2f72c88e0f)
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 
33 static struct
34 {
35 	int	(*comparf)(Ftw_t*, Ftw_t*);
36 } state;
37 
38 /*
39  * why does fts take FTSENT** instead of FTSENT*
40  */
41 
42 static int
ftscompare(Ftw_t * const * pf1,Ftw_t * const * pf2)43 ftscompare(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 
52 int
ftwalk(const char * path,int (* userf)(Ftw_t *),int flags,int (* comparf)(Ftw_t *,Ftw_t *))53 ftwalk(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