Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=44975 Signed-off-by: Fabian Maurer dark.shadow4@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
On Fri, 25 Oct 2019 at 17:56, Fabian Maurer dark.shadow4@web.de wrote:
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=44975 Signed-off-by: Fabian Maurer dark.shadow4@web.de
...
+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;
- }
...
That condition might (??) want to be something like (perhaps also testing if the handle is: STD_INPUT_HANDLE):
+ if (!success || !buffer_max)
otherwise your find implementation hangs for me with:
echo abc def | find "abc"
Robert
That condition might (??) want to be something like (perhaps also testing if the handle is: STD_INPUT_HANDLE):
if (!success || !buffer_max)
otherwise your find implementation hangs for me with:
echo abc def | find "abc"
Thanks for the notify, I'll look into it. I might have overlooked an edge case.
Regards, Fabian Maurer
I got a bit confused, since I ran into another (small) error, see https:// bugs.winehq.org/show_bug.cgi?id=48027 With native cmd it does work, so I suspected it's only that issue.
But you're completely right, I need to do the check differently, otherwise it hangs when using the < operator anyways. Thanks for investigating! I'll send in a patch right away.
Regards, Fabian Maurer