register FTS *sp; register FTSENT *p, *root; register int nitems;
FTS *sp; FTSENT *p, *root; int nitems;
fts_open(argv, options, compar)	char * const *argv;	register int options;	int (*compar) __P((const FTSENT **, const FTSENT **));{	register FTS *sp;	register FTSENT *p, *root;	register int nitems;	FTSENT *parent, *tmp;	int len;	/* Options check. */	if (options & ~FTS_OPTIONMASK) {		errno = EINVAL;		return (NULL);	}	/* Allocate/initialize the stream */	if ((sp = malloc((u_int)sizeof(FTS))) == NULL)		return (NULL);	memset(sp, 0, sizeof(FTS));	sp->fts_compar = compar;	sp->fts_options = options;	/* Logical walks turn on NOCHDIR; symbolic links are too hard. */	if (ISSET(FTS_LOGICAL))		SET(FTS_NOCHDIR);	/*	 * Start out with 1K of path space, and enough, in any case,	 * to hold the user's paths.	 */	if (fts_palloc(sp, MAX(fts_maxarglen(argv), MAXPATHLEN)))		goto mem1;	/* Allocate/initialize root's parent. */	if ((parent = fts_alloc(sp, "", 0)) == NULL)		goto mem2;	parent->fts_level = FTS_ROOTPARENTLEVEL;	/* Allocate/initialize root(s). */	for (root = NULL, nitems = 0; *argv; ++argv, ++nitems) {		/* Don't allow zero-length paths. */		if ((len = strlen(*argv)) == 0) {			errno = ENOENT;			goto mem3;		}		p = fts_alloc(sp, *argv, len);		p->fts_level = FTS_ROOTLEVEL;		p->fts_parent = parent;		p->fts_accpath = p->fts_name;		p->fts_info = fts_stat(sp, p, ISSET(FTS_COMFOLLOW));		/* Command-line "." and ".." are real directories. */		if (p->fts_info == FTS_DOT)			p->fts_info = FTS_D;		/*		 * If comparison routine supplied, traverse in sorted		 * order; otherwise traverse in the order specified.		 */		if (compar) {			p->fts_link = root;			root = p;		} else {			p->fts_link = NULL;			if (root == NULL)				tmp = root = p;			else {				tmp->fts_link = p;				tmp = p;			}		}	}	if (compar && nitems > 1)		root = fts_sort(sp, root, nitems);	/*	 * Allocate a dummy pointer and make fts_read think that we've just	 * finished the node before the root(s); set p->fts_info to FTS_INIT	 * so that everything about the "current" node is ignored.	 */	if ((sp->fts_cur = fts_alloc(sp, "", 0)) == NULL)		goto mem3;	sp->fts_cur->fts_link = root;	sp->fts_cur->fts_info = FTS_INIT;	/*	 * If using chdir(2), grab a file descriptor pointing to dot to ensure	 * that we can get back here; this could be avoided for some paths,	 * but almost certainly not worth the effort.  Slashes, symbolic links,	 * and ".." are all fairly nasty problems.  Note, if we can't get the	 * descriptor we run anyway, just more slowly.	 */	if (!ISSET(FTS_NOCHDIR) && (sp->fts_rfd = open(".", O_RDONLY, 0)) < 0)		SET(FTS_NOCHDIR);	return (sp);mem3:	fts_lfree(root);	free(parent);mem2:	free(sp->fts_path);mem1:	free(sp);	return (NULL);}