1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1985-2010 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Common Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
8 * *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
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 case FTS_SLNONE:
139 e->info = FTS_NS;
140 break;
141 case FTS_NSOK:
142 e->info = FTS_NSOK;
143 break;
144 }
145 rv = (*userf)((Ftw_t*)e);
146 e->info = oi;
147 if (e->status == ns)
148 e->status = os;
149 while (nd > 0)
150 dd[--nd]->info |= FTS_DD;
151 }
152 fts_close(f);
153 return rv;
154 }
155