mirror of
https://github.com/reactos/reactos.git
synced 2025-08-05 16:43:04 +00:00
[CMD][CMDUTILS][REPLACE] Make 'replace' command external (#7097)
JIRA issue: CORE-9444 - Delete 'replace' internal command. - Add 'replace' external command into base/applications/cmdutils/replace folder. - Add control break handler.
This commit is contained in:
parent
3dcae2ce0c
commit
1ffce3eb6d
57 changed files with 1786 additions and 870 deletions
603
base/applications/cmdutils/replace/replace.c
Normal file
603
base/applications/cmdutils/replace/replace.c
Normal file
|
@ -0,0 +1,603 @@
|
|||
/*
|
||||
* PROJECT: ReactOS Replace Command
|
||||
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
||||
* PURPOSE: Implements 'replace' command
|
||||
* COPYRIGHT: Copyright Samuel Erdtman (samuel@erdtman.se)
|
||||
* COPYRIGHT: Copyright 2024 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
|
||||
*/
|
||||
|
||||
#include "replace.h"
|
||||
|
||||
enum
|
||||
{
|
||||
REPLACE_ADD = 0x001, /* /A */
|
||||
REPLACE_CONFIRM = 0x002, /* /P */
|
||||
REPLACE_READ_ONLY = 0x004, /* /R */
|
||||
REPLACE_SUBDIR = 0x008, /* /S */
|
||||
REPLACE_DISK = 0x010, /* /W */
|
||||
REPLACE_UPDATE = 0x020, /* /U */
|
||||
};
|
||||
|
||||
/* just makes a print out if there is a problem with the switches */
|
||||
void invalid_switch(LPTSTR is)
|
||||
{
|
||||
ConOutResPrintf(STRING_REPLACE_ERROR1,is);
|
||||
ConOutResPrintf(STRING_REPLACE_HELP3);
|
||||
}
|
||||
|
||||
/* retrieves the path dependent on the input file name */
|
||||
void getPath(TCHAR* out, LPTSTR in)
|
||||
{
|
||||
if (_tcslen(in) == 2 && in[1] == _T(':'))
|
||||
GetRootPath(in,out,MAX_PATH);
|
||||
else
|
||||
GetFullPathName (in, MAX_PATH, out, NULL);
|
||||
}
|
||||
|
||||
/* makes the replace */
|
||||
INT replace(TCHAR source[MAX_PATH], TCHAR dest[MAX_PATH], DWORD dwFlags, BOOL *doMore)
|
||||
{
|
||||
TCHAR d[MAX_PATH];
|
||||
TCHAR s[MAX_PATH];
|
||||
HANDLE hFileSrc, hFileDest;
|
||||
DWORD dwAttrib, dwRead, dwWritten;
|
||||
LPBYTE buffer;
|
||||
BOOL bEof = FALSE;
|
||||
FILETIME srcCreationTime, destCreationTime, srcLastAccessTime, destLastAccessTime;
|
||||
FILETIME srcLastWriteTime, destLastWriteTime;
|
||||
GetPathCase(source, s);
|
||||
GetPathCase(dest, d);
|
||||
s[0] = _totupper(s[0]);
|
||||
d[0] = _totupper(d[0]);
|
||||
// ConOutPrintf(_T("old-src: %s\n"), s);
|
||||
// ConOutPrintf(_T("old-dest: %s\n"), d);
|
||||
// ConOutPrintf(_T("src: %s\n"), source);
|
||||
// ConOutPrintf(_T("dest: %s\n"), dest);
|
||||
|
||||
/* Open up the sourcefile */
|
||||
hFileSrc = CreateFile (source, GENERIC_READ, FILE_SHARE_READ,NULL, OPEN_EXISTING, 0, NULL);
|
||||
if (hFileSrc == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
ConOutResPrintf(STRING_COPY_ERROR1, source);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the time from source file to be used in the comparison
|
||||
* with dest time if update switch is set.
|
||||
*/
|
||||
GetFileTime (hFileSrc, &srcCreationTime, &srcLastAccessTime, &srcLastWriteTime);
|
||||
|
||||
/*
|
||||
* Retrieve the source attributes so that they later on
|
||||
* can be inserted in to the destination.
|
||||
*/
|
||||
dwAttrib = GetFileAttributes (source);
|
||||
|
||||
if (IsExistingFile (dest))
|
||||
{
|
||||
/*
|
||||
* Resets the attributes to avoid problems with read only files,
|
||||
* checks for read only has been made earlier.
|
||||
*/
|
||||
SetFileAttributes(dest,FILE_ATTRIBUTE_NORMAL);
|
||||
/*
|
||||
* Is the update flas set? The time has to be controled so that
|
||||
* only older files are replaced.
|
||||
*/
|
||||
if (dwFlags & REPLACE_UPDATE)
|
||||
{
|
||||
/* Read destination time */
|
||||
hFileDest = CreateFile(dest, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
|
||||
0, NULL);
|
||||
|
||||
if (hFileDest == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
ConOutResPrintf(STRING_COPY_ERROR1, dest);
|
||||
CloseHandle (hFileSrc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Compare time */
|
||||
GetFileTime (hFileDest, &destCreationTime, &destLastAccessTime, &destLastWriteTime);
|
||||
if (!((srcLastWriteTime.dwHighDateTime > destLastWriteTime.dwHighDateTime) ||
|
||||
(srcLastWriteTime.dwHighDateTime == destLastWriteTime.dwHighDateTime &&
|
||||
srcLastWriteTime.dwLowDateTime > destLastWriteTime.dwLowDateTime)))
|
||||
{
|
||||
CloseHandle (hFileSrc);
|
||||
CloseHandle (hFileDest);
|
||||
return 0;
|
||||
}
|
||||
CloseHandle (hFileDest);
|
||||
}
|
||||
/* Delete the old file */
|
||||
DeleteFile (dest);
|
||||
}
|
||||
|
||||
/* Check confirm flag, and take appropriate action */
|
||||
if (dwFlags & REPLACE_CONFIRM)
|
||||
{
|
||||
/* Output depending on add flag */
|
||||
if (dwFlags & REPLACE_ADD)
|
||||
ConOutResPrintf(STRING_REPLACE_HELP9, dest);
|
||||
else
|
||||
ConOutResPrintf(STRING_REPLACE_HELP10, dest);
|
||||
if ( !FilePromptYNA (0))
|
||||
{
|
||||
CloseHandle (hFileSrc);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Output depending on add flag */
|
||||
if (dwFlags & REPLACE_ADD)
|
||||
ConOutResPrintf(STRING_REPLACE_HELP11, dest);
|
||||
else
|
||||
ConOutResPrintf(STRING_REPLACE_HELP5, dest);
|
||||
|
||||
/* Make sure source and destination is not the same */
|
||||
if (!_tcscmp(s, d))
|
||||
{
|
||||
ConOutResPrintf(STRING_REPLACE_ERROR7);
|
||||
CloseHandle (hFileSrc);
|
||||
*doMore = FALSE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Open destination file to write to */
|
||||
hFileDest = CreateFile (dest, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
|
||||
if (hFileDest == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
CloseHandle (hFileSrc);
|
||||
ConOutResPrintf(STRING_REPLACE_ERROR7);
|
||||
*doMore = FALSE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get buffer for the copy process */
|
||||
buffer = VirtualAlloc(NULL, BUFF_SIZE, MEM_COMMIT, PAGE_READWRITE);
|
||||
if (buffer == NULL)
|
||||
{
|
||||
CloseHandle (hFileDest);
|
||||
CloseHandle (hFileSrc);
|
||||
ConOutResPrintf(STRING_ERROR_OUT_OF_MEMORY);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Put attribute and time to the new destination file */
|
||||
SetFileAttributes (dest, dwAttrib);
|
||||
SetFileTime (hFileDest, &srcCreationTime, &srcLastAccessTime, &srcLastWriteTime);
|
||||
do
|
||||
{
|
||||
/* Read data from source */
|
||||
ReadFile (hFileSrc, buffer, BUFF_SIZE, &dwRead, NULL);
|
||||
|
||||
/* Done? */
|
||||
if (dwRead == 0)
|
||||
break;
|
||||
|
||||
/* Write to destination file */
|
||||
WriteFile (hFileDest, buffer, dwRead, &dwWritten, NULL);
|
||||
|
||||
/* Done! or ctrl break! */
|
||||
if (dwWritten != dwRead || bCtrlBreak)
|
||||
{
|
||||
ConOutResPuts(STRING_COPY_ERROR3);
|
||||
VirtualFree (buffer, 0, MEM_RELEASE);
|
||||
CloseHandle (hFileDest);
|
||||
CloseHandle (hFileSrc);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
while (!bEof);
|
||||
|
||||
/* Return memory and close files */
|
||||
VirtualFree (buffer, 0, MEM_RELEASE);
|
||||
CloseHandle (hFileDest);
|
||||
CloseHandle (hFileSrc);
|
||||
|
||||
/* Return one file replaced */
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* Function to iterate over source files and call replace for each of them */
|
||||
INT recReplace(DWORD dwFlags,
|
||||
TCHAR szSrcPath[MAX_PATH],
|
||||
TCHAR szDestPath[MAX_PATH],
|
||||
BOOL *doMore)
|
||||
{
|
||||
TCHAR tmpDestPath[MAX_PATH], tmpSrcPath[MAX_PATH];
|
||||
INT filesReplaced=0;
|
||||
INT_PTR i;
|
||||
DWORD dwAttrib = 0;
|
||||
HANDLE hFile;
|
||||
WIN32_FIND_DATA findBuffer;
|
||||
|
||||
/* Get file handle to the sourcefile(s) */
|
||||
hFile = FindFirstFile (szSrcPath, &findBuffer);
|
||||
|
||||
/*
|
||||
* Strip the paths back to the folder they are in, so that
|
||||
* the different filenames can be added if more than one.
|
||||
*/
|
||||
for(i = (_tcslen(szSrcPath) - 1); i > -1; i--)
|
||||
{
|
||||
if (szSrcPath[i] != _T('\\'))
|
||||
szSrcPath[i] = _T('\0');
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
/* Go through all the sourcefiles and copy/replace them */
|
||||
do
|
||||
{
|
||||
if (bCtrlBreak)
|
||||
return filesReplaced;
|
||||
|
||||
/* Problem with file handler */
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
return filesReplaced;
|
||||
|
||||
/* We do not want to replace any .. . ocr directory */
|
||||
if (!_tcscmp (findBuffer.cFileName, _T(".")) ||
|
||||
!_tcscmp (findBuffer.cFileName, _T(".."))||
|
||||
findBuffer.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||
continue;
|
||||
|
||||
/* Add filename to destpath */
|
||||
_tcscpy(tmpDestPath,szDestPath);
|
||||
_tcscat (tmpDestPath, findBuffer.cFileName);
|
||||
|
||||
dwAttrib = GetFileAttributes(tmpDestPath);
|
||||
/* Check add flag */
|
||||
if (dwFlags & REPLACE_ADD)
|
||||
{
|
||||
if (IsExistingFile(tmpDestPath))
|
||||
continue;
|
||||
else
|
||||
dwAttrib = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!IsExistingFile(tmpDestPath))
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Check if file is read only, if so check if that should be ignored */
|
||||
if (dwAttrib & FILE_ATTRIBUTE_READONLY)
|
||||
{
|
||||
if (!(dwFlags & REPLACE_READ_ONLY))
|
||||
{
|
||||
ConOutResPrintf(STRING_REPLACE_ERROR5, tmpDestPath);
|
||||
*doMore = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add filename to sourcepath, insted of wildcards */
|
||||
_tcscpy(tmpSrcPath,szSrcPath);
|
||||
_tcscat (tmpSrcPath, findBuffer.cFileName);
|
||||
|
||||
/* Make the replace */
|
||||
if (replace(tmpSrcPath,tmpDestPath, dwFlags, doMore))
|
||||
{
|
||||
filesReplaced++;
|
||||
}
|
||||
else if (!*doMore)
|
||||
{
|
||||
/* The file to be replaced was the same as the source */
|
||||
filesReplaced = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Take next sourcefile if any */
|
||||
} while(FindNextFile (hFile, &findBuffer));
|
||||
|
||||
FindClose(hFile);
|
||||
|
||||
return filesReplaced;
|
||||
}
|
||||
|
||||
/* If /s switch is specifyed all subdirs has to be considered */
|
||||
INT recFindSubDirs(DWORD dwFlags,
|
||||
TCHAR szSrcPath[MAX_PATH],
|
||||
TCHAR szDestPath[MAX_PATH],
|
||||
BOOL *doMore)
|
||||
{
|
||||
HANDLE hFile;
|
||||
WIN32_FIND_DATA findBuffer;
|
||||
TCHAR tmpDestPath[MAX_PATH], tmpSrcPath[MAX_PATH];
|
||||
INT filesReplaced = 0;
|
||||
INT_PTR i;
|
||||
|
||||
/*
|
||||
* Add a wildcard to dest end so the it will be easy to iterate
|
||||
* over all the files and directorys in the dest directory.
|
||||
*/
|
||||
_tcscat(szDestPath, _T("*"));
|
||||
|
||||
/* Get the first file in the directory */
|
||||
hFile = FindFirstFile (szDestPath, &findBuffer);
|
||||
|
||||
/* Remove the star added earlier to dest path */
|
||||
for(i = (_tcslen(szDestPath) - 1); i > -1; i--)
|
||||
{
|
||||
if (szDestPath[i] != _T('\\'))
|
||||
szDestPath[i] = _T('\0');
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
/* Iterate over all filed directories in the dest dir */
|
||||
do
|
||||
{
|
||||
/* Save the source path so that it will not be wrecked */
|
||||
_tcscpy(tmpSrcPath,szSrcPath);
|
||||
/* Check for reading problems */
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
ConOutFormatMessage (GetLastError(), tmpSrcPath);
|
||||
return filesReplaced;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the we should enter the dir or if it is a file
|
||||
* or . or .. if so thake the next object to process.
|
||||
*/
|
||||
if (!_tcscmp (findBuffer.cFileName, _T(".")) ||
|
||||
!_tcscmp (findBuffer.cFileName, _T(".."))||
|
||||
IsExistingFile(findBuffer.cFileName))
|
||||
continue;
|
||||
/* Add the destpath and the new dir path to tempDestPath */
|
||||
_tcscpy(tmpDestPath,szDestPath);
|
||||
_tcscat (tmpDestPath, findBuffer.cFileName);
|
||||
/* Make sure that we have a directory */
|
||||
if (IsExistingDirectory(tmpDestPath))
|
||||
{
|
||||
/* Add a \ to the end or the path */
|
||||
if (szDestPath[_tcslen(tmpDestPath) - 1] != _T('\\'))
|
||||
_tcscat(tmpDestPath, _T("\\"));
|
||||
/* Call the function to replace files in the new directory */
|
||||
filesReplaced += recReplace(dwFlags, tmpSrcPath, tmpDestPath, doMore);
|
||||
/* If there were problems break e.g. read-only file */
|
||||
if (!*doMore)
|
||||
break;
|
||||
_tcscpy(tmpSrcPath,szSrcPath);
|
||||
/* Control the next level of subdirs */
|
||||
filesReplaced += recFindSubDirs(dwFlags,tmpSrcPath,tmpDestPath, doMore);
|
||||
if (!*doMore)
|
||||
break;
|
||||
}
|
||||
/* Get the next handle */
|
||||
} while(FindNextFile (hFile, &findBuffer));
|
||||
|
||||
FindClose(hFile);
|
||||
|
||||
return filesReplaced;
|
||||
}
|
||||
|
||||
INT cmd_replace(INT argc, WCHAR **argv)
|
||||
{
|
||||
LPTSTR *arg;
|
||||
INT i, filesReplaced = 0, nFiles, srcIndex = -1, destIndex = -1;
|
||||
DWORD dwFlags = 0;
|
||||
TCHAR szDestPath[MAX_PATH], szSrcPath[MAX_PATH], tmpSrcPath[MAX_PATH];
|
||||
BOOL doMore = TRUE;
|
||||
|
||||
--argc;
|
||||
++argv;
|
||||
|
||||
/* Help wanted? */
|
||||
if (argc == 1 && !_tcscmp(argv[0], _T("/?")))
|
||||
{
|
||||
ConOutResPrintf(STRING_REPLACE_HELP1);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
/* Divide the argument in to an array of c-strings */
|
||||
arg = argv;
|
||||
nFiles = argc;
|
||||
|
||||
/* Read options */
|
||||
for (i = 0; i < argc; i++)
|
||||
{
|
||||
if (arg[i][0] == _T('/'))
|
||||
{
|
||||
if (_tcslen(arg[i]) == 2)
|
||||
{
|
||||
switch (_totupper(arg[i][1]))
|
||||
{
|
||||
case _T('A'):
|
||||
dwFlags |= REPLACE_ADD;
|
||||
break;
|
||||
case _T('P'):
|
||||
dwFlags |= REPLACE_CONFIRM;
|
||||
break;
|
||||
case _T('R'):
|
||||
dwFlags |= REPLACE_READ_ONLY;
|
||||
break;
|
||||
case _T('S'):
|
||||
dwFlags |= REPLACE_SUBDIR;
|
||||
break;
|
||||
case _T('W'):
|
||||
dwFlags |= REPLACE_DISK;
|
||||
break;
|
||||
case _T('U'):
|
||||
dwFlags |= REPLACE_UPDATE;
|
||||
break;
|
||||
default:
|
||||
invalid_switch(arg[i]);
|
||||
return 11; /* Error */
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
invalid_switch(arg[i]);
|
||||
return 11; /* Error */
|
||||
}
|
||||
nFiles--;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (srcIndex == -1)
|
||||
{
|
||||
srcIndex = i;
|
||||
}
|
||||
else if (destIndex == -1)
|
||||
{
|
||||
destIndex = i;
|
||||
}
|
||||
else
|
||||
{
|
||||
invalid_switch(arg[i]);
|
||||
return 11; /* Error */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* See so that at least source is there */
|
||||
if (nFiles < 1)
|
||||
{
|
||||
ConOutResPrintf(STRING_REPLACE_HELP2);
|
||||
ConOutResPrintf(STRING_REPLACE_HELP3);
|
||||
return 11; /* Error */
|
||||
}
|
||||
|
||||
/* Check so that not both update and add switch is added and subdir */
|
||||
if ((dwFlags & REPLACE_UPDATE || dwFlags & REPLACE_SUBDIR) && (dwFlags & REPLACE_ADD))
|
||||
{
|
||||
ConOutResPrintf(STRING_REPLACE_ERROR4);
|
||||
ConOutResPrintf(STRING_REPLACE_HELP7);
|
||||
return 11; /* Error */
|
||||
}
|
||||
|
||||
/* If we have a destination get the full path */
|
||||
if (destIndex != -1)
|
||||
{
|
||||
if (_tcslen(arg[destIndex]) == 2 && arg[destIndex][1] == ':')
|
||||
GetRootPath(arg[destIndex],szDestPath,MAX_PATH);
|
||||
else
|
||||
{
|
||||
/* Check for wildcards in destination directory */
|
||||
if (_tcschr (arg[destIndex], _T('*')) != NULL ||
|
||||
_tcschr (arg[destIndex], _T('?')) != NULL)
|
||||
{
|
||||
ConOutResPrintf(STRING_REPLACE_ERROR2,arg[destIndex]);
|
||||
ConOutResPrintf(STRING_REPLACE_HELP3);
|
||||
return 3; /* Error */
|
||||
}
|
||||
getPath(szDestPath, arg[destIndex]);
|
||||
/* Make sure that destination exists */
|
||||
if (!IsExistingDirectory(szDestPath))
|
||||
{
|
||||
ConOutResPrintf(STRING_REPLACE_ERROR2, szDestPath);
|
||||
ConOutResPrintf(STRING_REPLACE_HELP3);
|
||||
return 3; /* Error */
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Dest is current dir */
|
||||
GetCurrentDirectory(MAX_PATH,szDestPath);
|
||||
}
|
||||
|
||||
/* Get the full source path */
|
||||
if (!(_tcslen(arg[srcIndex]) == 2 && arg[srcIndex][1] == ':'))
|
||||
getPath(szSrcPath, arg[srcIndex]);
|
||||
else
|
||||
_tcscpy(szSrcPath,arg[srcIndex]);
|
||||
|
||||
/* Source does not have wildcards */
|
||||
if (_tcschr (arg[srcIndex], _T('*')) == NULL &&
|
||||
_tcschr (arg[srcIndex], _T('?')) == NULL)
|
||||
{
|
||||
/* Check so that source is not a directory, because that is not allowed */
|
||||
if (IsExistingDirectory(szSrcPath))
|
||||
{
|
||||
ConOutResPrintf(STRING_REPLACE_ERROR6, szSrcPath);
|
||||
ConOutResPrintf(STRING_REPLACE_HELP3);
|
||||
return 2; /* Error */
|
||||
}
|
||||
/* Check if the file exists */
|
||||
if (!IsExistingFile(szSrcPath))
|
||||
{
|
||||
ConOutResPrintf(STRING_REPLACE_HELP3);
|
||||
return 2; /* Error */
|
||||
}
|
||||
}
|
||||
|
||||
/* /w switch is set so wait for any key to be pressed */
|
||||
if (dwFlags & REPLACE_DISK)
|
||||
{
|
||||
msg_pause();
|
||||
cgetchar();
|
||||
}
|
||||
|
||||
/* Add an extra \ to the destination path if needed */
|
||||
if (szDestPath[_tcslen(szDestPath) - 1] != _T('\\'))
|
||||
_tcscat(szDestPath, _T("\\"));
|
||||
|
||||
/* Save source path */
|
||||
_tcscpy(tmpSrcPath,szSrcPath);
|
||||
/* Replace in dest dir */
|
||||
filesReplaced += recReplace(dwFlags, tmpSrcPath, szDestPath, &doMore);
|
||||
/* If subdir switch is set replace in the subdirs to */
|
||||
if (dwFlags & REPLACE_SUBDIR && doMore)
|
||||
{
|
||||
filesReplaced += recFindSubDirs(dwFlags, szSrcPath, szDestPath, &doMore);
|
||||
}
|
||||
|
||||
/* If source == dest write no more */
|
||||
if (filesReplaced != -1)
|
||||
{
|
||||
/* No files replaced */
|
||||
if (filesReplaced==0)
|
||||
{
|
||||
/* Add switch dependent output */
|
||||
if (dwFlags & REPLACE_ADD)
|
||||
ConOutResPrintf(STRING_REPLACE_HELP7);
|
||||
else
|
||||
ConOutResPrintf(STRING_REPLACE_HELP3);
|
||||
}
|
||||
/* Some files replaced */
|
||||
else
|
||||
{
|
||||
/* Add switch dependent output */
|
||||
if (dwFlags & REPLACE_ADD)
|
||||
ConOutResPrintf(STRING_REPLACE_HELP8, filesReplaced);
|
||||
else
|
||||
ConOutResPrintf(STRING_REPLACE_HELP4, filesReplaced);
|
||||
}
|
||||
}
|
||||
|
||||
/* Return memory */
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
static BOOL CALLBACK
|
||||
CtrlHandlerRoutine(DWORD dwCtrlType)
|
||||
{
|
||||
switch (dwCtrlType)
|
||||
{
|
||||
case CTRL_C_EVENT: /* Ctrl+C */
|
||||
case CTRL_CLOSE_EVENT: /* Closing console? */
|
||||
bCtrlBreak = TRUE;
|
||||
return TRUE; /* Handled */
|
||||
|
||||
default:
|
||||
return FALSE; /* Ignored */
|
||||
}
|
||||
}
|
||||
|
||||
int wmain(int argc, WCHAR **argvW)
|
||||
{
|
||||
/* Handle Ctrl+C and console closing */
|
||||
SetConsoleCtrlHandler(CtrlHandlerRoutine, TRUE);
|
||||
|
||||
/* Initialize the Console Standard Streams */
|
||||
ConInitStdStreams();
|
||||
|
||||
return cmd_replace(argc, argvW);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue