From 5c637f58cad289f9cbb46517ba29f16b66973cea Mon Sep 17 00:00:00 2001 From: Alex Henrie Date: Sat, 22 Jul 2023 13:45:54 -0600 Subject: [PATCH] where: Implement search with default options. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=55282 --- programs/where/Makefile.in | 1 + programs/where/main.c | 116 ++++++++++++++++++++++++++++++++++++- 2 files changed, 114 insertions(+), 3 deletions(-) diff --git a/programs/where/Makefile.in b/programs/where/Makefile.in index bca42590176..125c550fa37 100644 --- a/programs/where/Makefile.in +++ b/programs/where/Makefile.in @@ -1,4 +1,5 @@ MODULE = where.exe +IMPORTS = shlwapi EXTRADLLFLAGS = -mconsole -municode diff --git a/programs/where/main.c b/programs/where/main.c index 6f90a222dce..bcabb812aa0 100644 --- a/programs/where/main.c +++ b/programs/where/main.c @@ -1,5 +1,6 @@ /* * Copyright 2020 Louis Lenders + * Copyright 2023 Alex Henrie * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -16,18 +17,127 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include +#include +#include + #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(where); +static BOOL found; + +static void search(const WCHAR *search_path, const WCHAR *pattern) +{ + static const WCHAR *extensions[] = {L"", L".bat", L".cmd", L".com", L".exe"}; + WCHAR glob[MAX_PATH]; + WCHAR match_path[MAX_PATH]; + WIN32_FIND_DATAW match; + HANDLE handle; + BOOL more; + int i; + + for (i = 0; i < ARRAY_SIZE(extensions); i++) + { + if (wcslen(search_path) + 1 + wcslen(pattern) + wcslen(extensions[i]) + 1 > ARRAY_SIZE(glob)) + { + ERR("Path too long\n"); + return; + } + /* Treat the extension as part of the pattern */ + wcscpy(glob, search_path); + wcscat(glob, L"\\"); + wcscat(glob, pattern); + wcscat(glob, extensions[i]); + + handle = FindFirstFileExW(glob, FindExInfoBasic, &match, 0, NULL, 0); + more = (handle != INVALID_HANDLE_VALUE); + + while (more) + { + if (PathCombineW(match_path, search_path, match.cFileName)) + { + printf("%ls\n", match_path); + found = TRUE; + } + more = FindNextFileW(handle, &match); + } + } +} + int __cdecl wmain(int argc, WCHAR *argv[]) { + WCHAR *pattern, *colon, *search_paths, *semicolon, *search_path; int i; - WINE_FIXME("stub:"); for (i = 0; i < argc; i++) - WINE_FIXME(" %s", wine_dbgstr_w(argv[i])); - WINE_FIXME("\n"); + { + if (argv[i][0] == '/') + { + FIXME("Unsupported option %ls\n", argv[i]); + return 1; + } + } + + for (i = 1; i < argc; i++) + { + pattern = argv[i]; + colon = wcsrchr(pattern, ':'); + + /* Check for a set of search paths prepended to the pattern */ + if (colon) + { + *colon = 0; + search_paths = pattern; + pattern = colon + 1; + } + else + { + DWORD len = GetEnvironmentVariableW(L"PATH", NULL, 0); + search_paths = malloc(len * sizeof(WCHAR)); + if (!search_paths) + { + ERR("Out of memory\n"); + return 1; + } + GetEnvironmentVariableW(L"PATH", search_paths, len); + } + + if (wcspbrk(pattern, L"\\/\r\n")) + { + /* Silently ignore invalid patterns */ + if (!colon) free(search_paths); + continue; + } + + if (!colon) + { + /* If the search paths were not explicitly specified, search the current directory first */ + WCHAR current_dir[MAX_PATH]; + if (GetCurrentDirectoryW(ARRAY_SIZE(current_dir), current_dir)) + search(current_dir, pattern); + } + + search_path = search_paths; + do + { + semicolon = wcschr(search_path, ';'); + if (semicolon) + *semicolon = 0; + if (*search_path) + search(search_path, pattern); + search_path = semicolon + 1; + } + while (semicolon); + + if (!colon) free(search_paths); + } + + if (!found) + { + fputs("File not found\n", stderr); + return 1; + } return 0; } -- 2.43.0