/*********************************************************************** * * * This software is part of the ast package * * Copyright (c) 1985-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * * * * Information and Software Systems Research * * AT&T Research * * Florham Park NJ * * * * Glenn Fowler * * David Korn * * Phong Vo * * * ***********************************************************************/ #pragma prototyped /* * Glenn Fowler * AT&T Research * * ftwalk on top of fts */ #include #include static struct { int (*comparf)(Ftw_t*, Ftw_t*); } state; /* * why does fts take FTSENT** instead of FTSENT* */ static int ftscompare(Ftw_t* const* pf1, Ftw_t* const* pf2) { return (*state.comparf)(*pf1, *pf2); } /* * the real thing -- well it used to be */ int ftwalk(const char* path, int (*userf)(Ftw_t*), int flags, int (*comparf)(Ftw_t*, Ftw_t*)) { register FTS* f; register FTSENT* e; register int children; register int rv; int oi; int ns; int os; int nd; FTSENT* x; FTSENT* dd[2]; flags ^= FTS_ONEPATH; if (flags & FTW_TWICE) flags &= ~(FTS_NOPREORDER|FTS_NOPOSTORDER); else if (flags & FTW_POST) flags |= FTS_NOPREORDER; else flags |= FTS_NOPOSTORDER; if (children = flags & FTW_CHILDREN) flags |= FTS_SEEDOT; state.comparf = comparf; if (!(f = fts_open((char* const*)path, flags, comparf ? ftscompare : 0))) { if (!path || !(flags & FTS_ONEPATH) && !(path = (const char*)(*((char**)path)))) return -1; ns = strlen(path) + 1; if (!(e = newof(0, FTSENT, 1, ns))) return -1; e->fts_accpath = e->fts_name = e->fts_path = strcpy((char*)(e + 1), path); e->fts_namelen = e->fts_pathlen = ns; e->fts_info = FTS_NS; e->parent = e; e->parent->link = e; rv = (*userf)((Ftw_t*)e); free(e); return rv; } rv = 0; if (children && (e = fts_children(f, 0))) { nd = 0; for (x = e; x; x = x->link) if (x->info & FTS_DD) { x->statb = *x->fts_statp; x->info &= ~FTS_DD; dd[nd++] = x; if (nd >= elementsof(dd)) break; } e->parent->link = e; rv = (*userf)((Ftw_t*)e->parent); e->parent->link = 0; while (nd > 0) dd[--nd]->info |= FTS_DD; for (x = e; x; x = x->link) if (!(x->info & FTS_D)) x->status = FTS_SKIP; } while (!rv && (e = fts_read(f))) { oi = e->info; os = e->status; ns = e->status = e->path == e->fts_accpath ? FTW_PATH : FTW_NAME; nd = 0; switch (e->info) { case FTS_D: case FTS_DNX: if (children) for (x = fts_children(f, 0); x; x = x->link) if (x->info & FTS_DD) { x->statb = *x->fts_statp; x->info &= ~FTS_DD; dd[nd++] = x; if (nd >= elementsof(dd)) break; } break; case FTS_DOT: continue; case FTS_ERR: case FTS_SLNONE: e->info = FTS_NS; break; case FTS_NSOK: e->info = FTS_NSOK; break; } rv = (*userf)((Ftw_t*)e); e->info = oi; if (e->status == ns) e->status = os; while (nd > 0) dd[--nd]->info |= FTS_DD; } fts_close(f); return rv; }