//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft shared
// source or premium shared source license agreement under which you licensed
// this source code. If you did not accept the terms of the license agreement,
// you are not authorized to use this source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the SOURCE.RTF on your install media or the root of your tools installation.
// THE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//

#include <windows.h>
#include <intsafe.h>

#include "cmd.hxx"
#include "cmdpipe.hxx"
#include "cmdrsc.h"

extern CmdState *pCmdState;
//
//	Code section
//
int cmdpipe_CreateNewFile (TCHAR *lpBuffer, int iBufSize) {
	TCHAR *lpTempDir = pCmdState->ehHash.hash_get (TEXT("TEMP"));

	if (lpTempDir)
		_tcscpy (lpBuffer, lpTempDir);
	else
		_tcscpy (lpBuffer, TEXT("\\"));

	TCHAR *lpEndBuf = _tcschr (lpBuffer, TEXT('\0'));
	
	ASSERT (lpEndBuf != lpBuffer);

	if (lpEndBuf - lpBuffer + 14 > iBufSize)
		return FALSE;

	if (*(lpEndBuf-1) != TEXT('\\'))
		*lpEndBuf++ = TEXT('\\');

	_tcscpy (lpEndBuf, TEXT("cmdpipe.000"));
	lpEndBuf += 8;

	for (int i = 0 ; i < 999 ; ++i) {
		lpEndBuf[0] = i / 100 + TEXT('0');
		lpEndBuf[1] = (i / 10) % 10 + TEXT('0');
		lpEndBuf[2] = i % 10 + TEXT('0');

		HANDLE hFile = CreateFile (lpBuffer, GENERIC_WRITE, 0, NULL,
								CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);

		if (hFile != INVALID_HANDLE_VALUE) {
			CloseHandle (hFile);
			return TRUE;
		}
	}

	return FALSE;
}

int cmdpipe_CheckForPipes (PipeDescriptor *&ppd) {
	TCHAR			*lpCmd   = pCmdState->lpBufCmd;
	TCHAR			*lpStart = lpCmd;
	int				inQuotes = FALSE;
	int				iRedirIn = FALSE;
	int				iRedirOut= FALSE;
	PipeDescriptor	*pPDCur  = NULL;

	ppd = NULL;

	for ( ; ; ++lpCmd) {
		if (*lpCmd == TEXT('"'))
			inQuotes = ! inQuotes;
		else if (*lpCmd == TEXT('>')) {
			if ((lpCmd == lpStart) || (*(lpCmd - 1) != TEXT('2')))
				iRedirOut = TRUE;
		} else if (*lpCmd == TEXT('<'))
			iRedirIn = TRUE;
		else if ((*lpCmd == TEXT('\0')) || (((*lpCmd == TEXT('|')) ||
							(*lpCmd == TEXT('&'))) && (! inQuotes))) {
			int fEnd = FALSE;

			if (*lpCmd == TEXT('\0')) {
				if (! pPDCur)
					return CMD_SUCCESS;

				fEnd = TRUE;
			}

			int fOutput = (*lpCmd == TEXT('|'));

			if ((lpCmd == lpStart) || (iRedirIn && pPDCur && pPDCur->lpFileName) || (iRedirOut && fOutput)) {
				cmdutil_Complain (IDS_ERROR_BADSYNTAX, TEXT("|"));
				cmdpipe_Release (ppd);
				return CMD_ERROR;
			}

			PipeDescriptor *pPDNew = (PipeDescriptor *)cmdutil_Alloc (sizeof(PipeDescriptor));

			*lpCmd			     = TEXT('\0');

			iRedirIn = iRedirOut = FALSE;
			pPDNew->lpCommand    = cmdutil_tcsdup (lpStart);
			pPDNew->iCommandSize = lpCmd - lpStart + 1;

			lpStart			   = lpCmd + 1;

			pPDNew->pPrev = pPDCur;

			if (pPDCur)
				pPDCur->pNext = pPDNew;
			else
				ppd = pPDNew;

			pPDCur = pPDNew;

			if (fOutput) {
				TCHAR sBuffer[CMD_BUF_REG];

				if (! cmdpipe_CreateNewFile (sBuffer, CMD_BUF_REG)) {
					cmdutil_Complain (IDS_ERROR_PIPE_CANT);
				
					cmdpipe_Release (ppd);
				
					return CMD_ERROR;
				}
				pPDNew->lpFileName = cmdutil_tcsdup (sBuffer);
			} else {
				pPDNew->lpFileName = NULL;

				if (fEnd)
					break;
			}
		}
	}
	
	return CMD_SUCCESS;
}

int cmdpipe_Recharge (PipeDescriptor *pPD) {
	if (! pPD)
		return CMD_SUCCESS;

	int iFileOutSize = pPD->lpFileName ? _tcslen (pPD->lpFileName) : 0;
	int iFileInSize = (pPD->pPrev && pPD->pPrev->lpFileName) ? _tcslen (pPD->pPrev->lpFileName) : 0;
	UINT iSz = 0;

        if (FAILED(CeUIntAdd4(pPD->iCommandSize, iFileInSize, iFileOutSize, 6, &iSz)) || ((int)iSz < 0))
            return CMD_ERROR;

	if (pCmdState->iBufCmdChars < (int)iSz) {
		pCmdState->iBufCmdChars = iSz;
		pCmdState->lpBufCmd = (TCHAR *)cmdutil_ReAlloc (pCmdState->lpBufCmd, pCmdState->iBufCmdChars * sizeof (TCHAR));
	}

	memcpy (pCmdState->lpBufCmd, pPD->lpCommand, pPD->iCommandSize * sizeof(TCHAR));
	
	int iCurrentOffset = pPD->iCommandSize - 1;

	if (iFileOutSize > 0) {
		memcpy (&pCmdState->lpBufCmd[iCurrentOffset], TEXT(" > "), sizeof(TCHAR) * 3);
		iCurrentOffset += 3;
		memcpy (&pCmdState->lpBufCmd[iCurrentOffset], pPD->lpFileName, (iFileOutSize + 1) * sizeof(TCHAR));
		iCurrentOffset += iFileOutSize;
	}

	if (iFileInSize > 0) {
		memcpy (&pCmdState->lpBufCmd[iCurrentOffset], TEXT(" < "), sizeof(TCHAR) * 3);
		iCurrentOffset += 3;
		memcpy (&pCmdState->lpBufCmd[iCurrentOffset], pPD->pPrev->lpFileName, (iFileInSize + 1) * sizeof(TCHAR));
		iCurrentOffset += iFileInSize;
	}

	ASSERT (iCurrentOffset < pCmdState->iBufCmdChars);

	if (pPD->pPrev && pPD->pPrev->pPrev) {	// Retire the prev prev output... no longer needed.
		TCHAR *lpFileName = pPD->pPrev->pPrev->lpFileName;
		if (lpFileName)
			DeleteFile (lpFileName);
		
		pPD->pPrev->pPrev->uiPipeFlags |= PIPE_DELETED;
	}

	return CMD_SUCCESS;
}

int cmdpipe_Release (PipeDescriptor *pPD) {
	while (pPD) {
		PipeDescriptor *pNext = pPD->pNext;
		
		if (pPD->lpFileName) {
			if (! (pPD->uiPipeFlags & PIPE_DELETED))
				DeleteFile (pPD->lpFileName);
			cmdutil_Free (pPD->lpFileName);
		}

		cmdutil_Free (pPD->lpCommand);
		cmdutil_Free (pPD);

		pPD = pNext;
	}
	return CMD_SUCCESS;
}

