/*
 *  DIRSTACK.C - pushd / pop (directory stack) internal commands.
 *
 *
 *  History:
 *
 *    14-Dec-1998 (Eric Kohl)
 *        Implemented PUSHD and POPD command.
 *
 *    20-Jan-1999 (Eric Kohl)
 *        Unicode and redirection safe!
 *
 *    20-Jan-1999 (Eric Kohl)
 *        Added DIRS command.
 */

#include <precomp.h>

#ifdef FEATURE_DIRECTORY_STACK

typedef struct tagDIRENTRY
{
	struct tagDIRENTRY *prev;
	struct tagDIRENTRY *next;
	TCHAR szPath[1];
} DIRENTRY, *LPDIRENTRY;


static INT nStackDepth;
static LPDIRENTRY lpStackTop;
static LPDIRENTRY lpStackBottom;


static INT
PushDirectory (LPTSTR pszPath)
{
	LPDIRENTRY lpDir = cmd_alloc(FIELD_OFFSET(DIRENTRY, szPath[_tcslen(pszPath) + 1]));
	if (!lpDir)
	{
		error_out_of_memory ();
		return -1;
	}

	lpDir->prev = NULL;
	lpDir->next = lpStackTop;
	if (lpStackTop == NULL)
		lpStackBottom = lpDir;
	else
		lpStackTop->prev = lpDir;
	lpStackTop = lpDir;

	_tcscpy(lpDir->szPath, pszPath);

	nStackDepth++;

	return nErrorLevel = 0;
}


static VOID
PopDirectory (VOID)
{
	LPDIRENTRY lpDir = lpStackTop;
	lpStackTop = lpDir->next;
	if (lpStackTop != NULL)
		lpStackTop->prev = NULL;
	else
		lpStackBottom = NULL;

	cmd_free (lpDir);

	nStackDepth--;
}


/*
 * initialize directory stack
 */
VOID InitDirectoryStack (VOID)
{
	nStackDepth = 0;
	lpStackTop = NULL;
	lpStackBottom = NULL;
}


/*
 * destroy directory stack
 */
VOID DestroyDirectoryStack (VOID)
{
	while (nStackDepth)
		PopDirectory ();
}


INT GetDirectoryStackDepth (VOID)
{
	return nStackDepth;
}


/*
 * pushd command
 */
INT CommandPushd (LPTSTR rest)
{
	TCHAR curPath[MAX_PATH];

	if (!_tcsncmp (rest, _T("/?"), 2))
	{
		ConOutResPuts(STRING_DIRSTACK_HELP1);
		return 0;
	}

	GetCurrentDirectory (MAX_PATH, curPath);

	if (rest[0] != _T('\0'))
	{
		if (!SetRootPath(NULL, rest))
			return 1;
	}

	return PushDirectory(curPath);
}


/*
 * popd command
 */
INT CommandPopd (LPTSTR rest)
{
	INT ret = 0;
	if (!_tcsncmp(rest, _T("/?"), 2))
	{
		ConOutResPuts(STRING_DIRSTACK_HELP2);
		return 0;
	}

	if (nStackDepth == 0)
		return 1;

	ret = _tchdir(lpStackTop->szPath) != 0;
	PopDirectory ();

	return ret;
}


/*
 * dirs command
 */
INT CommandDirs (LPTSTR rest)
{
	LPDIRENTRY lpDir;

	if (!_tcsncmp(rest, _T("/?"), 2))
	{
		ConOutResPuts(STRING_DIRSTACK_HELP3);
		return 0;
	}

    nErrorLevel = 0;

	lpDir = lpStackBottom;

	if (lpDir == NULL)
	{
		ConOutResPuts(STRING_DIRSTACK_HELP4);
		return 0;
	}

	while (lpDir != NULL)
	{
		ConOutPuts(lpDir->szPath);
		lpDir = lpDir->prev;
	}

	return 0;
}

#endif /* FEATURE_DIRECTORY_STACK */