/*
 *	tree.c
 *
 *	Tree Mode Module
 */

#include "fd.h"
#include "func.h"
#include "kanji.h"

#ifndef	_NOTREE

#if	MSDOS && !defined (_NODOSDRIVE)
extern int preparedrv __P_((int));
#endif


extern char fullpath[];
extern int win_x;
extern int win_y;
#ifndef	_NODOSDRIVE
extern int lastdrv;
#endif
extern int tradlayout;
extern int sizeinfo;

#define	DIRFIELD	3
#define	TREEFIELD	(((dircountlimit > 0) \
			? (n_column * 3) / 5 : n_column) - 2)
#define	FILEFIELD	((dircountlimit > 0) ? (n_column * 2) / 5 - 3 : 0)
#define	bufptr(y)	(&(tr_scr[(y - LFILETOP - 1) * (TREEFIELD + 1)]))

static int NEAR evaldir __P_((char *, int));
static treelist *NEAR maketree __P_((char *, treelist *, treelist *,
		int, int *));
static int NEAR _showtree __P_((treelist *, int, int, int));
static VOID NEAR showtree __P_((VOID_A));
static VOID NEAR treebar __P_((VOID_A));
static treelist *NEAR _searchtree __P_((treelist *, int, int));
static VOID NEAR searchtree __P_((VOID_A));
static int NEAR expandtree __P_((treelist *));
static int NEAR expandall __P_((treelist *));
static int NEAR treeup __P_((VOID_A));
static int NEAR treedown __P_((VOID_A));
static int NEAR freetree __P_((treelist *, int));
static VOID NEAR _tree_search __P_((VOID_A));
static int NEAR _tree_input __P_((VOID_A));
static char *NEAR _tree __P_((VOID_A));

int sorttree = 0;
int dircountlimit = 0;

static int redraw = 0;
static int tr_no = 0;
static int tr_line = 0;
static int tr_top = 0;
static int tr_bottom = 0;
static char *tr_scr = NULL;
static treelist *tr_root = NULL;
static treelist *tr_cur = NULL;


static int NEAR evaldir(dir, disp)
char *dir;
int disp;
{
	DIR *dirp;
	struct dirent *dp;
	struct stat st;
	char path[MAXPATHLEN];
	int i, x, y, w, len, limit;
#if	MSDOS
	char *cp;
#endif

	if ((limit = dircountlimit) <= 0) return(1);

	if (disp) for (i = LFILETOP + 1; i < LFILEBOTTOM; i++) {
		locate(TREEFIELD + 2, i);
		putch2('|');
		putterm(l_clear);
	}
	strcpy(path, dir);
#if	MSDOS
	cp = path;
	if (_dospath(cp)) cp += 2;
	if (strcmp(cp, _SS_)) strcatdelim(path);
#else
	if (strcmp(path, _SS_)) strcatdelim(path);
#endif
	len = strlen(path);
	i = x = 0;
	y = LFILETOP + 1;
	w = FILEFIELD / 2;
	if (!(dirp = Xopendir(dir))) return(0);
	while ((dp = Xreaddir(dirp))) {
		if (isdotdir(dp -> d_name)) continue;
		strcpy(&(path[len]), dp -> d_name);
		if (limit-- <= 0 || (stat2(path, &st) >= 0 && s_isdir(&st))) {
			if (!disp) {
				i++;
				break;
			}
		}
		else if (disp) {
			locate(x + TREEFIELD + 4, y);
			cprintf2("%-*.*k", w, w, dp -> d_name);
			i++;
			if (++y >= LFILEBOTTOM) {
				y = LFILETOP + 1;
				x += w + 1;
				if (x >= w * 2 + 2) break;
			}
		}
	}
	if (disp && !i) {
		locate(x + TREEFIELD + 4, LFILETOP + 1);
		cprintf2("%-*.*s", w, w, "[No Files]");
	}
	Xclosedir(dirp);
	return(i);
}

/*ARGSUSED*/
static treelist *NEAR maketree(path, list, parent, level, maxp)
char *path;
treelist *list, *parent;
int level, *maxp;
{
	DIR *dirp;
	struct dirent *dp;
	struct stat st;
	char *cp, *dir, *subdir, cwd[MAXPATHLEN];
#ifdef	_USEDOSEMU
	char tmp[MAXPATHLEN];
#endif
	int i, len;

	if ((level + 1) * DIRFIELD + 2 > TREEFIELD) {
		*maxp = -2;
		return(NULL);
	}
	if (intrkey()) {
		*maxp = -1;
		return(NULL);
	}
	if (!Xgetwd(cwd)) {
		*maxp = 0;
		return(NULL);
	}

#if	MSDOS
	if (_dospath(path)) path += 2;
#endif
	if (*path == _SC_) {
		dir = strdup2(_SS_);
		subdir = path + 1;
		if (!*subdir) subdir = NULL;
	}
#ifdef	_USEDOSEMU
	else if (_dospath(path)) {
		dir = strndup2(path, 3);
		subdir = path + 3;
		if (!*subdir) subdir = NULL;
	}
#endif
	else {
		len = (cp = strdelim(path, 0)) ? cp - path : strlen(path);
		dir = strndup2(path, len);
		subdir = (cp) ? cp + 1 : NULL;
	}

	if (!subdir) len = 0;
	else len = (cp = strdelim(subdir, 0)) ? cp - subdir : strlen(subdir);

	*maxp = 0;
	i = _chdir2(dir);
	free(dir);
	if (i < 0 || !(dirp = Xopendir("."))) return(NULL);

	i = 0;
	while ((dp = Xreaddir(dirp))) {
		if (isdotdir(dp -> d_name)
		|| Xstat(nodospath(tmp, dp -> d_name), &st) < 0
		|| !s_isdir(&st))
			continue;
		list = b_realloc(list, *maxp, treelist);
		if (!subdir) {
			list[*maxp].name = strdup2(dp -> d_name);
			list[*maxp].sub = NULL;
			list[*maxp].max = 0;
#ifndef	NODIRLOOP
			list[*maxp].dev = st.st_dev;
			list[*maxp].ino = st.st_ino;
			list[*maxp].parent = parent;
#endif
			(*maxp)++;
		}
		else if (!strnpathcmp(dp -> d_name, subdir, len)
		&& strlen(dp -> d_name) == len) {
			list[0].name = strdup2(dp -> d_name);
			list[0].sub = &(list[0]);
			list[0].max = 0;
#ifndef	NODIRLOOP
			list[0].dev = st.st_dev;
			list[0].ino = st.st_ino;
			list[0].parent = parent;
#endif
			if (++(*maxp) >= 2) break;
		}
		else {
			if (!(*maxp)) {
				list[0].name = NULL;
				list[0].sub = NULL;
				list[0].max = -1;
#ifndef	NODIRLOOP
				list[0].dev = 0;
				list[0].ino = 0;
				list[0].parent = NULL;
#endif
			}
			if (!i) {
				i++;
				list[1].name = NULL;
				list[1].sub = NULL;
				list[1].max = -1;
#ifndef	NODIRLOOP
				list[1].dev = 0;
				list[1].ino = 0;
				list[1].parent = NULL;
#endif
				if (++(*maxp) >= 2) break;
			}
		}
	}
	Xclosedir(dirp);
	if (list) for (i = 0; i < *maxp; i++) {
#ifndef	NODIRLOOP
		treelist *lp;

		if (!(list[i].name)) lp = NULL;
		else for (lp = parent; lp; lp = lp -> parent)
			if (lp -> dev == list[i].dev
			&& lp -> ino == list[i].ino) break;
		if (lp) {
			list[i].sub = NULL;
			list[i].max = 0;
		}
		else
#endif
		if (list[i].sub)
			list[i].sub = maketree(subdir, NULL, &(list[i]),
				level + 1, &(list[i].max));
		else {
			if (list[i].max >= 0 && list[i].name
			&& evaldir(nodospath(tmp, list[i].name), 0))
				list[i].max = -1;
		}
	}
	if (sorttree && sorton) qsort(list, *maxp, sizeof(treelist), cmptree);

#if	MSDOS
	if (_dospath(path)) path += 2;
#endif
#if	MSDOS || defined (_NODOSDRIVE)
	if (*path == _SC_)
#else
	if (*path == _SC_ || _dospath(path))
#endif
	{
		if (_chdir2(fullpath) < 0) error(fullpath);
	}
	else if (strcmp(path, ".") && _chdir2(cwd) < 0) error("..");
	return(list);
}

static int NEAR _showtree(list, max, nest, y)
treelist *list;
int max, nest, y;
{
	char *cp;
	int i, j, w, tmp;

	w = TREEFIELD - (nest * DIRFIELD) - 1;
	tmp = y;
	for (i = 0; i < max; i++) {
		if (nest > 0) {
			for (j = tmp; j < y; j++)
			if (j > LFILETOP && j < LFILEBOTTOM)
				*(bufptr(j) + (nest - 1) * DIRFIELD) = '|';
		}
		if (y > LFILETOP && y < LFILEBOTTOM) {
			cp = bufptr(y);
			if (nest > 0)
				memcpy(&(cp[(nest - 1) * DIRFIELD]), "+--", 3);
			if (!(list[i].name)) {
				tmp = (w > 3) ? 3 : w;
				memcpy(&(cp[nest * DIRFIELD]), "...", tmp);
			}
			else {
				tmp = strlen(list[i].name);
				if (tmp > w) tmp = w;
				memcpy(&(cp[nest * DIRFIELD]),
					list[i].name, tmp);
				if (list[i].max < 0)
					cp[nest * DIRFIELD + tmp] = '>';
			}
		}
		y++;
		tmp = y;
		if (w >= DIRFIELD && list[i].sub)
			y = _showtree(list[i].sub, list[i].max, nest + 1, y);
	}
	return(y);
}

static VOID NEAR showtree(VOID_A)
{
	int i;

	for (i = LFILETOP; i <= LFILEBOTTOM; i++) {
		locate(0, i);
		putterm(l_clear);
	}
	for (i = LFILETOP + 1; i < LFILEBOTTOM; i++) {
		memset(bufptr(i), ' ', TREEFIELD);
		bufptr(i)[TREEFIELD] = '\0';
	}
	_showtree(tr_root -> sub, 1, 0, tr_top);
	for (i = LFILETOP + 1; i < LFILEBOTTOM; i++) {
		locate(1, i);
		if (i == tr_line) putterm(t_standout);
		cprintf2("%-*.*k", TREEFIELD, TREEFIELD, bufptr(i));
		if (i == tr_line) putterm(end_standout);
	}
	evaldir(treepath, 1);
	keyflush();
}

static VOID NEAR treebar(VOID_A)
{
	locate(1, LFILETOP);
	cprintf2("Tree=%-*.*k", n_column - 6, n_column - 6, treepath);
	locate(0, L_MESLINE);
	putterm(l_clear);
}

VOID rewritetree(VOID_A)
{
	tr_scr = realloc2(tr_scr, (FILEPERROW - 1) * (TREEFIELD + 1));
	searchtree();
	showtree();
	treebar();
	tflush();
}

static treelist *NEAR _searchtree(list, max, nest)
treelist *list;
int max, nest;
{
	treelist *lp, *tmplp;
	int i, w, len;

	lp = NULL;
	w = TREEFIELD - (nest * DIRFIELD) - 1;
	for (i = 0; i < max; i++) {
		if (tr_bottom == tr_line) {
			lp = tr_root;
			tr_no = i;
			if (list[i].name) strcpy(treepath, list[i].name);
			else *treepath = '\0';
		}
		tr_bottom++;
		if (w >= DIRFIELD && list[i].sub) {
			tmplp = _searchtree(list[i].sub, list[i].max,
				nest + 1);
			if (tmplp) {
				lp = (tmplp == tr_root) ? &(list[i]) : tmplp;
				len = strlen(list[i].name);
#if	MSDOS
				if (!_dospath(list[i].name)
				|| list[i].name[2] != _SC_) len++;
				memmove(&(treepath[len]), treepath,
					strlen(treepath) + 1);
				memcpy(treepath, list[i].name, len - 1);
#else	/* !MSDOS */
# ifdef	_NODOSDRIVE
				if (*list[i].name != _SC_) len++;
# else
				if (*list[i].name != _SC_
				&& !_dospath(list[i].name)) len++;
# endif
				memmove(&(treepath[len]), treepath,
					strlen(treepath) + 1);
				if (*list[i].name != _SC_)
					memcpy(treepath, list[i].name,
						len - 1);
#endif	/* !MSDOS */
				treepath[len - 1] = _SC_;
			}
		}
	}
	return(lp);
}

static VOID NEAR searchtree(VOID_A)
{
	tr_bottom = tr_top;
	tr_cur = _searchtree(tr_root -> sub, 1, 0);
}

static int NEAR expandtree(list)
treelist *list;
{
	treelist *lp, *lptmp;
	char *cp;
	int i;

	lp = NULL;
	if (list -> sub) {
		lp = (treelist *)malloc2(sizeof(treelist));
		memcpy((char *)lp, (char *)&(list -> sub[0]),
			sizeof(treelist));
		for (i = 1; i < list -> max; i++)
			if ((list -> sub[i]).name) {
				free((list -> sub[i]).name);
				(list -> sub[i]).name = NULL;
			}
	}

	if (_chdir2(treepath) < 0) {
		if (list -> sub) error(treepath);
		list -> max = 0;
		return(1);
	}
	for (cp = treepath, i = 0; (cp = strdelim(cp, 0)); cp++, i++);
	lptmp = maketree(".", list -> sub, list, i, &(list -> max));
	if (_chdir2(fullpath) < 0) lostcwd(fullpath);
	if (list -> max < 0) {
		i = (list -> max < -1) ? 1 : 0;
		if (!(list -> sub)) list -> max = -1;
		else {
			list -> max = 2;
			(list -> sub[1]).name = NULL;
			free(lp);
		}
		return(i);
	}
	if (list -> sub) {
		if (!(lp -> name)) i = list -> max;
		else for (i = 0; i < list -> max; i++)
			if (lptmp[i].name
			&& !strpathcmp(lp -> name, lptmp[i].name)) break;
		if (i < list -> max) {
			free(lptmp[i].name);
			for (; i > 0; i--) memcpy((char *)&(lptmp[i]),
					(char *)&(lptmp[i - 1]),
					sizeof(treelist));
			memcpy((char *)&(lptmp[0]), (char *)lp,
				sizeof(treelist));
		}
		free(lp);
	}
	list -> sub = lptmp;
	return(1);
}

static int NEAR expandall(list)
treelist *list;
{
	char *cp;
	int i;

	if (!list || list -> max >= 0) return(1);
	if (!expandtree(list)) return(0);
	if (!(list -> sub)) return(1);
	cp = treepath + strlen(treepath);
	if (cp > treepath + 1) {
		strcatdelim(treepath);
		cp++;
	}
	for (i = 0; i < list -> max; i++) {
		strcpy(cp, (list -> sub[i]).name);
		if (!expandall(&(list -> sub[i]))) return(0);
	}
	return(1);
}

static int NEAR treeup(VOID_A)
{
	if (tr_line > LFILETOP + 1) tr_line--;
	else if (tr_top <= LFILETOP) tr_top++;
	else return(-1);
	searchtree();
	return(0);
}

static int NEAR treedown(VOID_A)
{
	char *cp;
	int oy, otop;

	oy = tr_line;
	otop = tr_top;
	if (tr_line < tr_bottom - 1 && tr_line < LFILEBOTTOM - 2)
		tr_line++;
	else if (tr_bottom >= LFILEBOTTOM) tr_top--;
	else return(-1);
	searchtree();

	if (!tr_cur || !(tr_cur -> sub)
	|| (tr_cur -> sub[tr_no]).max >= 0
	|| ((tr_cur -> sub[tr_no]).name)) return(0);

	waitmes();
	if ((cp = strrdelim(treepath, 0)) == strdelim(treepath, 0)) cp++;
	*cp = '\0';
	if (!expandtree(tr_cur)) {
		tr_line = oy;
		tr_top = otop;
		searchtree();
		return(-1);
	}
	searchtree();
	redraw = 1;
	return(0);
}

static int NEAR freetree(list, max)
treelist *list;
int max;
{
	int i, n;

	for (i = n = 0; i < max; i++) {
		n++;
		if (list[i].name) free(list[i].name);
		if (list[i].sub) n += freetree(list[i].sub, list[i].max);
	}
	free(list);
	return(n);
}

static VOID NEAR _tree_search(VOID_A)
{
	int oy, otop;

	oy = tr_line;
	otop = tr_top;

	while (strpathcmp(fullpath, treepath)) if (treeup() < 0) {
		tr_top = otop;
		tr_line = oy;
		searchtree();
		do {
			if (treedown() < 0) break;
		} while (strpathcmp(fullpath, treepath));
		break;
	}
}

static int NEAR _tree_input(VOID_A)
{
	treelist *old;
	char *cwd;
	int ch, tmp, half;

	keyflush();
	Xgetkey(-1, 0);
	ch = Xgetkey(1, 0);
	Xgetkey(-1, 0);

	old = tr_cur;
	switch (ch) {
		case K_UP:
			treeup();
			break;
		case K_DOWN:
			treedown();
			break;
		case K_PPAGE:
			half = (FILEPERROW - 1) / 2;
			tmp = LFILETOP + half + 1 - tr_line;
			if (tr_top + half > LFILETOP + 1)
				half = LFILETOP - tr_top + 1;
			if (half > 0) tr_top += half;
			for (;tmp > 0; tmp--) if (treedown() < 0) break;
			tr_line += tmp;
			searchtree();
			break;
		case K_NPAGE:
			half = (FILEPERROW - 1) / 2;
			tmp = half + (LFILETOP + half + 1) - tr_line;
			while (tmp-- > 0) if (treedown() < 0) break;
			tmp = tr_line - (LFILETOP + half + 1);
			tr_line = LFILETOP + half + 1;
			if (tr_bottom - tmp < LFILEBOTTOM - 1)
				tmp = tr_bottom - LFILEBOTTOM + 1;
			tr_top -= tmp;
			searchtree();
			break;
		case K_BEG:
		case K_HOME:
		case '<':
			tr_line = tr_top = LFILETOP + 1;
			searchtree();
			break;
		case K_EOL:
		case K_END:
		case '>':
			while (treedown() >= 0);
			break;
		case '?':
			_tree_search();
			break;
		case '(':
			tmp = tr_no - 1;
			do {
				if (treeup() < 0) break;
			} while (tmp >= 0 && (tr_cur != old || tr_no != tmp));
			break;
		case ')':
			tmp = tr_no + 1;
			do {
				if (treedown() < 0) break;
			} while (tmp < old -> max
			&& (tr_cur != old || tr_no != tmp));
			break;
		case '\t':
			if (!tr_cur || !(tr_cur -> sub)
			|| (tr_cur -> sub[tr_no]).max >= 0) break;
			waitmes();
			expandall(&(tr_cur -> sub[tr_no]));
			searchtree();
			redraw = 1;
			break;
		case K_RIGHT:
			if (!tr_cur || !(tr_cur -> sub)) break;
			if ((tr_cur -> sub[tr_no]).max >= 0) {
				if (!((tr_cur -> sub[tr_no]).sub)) break;
				if (treedown() < 0) break;
			}
			waitmes();
			expandtree(&(tr_cur -> sub[tr_no]));
			searchtree();
			redraw = 1;
			break;
		case K_LEFT:
			if (tr_cur && (tr_cur -> sub)
			&& (tr_cur -> sub[tr_no]).sub) {
				tmp = freetree((tr_cur -> sub[tr_no]).sub,
					(tr_cur -> sub[tr_no]).max);
				tr_bottom -= tmp;
				(tr_cur -> sub[tr_no]).max = -1;
				(tr_cur -> sub[tr_no]).sub = NULL;
				redraw = 1;
				break;
			}
/*FALLTHRU*/
		case K_BS:
			do {
				if (treeup() < 0) break;
			} while (&(tr_cur -> sub[tr_no]) != old);
			break;
		case 'l':
			if (!(cwd = inputstr(LOGD_K, 0, -1, NULL, 1))
			|| !*(cwd = evalpath(cwd, 0))) break;
			if (chdir2(cwd) >= 0) {
				free(cwd);
				break;
			}
			warning(-1, cwd);
			ch = '\0';
			free(cwd);
			break;
		case K_CTRL('L'):
			rewritefile(1);
			break;
		case K_ESC:
			break;
		default:
			if (!isupper2(ch)) break;
			if (tr_line == tr_bottom - 1) {
				tr_line = tr_top = LFILETOP + 1;
				searchtree();
			}
			else do {
				if (treedown() < 0) break;
				tmp = toupper2(*((tr_cur -> sub[tr_no]).name));
			} while (ch != tmp);
			break;
	}

	return(ch);
}

static char *NEAR _tree(VOID_A)
{
#ifndef	NODIRLOOP
	struct stat st;
# ifndef	_NODOSDRIVE
	char tmp[MAXPATHLEN];
# endif
#endif
	char *cp, *cwd, path[MAXPATHLEN];
	int ch, oy, otop;

	keyflush();
	waitmes();
	tr_root = (treelist *)malloc2(sizeof(treelist));
	tr_root -> name = NULL;
	tr_root -> max = 1;
	tr_root -> sub = tr_cur = (treelist *)malloc2(sizeof(treelist));
#ifndef	NODIRLOOP
	tr_root -> ino = 0;
	tr_root -> parent = NULL;
#endif
	treepath = path;
#if	MSDOS
	tr_cur[0].name = malloc2(3 + 1);
	strcpy(path, fullpath);
	strncpy2(tr_cur[0].name, path, 3);
#else	/* !MSDOS */
# ifdef	_NODOSDRIVE
	strcpy(path, fullpath);
	tr_cur[0].name = strdup2(_SS_);
# else
	if (dospath("", path)) tr_cur[0].name = strndup2(path, 3);
	else {
		strcpy(path, fullpath);
		tr_cur[0].name = strdup2(_SS_);
	}
# endif
#endif	/* !MSDOS */

#ifndef	NODIRLOOP
	if (Xstat(nodospath(tmp, tr_cur[0].name), &st) < 0)
		tr_cur[0].dev = tr_cur[0].ino = 0;
	else {
		tr_cur[0].dev = st.st_dev;
		tr_cur[0].ino = st.st_ino;
	}
	tr_cur[0].parent = NULL;
#endif
	tr_cur[0].sub = maketree(path, NULL, &(tr_cur[0]),
		0, &(tr_cur[0].max));

	tr_line = 0;
#if	MSDOS
	cwd = path + 2;
#else	/* !MSDOS */
	cwd = path;
# ifndef	_NODOSDRIVE
	if (_dospath(cwd)) cwd += 2;
# endif
#endif	/* !MSDOS */
	if (!strcmp(cwd, _SS_)) /*EMPTY*/;
	else for (cp = cwd; (cp = strdelim(cp, 0)); cp++, tr_line++)
		if ((tr_line + 1) * DIRFIELD + 2 > TREEFIELD
		|| !(tr_cur = &(tr_cur -> sub[0]))) break;
	tr_line += (tr_top = LFILETOP + 1);
	if (tr_line >= LFILEBOTTOM - 2) {
		tr_top += LFILEBOTTOM - 2 - tr_line;
		tr_line = LFILEBOTTOM - 2;
	}

	tr_scr = malloc2((FILEPERROW - 1) * (TREEFIELD + 1));
	searchtree();
	showtree();
	win_x = 0;
	do {
		treebar();
		oy = tr_line;
		otop = tr_top;
		redraw = 0;
		win_y = tr_line;
		locate(win_x, win_y);
		tflush();

		if ((ch = _tree_input()) == 'l') {
			free(tr_scr);
			freetree(tr_root, 1);
			return(fullpath);
		}

		if (redraw || tr_top != otop) showtree();
		else if (oy != tr_line) {
			locate(1, tr_line);
			putterm(t_standout);
			cprintf2("%-*.*k",
				TREEFIELD, TREEFIELD, bufptr(tr_line));
			putterm(end_standout);
			locate(1, oy);
			if (stable_standout) putterm(end_standout);
			else cprintf2("%-*.*k",
				TREEFIELD, TREEFIELD, bufptr(oy));
			evaldir(path, 1);
		}
	} while (ch != K_ESC && ch != K_CR);

	free(tr_scr);
	freetree(tr_root, 1);
	treepath = NULL;
	if (ch == K_ESC) return(NULL);
	return(strdup2(path));
}

/*ARGSUSED*/
char *tree(cleanup, ddp)
int cleanup, *ddp;
{
	char *path, *dupfullpath;

	if (FILEPERROW < WFILEMINTREE) {
		warning(0, NOROW_K);
		return(NULL);
	}
	dupfullpath = strdup2(fullpath);
	do {
		path = _tree();
	} while (path == fullpath);
	if (ddp) {
#ifndef	_NODOSDRIVE
# if	MSDOS
		if (lastdrv < 0) *ddp = preparedrv(dospath(path, NULL));
		else
# endif
		*ddp = lastdrv;
		lastdrv = -1;
#endif
	}
	if (chdir2(dupfullpath) < 0) lostcwd(NULL);
	free(dupfullpath);

	if (cleanup) rewritefile(1);
	return(path);
}
#endif	/* !_NOTREE */
