mirror of
https://github.com/reactos/reactos.git
synced 2024-08-30 15:18:33 +00:00
![Hermès Bélusca-Maïto](/assets/img/avatar_default.png)
ConInString() should display a newline when it encounters the terminating carriage-return pressed by the user for ending string output. + Remove the extra \n hacks in FilePromptYN[A]. Improve outputted strings from DATE and TIME commands. + Rename some STRING_***_ERROR defines. CORE-18489
368 lines
10 KiB
C
368 lines
10 KiB
C
/*
|
|
* TYPE.C - type internal command.
|
|
*
|
|
* History:
|
|
*
|
|
* 07/08/1998 (John P. Price)
|
|
* started.
|
|
*
|
|
* 07/12/98 (Rob Lake)
|
|
* Changed error messages
|
|
*
|
|
* 27-Jul-1998 (John P Price <linux-guru@gcfl.net>)
|
|
* added config.h include
|
|
*
|
|
* 07-Jan-1999 (Eric Kohl)
|
|
* Added support for quoted arguments (type "test file.dat").
|
|
* Cleaned up.
|
|
*
|
|
* 19-Jan-1999 (Eric Kohl)
|
|
* Unicode and redirection ready!
|
|
*
|
|
* 19-Jan-1999 (Paolo Pantaleo <paolopan@freemail.it>)
|
|
* Added multiple file support (copied from y.c)
|
|
*
|
|
* 30-Apr-2005 (Magnus Olsen <magnus@greatlord.com>)
|
|
* Remove all hardcoded strings in En.rc
|
|
*/
|
|
|
|
#include "precomp.h"
|
|
|
|
#ifdef INCLUDE_CMD_TYPE
|
|
|
|
static BOOL
|
|
FileGetString(
|
|
IN HANDLE hFile,
|
|
OUT LPTSTR lpBuffer,
|
|
IN LONG nBufferLength)
|
|
{
|
|
PCHAR pString;
|
|
DWORD dwRead;
|
|
LONG len = 0;
|
|
|
|
#ifdef _UNICODE
|
|
pString = cmd_alloc(nBufferLength);
|
|
#else
|
|
pString = lpBuffer;
|
|
#endif
|
|
|
|
if (ReadFile(hFile, pString, nBufferLength - 1, &dwRead, NULL))
|
|
{
|
|
/* Break at new line*/
|
|
PCHAR end = memchr(pString, '\n', dwRead);
|
|
len = dwRead;
|
|
if (end)
|
|
{
|
|
len = (LONG)(end - pString) + 1;
|
|
SetFilePointer(hFile, len - dwRead, NULL, FILE_CURRENT);
|
|
}
|
|
}
|
|
|
|
if (!len)
|
|
{
|
|
#ifdef _UNICODE
|
|
cmd_free(pString);
|
|
#endif
|
|
return FALSE;
|
|
}
|
|
|
|
pString[len++] = '\0';
|
|
#ifdef _UNICODE
|
|
MultiByteToWideChar(OutputCodePage, 0, pString, -1, lpBuffer, len);
|
|
cmd_free(pString);
|
|
#endif
|
|
return TRUE;
|
|
}
|
|
|
|
static BOOL
|
|
DoTypeFile(
|
|
IN LPTSTR FileName,
|
|
IN HANDLE hConsoleOut,
|
|
IN BOOL bNoFileName,
|
|
IN BOOL bPaging)
|
|
{
|
|
HANDLE hFile;
|
|
BOOL bIsFile;
|
|
DWORD dwFileSize;
|
|
DWORD dwFilePos;
|
|
DWORD dwRet;
|
|
LPTSTR errmsg;
|
|
TCHAR buff[256];
|
|
|
|
hFile = CreateFile(FileName,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL, NULL);
|
|
|
|
if (hFile == INVALID_HANDLE_VALUE)
|
|
{
|
|
// FIXME: Use ErrorMessage() ?
|
|
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
|
FORMAT_MESSAGE_IGNORE_INSERTS |
|
|
FORMAT_MESSAGE_FROM_SYSTEM,
|
|
NULL,
|
|
GetLastError(),
|
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
|
(LPTSTR)&errmsg,
|
|
0,
|
|
NULL);
|
|
ConErrPrintf(_T("%s - %s"), FileName, errmsg);
|
|
LocalFree(errmsg);
|
|
nErrorLevel = 1;
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* When reading from a file, retrieve its original size, so that
|
|
* we can stop reading it once we are beyond its original ending.
|
|
* This allows avoiding an infinite read loop in case the output
|
|
* of the file is redirected back to it.
|
|
* If we read from somewhere else (device, ...) don't do anything;
|
|
* we will stop when ReadFile() fails (e.g. when Ctrl-Z is seen...).
|
|
*/
|
|
bIsFile = ((GetFileType(hFile) & ~FILE_TYPE_REMOTE) == FILE_TYPE_DISK);
|
|
if (bIsFile)
|
|
{
|
|
dwFileSize = GetFileSize(hFile, NULL);
|
|
if ((dwFileSize == INVALID_FILE_SIZE) &&
|
|
(GetLastError() != ERROR_SUCCESS))
|
|
{
|
|
WARN("Error when retrieving file size, or size too large (%d)\n",
|
|
dwFileSize);
|
|
dwFileSize = 0;
|
|
}
|
|
dwFilePos = SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
|
|
if ((dwFilePos == INVALID_SET_FILE_POINTER) &&
|
|
(GetLastError() != ERROR_SUCCESS))
|
|
{
|
|
WARN("Error when setting file pointer\n");
|
|
dwFilePos = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dwFileSize = dwFilePos = 0;
|
|
}
|
|
|
|
/*
|
|
* Display the file name on StdErr if required, so that if StdOut
|
|
* alone is redirected, we can obtain the file contents only.
|
|
*/
|
|
if (!bNoFileName)
|
|
ConErrPrintf(_T("\n%s\n\n\n"), FileName);
|
|
|
|
if (bPaging)
|
|
{
|
|
while (FileGetString(hFile, buff, ARRAYSIZE(buff)))
|
|
{
|
|
if (!ConOutPrintfPaging(FALSE, _T("%s"), buff))
|
|
{
|
|
bCtrlBreak = FALSE;
|
|
CloseHandle(hFile);
|
|
nErrorLevel = 1;
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* If we read from a file, check where we are and stop
|
|
* once we are beyond the original end of the file.
|
|
*/
|
|
if (bIsFile)
|
|
{
|
|
dwFilePos = SetFilePointer(hFile, 0, NULL, FILE_CURRENT);
|
|
if ((dwFilePos == INVALID_SET_FILE_POINTER) &&
|
|
(GetLastError() != ERROR_SUCCESS))
|
|
{
|
|
WARN("Error when getting file pointer\n");
|
|
break;
|
|
}
|
|
if (dwFilePos >= dwFileSize)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
while (ReadFile(hFile, buff, sizeof(buff), &dwRet, NULL) && dwRet > 0)
|
|
{
|
|
WriteFile(hConsoleOut, buff, dwRet, &dwRet, NULL);
|
|
if (bCtrlBreak)
|
|
{
|
|
bCtrlBreak = FALSE;
|
|
CloseHandle(hFile);
|
|
nErrorLevel = 1;
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* If we read from a file, check where we are and stop
|
|
* once we are beyond the original end of the file.
|
|
*/
|
|
if (bIsFile)
|
|
{
|
|
dwFilePos = SetFilePointer(hFile, 0, NULL, FILE_CURRENT);
|
|
if ((dwFilePos == INVALID_SET_FILE_POINTER) &&
|
|
(GetLastError() != ERROR_SUCCESS))
|
|
{
|
|
WARN("Error when getting file pointer\n");
|
|
break;
|
|
}
|
|
if (dwFilePos >= dwFileSize)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
CloseHandle(hFile);
|
|
return TRUE;
|
|
}
|
|
|
|
INT cmd_type(LPTSTR param)
|
|
{
|
|
INT argc, i;
|
|
LPTSTR* argv;
|
|
LPTSTR errmsg;
|
|
HANDLE hConsoleOut;
|
|
BOOL bNoFileName = FALSE;
|
|
BOOL bPaging = FALSE;
|
|
BOOL bFileFound;
|
|
DWORD dwLastError;
|
|
UINT nFileSpecs = 0;
|
|
HANDLE hFind;
|
|
WIN32_FIND_DATA FindData;
|
|
|
|
if (!_tcsncmp(param, _T("/?"), 2))
|
|
{
|
|
ConOutResPaging(TRUE, STRING_TYPE_HELP1);
|
|
return 0;
|
|
}
|
|
|
|
if (!*param)
|
|
{
|
|
error_req_param_missing();
|
|
return 1;
|
|
}
|
|
|
|
/* Parse the command line. We will manually expand any file specification present. */
|
|
argv = split(param, &argc, FALSE, FALSE);
|
|
|
|
/* Loop through the options, count also the specified number of file specifications */
|
|
for (i = 0; i < argc; ++i)
|
|
{
|
|
if (argv[i][0] == _T('/'))
|
|
{
|
|
if (_tcslen(argv[i]) == 2)
|
|
{
|
|
switch (_totupper(argv[i][1]))
|
|
{
|
|
case _T('N'):
|
|
bNoFileName = TRUE;
|
|
continue;
|
|
|
|
case _T('P'):
|
|
bPaging = TRUE;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// error_invalid_switch(argv[i] + 1);
|
|
ConErrResPrintf(STRING_TYPE_ERROR, argv[i] + 1);
|
|
nErrorLevel = 1;
|
|
goto Quit;
|
|
}
|
|
|
|
/* This should be a file specification */
|
|
++nFileSpecs;
|
|
}
|
|
|
|
nErrorLevel = 0;
|
|
|
|
hConsoleOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
|
|
/* Reset paging state */
|
|
if (bPaging)
|
|
ConOutPrintfPaging(TRUE, _T(""));
|
|
|
|
/* Now loop through the files */
|
|
for (i = 0; i < argc; ++i)
|
|
{
|
|
/* Skip the options */
|
|
if (argv[i][0] == _T('/'))
|
|
continue;
|
|
|
|
/* If wildcards are present in this file specification, perform a file enumeration */
|
|
if (_tcschr(argv[i], _T('*')) || _tcschr(argv[i], _T('?')))
|
|
{
|
|
dwLastError = ERROR_SUCCESS;
|
|
bFileFound = FALSE;
|
|
|
|
hFind = FindFirstFile(argv[i], &FindData);
|
|
|
|
if (hFind != INVALID_HANDLE_VALUE)
|
|
{
|
|
/* Loop through all the files */
|
|
do
|
|
{
|
|
/* Ignore any directory silently */
|
|
if (!_tcscmp(FindData.cFileName, _T(".")) ||
|
|
!_tcscmp(FindData.cFileName, _T("..")) ||
|
|
(FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
bFileFound = TRUE;
|
|
if (!DoTypeFile(FindData.cFileName, hConsoleOut, bNoFileName, bPaging))
|
|
{
|
|
FindClose(hFind);
|
|
goto Quit;
|
|
}
|
|
|
|
} while (FindNextFile(hFind, &FindData));
|
|
|
|
FindClose(hFind);
|
|
}
|
|
|
|
/*
|
|
* Return an error if the file specification could not be resolved,
|
|
* or no actual files were encountered (but only directories).
|
|
*/
|
|
if (hFind == INVALID_HANDLE_VALUE)
|
|
dwLastError = GetLastError();
|
|
else if (!bFileFound)
|
|
dwLastError = ERROR_FILE_NOT_FOUND;
|
|
|
|
if (dwLastError != ERROR_SUCCESS)
|
|
{
|
|
// FIXME: Use ErrorMessage() ?
|
|
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
|
FORMAT_MESSAGE_IGNORE_INSERTS |
|
|
FORMAT_MESSAGE_FROM_SYSTEM,
|
|
NULL,
|
|
dwLastError,
|
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
|
(LPTSTR)&errmsg,
|
|
0,
|
|
NULL);
|
|
ConErrPrintf(_T("%s - %s"), argv[i], errmsg);
|
|
LocalFree(errmsg);
|
|
nErrorLevel = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!DoTypeFile(argv[i], hConsoleOut, (bNoFileName || (nFileSpecs <= 1)), bPaging))
|
|
goto Quit;
|
|
}
|
|
|
|
/* Continue with the next file specification */
|
|
}
|
|
|
|
Quit:
|
|
freep(argv);
|
|
return nErrorLevel;
|
|
}
|
|
|
|
#endif
|