find.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. /*
  2. * Copyright 2018 Fabian Maurer
  3. *
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Lesser General Public
  6. * License as published by the Free Software Foundation; either
  7. * version 2.1 of the License, or (at your option) any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Lesser General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Lesser General Public
  15. * License along with this library; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  17. */
  18. #include <windows.h>
  19. #include <stdlib.h>
  20. #include <shlwapi.h>
  21. #include "wine/heap.h"
  22. #include "wine/debug.h"
  23. #include "resources.h"
  24. WINE_DEFAULT_DEBUG_CHANNEL(find);
  25. static BOOL read_char_from_handle(HANDLE handle, char *char_out)
  26. {
  27. static char buffer[4096];
  28. static DWORD buffer_max = 0;
  29. static DWORD buffer_pos = 0;
  30. /* Read next content into buffer */
  31. if (buffer_pos >= buffer_max)
  32. {
  33. BOOL success = ReadFile(handle, buffer, 4096, &buffer_max, NULL);
  34. if (!success || !buffer_max)
  35. return FALSE;
  36. buffer_pos = 0;
  37. }
  38. *char_out = buffer[buffer_pos++];
  39. return TRUE;
  40. }
  41. /* Read a line from a handle, returns NULL if the end is reached */
  42. static WCHAR* read_line_from_handle(HANDLE handle)
  43. {
  44. int line_max = 4096;
  45. int length = 0;
  46. WCHAR *line_converted;
  47. int line_converted_length;
  48. BOOL success;
  49. char *line = heap_alloc(line_max);
  50. for (;;)
  51. {
  52. char c;
  53. success = read_char_from_handle(handle, &c);
  54. /* Check for EOF */
  55. if (!success)
  56. {
  57. if (length == 0)
  58. return NULL;
  59. else
  60. break;
  61. }
  62. if (c == '\n')
  63. break;
  64. /* Make sure buffer is large enough */
  65. if (length + 1 >= line_max)
  66. {
  67. line_max *= 2;
  68. line = heap_realloc(line, line_max);
  69. }
  70. line[length++] = c;
  71. }
  72. line[length] = 0;
  73. if (length - 1 >= 0 && line[length - 1] == '\r') /* Strip \r of windows line endings */
  74. line[length - 1] = 0;
  75. line_converted_length = MultiByteToWideChar(CP_ACP, 0, line, -1, 0, 0);
  76. line_converted = heap_alloc(line_converted_length * sizeof(WCHAR));
  77. MultiByteToWideChar(CP_ACP, 0, line, -1, line_converted, line_converted_length);
  78. heap_free(line);
  79. return line_converted;
  80. }
  81. static void write_to_stdout(const WCHAR *str)
  82. {
  83. char *str_converted;
  84. UINT str_converted_length;
  85. DWORD bytes_written;
  86. UINT str_length = lstrlenW(str);
  87. int codepage = CP_ACP;
  88. str_converted_length = WideCharToMultiByte(codepage, 0, str, str_length, NULL, 0, NULL, NULL);
  89. str_converted = heap_alloc(str_converted_length);
  90. WideCharToMultiByte(codepage, 0, str, str_length, str_converted, str_converted_length, NULL, NULL);
  91. WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), str_converted, str_converted_length, &bytes_written, NULL);
  92. if (bytes_written < str_converted_length)
  93. ERR("Failed to write output\n");
  94. heap_free(str_converted);
  95. }
  96. static BOOL run_find_for_line(const WCHAR *line, const WCHAR *tofind)
  97. {
  98. void *found;
  99. if (lstrlenW(line) == 0 || lstrlenW(tofind) == 0)
  100. return FALSE;
  101. found = wcsstr(line, tofind);
  102. if (found)
  103. {
  104. write_to_stdout(line);
  105. write_to_stdout(L"\r\n");
  106. return TRUE;
  107. }
  108. return FALSE;
  109. }
  110. static void output_resource_message(int id)
  111. {
  112. WCHAR buffer[64];
  113. LoadStringW(GetModuleHandleW(NULL), id, buffer, ARRAY_SIZE(buffer));
  114. write_to_stdout(buffer);
  115. }
  116. int __cdecl wmain(int argc, WCHAR *argv[])
  117. {
  118. WCHAR *line;
  119. WCHAR *tofind = NULL;
  120. int i;
  121. int exitcode;
  122. int file_paths_len = 0;
  123. int file_paths_max = 0;
  124. WCHAR** file_paths = NULL;
  125. TRACE("running find:");
  126. for (i = 0; i < argc; i++)
  127. {
  128. TRACE(" %s", wine_dbgstr_w(argv[i]));
  129. }
  130. TRACE("\n");
  131. for (i = 1; i < argc; i++)
  132. {
  133. if (argv[i][0] == '/')
  134. {
  135. output_resource_message(IDS_INVALID_SWITCH);
  136. return 2;
  137. }
  138. else if (tofind == NULL)
  139. {
  140. tofind = argv[i];
  141. }
  142. else
  143. {
  144. if (file_paths_len >= file_paths_max)
  145. {
  146. file_paths_max = file_paths_max ? file_paths_max * 2 : 2;
  147. file_paths = heap_realloc(file_paths, sizeof(WCHAR*) * file_paths_max);
  148. }
  149. file_paths[file_paths_len++] = argv[i];
  150. }
  151. }
  152. if (tofind == NULL)
  153. {
  154. output_resource_message(IDS_INVALID_PARAMETER);
  155. return 2;
  156. }
  157. exitcode = 1;
  158. if (file_paths_len > 0)
  159. {
  160. for (i = 0; i < file_paths_len; i++)
  161. {
  162. HANDLE input;
  163. WCHAR file_path_upper[MAX_PATH];
  164. wcscpy(file_path_upper, file_paths[i]);
  165. wcsupr(file_path_upper);
  166. input = CreateFileW(file_paths[i], GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
  167. if (input == INVALID_HANDLE_VALUE)
  168. {
  169. WCHAR buffer_message[64];
  170. WCHAR message[300];
  171. LoadStringW(GetModuleHandleW(NULL), IDS_FILE_NOT_FOUND, buffer_message, ARRAY_SIZE(buffer_message));
  172. wsprintfW(message, buffer_message, file_path_upper);
  173. write_to_stdout(message);
  174. continue;
  175. }
  176. write_to_stdout(L"\r\n---------- ");
  177. write_to_stdout(file_path_upper);
  178. write_to_stdout(L"\r\n");
  179. while ((line = read_line_from_handle(input)) != NULL)
  180. {
  181. if (run_find_for_line(line, tofind))
  182. exitcode = 0;
  183. heap_free(line);
  184. }
  185. CloseHandle(input);
  186. }
  187. }
  188. else
  189. {
  190. HANDLE input = GetStdHandle(STD_INPUT_HANDLE);
  191. while ((line = read_line_from_handle(input)) != NULL)
  192. {
  193. if (run_find_for_line(line, tofind))
  194. exitcode = 0;
  195. heap_free(line);
  196. }
  197. }
  198. heap_free(file_paths);
  199. return exitcode;
  200. }