/* * A file look-up utility to complement updatedb * * Compile and run updatedb command first to create locate.db file. Then, * compile this program with Visual Studio and run the program in console with * a file name argument. For example, the command * * locate autoexec * * might output something like * * c:/AUTOEXEC.BAT * c:/WINDOWS/repair/autoexec.nt * c:/WINDOWS/system32/AUTOEXEC.NT * * Be ware that this file uses wide-character API which is not compatible * with Linux or other major Unixes. * * Copyright (C) 1998-2019 Toni Ronkko * This file is part of dirent. Dirent may be freely distributed * under the MIT license. For all details and documentation, see * https://github.com/tronkko/dirent */ #include #include #include #include #ifdef WIN32 # include # include #endif #include /* File name and location of database file */ #define DB_LOCATION L"locate.db" /* Forward-decl */ static int db_locate (const wchar_t *pattern); static int db_match (const wchar_t *fn, const wchar_t *pattern); static void db_open (void); static void db_close (void); static int db_read (wchar_t *buffer, size_t max); /* Module local variables */ static FILE *db = NULL; int main( int argc, char *argv[]) { #ifdef WIN32 int i; /* Prepare for unicode output */ _setmode (_fileno (stdout), _O_U16TEXT); /* For each pattern in command line */ i = 1; while (i < argc) { wchar_t buffer[PATH_MAX + 1]; errno_t error; size_t n; int count = 0; /* Convert ith argument to wide-character string */ error = mbstowcs_s (&n, buffer, PATH_MAX, argv[i], _TRUNCATE); if (!error) { /* Find files matching pattern */ count = db_locate (buffer); /* Output warning if string is not found */ if (count == 0) { wprintf (L"%s not found\n", buffer); } } i++; } if (argc < 2) { wprintf (L"Usage: locate pattern\n"); exit (EXIT_FAILURE); } #else printf ("locate only works on Microsoft Windows\n"); #endif return EXIT_SUCCESS; } /* Match pattern against files in locate.db file */ static int db_locate( const wchar_t *pattern) { int count = 0; #ifdef WIN32 wchar_t buffer[PATH_MAX + 1]; /* Open locate.db for read */ db_open (); /* Read one directory and file name at a time from database file */ while (db_read (buffer, PATH_MAX + 1)) { /* See if file name in buffer matches the search pattern */ if (db_match (buffer, pattern)) { /* Match found => output file name and path */ wprintf (L"%s\n", buffer); count++; } } db_close (); #endif return count; } /* Match pattern against file name */ static int db_match( const wchar_t *fn, const wchar_t *pattern) { int found = 0; #ifdef WIN32 wchar_t *p; wchar_t base[PATH_MAX + 1]; wchar_t patt[PATH_MAX + 1]; int i; int done = 0; /* Locate zero-terminator from fn */ p = wcschr (fn, '\0'); /* Find base name from buffer */ while (fn < p && !done) { switch (p[-1]) { case ':': case '/': case '\\': /* Final path separator found */ done = 1; break; default: /* No path separator yet */ p--; } } /* Convert base name to lower case */ i = 0; while (i < PATH_MAX && p[i] != '\0') { base[i] = towlower (p[i]); i++; } base[i] = '\0'; /* Convert search pattern to lower case */ i = 0; while (i < PATH_MAX && pattern[i] != '\0') { patt[i] = towlower (pattern[i]); i++; } patt[i] = '\0'; /* See if file name matches pattern */ if (wcsstr (base, patt) != NULL) { found = 1; } else { found = 0; } #endif return found; } /* * Read line from locate.db. This function is same as fgetws() except * that new-line at the end of line is not included. */ static int db_read( wchar_t *buffer, size_t max) { int ok = 0; #ifdef WIN32 size_t i = 0; wchar_t c; int done = 0; do { /* Read wide-character from stream */ if (db) { c = fgetwc (db); } else { wprintf (L"Database not open\n"); exit (EXIT_SUCCESS); } /* Determine how to process character */ switch (c) { case '\r': /* Ignore, should be handled by run-time libraries */ /*NOP*/; break; case '\n': /* End of string => return file name and true */ done = 1; ok = 1; break; case /*EOF*/WEOF: /* End of file */ done = 1; if (i == 0) { /* No data in buffer => return false to indicate EOF */ ok = 0; } else { /* Data in buffer => return true */ ok = 1; } break; default: /* Store character */ if (i < max - 1) { buffer[i++] = c; } else { buffer[max - 1] = '\0'; wprintf (L"Buffer too small: %s", buffer); exit (EXIT_FAILURE); } } } while (!done); /* Zero-terminate buffer */ buffer[i] = '\0'; #endif return ok; } /* Open database file locate.db */ static void db_open( void) { #ifdef WIN32 if (db == NULL) { errno_t error; /* Open file for writing */ error = _wfopen_s (&db, DB_LOCATION, L"rt, ccs=UNICODE"); if (error) { wprintf (L"Cannot open %s\n", DB_LOCATION); exit (EXIT_FAILURE); } } #endif } /* Close database file */ static void db_close( void) { if (db) { fclose (db); db = NULL; } }