find: First implementation.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=44975 Signed-off-by: Fabian Maurer <dark.shadow4@web.de> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
de94cfa775
commit
e1bcf2d88a
|
@ -1,5 +1,8 @@
|
||||||
MODULE = find.exe
|
MODULE = find.exe
|
||||||
|
IMPORTS = user32
|
||||||
|
|
||||||
EXTRADLLFLAGS = -mconsole -municode -mno-cygwin
|
EXTRADLLFLAGS = -mconsole -municode -mno-cygwin
|
||||||
|
|
||||||
C_SRCS = find.c
|
C_SRCS = find.c
|
||||||
|
|
||||||
|
RC_SRCS = find.rc
|
||||||
|
|
|
@ -16,18 +16,180 @@
|
||||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
* 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 "wine/debug.h"
|
||||||
|
#include "resources.h"
|
||||||
|
|
||||||
WINE_DEFAULT_DEBUG_CHANNEL(find);
|
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[])
|
int __cdecl wmain(int argc, WCHAR *argv[])
|
||||||
{
|
{
|
||||||
|
WCHAR *line;
|
||||||
|
WCHAR *tofind = NULL;
|
||||||
int i;
|
int i;
|
||||||
|
int exitcode;
|
||||||
|
HANDLE input;
|
||||||
|
|
||||||
WINE_FIXME("stub:");
|
TRACE("running find:");
|
||||||
for (i = 0; i < argc; i++)
|
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");
|
||||||
|
|
||||||
return 0;
|
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 exitcode;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"
|
||||||
|
}
|
|
@ -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 */
|
|
@ -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"
|
ok_(file, line)(strings_are_equal, "\n#################### Expected:\n"
|
||||||
"%s\n"
|
"%s\n"
|
||||||
"#################### But got:\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);
|
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);
|
ok_(file, line)(exitcode == exitcode_expected, "Expected exitcode %d, got %d\n", exitcode_expected, exitcode);
|
||||||
|
|
||||||
heap_free(child_output);
|
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)
|
static void test_errors(void)
|
||||||
{
|
{
|
||||||
run_find_stdin_str("", "", "FIND: Parameter format not correct\r\n", 2);
|
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);
|
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", "", "FIND: Parameter format not correct\r\n", 2);
|
||||||
run_find_stdin_str("\"test\" /XYZ", "", "FIND: Invalid switch\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\"", "", "", 1);
|
||||||
run_find_stdin_str("\"test\"", "test", "test\r\n", 0);
|
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\"", "test2", "test2\r\n", 0);
|
||||||
|
run_find_stdin_str("\"test\"", "test\r2", "test\r2\r\n", 0);
|
||||||
run_find_stdin_str("\"test2\"", "test", "", 1);
|
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);
|
run_find_stdin_unicode(str_jap_utf16be_nobom, str_empty, 1);
|
||||||
|
|
||||||
/* Test utf16le */
|
/* Test utf16le */
|
||||||
|
todo_wine
|
||||||
run_find_stdin_unicode(str_jap_utf16le_bom, str_jap_utf16le_bom, 0);
|
run_find_stdin_unicode(str_jap_utf16le_bom, str_jap_utf16le_bom, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue