[PATCH] find: First implementation

Fabian Maurer dark.shadow4 at web.de
Fri Oct 25 11:55:42 CDT 2019


Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=44975
Signed-off-by: Fabian Maurer <dark.shadow4 at web.de>
---
 programs/find/Makefile.in  |   4 +-
 programs/find/find.c       | 170 ++++++++++++++++++++++++++++++++++++-
 programs/find/find.rc      |  25 ++++++
 programs/find/resources.h  |  27 ++++++
 programs/find/tests/find.c |   6 +-
 5 files changed, 225 insertions(+), 7 deletions(-)
 create mode 100644 programs/find/find.rc
 create mode 100644 programs/find/resources.h

diff --git a/programs/find/Makefile.in b/programs/find/Makefile.in
index 0c6b334f29..f572a371b4 100644
--- a/programs/find/Makefile.in
+++ b/programs/find/Makefile.in
@@ -1,5 +1,7 @@
 MODULE    = find.exe
-
+IMPORTS   = user32
 EXTRADLLFLAGS = -mconsole -municode -mno-cygwin

 C_SRCS = find.c
+
+RC_SRCS = find.rc
diff --git a/programs/find/find.c b/programs/find/find.c
index 0c8ba1fcd7..3794a8190f 100644
--- a/programs/find/find.c
+++ b/programs/find/find.c
@@ -16,18 +16,180 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */

+#include <windows.h>
+#include <stdlib.h>
+#include <shlwapi.h>
+
+#include "wine/heap.h"
 #include "wine/debug.h"
+#include "resources.h"

 WINE_DEFAULT_DEBUG_CHANNEL(find);

+static BOOL read_char_from_handle(HANDLE handle, char *char_out)
+{
+    static char buffer[4096];
+    static UINT buffer_max = 0;
+    static UINT buffer_pos = 0;
+
+    /* Read next content into buffer */
+    if (buffer_pos >= buffer_max)
+    {
+        BOOL success = ReadFile(handle, buffer, 4096, &buffer_max, NULL);
+        if (!success)
+            return FALSE;
+        buffer_pos = 0;
+    }
+
+    *char_out = buffer[buffer_pos++];
+    return TRUE;
+}
+
+/* Read a line from a handle, returns NULL if the end is reached */
+static WCHAR* read_line_from_handle(HANDLE handle)
+{
+    int line_max = 4096;
+    int length = 0;
+    WCHAR *line_converted;
+    int line_converted_length;
+    BOOL success;
+    char *line = heap_alloc(line_max);
+
+    for (;;)
+    {
+        char c;
+        success = read_char_from_handle(handle, &c);
+
+        /* Check for EOF */
+        if (!success)
+        {
+            if (length == 0)
+                return NULL;
+            else
+                break;
+        }
+
+        if (c == '\n')
+            break;
+
+        /* Make sure buffer is large enough */
+        if (length + 1 >= line_max)
+        {
+            line_max *= 2;
+            line = heap_realloc(line, line_max);
+        }
+
+        line[length++] = c;
+    }
+
+    line[length] = 0;
+    if (length - 1 >= 0 && line[length - 1] == '\r') /* Strip \r of windows line endings */
+        line[length - 1] = 0;
+
+    line_converted_length = MultiByteToWideChar(CP_ACP, 0, line, -1, 0, 0);
+    line_converted = heap_alloc(line_converted_length * sizeof(WCHAR));
+    MultiByteToWideChar(CP_ACP, 0, line, -1, line_converted, line_converted_length);
+
+    heap_free(line);
+
+    return line_converted;
+}
+
+static void write_to_stdout(const WCHAR *str)
+{
+    char *str_converted;
+    UINT str_converted_length;
+    DWORD bytes_written;
+    UINT str_length = lstrlenW(str);
+    int codepage = CP_ACP;
+
+    str_converted_length = WideCharToMultiByte(codepage, 0, str, str_length, NULL, 0, NULL, NULL);
+    str_converted = heap_alloc(str_converted_length);
+    WideCharToMultiByte(codepage, 0, str, str_length, str_converted, str_converted_length, NULL, NULL);
+
+    WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), str_converted, str_converted_length, &bytes_written, NULL);
+    if (bytes_written < str_converted_length)
+        ERR("Failed to write output\n");
+
+    heap_free(str_converted);
+}
+
+static BOOL run_find_for_line(const WCHAR *line, const WCHAR *tofind)
+{
+    void *found;
+    WCHAR lineending[] = {'\r', '\n', 0};
+
+    if (lstrlenW(line) == 0 || lstrlenW(tofind) == 0)
+        return FALSE;
+
+    found = wcsstr(line, tofind);
+
+    if (found)
+    {
+        write_to_stdout(line);
+        write_to_stdout(lineending);
+        return TRUE;
+    }
+
+    return FALSE;
+}
+
+static void output_resource_message(int id)
+{
+    WCHAR buffer[64];
+    LoadStringW(GetModuleHandleW(NULL), id, buffer, ARRAY_SIZE(buffer));
+    write_to_stdout(buffer);
+}
+
 int __cdecl wmain(int argc, WCHAR *argv[])
 {
+    WCHAR *line;
+    WCHAR *tofind = NULL;
     int i;
+    int exitcode;
+    HANDLE input;

-    WINE_FIXME("stub:");
+    TRACE("running find:");
     for (i = 0; i < argc; i++)
-        WINE_FIXME(" %s", wine_dbgstr_w(argv[i]));
-    WINE_FIXME("\n");
+    {
+        TRACE(" %s", wine_dbgstr_w(argv[i]));
+    }
+    TRACE("\n");
+
+    input = GetStdHandle(STD_INPUT_HANDLE);
+
+    for (i = 1; i < argc; i++)
+    {
+        if (argv[i][0] == '/')
+        {
+            output_resource_message(IDS_INVALID_SWITCH);
+            return 2;
+        }
+        else if(tofind == NULL)
+        {
+            tofind = argv[i];
+        }
+        else
+        {
+            FIXME("Searching files not supported yet\n");
+            return 1000;
+        }
+    }
+
+    if (tofind == NULL)
+    {
+        output_resource_message(IDS_INVALID_PARAMETER);
+        return 2;
+    }
+
+    exitcode = 1;
+    while ((line = read_line_from_handle(input)) != NULL)
+    {
+        if (run_find_for_line(line, tofind))
+            exitcode = 0;
+
+        heap_free(line);
+    }

-    return 0;
+    return exitcode;
 }
diff --git a/programs/find/find.rc b/programs/find/find.rc
new file mode 100644
index 0000000000..8c358c8677
--- /dev/null
+++ b/programs/find/find.rc
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2019 Fabian Maurer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "resources.h"
+
+STRINGTABLE
+{
+    IDS_INVALID_PARAMETER "FIND: Parameter format not correct\r\n"
+    IDS_INVALID_SWITCH    "FIND: Invalid switch\r\n"
+}
diff --git a/programs/find/resources.h b/programs/find/resources.h
new file mode 100644
index 0000000000..2ebe197b7d
--- /dev/null
+++ b/programs/find/resources.h
@@ -0,0 +1,27 @@
+/*
+ * Resource IDs
+ *
+ * Copyright 2019 Fabian Maurer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef __WINE_FIND_RESOURCES_H
+#define __WINE_FIND_RESOURCES_H
+
+#define IDS_INVALID_PARAMETER 1000
+#define IDS_INVALID_SWITCH    1001
+
+#endif  /* __WINE_FIND_RESOURCES_H */
diff --git a/programs/find/tests/find.c b/programs/find/tests/find.c
index 8af21a53fa..147b59c8ce 100644
--- a/programs/find/tests/find.c
+++ b/programs/find/tests/find.c
@@ -90,7 +90,6 @@ static void check_find_output(const BYTE *child_output, int child_output_len, co

     }

-    todo_wine_if(out_expected_len != 0)
     ok_(file, line)(strings_are_equal, "\n#################### Expected:\n"
                                        "%s\n"
                                        "#################### But got:\n"
@@ -176,7 +175,6 @@ static void run_find_stdin_(const WCHAR *commandline, const BYTE *input, int inp

     check_find_output(child_output, child_output_len, out_expected, out_expected_len, file, line);

-    todo_wine_if(exitcode_expected  != 0)
     ok_(file, line)(exitcode == exitcode_expected, "Expected exitcode %d, got %d\n", exitcode_expected, exitcode);

     heap_free(child_output);
@@ -227,7 +225,9 @@ static void run_find_stdin_unicode_(const BYTE *input, int input_len, const BYTE
 static void test_errors(void)
 {
     run_find_stdin_str("",       "", "FIND: Parameter format not correct\r\n", 2);
+    todo_wine /* Quotes are not properly passed into wine yet */
     run_find_stdin_str("test",   "", "FIND: Parameter format not correct\r\n", 2);
+    todo_wine /* Quotes are not properly passed into wine yet */
     run_find_stdin_str("\"test", "", "FIND: Parameter format not correct\r\n", 2);
     run_find_stdin_str("\"test\" /XYZ", "", "FIND: Invalid switch\r\n", 2);
 }
@@ -238,6 +238,7 @@ static void test_singleline_without_switches(void)
     run_find_stdin_str("\"test\"",  "",      "",          1);
     run_find_stdin_str("\"test\"",  "test",  "test\r\n",  0);
     run_find_stdin_str("\"test\"",  "test2", "test2\r\n", 0);
+    run_find_stdin_str("\"test\"",  "test\r2", "test\r2\r\n", 0);
     run_find_stdin_str("\"test2\"", "test",  "",          1);
 }

@@ -297,6 +298,7 @@ static void test_unicode_support(void)
     run_find_stdin_unicode(str_jap_utf16be_nobom, str_empty, 1);

     /* Test utf16le */
+    todo_wine
     run_find_stdin_unicode(str_jap_utf16le_bom, str_jap_utf16le_bom, 0);
 }

--
2.23.0




More information about the wine-devel mailing list