mirror of
https://github.com/reactos/reactos.git
synced 2024-09-28 13:34:53 +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
|
@ -2,6 +2,6 @@ include_directories(${REACTOS_SOURCE_DIR}/sdk/lib/conutils)
|
||||||
|
|
||||||
add_executable(fc fc.c texta.c textw.c fc.rc)
|
add_executable(fc fc.c texta.c textw.c fc.rc)
|
||||||
set_module_type(fc win32cui UNICODE)
|
set_module_type(fc win32cui UNICODE)
|
||||||
target_link_libraries(fc conutils wine ${PSEH_LIB})
|
target_link_libraries(fc conutils ${PSEH_LIB})
|
||||||
add_importlibs(fc msvcrt user32 kernel32 ntdll)
|
add_importlibs(fc msvcrt shlwapi user32 kernel32)
|
||||||
add_cd_file(TARGET fc DESTINATION reactos/system32 FOR all)
|
add_cd_file(TARGET fc DESTINATION reactos/system32 FOR all)
|
||||||
|
|
|
@ -40,6 +40,8 @@
|
||||||
va_end(va);
|
va_end(va);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#include <strsafe.h>
|
||||||
|
#include <shlwapi.h>
|
||||||
|
|
||||||
FCRET NoDifference(VOID)
|
FCRET NoDifference(VOID)
|
||||||
{
|
{
|
||||||
|
@ -271,21 +273,26 @@ static FCRET TextFileCompare(FILECOMPARE *pFC)
|
||||||
ret = NoDifference();
|
ret = NoDifference();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
hMapping0 = CreateFileMappingW(hFile0, NULL, PAGE_READONLY,
|
if (cb0.QuadPart > 0)
|
||||||
cb0.HighPart, cb0.LowPart, NULL);
|
|
||||||
if (hMapping0 == NULL)
|
|
||||||
{
|
{
|
||||||
ret = CannotRead(pFC->file[0]);
|
hMapping0 = CreateFileMappingW(hFile0, NULL, PAGE_READONLY,
|
||||||
break;
|
cb0.HighPart, cb0.LowPart, NULL);
|
||||||
|
if (hMapping0 == NULL)
|
||||||
|
{
|
||||||
|
ret = CannotRead(pFC->file[0]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
hMapping1 = CreateFileMappingW(hFile1, NULL, PAGE_READONLY,
|
if (cb1.QuadPart > 0)
|
||||||
cb1.HighPart, cb1.LowPart, NULL);
|
|
||||||
if (hMapping1 == NULL)
|
|
||||||
{
|
{
|
||||||
ret = CannotRead(pFC->file[1]);
|
hMapping1 = CreateFileMappingW(hFile1, NULL, PAGE_READONLY,
|
||||||
break;
|
cb1.HighPart, cb1.LowPart, NULL);
|
||||||
|
if (hMapping1 == NULL)
|
||||||
|
{
|
||||||
|
ret = CannotRead(pFC->file[1]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fUnicode)
|
if (fUnicode)
|
||||||
ret = TextCompareW(pFC, &hMapping0, &cb0, &hMapping1, &cb1);
|
ret = TextCompareW(pFC, &hMapping0, &cb0, &hMapping1, &cb1);
|
||||||
else
|
else
|
||||||
|
@ -330,24 +337,210 @@ static BOOL IsBinaryExt(LPCWSTR filename)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define HasWildcard(filename) \
|
|
||||||
((wcschr((filename), L'*') != NULL) || (wcschr((filename), L'?') != NULL))
|
|
||||||
|
|
||||||
static FCRET FileCompare(FILECOMPARE *pFC)
|
static FCRET FileCompare(FILECOMPARE *pFC)
|
||||||
{
|
{
|
||||||
|
FCRET ret;
|
||||||
ConResPrintf(StdOut, IDS_COMPARING, pFC->file[0], pFC->file[1]);
|
ConResPrintf(StdOut, IDS_COMPARING, pFC->file[0], pFC->file[1]);
|
||||||
|
|
||||||
if (!(pFC->dwFlags & FLAG_L) &&
|
if (!(pFC->dwFlags & FLAG_L) &&
|
||||||
((pFC->dwFlags & FLAG_B) || IsBinaryExt(pFC->file[0]) || IsBinaryExt(pFC->file[1])))
|
((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)
|
static FCRET WildcardFileCompare(FILECOMPARE *pFC)
|
||||||
{
|
{
|
||||||
FCRET ret;
|
BOOL fWild0, fWild1;
|
||||||
|
|
||||||
if (pFC->dwFlags & FLAG_HELP)
|
if (pFC->dwFlags & FLAG_HELP)
|
||||||
{
|
{
|
||||||
|
@ -361,15 +554,24 @@ static FCRET WildcardFileCompare(FILECOMPARE *pFC)
|
||||||
return FCRET_INVALID;
|
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
|
if (IsTitleWild(pFC->file[0]) && IsTitleWild(pFC->file[1]))
|
||||||
ConResPuts(StdErr, IDS_CANT_USE_WILDCARD);
|
return FileCompareWildTitle(pFC);
|
||||||
|
else
|
||||||
|
return FileCompareBothWild(pFC);
|
||||||
}
|
}
|
||||||
|
else if (fWild0)
|
||||||
ret = FileCompare(pFC);
|
{
|
||||||
ConPuts(StdOut, L"\n");
|
return FileCompareOneSideWild(pFC, FALSE);
|
||||||
return ret;
|
}
|
||||||
|
else if (fWild1)
|
||||||
|
{
|
||||||
|
return FileCompareOneSideWild(pFC, TRUE);
|
||||||
|
}
|
||||||
|
return FileCompare(pFC);
|
||||||
}
|
}
|
||||||
|
|
||||||
int wmain(int argc, WCHAR **argv)
|
int wmain(int argc, WCHAR **argv)
|
||||||
|
|
|
@ -5,16 +5,6 @@
|
||||||
* COPYRIGHT: Copyright 2021 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
|
* COPYRIGHT: Copyright 2021 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
|
||||||
*/
|
*/
|
||||||
#include "fc.h"
|
#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'))
|
#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'));
|
bCR = (ichNext > 0) && (psz[ichNext - 1] == TEXT('\r'));
|
||||||
cchNode = ichNext - ich - bCR;
|
cchNode = ichNext - ich - bCR;
|
||||||
TRACE("ich:%ld, cch:%ld, ichNext:%ld, cchNode:%ld\n", ich, cch, ichNext, cchNode);
|
|
||||||
pszLine = AllocLine(&psz[ich], cchNode);
|
pszLine = AllocLine(&psz[ich], cchNode);
|
||||||
node = AllocNode(pszLine, lineno++);
|
node = AllocNode(pszLine, lineno++);
|
||||||
if (!node || !ConvertNode(pFC, node))
|
if (!node || !ConvertNode(pFC, node))
|
||||||
|
@ -524,10 +513,10 @@ Resync(FILECOMPARE *pFC, struct list **pptr0, struct list **pptr1)
|
||||||
static FCRET
|
static FCRET
|
||||||
Finalize(FILECOMPARE* pFC, struct list *ptr0, struct list* ptr1, BOOL fDifferent)
|
Finalize(FILECOMPARE* pFC, struct list *ptr0, struct list* ptr1, BOOL fDifferent)
|
||||||
{
|
{
|
||||||
if (!ptr0 || !ptr1)
|
if (!ptr0 && !ptr1)
|
||||||
{
|
{
|
||||||
if (fDifferent)
|
if (fDifferent)
|
||||||
return FCRET_DIFFERENT;
|
return Different(pFC->file[0], pFC->file[1]);
|
||||||
return NoDifference();
|
return NoDifference();
|
||||||
}
|
}
|
||||||
else
|
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,
|
FCRET TextCompare(FILECOMPARE *pFC, HANDLE *phMapping0, const LARGE_INTEGER *pcb0,
|
||||||
HANDLE *phMapping1, const LARGE_INTEGER *pcb1)
|
HANDLE *phMapping1, const LARGE_INTEGER *pcb1)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue