https://git.reactos.org/?p=reactos.git;a=commitdiff;h=8bf471105e2d0bbb3c1d913647e5ce88d9b3d0d4

commit 8bf471105e2d0bbb3c1d913647e5ce88d9b3d0d4
Author:     Katayama Hirofumi MZ <[email protected]>
AuthorDate: Sun Apr 25 13:06:13 2021 +0900
Commit:     GitHub <[email protected]>
CommitDate: Sun Apr 25 13:06:13 2021 +0900

    [CMDUTILS][FC] Initial implement FC command (#3622)
    
    Implement FC (file comparison) command. As a starting point, we support 
binary mode comparison at first. Text mode comparison and wildcard are not 
supported yet. CORE-17500
---
 base/applications/cmdutils/CMakeLists.txt    |   1 +
 base/applications/cmdutils/fc/CMakeLists.txt |   7 +
 base/applications/cmdutils/fc/fc.c           | 496 +++++++++++++++++++++++++++
 base/applications/cmdutils/fc/fc.rc          |  12 +
 base/applications/cmdutils/fc/lang/en-US.rc  |  41 +++
 base/applications/cmdutils/fc/resource.h     |  13 +
 6 files changed, 570 insertions(+)

diff --git a/base/applications/cmdutils/CMakeLists.txt 
b/base/applications/cmdutils/CMakeLists.txt
index 43b10eb6c73..f1cd0b9fd1d 100644
--- a/base/applications/cmdutils/CMakeLists.txt
+++ b/base/applications/cmdutils/CMakeLists.txt
@@ -8,6 +8,7 @@ add_subdirectory(cscript)
 add_subdirectory(dbgprint)
 add_subdirectory(doskey)
 add_subdirectory(eventcreate)
+add_subdirectory(fc)
 add_subdirectory(find)
 add_subdirectory(fsutil)
 add_subdirectory(help)
diff --git a/base/applications/cmdutils/fc/CMakeLists.txt 
b/base/applications/cmdutils/fc/CMakeLists.txt
new file mode 100644
index 00000000000..fec64446ae1
--- /dev/null
+++ b/base/applications/cmdutils/fc/CMakeLists.txt
@@ -0,0 +1,7 @@
+include_directories(${REACTOS_SOURCE_DIR}/sdk/lib/conutils)
+
+add_executable(fc fc.c fc.rc)
+set_module_type(fc win32cui UNICODE)
+target_link_libraries(fc conutils ${PSEH_LIB})
+add_importlibs(fc msvcrt user32 kernel32)
+add_cd_file(TARGET fc DESTINATION reactos/system32 FOR all)
diff --git a/base/applications/cmdutils/fc/fc.c 
b/base/applications/cmdutils/fc/fc.c
new file mode 100644
index 00000000000..1697219c6cb
--- /dev/null
+++ b/base/applications/cmdutils/fc/fc.c
@@ -0,0 +1,496 @@
+/*
+ * PROJECT:     ReactOS FC Command
+ * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE:     Comparing files
+ * COPYRIGHT:   Copyright 2021 Katayama Hirofumi MZ 
([email protected])
+ */
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <windef.h>
+#include <winbase.h>
+#include <winuser.h>
+#include <winnls.h>
+#include <conutils.h>
+#include "resource.h"
+
+// See also: 
https://stackoverflow.com/questions/33125766/compare-files-with-a-cmd
+typedef enum FCRET { // return code of FC command
+    FCRET_INVALID = -1, FCRET_IDENTICAL = 0, FCRET_DIFFERENT = 1, 
FCRET_CANT_FIND = 2
+} FCRET;
+
+#ifdef _WIN64
+    #define MAX_VIEW_SIZE (256 * 1024 * 1024) // 256 MB
+#else
+    #define MAX_VIEW_SIZE (64 * 1024 * 1024) // 64 MB
+#endif
+
+#define FLAG_A (1 << 0)
+#define FLAG_B (1 << 1)
+#define FLAG_C (1 << 2)
+#define FLAG_L (1 << 3)
+#define FLAG_LBn (1 << 4)
+#define FLAG_N (1 << 5)
+#define FLAG_OFFLINE (1 << 6)
+#define FLAG_T (1 << 7)
+#define FLAG_U (1 << 8)
+#define FLAG_W (1 << 9)
+#define FLAG_nnnn (1 << 10)
+#define FLAG_HELP (1 << 11)
+
+typedef struct FILECOMPARE {
+    DWORD dwFlags; // FLAG_...
+    INT n, nnnn;
+    LPCWSTR file1, file2;
+} FILECOMPARE;
+
+static FCRET NoDifference(VOID)
+{
+    ConResPuts(StdOut, IDS_NO_DIFFERENCE);
+    return FCRET_IDENTICAL;
+}
+
+static FCRET Different(LPCWSTR file1, LPCWSTR file2)
+{
+    ConResPrintf(StdOut, IDS_DIFFERENT, file1, file2);
+    return FCRET_DIFFERENT;
+}
+
+static FCRET LongerThan(LPCWSTR file1, LPCWSTR file2)
+{
+    ConResPrintf(StdOut, IDS_LONGER_THAN, file1, file2);
+    return FCRET_DIFFERENT;
+}
+
+static FCRET OutOfMemory(VOID)
+{
+    ConResPuts(StdErr, IDS_OUT_OF_MEMORY);
+    return FCRET_INVALID;
+}
+
+static FCRET CannotRead(LPCWSTR file)
+{
+    ConResPrintf(StdErr, IDS_CANNOT_READ, file);
+    return FCRET_INVALID;
+}
+
+static FCRET InvalidSwitch(VOID)
+{
+    ConResPuts(StdErr, IDS_INVALID_SWITCH);
+    return FCRET_INVALID;
+}
+
+static HANDLE DoOpenFileForInput(LPCWSTR file)
+{
+    HANDLE hFile = CreateFileW(file, GENERIC_READ, FILE_SHARE_READ, NULL, 
OPEN_EXISTING, 0, NULL);
+    if (hFile == INVALID_HANDLE_VALUE)
+    {
+        ConResPrintf(StdErr, IDS_CANNOT_OPEN, file);
+    }
+    return hFile;
+}
+
+static FCRET BinaryFileCompare(FILECOMPARE *pFC)
+{
+    FCRET ret;
+    HANDLE hFile1, hFile2, hMapping1 = NULL, hMapping2 = NULL;
+    LPBYTE pb1 = NULL, pb2 = NULL;
+    LARGE_INTEGER ib, cb1, cb2, cbCommon;
+    DWORD cbView, ibView;
+    BOOL fDifferent = FALSE;
+
+    hFile1 = DoOpenFileForInput(pFC->file1);
+    if (hFile1 == INVALID_HANDLE_VALUE)
+        return FCRET_CANT_FIND;
+    hFile2 = DoOpenFileForInput(pFC->file2);
+    if (hFile2 == INVALID_HANDLE_VALUE)
+    {
+        CloseHandle(hFile1);
+        return FCRET_CANT_FIND;
+    }
+
+    do
+    {
+        if (_wcsicmp(pFC->file1, pFC->file2) == 0)
+        {
+            ret = NoDifference();
+            break;
+        }
+        if (!GetFileSizeEx(hFile1, &cb1))
+        {
+            ret = CannotRead(pFC->file1);
+            break;
+        }
+        if (!GetFileSizeEx(hFile2, &cb2))
+        {
+            ret = CannotRead(pFC->file2);
+            break;
+        }
+        cbCommon.QuadPart = min(cb1.QuadPart, cb2.QuadPart);
+        if (cbCommon.QuadPart > 0)
+        {
+            hMapping1 = CreateFileMappingW(hFile1, NULL, PAGE_READONLY,
+                                           cb1.HighPart, cb1.LowPart, NULL);
+            if (hMapping1 == NULL)
+            {
+                ret = CannotRead(pFC->file1);
+                break;
+            }
+            hMapping2 = CreateFileMappingW(hFile2, NULL, PAGE_READONLY,
+                                           cb2.HighPart, cb2.LowPart, NULL);
+            if (hMapping2 == NULL)
+            {
+                ret = CannotRead(pFC->file2);
+                break;
+            }
+
+            ret = FCRET_IDENTICAL;
+            for (ib.QuadPart = 0; ib.QuadPart < cbCommon.QuadPart; )
+            {
+                cbView = (DWORD)min(cbCommon.QuadPart - ib.QuadPart, 
MAX_VIEW_SIZE);
+                pb1 = MapViewOfFile(hMapping1, FILE_MAP_READ, ib.HighPart, 
ib.LowPart, cbView);
+                pb2 = MapViewOfFile(hMapping2, FILE_MAP_READ, ib.HighPart, 
ib.LowPart, cbView);
+                if (!pb1 || !pb2)
+                {
+                    ret = OutOfMemory();
+                    break;
+                }
+                for (ibView = 0; ibView < cbView; ++ib.QuadPart, ++ibView)
+                {
+                    if (pb1[ibView] == pb2[ibView])
+                        continue;
+
+                    fDifferent = TRUE;
+                    if (cbCommon.QuadPart > MAXDWORD)
+                    {
+                        ConPrintf(StdOut, L"%016I64X: %02X %02X\n", 
ib.QuadPart,
+                                  pb1[ibView], pb2[ibView]);
+                    }
+                    else
+                    {
+                        ConPrintf(StdOut, L"%08lX: %02X %02X\n", ib.LowPart,
+                                  pb1[ibView], pb2[ibView]);
+                    }
+                }
+                UnmapViewOfFile(pb1);
+                UnmapViewOfFile(pb2);
+                pb1 = pb2 = NULL;
+            }
+            if (ret != FCRET_IDENTICAL)
+                break;
+        }
+
+        if (cb1.QuadPart < cb2.QuadPart)
+            ret = LongerThan(pFC->file2, pFC->file1);
+        else if (cb1.QuadPart > cb2.QuadPart)
+            ret = LongerThan(pFC->file1, pFC->file2);
+        else if (fDifferent)
+            ret = Different(pFC->file1, pFC->file2);
+        else
+            ret = NoDifference();
+    } while (0);
+
+    UnmapViewOfFile(pb1);
+    UnmapViewOfFile(pb2);
+    CloseHandle(hMapping1);
+    CloseHandle(hMapping2);
+    CloseHandle(hFile1);
+    CloseHandle(hFile2);
+    return ret;
+}
+
+static FCRET
+UnicodeTextCompare(FILECOMPARE *pFC, HANDLE hMapping1, const LARGE_INTEGER 
*pcb1,
+                                     HANDLE hMapping2, const LARGE_INTEGER 
*pcb2)
+{
+    FCRET ret;
+    BOOL fIgnoreCase = !!(pFC->dwFlags & FLAG_C);
+    DWORD dwCmpFlags = (fIgnoreCase ? NORM_IGNORECASE : 0);
+    LPCWSTR psz1, psz2;
+    LARGE_INTEGER cch1 = { .QuadPart = pcb1->QuadPart / sizeof(WCHAR) };
+    LARGE_INTEGER cch2 = { .QuadPart = pcb1->QuadPart / sizeof(WCHAR) };
+
+    do
+    {
+        psz1 = MapViewOfFile(hMapping1, FILE_MAP_READ, 0, 0, pcb1->LowPart);
+        psz2 = MapViewOfFile(hMapping2, FILE_MAP_READ, 0, 0, pcb2->LowPart);
+        if (!psz1 || !psz2)
+        {
+            ret = OutOfMemory();
+            break;
+        }
+        if (cch1.QuadPart < MAXLONG && cch2.QuadPart < MAXLONG)
+        {
+            if (CompareStringW(0, dwCmpFlags, psz1, cch1.LowPart,
+                                              psz2, cch2.LowPart) == 
CSTR_EQUAL)
+            {
+                ret = NoDifference();
+                break;
+            }
+        }
+        // TODO: compare each lines
+        // TODO: large file support
+        ret = Different(pFC->file1, pFC->file2);
+    } while (0);
+
+    UnmapViewOfFile(psz1);
+    UnmapViewOfFile(psz2);
+    return ret;
+}
+
+static FCRET
+AnsiTextCompare(FILECOMPARE *pFC, HANDLE hMapping1, const LARGE_INTEGER *pcb1,
+                                  HANDLE hMapping2, const LARGE_INTEGER *pcb2)
+{
+    FCRET ret;
+    BOOL fIgnoreCase = !!(pFC->dwFlags & FLAG_C);
+    DWORD dwCmpFlags = (fIgnoreCase ? NORM_IGNORECASE : 0);
+    LPSTR psz1, psz2;
+
+    do
+    {
+        psz1 = MapViewOfFile(hMapping1, FILE_MAP_READ, 0, 0, pcb1->LowPart);
+        psz2 = MapViewOfFile(hMapping2, FILE_MAP_READ, 0, 0, pcb2->LowPart);
+        if (!psz1 || !psz2)
+        {
+            ret = OutOfMemory();
+            break;
+        }
+        if (pcb1->QuadPart < MAXLONG && pcb2->QuadPart < MAXLONG)
+        {
+            if (CompareStringA(0, dwCmpFlags, psz1, pcb1->LowPart,
+                                              psz2, pcb2->LowPart) == 
CSTR_EQUAL)
+            {
+                ret = NoDifference();
+                break;
+            }
+        }
+        // TODO: compare each lines
+        // TODO: large file support
+        ret = Different(pFC->file1, pFC->file2);
+    } while (0);
+
+    UnmapViewOfFile(psz1);
+    UnmapViewOfFile(psz2);
+    return ret;
+}
+
+static FCRET TextFileCompare(FILECOMPARE *pFC)
+{
+    FCRET ret;
+    HANDLE hFile1, hFile2, hMapping1 = NULL, hMapping2 = NULL;
+    LARGE_INTEGER cb1, cb2;
+    BOOL fUnicode = !!(pFC->dwFlags & FLAG_U);
+
+    hFile1 = DoOpenFileForInput(pFC->file1);
+    if (hFile1 == INVALID_HANDLE_VALUE)
+        return FCRET_CANT_FIND;
+    hFile2 = DoOpenFileForInput(pFC->file2);
+    if (hFile2 == INVALID_HANDLE_VALUE)
+    {
+        CloseHandle(hFile1);
+        return FCRET_CANT_FIND;
+    }
+
+    do
+    {
+        if (_wcsicmp(pFC->file1, pFC->file2) == 0)
+        {
+            ret = NoDifference();
+            break;
+        }
+        if (!GetFileSizeEx(hFile1, &cb1))
+        {
+            ret = CannotRead(pFC->file1);
+            break;
+        }
+        if (!GetFileSizeEx(hFile2, &cb2))
+        {
+            ret = CannotRead(pFC->file2);
+            break;
+        }
+        if (cb1.QuadPart == 0 && cb2.QuadPart == 0)
+        {
+            ret = NoDifference();
+            break;
+        }
+        hMapping1 = CreateFileMappingW(hFile1, NULL, PAGE_READONLY,
+                                       cb1.HighPart, cb1.LowPart, NULL);
+        if (hMapping1 == NULL)
+        {
+            ret = CannotRead(pFC->file1);
+            break;
+        }
+        hMapping2 = CreateFileMappingW(hFile2, NULL, PAGE_READONLY,
+                                       cb2.HighPart, cb2.LowPart, NULL);
+        if (hMapping2 == NULL)
+        {
+            ret = CannotRead(pFC->file2);
+            break;
+        }
+
+        if (fUnicode)
+            ret = UnicodeTextCompare(pFC, hMapping1, &cb1, hMapping2, &cb2);
+        else
+            ret = AnsiTextCompare(pFC, hMapping1, &cb1, hMapping2, &cb2);
+    } while (0);
+
+    CloseHandle(hMapping1);
+    CloseHandle(hMapping2);
+    CloseHandle(hFile1);
+    CloseHandle(hFile2);
+    return ret;
+}
+
+static BOOL IsBinaryExt(LPCWSTR filename)
+{
+    // Don't change this array. This is by design.
+    // See also: 
https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/fc
+    static const LPCWSTR s_exts[] = { L"EXE", L"COM", L"SYS", L"OBJ", L"LIB", 
L"BIN" };
+    size_t iext;
+    LPCWSTR pch, ext, pch1 = wcsrchr(filename, L'\\'), pch2 = 
wcsrchr(filename, L'/');
+    if (!pch1 && !pch2)
+        pch = filename;
+    else if (!pch1 && pch2)
+        pch = pch2;
+    else if (pch1 && !pch2)
+        pch = pch1;
+    else if (pch1 < pch2)
+        pch = pch2;
+    else
+        pch = pch1;
+
+    ext = wcsrchr(pch, L'.');
+    if (ext)
+    {
+        ++ext;
+        for (iext = 0; iext < _countof(s_exts); ++iext)
+        {
+            if (_wcsicmp(ext, s_exts[iext]) == 0)
+                return TRUE;
+        }
+    }
+    return FALSE;
+}
+
+#define HasWildcard(filename) \
+    ((wcschr((filename), L'*') != NULL) || (wcschr((filename), L'?') != NULL))
+
+static FCRET FileCompare(FILECOMPARE *pFC)
+{
+    ConResPrintf(StdOut, IDS_COMPARING, pFC->file1, pFC->file2);
+
+    if (!(pFC->dwFlags & FLAG_L) &&
+        ((pFC->dwFlags & FLAG_B) || IsBinaryExt(pFC->file1) || 
IsBinaryExt(pFC->file2)))
+    {
+        return BinaryFileCompare(pFC);
+    }
+    return TextFileCompare(pFC);
+}
+
+static FCRET WildcardFileCompare(FILECOMPARE *pFC)
+{
+    if (pFC->dwFlags & FLAG_HELP)
+    {
+        ConResPuts(StdOut, IDS_USAGE);
+        return FCRET_INVALID;
+    }
+
+    if (!pFC->file1 || !pFC->file2)
+    {
+        ConResPuts(StdErr, IDS_NEEDS_FILES);
+        return FCRET_INVALID;
+    }
+
+    if (HasWildcard(pFC->file1) || HasWildcard(pFC->file2))
+    {
+        // TODO: wildcard
+        ConResPuts(StdErr, IDS_CANT_USE_WILDCARD);
+    }
+
+    return FileCompare(pFC);
+}
+
+int wmain(int argc, WCHAR **argv)
+{
+    FILECOMPARE fc = { .dwFlags = 0, .n = 100, .nnnn = 2 };
+    wchar_t *endptr;
+    INT i;
+
+    /* Initialize the Console Standard Streams */
+    ConInitStdStreams();
+
+    for (i = 1; i < argc; ++i)
+    {
+        if (argv[i][0] != L'/')
+        {
+            if (!fc.file1)
+                fc.file1 = argv[i];
+            else if (!fc.file2)
+                fc.file2 = argv[i];
+            else
+                return InvalidSwitch();
+            continue;
+        }
+        switch (towupper(argv[i][1]))
+        {
+            case L'A':
+                fc.dwFlags |= FLAG_A;
+                break;
+            case L'B':
+                fc.dwFlags |= FLAG_B;
+                break;
+            case L'C':
+                fc.dwFlags |= FLAG_C;
+                break;
+            case L'L':
+                if (_wcsicmp(argv[i], L"/L") == 0)
+                {
+                    fc.dwFlags |= FLAG_L;
+                }
+                else if (towupper(argv[i][2]) == L'B')
+                {
+                    if (iswdigit(argv[i][3]))
+                    {
+                        fc.dwFlags |= FLAG_LBn;
+                        fc.n = wcstoul(&argv[i][3], &endptr, 10);
+                        if (endptr == NULL || *endptr != 0)
+                            return InvalidSwitch();
+                    }
+                    else
+                    {
+                        return InvalidSwitch();
+                    }
+                }
+                break;
+            case L'N':
+                fc.dwFlags |= FLAG_N;
+                break;
+            case L'O':
+                if (_wcsicmp(argv[i], L"/OFF") == 0 || _wcsicmp(argv[i], 
L"/OFFLINE") == 0)
+                {
+                    fc.dwFlags |= FLAG_OFFLINE;
+                }
+                break;
+            case L'T':
+                fc.dwFlags |= FLAG_T;
+                break;
+            case L'W':
+                fc.dwFlags |= FLAG_W;
+                break;
+            case L'0': case L'1': case L'2': case L'3': case L'4':
+            case L'5': case L'6': case L'7': case L'8': case L'9':
+                fc.nnnn = wcstoul(&argv[i][1], &endptr, 10);
+                if (endptr == NULL || *endptr != 0)
+                    return InvalidSwitch();
+                fc.dwFlags |= FLAG_nnnn;
+                break;
+            case L'?':
+                fc.dwFlags |= FLAG_HELP;
+                break;
+            default:
+                return InvalidSwitch();
+        }
+    }
+    return WildcardFileCompare(&fc);
+}
diff --git a/base/applications/cmdutils/fc/fc.rc 
b/base/applications/cmdutils/fc/fc.rc
new file mode 100644
index 00000000000..322c3678dee
--- /dev/null
+++ b/base/applications/cmdutils/fc/fc.rc
@@ -0,0 +1,12 @@
+#include <windef.h>
+#include "resource.h"
+
+#define REACTOS_STR_FILE_DESCRIPTION    "ReactOS FC Command"
+#define REACTOS_STR_INTERNAL_NAME       "fc"
+#define REACTOS_STR_ORIGINAL_FILENAME   "fc.exe"
+#include <reactos/version.rc>
+
+#pragma code_page(65001) /* UTF-8 */
+#ifdef LANGUAGE_EN_US
+    #include "lang/en-US.rc"
+#endif
diff --git a/base/applications/cmdutils/fc/lang/en-US.rc 
b/base/applications/cmdutils/fc/lang/en-US.rc
new file mode 100644
index 00000000000..6c8516297b3
--- /dev/null
+++ b/base/applications/cmdutils/fc/lang/en-US.rc
@@ -0,0 +1,41 @@
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+
+STRINGTABLE
+BEGIN
+    IDS_USAGE "Compares two files or sets of files and displays the 
differences between\n\
+them\n\
+\n\
+FC [/A] [/C] [/L] [/LBn] [/N] [/OFF[LINE]] [/T] [/U] [/W] [/nnnn]\n\
+   [drive1:][path1]filename1 [drive2:][path2]filename2\n\
+FC /B [drive1:][path1]filename1 [drive2:][path2]filename2\n\
+\n\
+  /A         Displays only first and last lines for each set of differences.\n\
+  /B         Performs a binary comparison.\n\
+  /C         Disregards the case of letters.\n\
+  /L         Compares files as ASCII text.\n\
+  /LBn       Sets the maximum consecutive mismatches to the specified\n\
+             number of lines (default: 100).\n\
+  /N         Displays the line numbers on an ASCII comparison.\n\
+  /OFF[LINE] Doesn't skip files with offline attribute set.\n\
+  /T         Doesn't expand tabs to spaces (default: expand).\n\
+  /U         Compare files as UNICODE text files.\n\
+  /W         Compresses white space (tabs and spaces) for comparison.\n\
+  /nnnn      Specifies the number of consecutive lines that must match\n\
+             after a mismatch (default: 2).\n\
+  [drive1:][path1]filename1\n\
+             Specifies the first file or set of files to compare.\n\
+  [drive2:][path2]filename2\n\
+             Specifies the second file or set of files to compare.\n"
+    IDS_NO_DIFFERENCE "FC: no differences encountered\n"
+    IDS_LONGER_THAN "FC: %ls longer than %ls\n"
+    IDS_COMPARING "Comparing files %ls and %ls\n"
+    IDS_OUT_OF_MEMORY "FC: Out of memory\n"
+    IDS_CANNOT_READ "FC: cannot read from %ls\n"
+    IDS_INVALID_SWITCH "FC: Invalid Switch\n"
+    IDS_CANNOT_OPEN "FC: cannot open %ls - No such file or folder\n"
+    IDS_NEEDS_FILES "FC: Insufficient number of file specifications\n"
+    IDS_CANT_USE_WILDCARD "Wildcard ('*' and '?') are not supported yet\n"
+    IDS_DIFFERENT "FC: File %ls and %ls are different\n"
+    IDS_TOO_LARGE "FC: File %ls too large\n"
+    IDS_RESYNCH_FAILED "Resynch failed. Files are too different."
+END
diff --git a/base/applications/cmdutils/fc/resource.h 
b/base/applications/cmdutils/fc/resource.h
new file mode 100644
index 00000000000..45f8e032bd8
--- /dev/null
+++ b/base/applications/cmdutils/fc/resource.h
@@ -0,0 +1,13 @@
+#define IDS_USAGE               1000
+#define IDS_NO_DIFFERENCE       1001
+#define IDS_LONGER_THAN         1002
+#define IDS_COMPARING           1003
+#define IDS_OUT_OF_MEMORY       1004
+#define IDS_CANNOT_READ         1005
+#define IDS_INVALID_SWITCH      1006
+#define IDS_CANNOT_OPEN         1007
+#define IDS_NEEDS_FILES         1008
+#define IDS_CANT_USE_WILDCARD   1009
+#define IDS_DIFFERENT           1010
+#define IDS_TOO_LARGE           1011
+#define IDS_RESYNCH_FAILED      1012

Reply via email to