2012-10-03 15:25:52 +00:00
|
|
|
/*
|
|
|
|
* Copyright 2012 Qian Hong
|
2023-04-17 08:07:18 +00:00
|
|
|
* Copyright 2023 Zhiyi Zhang for CodeWeavers
|
2012-10-03 15:25:52 +00:00
|
|
|
*
|
|
|
|
* 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
|
|
|
|
*/
|
|
|
|
|
2023-04-17 08:07:18 +00:00
|
|
|
#include <windows.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include "findstr.h"
|
2012-10-03 15:25:52 +00:00
|
|
|
#include "wine/debug.h"
|
|
|
|
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(findstr);
|
|
|
|
|
2023-04-17 08:07:18 +00:00
|
|
|
static int WINAPIV findstr_error_wprintf(int msg, ...)
|
|
|
|
{
|
|
|
|
WCHAR msg_buffer[MAXSTRING];
|
|
|
|
va_list va_args;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
LoadStringW(GetModuleHandleW(NULL), msg, msg_buffer, ARRAY_SIZE(msg_buffer));
|
|
|
|
va_start(va_args, msg);
|
|
|
|
ret = vfwprintf(stderr, msg_buffer, va_args);
|
|
|
|
va_end(va_args);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int findstr_message(int msg)
|
|
|
|
{
|
|
|
|
WCHAR msg_buffer[MAXSTRING];
|
|
|
|
|
|
|
|
LoadStringW(GetModuleHandleW(NULL), msg, msg_buffer, ARRAY_SIZE(msg_buffer));
|
|
|
|
return wprintf(msg_buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
static BOOL add_file(struct findstr_file **head, const WCHAR *path)
|
|
|
|
{
|
|
|
|
struct findstr_file **ptr, *new_file;
|
|
|
|
|
|
|
|
ptr = head;
|
|
|
|
while (*ptr)
|
|
|
|
ptr = &((*ptr)->next);
|
|
|
|
|
|
|
|
new_file = calloc(1, sizeof(*new_file));
|
|
|
|
if (!new_file)
|
|
|
|
{
|
|
|
|
WINE_ERR("Out of memory.\n");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!path)
|
|
|
|
{
|
|
|
|
new_file->file = stdin;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
new_file->file = _wfopen(path, L"rt,ccs=unicode");
|
|
|
|
if (!new_file->file)
|
|
|
|
{
|
|
|
|
findstr_error_wprintf(STRING_CANNOT_OPEN, path);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*ptr = new_file;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void add_string(struct findstr_string **head, const WCHAR *string)
|
|
|
|
{
|
|
|
|
struct findstr_string **ptr, *new_string;
|
|
|
|
|
|
|
|
ptr = head;
|
|
|
|
while (*ptr)
|
|
|
|
ptr = &((*ptr)->next);
|
|
|
|
|
|
|
|
new_string = calloc(1, sizeof(*new_string));
|
|
|
|
if (!new_string)
|
|
|
|
{
|
|
|
|
WINE_ERR("Out of memory.\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
new_string->string = string;
|
|
|
|
*ptr = new_string;
|
|
|
|
}
|
|
|
|
|
2019-10-17 15:05:47 +00:00
|
|
|
int __cdecl wmain(int argc, WCHAR *argv[])
|
2012-10-03 15:25:52 +00:00
|
|
|
{
|
2023-04-17 08:07:18 +00:00
|
|
|
struct findstr_string *string_head = NULL, *current_string, *next_string;
|
|
|
|
struct findstr_file *file_head = NULL, *current_file, *next_file;
|
|
|
|
WCHAR *string, *ptr, *buffer, line[MAXSTRING];
|
|
|
|
BOOL has_string = FALSE, has_file = FALSE;
|
|
|
|
int ret = 1, i, j;
|
2012-10-03 15:25:52 +00:00
|
|
|
|
|
|
|
for (i = 0; i < argc; i++)
|
2023-04-17 08:07:18 +00:00
|
|
|
WINE_TRACE("%s ", wine_dbgstr_w(argv[i]));
|
|
|
|
WINE_TRACE("\n");
|
|
|
|
|
|
|
|
if (argc == 1)
|
|
|
|
{
|
|
|
|
findstr_error_wprintf(STRING_BAD_COMMAND_LINE);
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 1; i < argc; i++)
|
|
|
|
{
|
|
|
|
if (argv[i][0] == '/')
|
|
|
|
{
|
|
|
|
if (argv[i][1] == '\0')
|
|
|
|
{
|
|
|
|
findstr_error_wprintf(STRING_BAD_COMMAND_LINE);
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
j = 1;
|
|
|
|
while (argv[i][j] != '\0')
|
|
|
|
{
|
|
|
|
switch(argv[i][j])
|
|
|
|
{
|
|
|
|
case '?':
|
|
|
|
findstr_message(STRING_USAGE);
|
|
|
|
ret = 0;
|
|
|
|
goto done;
|
|
|
|
case 'C':
|
|
|
|
case 'c':
|
|
|
|
if (argv[i][j + 1] == ':')
|
|
|
|
{
|
|
|
|
ptr = argv[i] + j + 2;
|
|
|
|
if (*ptr == '"')
|
|
|
|
ptr++;
|
|
|
|
|
|
|
|
string = ptr;
|
|
|
|
while (*ptr != '"' && *ptr != '\0' )
|
|
|
|
ptr++;
|
|
|
|
*ptr = '\0';
|
|
|
|
j = ptr - argv[i] - 1;
|
|
|
|
add_string(&string_head, string);
|
|
|
|
has_string = TRUE;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
findstr_error_wprintf(STRING_IGNORED, argv[i][j]);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
j++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (!has_string)
|
|
|
|
{
|
|
|
|
string = wcstok(argv[i], L" ", &buffer);
|
|
|
|
if (string)
|
|
|
|
{
|
|
|
|
add_string(&string_head, string);
|
|
|
|
has_string = TRUE;
|
|
|
|
}
|
|
|
|
while ((string = wcstok(NULL, L" ", &buffer)))
|
|
|
|
add_string(&string_head, string);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (!add_file(&file_head, argv[i]))
|
|
|
|
goto done;
|
|
|
|
has_file = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!has_string)
|
|
|
|
{
|
|
|
|
findstr_error_wprintf(STRING_BAD_COMMAND_LINE);
|
|
|
|
ret = 2;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!has_file)
|
|
|
|
add_file(&file_head, NULL);
|
|
|
|
|
|
|
|
current_file = file_head;
|
|
|
|
while (current_file)
|
|
|
|
{
|
|
|
|
while (fgetws(line, ARRAY_SIZE(line), current_file->file))
|
|
|
|
{
|
|
|
|
current_string = string_head;
|
|
|
|
while (current_string)
|
|
|
|
{
|
|
|
|
if (wcsstr(line, current_string->string))
|
|
|
|
{
|
|
|
|
wprintf(line);
|
|
|
|
if (current_file->file == stdin)
|
|
|
|
wprintf(L"\n");
|
|
|
|
ret = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
current_string = current_string->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
current_file = current_file->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
done:
|
|
|
|
current_file = file_head;
|
|
|
|
while (current_file)
|
|
|
|
{
|
|
|
|
next_file = current_file->next;
|
|
|
|
if (current_file->file != stdin)
|
|
|
|
fclose(current_file->file);
|
|
|
|
free(current_file);
|
|
|
|
current_file = next_file;
|
|
|
|
}
|
2012-10-03 15:25:52 +00:00
|
|
|
|
2023-04-17 08:07:18 +00:00
|
|
|
current_string = string_head;
|
|
|
|
while (current_string)
|
|
|
|
{
|
|
|
|
next_string = current_string->next;
|
|
|
|
free(current_string);
|
|
|
|
current_string = next_string;
|
|
|
|
}
|
|
|
|
return ret;
|
2012-10-03 15:25:52 +00:00
|
|
|
}
|