mirror of
https://github.com/reactos/reactos.git
synced 2025-02-20 15:35:04 +00:00
[CMDUTILS][FC] Implement FC wildcard handling (#3640)
Implement wildcard handling on FC (file comparison) command. And fix the bugs on zero-sized files. CORE-17500
This commit is contained in:
parent
3644f3efca
commit
7b27e7c4ff
3 changed files with 231 additions and 39 deletions
|
@ -2,6 +2,6 @@ include_directories(${REACTOS_SOURCE_DIR}/sdk/lib/conutils)
|
|||
|
||||
add_executable(fc fc.c texta.c textw.c fc.rc)
|
||||
set_module_type(fc win32cui UNICODE)
|
||||
target_link_libraries(fc conutils wine ${PSEH_LIB})
|
||||
add_importlibs(fc msvcrt user32 kernel32 ntdll)
|
||||
target_link_libraries(fc conutils ${PSEH_LIB})
|
||||
add_importlibs(fc msvcrt shlwapi user32 kernel32)
|
||||
add_cd_file(TARGET fc DESTINATION reactos/system32 FOR all)
|
||||
|
|
|
@ -40,6 +40,8 @@
|
|||
va_end(va);
|
||||
}
|
||||
#endif
|
||||
#include <strsafe.h>
|
||||
#include <shlwapi.h>
|
||||
|
||||
FCRET NoDifference(VOID)
|
||||
{
|
||||
|
@ -271,21 +273,26 @@ static FCRET TextFileCompare(FILECOMPARE *pFC)
|
|||
ret = NoDifference();
|
||||
break;
|
||||
}
|
||||
hMapping0 = CreateFileMappingW(hFile0, NULL, PAGE_READONLY,
|
||||
cb0.HighPart, cb0.LowPart, NULL);
|
||||
if (hMapping0 == NULL)
|
||||
if (cb0.QuadPart > 0)
|
||||
{
|
||||
ret = CannotRead(pFC->file[0]);
|
||||
break;
|
||||
hMapping0 = CreateFileMappingW(hFile0, NULL, PAGE_READONLY,
|
||||
cb0.HighPart, cb0.LowPart, NULL);
|
||||
if (hMapping0 == NULL)
|
||||
{
|
||||
ret = CannotRead(pFC->file[0]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
hMapping1 = CreateFileMappingW(hFile1, NULL, PAGE_READONLY,
|
||||
cb1.HighPart, cb1.LowPart, NULL);
|
||||
if (hMapping1 == NULL)
|
||||
if (cb1.QuadPart > 0)
|
||||
{
|
||||
ret = CannotRead(pFC->file[1]);
|
||||
break;
|
||||
hMapping1 = CreateFileMappingW(hFile1, NULL, PAGE_READONLY,
|
||||
cb1.HighPart, cb1.LowPart, NULL);
|
||||
if (hMapping1 == NULL)
|
||||
{
|
||||
ret = CannotRead(pFC->file[1]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (fUnicode)
|
||||
ret = TextCompareW(pFC, &hMapping0, &cb0, &hMapping1, &cb1);
|
||||
else
|
||||
|
@ -330,24 +337,210 @@ static BOOL IsBinaryExt(LPCWSTR filename)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
#define HasWildcard(filename) \
|
||||
((wcschr((filename), L'*') != NULL) || (wcschr((filename), L'?') != NULL))
|
||||
|
||||
static FCRET FileCompare(FILECOMPARE *pFC)
|
||||
{
|
||||
FCRET ret;
|
||||
ConResPrintf(StdOut, IDS_COMPARING, pFC->file[0], pFC->file[1]);
|
||||
|
||||
if (!(pFC->dwFlags & FLAG_L) &&
|
||||
((pFC->dwFlags & FLAG_B) || IsBinaryExt(pFC->file[0]) || IsBinaryExt(pFC->file[1])))
|
||||
{
|
||||
return BinaryFileCompare(pFC);
|
||||
ret = BinaryFileCompare(pFC);
|
||||
}
|
||||
return TextFileCompare(pFC);
|
||||
else
|
||||
{
|
||||
ret = TextFileCompare(pFC);
|
||||
}
|
||||
|
||||
ConPuts(StdOut, L"\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Is it L"." or L".."? */
|
||||
#define IS_DOTS(pch) \
|
||||
((*(pch) == L'.') && (((pch)[1] == 0) || (((pch)[1] == L'.') && ((pch)[2] == 0))))
|
||||
#define HasWildcard(filename) \
|
||||
((wcschr((filename), L'*') != NULL) || (wcschr((filename), L'?') != NULL))
|
||||
|
||||
static inline BOOL IsTitleWild(LPCWSTR filename)
|
||||
{
|
||||
LPCWSTR pch = PathFindFileNameW(filename);
|
||||
return (pch && *pch == L'*' && pch[1] == L'.' && !HasWildcard(&pch[2]));
|
||||
}
|
||||
|
||||
static FCRET FileCompareOneSideWild(const FILECOMPARE *pFC, BOOL bWildRight)
|
||||
{
|
||||
FCRET ret = FCRET_IDENTICAL;
|
||||
WIN32_FIND_DATAW find;
|
||||
HANDLE hFind;
|
||||
WCHAR szPath[MAX_PATH];
|
||||
FILECOMPARE fc;
|
||||
|
||||
hFind = FindFirstFileW(pFC->file[bWildRight], &find);
|
||||
if (hFind == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
ConResPrintf(StdErr, IDS_CANNOT_OPEN, pFC->file[bWildRight]);
|
||||
ConPuts(StdOut, L"\n");
|
||||
return FCRET_CANT_FIND;
|
||||
}
|
||||
StringCbCopyW(szPath, sizeof(szPath), pFC->file[bWildRight]);
|
||||
|
||||
fc = *pFC;
|
||||
fc.file[!bWildRight] = pFC->file[!bWildRight];
|
||||
fc.file[bWildRight] = szPath;
|
||||
do
|
||||
{
|
||||
if (IS_DOTS(find.cFileName))
|
||||
continue;
|
||||
|
||||
// replace file title
|
||||
PathRemoveFileSpecW(szPath);
|
||||
PathAppendW(szPath, find.cFileName);
|
||||
|
||||
switch (FileCompare(&fc))
|
||||
{
|
||||
case FCRET_IDENTICAL:
|
||||
break;
|
||||
case FCRET_DIFFERENT:
|
||||
if (ret != FCRET_INVALID)
|
||||
ret = FCRET_DIFFERENT;
|
||||
break;
|
||||
default:
|
||||
ret = FCRET_INVALID;
|
||||
break;
|
||||
}
|
||||
} while (FindNextFileW(hFind, &find));
|
||||
|
||||
FindClose(hFind);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static FCRET FileCompareWildTitle(const FILECOMPARE *pFC)
|
||||
{
|
||||
FCRET ret = FCRET_IDENTICAL;
|
||||
WIN32_FIND_DATAW find;
|
||||
HANDLE hFind;
|
||||
WCHAR szPath0[MAX_PATH], szPath1[MAX_PATH];
|
||||
FILECOMPARE fc;
|
||||
LPWSTR pch;
|
||||
|
||||
hFind = FindFirstFileW(pFC->file[0], &find);
|
||||
if (hFind == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
ConResPrintf(StdErr, IDS_CANNOT_OPEN, pFC->file[0]);
|
||||
ConPuts(StdOut, L"\n");
|
||||
return FCRET_CANT_FIND;
|
||||
}
|
||||
StringCbCopyW(szPath0, sizeof(szPath0), pFC->file[0]);
|
||||
StringCbCopyW(szPath1, sizeof(szPath1), pFC->file[1]);
|
||||
pch = PathFindExtensionW(pFC->file[1]);
|
||||
|
||||
fc = *pFC;
|
||||
fc.file[0] = szPath0;
|
||||
fc.file[1] = szPath1;
|
||||
do
|
||||
{
|
||||
if (IS_DOTS(find.cFileName))
|
||||
continue;
|
||||
|
||||
// replace file title
|
||||
PathRemoveFileSpecW(szPath0);
|
||||
PathRemoveFileSpecW(szPath1);
|
||||
PathAppendW(szPath0, find.cFileName);
|
||||
PathAppendW(szPath1, find.cFileName);
|
||||
|
||||
// replace dot extension
|
||||
PathRemoveExtensionW(szPath1);
|
||||
PathAddExtensionW(szPath1, pch);
|
||||
|
||||
switch (FileCompare(&fc))
|
||||
{
|
||||
case FCRET_IDENTICAL:
|
||||
break;
|
||||
case FCRET_DIFFERENT:
|
||||
if (ret != FCRET_INVALID)
|
||||
ret = FCRET_DIFFERENT;
|
||||
break;
|
||||
default:
|
||||
ret = FCRET_INVALID;
|
||||
break;
|
||||
}
|
||||
} while (FindNextFileW(hFind, &find));
|
||||
|
||||
FindClose(hFind);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static FCRET FileCompareBothWild(const FILECOMPARE *pFC)
|
||||
{
|
||||
FCRET ret = FCRET_IDENTICAL;
|
||||
WIN32_FIND_DATAW find0, find1;
|
||||
HANDLE hFind0, hFind1;
|
||||
WCHAR szPath0[MAX_PATH], szPath1[MAX_PATH];
|
||||
FILECOMPARE fc;
|
||||
|
||||
hFind0 = FindFirstFileW(pFC->file[0], &find0);
|
||||
if (hFind0 == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
ConResPrintf(StdErr, IDS_CANNOT_OPEN, pFC->file[0]);
|
||||
ConPuts(StdOut, L"\n");
|
||||
return FCRET_CANT_FIND;
|
||||
}
|
||||
hFind1 = FindFirstFileW(pFC->file[1], &find1);
|
||||
if (hFind1 == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
CloseHandle(hFind0);
|
||||
ConResPrintf(StdErr, IDS_CANNOT_OPEN, pFC->file[1]);
|
||||
ConPuts(StdOut, L"\n");
|
||||
return FCRET_CANT_FIND;
|
||||
}
|
||||
StringCbCopyW(szPath0, sizeof(szPath0), pFC->file[0]);
|
||||
StringCbCopyW(szPath1, sizeof(szPath1), pFC->file[1]);
|
||||
|
||||
fc = *pFC;
|
||||
fc.file[0] = szPath0;
|
||||
fc.file[1] = szPath1;
|
||||
do
|
||||
{
|
||||
while (IS_DOTS(find0.cFileName))
|
||||
{
|
||||
if (!FindNextFileW(hFind0, &find0))
|
||||
goto quit;
|
||||
}
|
||||
while (IS_DOTS(find1.cFileName))
|
||||
{
|
||||
if (!FindNextFileW(hFind1, &find1))
|
||||
goto quit;
|
||||
}
|
||||
|
||||
// replace file title
|
||||
PathRemoveFileSpecW(szPath0);
|
||||
PathRemoveFileSpecW(szPath1);
|
||||
PathAppendW(szPath0, find0.cFileName);
|
||||
PathAppendW(szPath1, find1.cFileName);
|
||||
|
||||
switch (FileCompare(&fc))
|
||||
{
|
||||
case FCRET_IDENTICAL:
|
||||
break;
|
||||
case FCRET_DIFFERENT:
|
||||
if (ret != FCRET_INVALID)
|
||||
ret = FCRET_DIFFERENT;
|
||||
break;
|
||||
default:
|
||||
ret = FCRET_INVALID;
|
||||
break;
|
||||
}
|
||||
} while (FindNextFileW(hFind0, &find0) && FindNextFileW(hFind1, &find1));
|
||||
quit:
|
||||
CloseHandle(hFind0);
|
||||
CloseHandle(hFind1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static FCRET WildcardFileCompare(FILECOMPARE *pFC)
|
||||
{
|
||||
FCRET ret;
|
||||
BOOL fWild0, fWild1;
|
||||
|
||||
if (pFC->dwFlags & FLAG_HELP)
|
||||
{
|
||||
|
@ -361,15 +554,24 @@ static FCRET WildcardFileCompare(FILECOMPARE *pFC)
|
|||
return FCRET_INVALID;
|
||||
}
|
||||
|
||||
if (HasWildcard(pFC->file[0]) || HasWildcard(pFC->file[1]))
|
||||
fWild0 = HasWildcard(pFC->file[0]);
|
||||
fWild1 = HasWildcard(pFC->file[1]);
|
||||
if (fWild0 && fWild1)
|
||||
{
|
||||
// TODO: wildcard
|
||||
ConResPuts(StdErr, IDS_CANT_USE_WILDCARD);
|
||||
if (IsTitleWild(pFC->file[0]) && IsTitleWild(pFC->file[1]))
|
||||
return FileCompareWildTitle(pFC);
|
||||
else
|
||||
return FileCompareBothWild(pFC);
|
||||
}
|
||||
|
||||
ret = FileCompare(pFC);
|
||||
ConPuts(StdOut, L"\n");
|
||||
return ret;
|
||||
else if (fWild0)
|
||||
{
|
||||
return FileCompareOneSideWild(pFC, FALSE);
|
||||
}
|
||||
else if (fWild1)
|
||||
{
|
||||
return FileCompareOneSideWild(pFC, TRUE);
|
||||
}
|
||||
return FileCompare(pFC);
|
||||
}
|
||||
|
||||
int wmain(int argc, WCHAR **argv)
|
||||
|
|
|
@ -5,16 +5,6 @@
|
|||
* COPYRIGHT: Copyright 2021 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
|
||||
*/
|
||||
#include "fc.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef __REACTOS__
|
||||
#include <wine/debug.h>
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(fc);
|
||||
#else
|
||||
#define ERR /*empty*/
|
||||
#define WARN /*empty*/
|
||||
#define TRACE /*empty*/
|
||||
#endif
|
||||
|
||||
#define IS_SPACE(ch) ((ch) == TEXT(' ') || (ch) == TEXT('\t'))
|
||||
|
||||
|
@ -297,7 +287,6 @@ ParseLines(const FILECOMPARE *pFC, HANDLE *phMapping,
|
|||
{
|
||||
bCR = (ichNext > 0) && (psz[ichNext - 1] == TEXT('\r'));
|
||||
cchNode = ichNext - ich - bCR;
|
||||
TRACE("ich:%ld, cch:%ld, ichNext:%ld, cchNode:%ld\n", ich, cch, ichNext, cchNode);
|
||||
pszLine = AllocLine(&psz[ich], cchNode);
|
||||
node = AllocNode(pszLine, lineno++);
|
||||
if (!node || !ConvertNode(pFC, node))
|
||||
|
@ -524,10 +513,10 @@ Resync(FILECOMPARE *pFC, struct list **pptr0, struct list **pptr1)
|
|||
static FCRET
|
||||
Finalize(FILECOMPARE* pFC, struct list *ptr0, struct list* ptr1, BOOL fDifferent)
|
||||
{
|
||||
if (!ptr0 || !ptr1)
|
||||
if (!ptr0 && !ptr1)
|
||||
{
|
||||
if (fDifferent)
|
||||
return FCRET_DIFFERENT;
|
||||
return Different(pFC->file[0], pFC->file[1]);
|
||||
return NoDifference();
|
||||
}
|
||||
else
|
||||
|
@ -539,6 +528,7 @@ Finalize(FILECOMPARE* pFC, struct list *ptr0, struct list* ptr1, BOOL fDifferent
|
|||
}
|
||||
}
|
||||
|
||||
// FIXME: "cmd_apitest fc" has some failures.
|
||||
FCRET TextCompare(FILECOMPARE *pFC, HANDLE *phMapping0, const LARGE_INTEGER *pcb0,
|
||||
HANDLE *phMapping1, const LARGE_INTEGER *pcb1)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue