🛠️🐜 Antkeeper superbuild with dependencies included https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

281 lines
5.9 KiB

  1. /*
  2. * A file look-up utility to complement updatedb
  3. *
  4. * Compile and run updatedb command first to create locate.db file. Then,
  5. * compile this program with Visual Studio and run the program in console with
  6. * a file name argument. For example, the command
  7. *
  8. * locate autoexec
  9. *
  10. * might output something like
  11. *
  12. * c:/AUTOEXEC.BAT
  13. * c:/WINDOWS/repair/autoexec.nt
  14. * c:/WINDOWS/system32/AUTOEXEC.NT
  15. *
  16. * Be ware that this file uses wide-character API which is not compatible
  17. * with Linux or other major Unixes.
  18. *
  19. * Copyright (C) 1998-2019 Toni Ronkko
  20. * This file is part of dirent. Dirent may be freely distributed
  21. * under the MIT license. For all details and documentation, see
  22. * https://github.com/tronkko/dirent
  23. */
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <string.h>
  27. #include <wchar.h>
  28. #ifdef WIN32
  29. # include <io.h>
  30. # include <fcntl.h>
  31. #endif
  32. #include <dirent.h>
  33. /* File name and location of database file */
  34. #define DB_LOCATION L"locate.db"
  35. /* Forward-decl */
  36. static int db_locate (const wchar_t *pattern);
  37. static int db_match (const wchar_t *fn, const wchar_t *pattern);
  38. static void db_open (void);
  39. static void db_close (void);
  40. static int db_read (wchar_t *buffer, size_t max);
  41. /* Module local variables */
  42. static FILE *db = NULL;
  43. int
  44. main(
  45. int argc, char *argv[])
  46. {
  47. #ifdef WIN32
  48. int i;
  49. /* Prepare for unicode output */
  50. _setmode (_fileno (stdout), _O_U16TEXT);
  51. /* For each pattern in command line */
  52. i = 1;
  53. while (i < argc) {
  54. wchar_t buffer[PATH_MAX + 1];
  55. errno_t error;
  56. size_t n;
  57. int count = 0;
  58. /* Convert ith argument to wide-character string */
  59. error = mbstowcs_s (&n, buffer, PATH_MAX, argv[i], _TRUNCATE);
  60. if (!error) {
  61. /* Find files matching pattern */
  62. count = db_locate (buffer);
  63. /* Output warning if string is not found */
  64. if (count == 0) {
  65. wprintf (L"%s not found\n", buffer);
  66. }
  67. }
  68. i++;
  69. }
  70. if (argc < 2) {
  71. wprintf (L"Usage: locate pattern\n");
  72. exit (EXIT_FAILURE);
  73. }
  74. #else
  75. printf ("locate only works on Microsoft Windows\n");
  76. #endif
  77. return EXIT_SUCCESS;
  78. }
  79. /* Match pattern against files in locate.db file */
  80. static int
  81. db_locate(
  82. const wchar_t *pattern)
  83. {
  84. int count = 0;
  85. #ifdef WIN32
  86. wchar_t buffer[PATH_MAX + 1];
  87. /* Open locate.db for read */
  88. db_open ();
  89. /* Read one directory and file name at a time from database file */
  90. while (db_read (buffer, PATH_MAX + 1)) {
  91. /* See if file name in buffer matches the search pattern */
  92. if (db_match (buffer, pattern)) {
  93. /* Match found => output file name and path */
  94. wprintf (L"%s\n", buffer);
  95. count++;
  96. }
  97. }
  98. db_close ();
  99. #endif
  100. return count;
  101. }
  102. /* Match pattern against file name */
  103. static int
  104. db_match(
  105. const wchar_t *fn, const wchar_t *pattern)
  106. {
  107. int found = 0;
  108. #ifdef WIN32
  109. wchar_t *p;
  110. wchar_t base[PATH_MAX + 1];
  111. wchar_t patt[PATH_MAX + 1];
  112. int i;
  113. int done = 0;
  114. /* Locate zero-terminator from fn */
  115. p = wcschr (fn, '\0');
  116. /* Find base name from buffer */
  117. while (fn < p && !done) {
  118. switch (p[-1]) {
  119. case ':':
  120. case '/':
  121. case '\\':
  122. /* Final path separator found */
  123. done = 1;
  124. break;
  125. default:
  126. /* No path separator yet */
  127. p--;
  128. }
  129. }
  130. /* Convert base name to lower case */
  131. i = 0;
  132. while (i < PATH_MAX && p[i] != '\0') {
  133. base[i] = towlower (p[i]);
  134. i++;
  135. }
  136. base[i] = '\0';
  137. /* Convert search pattern to lower case */
  138. i = 0;
  139. while (i < PATH_MAX && pattern[i] != '\0') {
  140. patt[i] = towlower (pattern[i]);
  141. i++;
  142. }
  143. patt[i] = '\0';
  144. /* See if file name matches pattern */
  145. if (wcsstr (base, patt) != NULL) {
  146. found = 1;
  147. } else {
  148. found = 0;
  149. }
  150. #endif
  151. return found;
  152. }
  153. /*
  154. * Read line from locate.db. This function is same as fgetws() except
  155. * that new-line at the end of line is not included.
  156. */
  157. static int
  158. db_read(
  159. wchar_t *buffer, size_t max)
  160. {
  161. int ok = 0;
  162. #ifdef WIN32
  163. size_t i = 0;
  164. wchar_t c;
  165. int done = 0;
  166. do {
  167. /* Read wide-character from stream */
  168. if (db) {
  169. c = fgetwc (db);
  170. } else {
  171. wprintf (L"Database not open\n");
  172. exit (EXIT_SUCCESS);
  173. }
  174. /* Determine how to process character */
  175. switch (c) {
  176. case '\r':
  177. /* Ignore, should be handled by run-time libraries */
  178. /*NOP*/;
  179. break;
  180. case '\n':
  181. /* End of string => return file name and true */
  182. done = 1;
  183. ok = 1;
  184. break;
  185. case /*EOF*/WEOF:
  186. /* End of file */
  187. done = 1;
  188. if (i == 0) {
  189. /* No data in buffer => return false to indicate EOF */
  190. ok = 0;
  191. } else {
  192. /* Data in buffer => return true */
  193. ok = 1;
  194. }
  195. break;
  196. default:
  197. /* Store character */
  198. if (i < max - 1) {
  199. buffer[i++] = c;
  200. } else {
  201. buffer[max - 1] = '\0';
  202. wprintf (L"Buffer too small: %s", buffer);
  203. exit (EXIT_FAILURE);
  204. }
  205. }
  206. } while (!done);
  207. /* Zero-terminate buffer */
  208. buffer[i] = '\0';
  209. #endif
  210. return ok;
  211. }
  212. /* Open database file locate.db */
  213. static void
  214. db_open(
  215. void)
  216. {
  217. #ifdef WIN32
  218. if (db == NULL) {
  219. errno_t error;
  220. /* Open file for writing */
  221. error = _wfopen_s (&db, DB_LOCATION, L"rt, ccs=UNICODE");
  222. if (error) {
  223. wprintf (L"Cannot open %s\n", DB_LOCATION);
  224. exit (EXIT_FAILURE);
  225. }
  226. }
  227. #endif
  228. }
  229. /* Close database file */
  230. static void
  231. db_close(
  232. void)
  233. {
  234. if (db) {
  235. fclose (db);
  236. db = NULL;
  237. }
  238. }