@ -1 +1 @@ | |||
Subproject commit bd7cda4f17855ef021c45c0a657a7e319c560349 | |||
Subproject commit f1764a0ed33533a45c2da8251dac6b284156082d |
@ -1 +1 @@ | |||
Subproject commit 5d530b0d8735345c28934b8b6c910f36197271d9 | |||
Subproject commit 3c26a6fe64a782d7aba0db7ee331e646060cc095 |
@ -1,17 +0,0 @@ | |||
/CMakeCache.txt | |||
/CMakeFiles | |||
/CTestTestfile.cmake | |||
/DartConfiguration.tcl | |||
/Makefile | |||
/Testing | |||
/Win32 | |||
/cmake_install.cmake | |||
/find | |||
/locate | |||
/ls | |||
/t-compile | |||
/t-dirent | |||
/updatedb | |||
/*.filters | |||
/*.vcxproj | |||
/*.dir |
@ -1,59 +0,0 @@ | |||
cmake_minimum_required (VERSION 2.8.11) | |||
project (dirent LANGUAGES C CXX) | |||
# User options | |||
option(DIRENT_BUILD_TESTS "Build bundled tests" ON) | |||
message(STATUS "Build test and example programs: ${DIRENT_BUILD_TESTS}") | |||
# Initialize C and C++ compilers | |||
enable_language (C CXX) | |||
# Compile in debug mode by default | |||
if (NOT CMAKE_BUILD_TYPE) | |||
set (CMAKE_BUILD_TYPE Debug | |||
CACHE STRING | |||
"Type of build: None Debug Release RelWithDebInfo MinSizeRel." | |||
FORCE | |||
) | |||
endif (NOT CMAKE_BUILD_TYPE) | |||
# Use the include directory only on Windows | |||
if (WIN32) | |||
include_directories (${CMAKE_SOURCE_DIR}/include) | |||
endif (WIN32) | |||
# Install dirent.h | |||
if (WIN32) | |||
install (FILES include/dirent.h DESTINATION include) | |||
endif (WIN32) | |||
# Add distclean target | |||
add_custom_target (distclean | |||
COMMAND ${CMAKE_BUILD_TOOL} clean | |||
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_SOURCE_DIR}/distclean.cmake | |||
) | |||
# Build example programs | |||
if(DIRENT_BUILD_TESTS) | |||
add_executable (find examples/find.c) | |||
add_executable (ls examples/ls.c) | |||
add_executable (locate examples/locate.c) | |||
add_executable (updatedb examples/updatedb.c) | |||
add_executable (scandir examples/scandir.c) | |||
add_executable (cat examples/cat.c) | |||
# Build test programs | |||
include (CTest) | |||
add_custom_target (check COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure -C ${CMAKE_CFG_INTDIR}) | |||
function (add_test_executable TEST_NAME) | |||
add_executable (${TEST_NAME} EXCLUDE_FROM_ALL ${ARGN}) | |||
add_test (NAME ${TEST_NAME} WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} COMMAND $<TARGET_FILE:${TEST_NAME}>) | |||
add_dependencies (check ${TEST_NAME}) | |||
endfunction (add_test_executable) | |||
add_test_executable (t-compile tests/t-compile.c) | |||
add_test_executable (t-dirent tests/t-dirent.c) | |||
add_test_executable (t-scandir tests/t-scandir.c) | |||
add_test_executable (t-unicode tests/t-unicode.c) | |||
add_test_executable (t-cplusplus tests/t-cplusplus.cpp) | |||
endif(DIRENT_BUILD_TESTS) |
@ -1,129 +0,0 @@ | |||
2018-05-08 Toni Rönkkö | |||
* Version 1.23.2: fixes bad scandir prototype. | |||
2017-08-27 Toni Rönkkö | |||
* Version 1.23: support readdir_r and scandir functions. | |||
2017-07-18 Toni Rönkkö | |||
* Created release branches v1.22 and v1.21 to Git. Published version | |||
1.22 at softagalleria.net. | |||
2016-09-11 Toni Rönkkö | |||
* Version 1.22: added support for CMake. Thanks to Paul Fultz II. | |||
2014-09-25 Toni Rönkkö | |||
* Version 1.21: compiles correctly under Open Watcom. Thanks to | |||
Virgil Banowetz for a patch! | |||
2014-04-07 Toni Rönkkö | |||
* Version 1.20.1: the zip file from the previous version did not open | |||
correctly with Microsoft's compressed folders. Thanks to Alexandre | |||
for info! | |||
2014-03-17 Toni Ronkko | |||
* Version 1.20: dirent.h compiles correctly in 64-bit architecture. | |||
Thanks to Aaron Simmons! | |||
2014-03-03 Toni Ronkko | |||
* Version 1.13.2: define DT_LNK for compatibility with Unix | |||
programs. Thanks to Joel Bruick for suggestion! | |||
2013-01-27 Toni Ronkko | |||
* Version 1.13.1: patch from Edward Berner fixes set_errno() on | |||
Windows NT 4.0. | |||
* Revised wcstombs() and mbstowcs() wrappers to make sure that they do | |||
not write past their target string. | |||
* PATH_MAX from windows.h includes zero terminator so there is no | |||
need to add one extra byte to variables and structures. | |||
2012-12-12 Toni Ronkko | |||
* Version 1.13: use the traditional 8+3 file naming scheme if a file | |||
name cannot be represented in the default ANSI code page. Now | |||
compiles again with MSVC 6.0. Thanks to Konstantin Khomoutov for | |||
testing. | |||
2012-10-01 Toni Ronkko | |||
* Version 1.12.1: renamed wide-character DIR structure _wDIR to | |||
_WDIR (with capital W) in order to maintain compatibility with MingW. | |||
2012-09-30 Toni Ronkko | |||
* Version 1.12: define PATH_MAX and NAME_MAX. Added wide-character | |||
variants _wDIR, _wdirent, _wopendir(), _wreaddir(), _wclosedir() and | |||
_wrewinddir(). Thanks to Edgar Buerkle and Jan Nijtmans for ideas | |||
and code. | |||
* Now avoiding windows.h. This allows dirent.h to be integrated | |||
more easily into programs using winsock. Thanks to Fernando | |||
Azaldegui. | |||
2011-03-15 Toni Ronkko | |||
* Version 1.11: defined FILE_ATTRIBUTE_DEVICE for MSVC 6.0. | |||
2010-08-11 Toni Ronkko | |||
* Version 1.10: added d_type and d_namlen fields to dirent structure. | |||
The former is especially useful for determining whether directory | |||
entry represents a file or a directory. For more information, see | |||
http://www.delorie.com/gnu/docs/glibc/libc_270.html | |||
* Improved conformance to the standards. For example, errno is now | |||
set properly on failure and assert() is never used. Thanks to Peter | |||
Brockam for suggestions. | |||
* Fixed a bug in rewinddir(): when using relative directory names, | |||
change of working directory no longer causes rewinddir() to fail. | |||
2009-12-15 John Cunningham | |||
* Version 1.9: added rewinddir member function | |||
2008-01-18 Toni Ronkko | |||
* Version 1.8: Using FindFirstFileA and WIN32_FIND_DATAA to avoid | |||
converting string between multi-byte and unicode representations. | |||
This makes the code simpler and also allows the code to be compiled | |||
under MingW. Thanks to Azriel Fasten for the suggestion. | |||
2007-03-04 Toni Ronkko | |||
* Bug fix: due to the strncpy_s() function this file only compiled in | |||
Visual Studio 2005. Using the new string functions only when the | |||
compiler version allows. | |||
2006-11-02 Toni Ronkko | |||
* Major update: removed support for Watcom C, MS-DOS and Turbo C to | |||
simplify the file, updated the code to compile cleanly on Visual | |||
Studio 2005 with both unicode and multi-byte character strings, | |||
removed rewinddir() as it had a bug. | |||
2006-08-20 Toni Ronkko | |||
* Removed all remarks about MSVC 1.0, which is antiqued now. | |||
Simplified comments by removing SGML tags. | |||
2002-05-14 Toni Ronkko | |||
* Embedded the function definitions directly to the header so that no | |||
source modules need to be included in the Visual Studio project. | |||
Removed all the dependencies to other projects so that this header | |||
file can be used independently. | |||
1998-05-28 Toni Ronkko | |||
* First version. |
@ -1,21 +0,0 @@ | |||
The MIT License (MIT) | |||
Copyright (c) 1998-2019 Toni Ronkko | |||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||
of this software and associated documentation files (the "Software"), to deal | |||
in the Software without restriction, including without limitation the rights | |||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
copies of the Software, and to permit persons to whom the Software is | |||
furnished to do so, subject to the following conditions: | |||
The above copyright notice and this permission notice shall be included in all | |||
copies or substantial portions of the Software. | |||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
SOFTWARE. |
@ -1,101 +0,0 @@ | |||
# Dirent | |||
Dirent is a C/C++ programming interface that allows programmers to retrieve | |||
information about files and directories under Linux/UNIX. This project | |||
provides Linux compatible Dirent interface for Microsoft Windows. | |||
# Installation | |||
Download the latest Dirent installation package from | |||
[GitHub](https://github.com/tronkko/dirent/releases) and | |||
unpack the installation file with 7-zip, for example. The installation | |||
package contains dirent.h file as well as a few example programs and | |||
tests. | |||
## Install Dirent for All Programs | |||
To make dirent.h available for all C/C++ programs, simply copy the | |||
``include/dirent.h`` file to the system include directory. System include | |||
directory contains header files such as assert.h and windows.h. In Visual | |||
Studio 2008, for example, the system include may be found at | |||
``C:\Program Files\Microsoft Visual Studio 9.0\VC\include``. | |||
Everything you need is included in the single dirent.h file, and you can | |||
start using Dirent immediately -- there is no need to add files to your | |||
Visual Studio project. | |||
## Embed Dirent into Your Own Project | |||
If you wish to distribute dirent.h alongside with your own source code, then | |||
copy ``include/dirent.h`` file to a new sub-directory within your project and | |||
add that directory to include path on Windows while omitting the directory | |||
under Linux/UNIX. This allows your project to be compiled against native | |||
dirent.h on Linux/UNIX while substituting the functionality on Microsoft | |||
Windows. | |||
## Examples | |||
The installation package contains four example programs: | |||
Program | Purpose | |||
-------- | ----------------------------------------------------------------- | |||
ls | List files in a directory, e.g. ls "c:\Program Files" | |||
find | Find files in subdirectories, e.g. find "c:\Program Files\CMake" | |||
updatedb | Build database of files in a drive, e.g. updatedb c:\ | |||
locate | Locate a file from database, e.g. locate notepad | |||
scandir | Demonstrate scandir() function | |||
cat | Print a text file to screen | |||
To build the example programs, first install [CMake](https://cmake.org/). | |||
Then, with CMake installed, open command prompt and create a temporary | |||
directory ``c:\temp\dirent`` for the build files as | |||
``` | |||
c:\ | |||
mkdir temp | |||
mkdir temp\dirent | |||
cd temp\dirent | |||
``` | |||
Generate build files as | |||
``` | |||
cmake d:\dirent | |||
``` | |||
where ``d:\dirent`` is the root directory of the Dirent package (containing | |||
this README.md and LICENSE file). | |||
Once CMake is finished, open Visual Studio, load the generated dirent.sln file | |||
from the build directory and build the solution. Once the build completes, run | |||
the example programs from the command prompt as | |||
``` | |||
cd Debug | |||
ls . | |||
find . | |||
updatedb c:\ | |||
locate cmd.exe | |||
``` | |||
You can omit generation of test and example programs by appending option | |||
`-DDIRENT_BUILD_TESTS=OFF` to the CMake command line. | |||
# Copying | |||
Dirent may be freely distributed under the MIT license. See the | |||
[LICENSE](LICENSE) file for details. | |||
# Alternatives to Dirent | |||
I ported Dirent to Microsoft Windows in 1998 when only a few alternatives | |||
were available. However, the situation has changed since then and nowadays | |||
both [Cygwin](http://www.cygwin.com) and [MingW](http://www.mingw.org) | |||
allow you to compile a great number of UNIX programs in Microsoft Windows. | |||
They both provide a full dirent API as well as many other UNIX APIs. MingW | |||
can even be used for commercial applications! |
@ -1,62 +0,0 @@ | |||
# Remove CMake generated temporary files | |||
set (cmake_generated | |||
${CMAKE_BINARY_DIR}/ALL_BUILD.vcxproj | |||
${CMAKE_BINARY_DIR}/ALL_BUILD.vcxproj.filters | |||
${CMAKE_BINARY_DIR}/CMakeCache.txt | |||
${CMAKE_BINARY_DIR}/CMakeFiles | |||
${CMAKE_BINARY_DIR}/CTestTestfile.cmake | |||
${CMAKE_BINARY_DIR}/Continuous.vcxproj | |||
${CMAKE_BINARY_DIR}/Continuous.vcxproj.filters | |||
${CMAKE_BINARY_DIR}/DartConfiguration.tcl | |||
${CMAKE_BINARY_DIR}/Debug | |||
${CMAKE_BINARY_DIR}/Experimental.vcxproj | |||
${CMAKE_BINARY_DIR}/Experimental.vcxproj.filters | |||
${CMAKE_BINARY_DIR}/INSTALL.vcxproj | |||
${CMAKE_BINARY_DIR}/INSTALL.vcxproj.filters | |||
${CMAKE_BINARY_DIR}/Makefile | |||
${CMAKE_BINARY_DIR}/Nightly.vcxproj | |||
${CMAKE_BINARY_DIR}/Nightly.vcxproj.filters | |||
${CMAKE_BINARY_DIR}/NightlyMemoryCheck.vcxproj | |||
${CMAKE_BINARY_DIR}/NightlyMemoryCheck.vcxproj.filters | |||
${CMAKE_BINARY_DIR}/RUN_TESTS.vcxproj | |||
${CMAKE_BINARY_DIR}/RUN_TESTS.vcxproj.filters | |||
${CMAKE_BINARY_DIR}/Testing | |||
${CMAKE_BINARY_DIR}/Win32 | |||
${CMAKE_BINARY_DIR}/ZERO_CHECK.vcxproj | |||
${CMAKE_BINARY_DIR}/ZERO_CHECK.vcxproj.filters | |||
${CMAKE_BINARY_DIR}/check.vcxproj | |||
${CMAKE_BINARY_DIR}/check.vcxproj.filters | |||
${CMAKE_BINARY_DIR}/cmake_install.cmake | |||
${CMAKE_BINARY_DIR}/dirent.sln | |||
${CMAKE_BINARY_DIR}/distclean.vcxproj | |||
${CMAKE_BINARY_DIR}/distclean.vcxproj.filters | |||
${CMAKE_BINARY_DIR}/find | |||
${CMAKE_BINARY_DIR}/find.dir | |||
${CMAKE_BINARY_DIR}/find.vcxproj | |||
${CMAKE_BINARY_DIR}/find.vcxproj.filters | |||
${CMAKE_BINARY_DIR}/locate | |||
${CMAKE_BINARY_DIR}/locate.dir | |||
${CMAKE_BINARY_DIR}/locate.vcxproj | |||
${CMAKE_BINARY_DIR}/locate.vcxproj.filters | |||
${CMAKE_BINARY_DIR}/ls | |||
${CMAKE_BINARY_DIR}/ls.dir | |||
${CMAKE_BINARY_DIR}/ls.vcxproj | |||
${CMAKE_BINARY_DIR}/ls.vcxproj.filters | |||
${CMAKE_BINARY_DIR}/t-compile | |||
${CMAKE_BINARY_DIR}/t-compile.dir | |||
${CMAKE_BINARY_DIR}/t-compile.vcxproj | |||
${CMAKE_BINARY_DIR}/t-compile.vcxproj.filters | |||
${CMAKE_BINARY_DIR}/t-dirent | |||
${CMAKE_BINARY_DIR}/t-dirent.dir | |||
${CMAKE_BINARY_DIR}/t-dirent.vcxproj | |||
${CMAKE_BINARY_DIR}/t-dirent.vcxproj.filters | |||
${CMAKE_BINARY_DIR}/updatedb | |||
${CMAKE_BINARY_DIR}/updatedb.dir | |||
${CMAKE_BINARY_DIR}/updatedb.vcxproj | |||
${CMAKE_BINARY_DIR}/updatedb.vcxproj.filters | |||
) | |||
foreach (file ${cmake_generated}) | |||
if (EXISTS ${file}) | |||
file (REMOVE_RECURSE ${file}) | |||
endif() | |||
endforeach (file) |
@ -1,85 +0,0 @@ | |||
/* | |||
* Output contents of a file. | |||
* | |||
* Compile this file with Visual Studio and run the produced command in | |||
* console with a file name argument. For example, command | |||
* | |||
* cat include\dirent.h | |||
* | |||
* will output the dirent.h to screen. | |||
* | |||
* 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 | |||
*/ | |||
#define _CRT_SECURE_NO_WARNINGS | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <dirent.h> | |||
#include <errno.h> | |||
#include <locale.h> | |||
static void output_file (const char *fn); | |||
int | |||
main( | |||
int argc, char *argv[]) | |||
{ | |||
int i; | |||
/* Select default locale */ | |||
setlocale (LC_ALL, ""); | |||
/* Require at least one file */ | |||
if (argc == 1) { | |||
fprintf (stderr, "Usage: cat filename\n"); | |||
return EXIT_FAILURE; | |||
} | |||
/* For each file name argument in command line */ | |||
i = 1; | |||
while (i < argc) { | |||
output_file (argv[i]); | |||
i++; | |||
} | |||
return EXIT_SUCCESS; | |||
} | |||
/* | |||
* Output file to screen | |||
*/ | |||
static void | |||
output_file( | |||
const char *fn) | |||
{ | |||
FILE *fp; | |||
/* Open file */ | |||
fp = fopen (fn, "r"); | |||
if (fp != NULL) { | |||
size_t n; | |||
char buffer[4096]; | |||
/* Output file to screen */ | |||
do { | |||
/* Read some bytes from file */ | |||
n = fread (buffer, 1, 4096, fp); | |||
/* Output bytes to screen */ | |||
fwrite (buffer, 1, n, stdout); | |||
} while (n != 0); | |||
/* Close file */ | |||
fclose (fp); | |||
} else { | |||
/* Could not open directory */ | |||
fprintf (stderr, "Cannot open %s (%s)\n", fn, strerror (errno)); | |||
exit (EXIT_FAILURE); | |||
} | |||
} |
@ -1,147 +0,0 @@ | |||
/* | |||
* An example demonstrating recursive directory traversal. | |||
* | |||
* Compile this file with Visual Studio and run the produced command in | |||
* console with a directory name argument. For example, command | |||
* | |||
* find "C:\Program Files" | |||
* | |||
* will output thousands of file names such as | |||
* | |||
* c:\Program Files/7-Zip/7-zip.chm | |||
* c:\Program Files/7-Zip/7-zip.dll | |||
* c:\Program Files/7-Zip/7z.dll | |||
* c:\Program Files/Adobe/Reader 10.0/Reader/logsession.dll | |||
* c:\Program Files/Adobe/Reader 10.0/Reader/LogTransport2.exe | |||
* c:\Program Files/Windows NT/Accessories/wordpad.exe | |||
* c:\Program Files/Windows NT/Accessories/write.wpc | |||
* | |||
* The find command provided by this file is only an example: the command does | |||
* not provide options to restrict the output to certain files as the Linux | |||
* version does. | |||
* | |||
* 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 | |||
*/ | |||
#define _CRT_SECURE_NO_WARNINGS | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <dirent.h> | |||
#include <errno.h> | |||
#include <locale.h> | |||
static int find_directory (const char *dirname); | |||
int | |||
main( | |||
int argc, char *argv[]) | |||
{ | |||
int i; | |||
int ok; | |||
/* Select default locale */ | |||
setlocale (LC_ALL, ""); | |||
/* For each directory in command line */ | |||
i = 1; | |||
while (i < argc) { | |||
ok = find_directory (argv[i]); | |||
if (!ok) { | |||
exit (EXIT_FAILURE); | |||
} | |||
i++; | |||
} | |||
/* List current working directory if no arguments on command line */ | |||
if (argc == 1) { | |||
find_directory ("."); | |||
} | |||
return EXIT_SUCCESS; | |||
} | |||
/* Find files and subdirectories recursively */ | |||
static int | |||
find_directory( | |||
const char *dirname) | |||
{ | |||
DIR *dir; | |||
char buffer[PATH_MAX + 2]; | |||
char *p = buffer; | |||
const char *src; | |||
char *end = &buffer[PATH_MAX]; | |||
int ok; | |||
/* Copy directory name to buffer */ | |||
src = dirname; | |||
while (p < end && *src != '\0') { | |||
*p++ = *src++; | |||
} | |||
*p = '\0'; | |||
/* Open directory stream */ | |||
dir = opendir (dirname); | |||
if (dir != NULL) { | |||
struct dirent *ent; | |||
/* Print all files and directories within the directory */ | |||
while ((ent = readdir (dir)) != NULL) { | |||
char *q = p; | |||
char c; | |||
/* Get final character of directory name */ | |||
if (buffer < q) { | |||
c = q[-1]; | |||
} else { | |||
c = ':'; | |||
} | |||
/* Append directory separator if not already there */ | |||
if (c != ':' && c != '/' && c != '\\') { | |||
*q++ = '/'; | |||
} | |||
/* Append file name */ | |||
src = ent->d_name; | |||
while (q < end && *src != '\0') { | |||
*q++ = *src++; | |||
} | |||
*q = '\0'; | |||
/* Decide what to do with the directory entry */ | |||
switch (ent->d_type) { | |||
case DT_LNK: | |||
case DT_REG: | |||
/* Output file name with directory */ | |||
printf ("%s\n", buffer); | |||
break; | |||
case DT_DIR: | |||
/* Scan sub-directory recursively */ | |||
if (strcmp (ent->d_name, ".") != 0 | |||
&& strcmp (ent->d_name, "..") != 0) { | |||
find_directory (buffer); | |||
} | |||
break; | |||
default: | |||
/* Ignore device entries */ | |||
/*NOP*/; | |||
} | |||
} | |||
closedir (dir); | |||
ok = 1; | |||
} else { | |||
/* Could not open directory */ | |||
fprintf (stderr, "Cannot open %s (%s)\n", dirname, strerror (errno)); | |||
ok = 0; | |||
} | |||
return ok; | |||
} |
@ -1,281 +0,0 @@ | |||
/* | |||
* 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 <stdio.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <wchar.h> | |||
#ifdef WIN32 | |||
# include <io.h> | |||
# include <fcntl.h> | |||
#endif | |||
#include <dirent.h> | |||
/* 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; | |||
} | |||
} |
@ -1,103 +0,0 @@ | |||
/* | |||
* An example demonstrating basic directory listing. | |||
* | |||
* Compile this file with Visual Studio and run the produced command in | |||
* console with a directory name argument. For example, command | |||
* | |||
* ls "c:\Program Files" | |||
* | |||
* might output something like | |||
* | |||
* ./ | |||
* ../ | |||
* 7-Zip/ | |||
* Internet Explorer/ | |||
* Microsoft Visual Studio 9.0/ | |||
* Microsoft.NET/ | |||
* Mozilla Firefox/ | |||
* | |||
* The ls command provided by this file is only an example: the command does | |||
* not have any fancy options like "ls -al" in Linux and the command does not | |||
* support file name matching like "ls *.c". | |||
* | |||
* 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 | |||
*/ | |||
#define _CRT_SECURE_NO_WARNINGS | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <dirent.h> | |||
#include <errno.h> | |||
#include <locale.h> | |||
static void list_directory (const char *dirname); | |||
int | |||
main( | |||
int argc, char *argv[]) | |||
{ | |||
int i; | |||
/* Select default locale */ | |||
setlocale (LC_ALL, ""); | |||
/* For each directory in command line */ | |||
i = 1; | |||
while (i < argc) { | |||
list_directory (argv[i]); | |||
i++; | |||
} | |||
/* List current working directory if no arguments on command line */ | |||
if (argc == 1) { | |||
list_directory ("."); | |||
} | |||
return EXIT_SUCCESS; | |||
} | |||
/* | |||
* List files and directories within a directory. | |||
*/ | |||
static void | |||
list_directory( | |||
const char *dirname) | |||
{ | |||
DIR *dir; | |||
struct dirent *ent; | |||
/* Open directory stream */ | |||
dir = opendir (dirname); | |||
if (dir != NULL) { | |||
/* Print all files and directories within the directory */ | |||
while ((ent = readdir (dir)) != NULL) { | |||
switch (ent->d_type) { | |||
case DT_REG: | |||
printf ("%s\n", ent->d_name); | |||
break; | |||
case DT_DIR: | |||
printf ("%s/\n", ent->d_name); | |||
break; | |||
case DT_LNK: | |||
printf ("%s@\n", ent->d_name); | |||
break; | |||
default: | |||
printf ("%s*\n", ent->d_name); | |||
} | |||
} | |||
closedir (dir); | |||
} else { | |||
/* Could not open directory */ | |||
fprintf (stderr, "Cannot open %s (%s)\n", dirname, strerror (errno)); | |||
exit (EXIT_FAILURE); | |||
} | |||
} |
@ -1,110 +0,0 @@ | |||
/* | |||
* Example program demonstrating the use of scandir function. | |||
* | |||
* Compile this file with Visual Studio and run the produced command in | |||
* console with a directory name argument. For example, command | |||
* | |||
* scandir "c:\Program Files" | |||
* | |||
* might output something like | |||
* | |||
* ./ | |||
* ../ | |||
* 7-Zip/ | |||
* Internet Explorer/ | |||
* Microsoft Visual Studio 9.0/ | |||
* Microsoft.NET/ | |||
* Mozilla Firefox/ | |||
* | |||
* 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 | |||
*/ | |||
#define _CRT_SECURE_NO_WARNINGS | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <dirent.h> | |||
#include <errno.h> | |||
#include <locale.h> | |||
static void list_directory (const char *dirname); | |||
int | |||
main( | |||
int argc, char *argv[]) | |||
{ | |||
int i; | |||
/* Select default locale */ | |||
setlocale (LC_ALL, ""); | |||
/* For each directory in command line */ | |||
i = 1; | |||
while (i < argc) { | |||
list_directory (argv[i]); | |||
i++; | |||
} | |||
/* List current working directory if no arguments on command line */ | |||
if (argc == 1) { | |||
list_directory ("."); | |||
} | |||
return EXIT_SUCCESS; | |||
} | |||
/* | |||
* List files and directories within a directory. | |||
*/ | |||
static void | |||
list_directory( | |||
const char *dirname) | |||
{ | |||
struct dirent **files; | |||
int i; | |||
int n; | |||
/* Scan files in directory */ | |||
n = scandir (dirname, &files, NULL, alphasort); | |||
if (n >= 0) { | |||
/* Loop through file names */ | |||
for (i = 0; i < n; i++) { | |||
struct dirent *ent; | |||
/* Get pointer to file entry */ | |||
ent = files[i]; | |||
/* Output file name */ | |||
switch (ent->d_type) { | |||
case DT_REG: | |||
printf ("%s\n", ent->d_name); | |||
break; | |||
case DT_DIR: | |||
printf ("%s/\n", ent->d_name); | |||
break; | |||
case DT_LNK: | |||
printf ("%s@\n", ent->d_name); | |||
break; | |||
default: | |||
printf ("%s*\n", ent->d_name); | |||
} | |||
} | |||
/* Release file names */ | |||
for (i = 0; i < n; i++) { | |||
free (files[i]); | |||
} | |||
free (files); | |||
} else { | |||
fprintf (stderr, "Cannot open %s (%s)\n", dirname, strerror (errno)); | |||
exit (EXIT_FAILURE); | |||
} | |||
} |
@ -1,232 +0,0 @@ | |||
/* | |||
* An example demonstrating wide-character functions | |||
* | |||
* Compile this file with Visual Studio and run the produced command in | |||
* console with a directory name argument. For example, command | |||
* | |||
* updatedb C:\ | |||
* | |||
* will produce the file locate.db with one file name per line such as | |||
* | |||
* c:\Program Files/7-Zip/7-zip.chm | |||
* c:\Program Files/7-Zip/7-zip.dll | |||
* c:\Program Files/7-Zip/7z.dll | |||
* c:\Program Files/Adobe/Reader 10.0/Reader/logsession.dll | |||
* c:\Program Files/Adobe/Reader 10.0/Reader/LogTransport2.exe | |||
* c:\Program Files/Windows NT/Accessories/wordpad.exe | |||
* c:\Program Files/Windows NT/Accessories/write.wpc | |||
* | |||
* 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 <stdio.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <wchar.h> | |||
#ifdef WIN32 | |||
# include <io.h> | |||
# include <fcntl.h> | |||
#endif | |||
#include <dirent.h> | |||
/* File name and location of database file */ | |||
#define DB_LOCATION L"locate.db" | |||
/* Forward-decl */ | |||
static int update_directory (const wchar_t *dirname); | |||
static void db_open (void); | |||
static void db_close (void); | |||
static void db_store (const wchar_t *dirname); | |||
/* Module local variables */ | |||
static FILE *db = NULL; | |||
int | |||
main( | |||
int argc, char *argv[]) | |||
{ | |||
#ifdef WIN32 | |||
int i; | |||
int ok; | |||
/* Prepare for unicode output */ | |||
_setmode (_fileno (stdout), _O_U16TEXT); | |||
/* Open locate.db */ | |||
db_open (); | |||
/* For each directory in command line */ | |||
i = 1; | |||
while (i < argc) { | |||
wchar_t buffer[PATH_MAX + 1]; | |||
errno_t error; | |||
size_t n; | |||
/* Convert ith argument to wide-character string */ | |||
error = mbstowcs_s (&n, buffer, PATH_MAX, argv[i], _TRUNCATE); | |||
if (!error) { | |||
/* Scan directory for files */ | |||
ok = update_directory (buffer); | |||
if (!ok) { | |||
wprintf (L"Cannot open directory %s\n", buffer); | |||
exit (EXIT_FAILURE); | |||
} | |||
} | |||
i++; | |||
} | |||
/* Use current working directory if no arguments on command line */ | |||
if (argc == 1) { | |||
update_directory (L"."); | |||
} | |||
db_close (); | |||
#else | |||
printf ("updatedb only works on Microsoft Windows\n"); | |||
#endif | |||
return EXIT_SUCCESS; | |||
} | |||
/* Find files recursively */ | |||
static int | |||
update_directory( | |||
const wchar_t *dirname) | |||
{ | |||
int ok = 0; | |||
#ifdef WIN32 | |||
_WDIR *dir; | |||
wchar_t buffer[PATH_MAX + 2]; | |||
wchar_t *p = buffer; | |||
const wchar_t *src; | |||
wchar_t *end = &buffer[PATH_MAX]; | |||
/* Copy directory name to buffer */ | |||
src = dirname; | |||
while (p < end && *src != '\0') { | |||
*p++ = *src++; | |||
} | |||
*p = '\0'; | |||
/* Open directory stream */ | |||
dir = _wopendir (dirname); | |||
if (dir != NULL) { | |||
struct _wdirent *ent; | |||
/* Print all files and directories within the directory */ | |||
while ((ent = _wreaddir (dir)) != NULL) { | |||
wchar_t *q = p; | |||
wchar_t c; | |||
/* Get final character of directory name */ | |||
if (buffer < q) { | |||
c = q[-1]; | |||
} else { | |||
c = ':'; | |||
} | |||
/* Append directory separator if not already there */ | |||
if (c != ':' && c != '/' && c != '\\') { | |||
*q++ = '/'; | |||
} | |||
/* Append file name */ | |||
src = ent->d_name; | |||
while (q < end && *src != '\0') { | |||
*q++ = *src++; | |||
} | |||
*q = '\0'; | |||
/* Decide what to do with the directory entry */ | |||
switch (ent->d_type) { | |||
case DT_REG: | |||
/* Store file name */ | |||
db_store (buffer); | |||
break; | |||
case DT_DIR: | |||
/* Scan sub-directory recursively */ | |||
if (wcscmp (ent->d_name, L".") != 0 | |||
&& wcscmp (ent->d_name, L"..") != 0) { | |||
update_directory (buffer); | |||
} | |||
break; | |||
default: | |||
/* Do not device entries */ | |||
/*NOP*/; | |||
} | |||
} | |||
wclosedir (dir); | |||
ok = 1; | |||
} else { | |||
/* Cannot open directory */ | |||
ok = 0; | |||
} | |||
#endif | |||
return ok; | |||
} | |||
/* Store file name to locate.db */ | |||
static void | |||
db_store( | |||
const wchar_t *dirname) | |||
{ | |||
#ifdef WIN32 | |||
if (db) { | |||
/* Output line to file */ | |||
fwprintf (db, L"%s\n", dirname); | |||
} else { | |||
wprintf (L"Database not open\n"); | |||
exit (EXIT_FAILURE); | |||
} | |||
#endif | |||
} | |||
/* 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"wt, 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; | |||
} | |||
} |
@ -1,3 +0,0 @@ | |||
This file ensures that the directory dir will be created accordingly when | |||
you unzip dirent to your computer. The directory itself is needed by the | |||
test program t-dirent. |
@ -1 +0,0 @@ | |||
This dummy file is needed by the test program t-dirent. |
@ -1,2 +0,0 @@ | |||
This directory contains some random files for the t-scandir test program. The | |||
files are empty and only the file names matter. |
@ -1,47 +0,0 @@ | |||
/* | |||
* Test program to make sure that dirent compiles cleanly with winsock. | |||
* | |||
* 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 <dirent.h> | |||
#ifdef WIN32 | |||
# include <winsock2.h> | |||
# include <ws2tcpip.h> | |||
#endif | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
int | |||
main( | |||
int argc, char *argv[]) | |||
{ | |||
struct dirent *dirp = NULL; | |||
(void) argc; | |||
(void) argv; | |||
#ifdef _DIRENT_HAVE_D_TYPE | |||
printf ("Has d_type\n"); | |||
#endif | |||
#ifdef _DIRENT_HAVE_D_NAMLEN | |||
printf ("Has d_namlen\n"); | |||
#endif | |||
#ifdef _D_EXACT_NAMLEN | |||
printf ("Has _D_EXACT_NAMLEN\n"); | |||
#endif | |||
#ifdef _D_ALLOC_NAMLEN | |||
printf ("Has _D_ALLOC_NAMLEN\n"); | |||
#endif | |||
#ifdef _D_ALLOC_NAMLEN | |||
printf ("Has _D_ALLOC_NAMLEN\n"); | |||
#endif | |||
printf ("Length of d_name with terminator: %d\n", | |||
(int) sizeof (dirp->d_name)); | |||
printf ("OK\n"); | |||
return EXIT_SUCCESS; | |||
} |
@ -1,160 +0,0 @@ | |||
/* | |||
* Test program to make sure that dirent compiles cleanly with C++ | |||
* | |||
* 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 <iostream> | |||
#include <string.h> | |||
#include <dirent.h> | |||
#include <assert.h> | |||
using namespace std; | |||
/* Filter and sort functions */ | |||
static int only_readme (const struct dirent *entry); | |||
int | |||
main( | |||
int argc, char *argv[]) | |||
{ | |||
(void) argc; | |||
(void) argv; | |||
/* Basic directory retrieval */ | |||
{ | |||
DIR *dir; | |||
struct dirent *ent; | |||
int found = 0; | |||
/* Open directory */ | |||
dir = opendir ("tests/1"); | |||
if (dir == NULL) { | |||
cerr << "Directory tests/1 not found" << endl; | |||
abort (); | |||
} | |||
/* Read entries */ | |||
while ((ent = readdir (dir)) != NULL) { | |||
/* Check each file */ | |||
if (strcmp (ent->d_name, ".") == 0) { | |||
/* Directory itself */ | |||
#ifdef _DIRENT_HAVE_D_TYPE | |||
assert (ent->d_type == DT_DIR); | |||
#endif | |||
#ifdef _DIRENT_HAVE_D_NAMLEN | |||
assert (ent->d_namlen == 1); | |||
#endif | |||
#ifdef _D_EXACT_NAMLEN | |||
assert (_D_EXACT_NAMLEN(ent) == 1); | |||
#endif | |||
#ifdef _D_ALLOC_NAMLEN | |||
assert (_D_ALLOC_NAMLEN(ent) > 1); | |||
#endif | |||
found += 1; | |||
} else if (strcmp (ent->d_name, "..") == 0) { | |||
/* Parent directory */ | |||
#ifdef _DIRENT_HAVE_D_TYPE | |||
assert (ent->d_type == DT_DIR); | |||
#endif | |||
#ifdef _DIRENT_HAVE_D_NAMLEN | |||
assert (ent->d_namlen == 2); | |||
#endif | |||
#ifdef _D_EXACT_NAMLEN | |||
assert (_D_EXACT_NAMLEN(ent) == 2); | |||
#endif | |||
#ifdef _D_ALLOC_NAMLEN | |||
assert (_D_ALLOC_NAMLEN(ent) > 2); | |||
#endif | |||
found += 2; | |||
} else if (strcmp (ent->d_name, "file") == 0) { | |||
/* Regular file */ | |||
#ifdef _DIRENT_HAVE_D_TYPE | |||
assert (ent->d_type == DT_REG); | |||
#endif | |||
#ifdef _DIRENT_HAVE_D_NAMLEN | |||
assert (ent->d_namlen == 4); | |||
#endif | |||
#ifdef _D_EXACT_NAMLEN | |||
assert (_D_EXACT_NAMLEN(ent) == 4); | |||
#endif | |||
#ifdef _D_ALLOC_NAMLEN | |||
assert (_D_ALLOC_NAMLEN(ent) > 4); | |||
#endif | |||
found += 4; | |||
} else if (strcmp (ent->d_name, "dir") == 0) { | |||
/* Just a directory */ | |||
#ifdef _DIRENT_HAVE_D_TYPE | |||
assert (ent->d_type == DT_DIR); | |||
#endif | |||
#ifdef _DIRENT_HAVE_D_NAMLEN | |||
assert (ent->d_namlen == 3); | |||
#endif | |||
#ifdef _D_EXACT_NAMLEN | |||
assert (_D_EXACT_NAMLEN(ent) == 3); | |||
#endif | |||
#ifdef _D_ALLOC_NAMLEN | |||
assert (_D_ALLOC_NAMLEN(ent) > 3); | |||
#endif | |||
found += 8; | |||
} else { | |||
/* Other file */ | |||
cerr << "Unexpected file " << ent->d_name << endl; | |||
abort (); | |||
} | |||
} | |||
/* Make sure that all files were found */ | |||
assert (found == 0xf); | |||
closedir (dir); | |||
} | |||
/* Basic scan with simple filter function */ | |||
{ | |||
struct dirent **files; | |||
int n; | |||
int i; | |||
/* Read directory entries */ | |||
n = scandir ("tests/3", &files, only_readme, alphasort); | |||
assert (n == 1); | |||
/* Make sure that the filter works */ | |||
assert (strcmp (files[0]->d_name, "README.txt") == 0); | |||
/* Release file names */ | |||
for (i = 0; i < n; i++) { | |||
free (files[i]); | |||
} | |||
free (files); | |||
} | |||
cout << "OK" << endl; | |||
return EXIT_SUCCESS; | |||
} | |||
/* Only pass README.txt file */ | |||
static int | |||
only_readme (const struct dirent *entry) | |||
{ | |||
int pass; | |||
if (strcmp (entry->d_name, "README.txt") == 0) { | |||
pass = 1; | |||
} else { | |||
pass = 0; | |||
} | |||
return pass; | |||
} |
@ -1,633 +0,0 @@ | |||
/* | |||
* A test program to make sure that dirent works correctly. | |||
* | |||
* 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 <stdio.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#ifdef _MSC_VER | |||
# include <direct.h> | |||
# define chdir(x) _chdir(x) | |||
#else | |||
# include <unistd.h> | |||
#endif | |||
#include <sys/stat.h> | |||
#include <dirent.h> | |||
#include <errno.h> | |||
#undef NDEBUG | |||
#include <assert.h> | |||
int | |||
main( | |||
int argc, char *argv[]) | |||
{ | |||
(void) argc; | |||
(void) argv; | |||
/* File type macros */ | |||
{ | |||
assert (DTTOIF(DT_REG) == S_IFREG); | |||
assert (DTTOIF(DT_DIR) == S_IFDIR); | |||
assert (DTTOIF(DT_FIFO) == S_IFIFO); | |||
assert (DTTOIF(DT_SOCK) == S_IFSOCK); | |||
assert (DTTOIF(DT_CHR) == S_IFCHR); | |||
assert (DTTOIF(DT_BLK) == S_IFBLK); | |||
assert (IFTODT(S_IFREG) == DT_REG); | |||
assert (IFTODT(S_IFDIR) == DT_DIR); | |||
assert (IFTODT(S_IFIFO) == DT_FIFO); | |||
assert (IFTODT(S_IFSOCK) == DT_SOCK); | |||
assert (IFTODT(S_IFCHR) == DT_CHR); | |||
assert (IFTODT(S_IFBLK) == DT_BLK); | |||
} | |||
/* Basic directory retrieval */ | |||
{ | |||
DIR *dir; | |||
struct dirent *ent; | |||
int found = 0; | |||
/* Open directory */ | |||
dir = opendir ("tests/1"); | |||
if (dir == NULL) { | |||
fprintf (stderr, "Directory tests/1 not found\n"); | |||
abort (); | |||
} | |||
/* Read entries */ | |||
while ((ent = readdir (dir)) != NULL) { | |||
/* Check each file */ | |||
if (strcmp (ent->d_name, ".") == 0) { | |||
/* Directory itself */ | |||
#ifdef _DIRENT_HAVE_D_TYPE | |||
assert (ent->d_type == DT_DIR); | |||
#endif | |||
#ifdef _DIRENT_HAVE_D_NAMLEN | |||
assert (ent->d_namlen == 1); | |||
#endif | |||
#ifdef _D_EXACT_NAMLEN | |||
assert (_D_EXACT_NAMLEN(ent) == 1); | |||
#endif | |||
#ifdef _D_ALLOC_NAMLEN | |||
assert (_D_ALLOC_NAMLEN(ent) > 1); | |||
#endif | |||
found += 1; | |||
} else if (strcmp (ent->d_name, "..") == 0) { | |||
/* Parent directory */ | |||
#ifdef _DIRENT_HAVE_D_TYPE | |||
assert (ent->d_type == DT_DIR); | |||
#endif | |||
#ifdef _DIRENT_HAVE_D_NAMLEN | |||
assert (ent->d_namlen == 2); | |||
#endif | |||
#ifdef _D_EXACT_NAMLEN | |||
assert (_D_EXACT_NAMLEN(ent) == 2); | |||
#endif | |||
#ifdef _D_ALLOC_NAMLEN | |||
assert (_D_ALLOC_NAMLEN(ent) > 2); | |||
#endif | |||
found += 2; | |||
} else if (strcmp (ent->d_name, "file") == 0) { | |||
/* Regular file */ | |||
#ifdef _DIRENT_HAVE_D_TYPE | |||
assert (ent->d_type == DT_REG); | |||
#endif | |||
#ifdef _DIRENT_HAVE_D_NAMLEN | |||
assert (ent->d_namlen == 4); | |||
#endif | |||
#ifdef _D_EXACT_NAMLEN | |||
assert (_D_EXACT_NAMLEN(ent) == 4); | |||
#endif | |||
#ifdef _D_ALLOC_NAMLEN | |||
assert (_D_ALLOC_NAMLEN(ent) > 4); | |||
#endif | |||
found += 4; | |||
} else if (strcmp (ent->d_name, "dir") == 0) { | |||
/* Just a directory */ | |||
#ifdef _DIRENT_HAVE_D_TYPE | |||
assert (ent->d_type == DT_DIR); | |||
#endif | |||
#ifdef _DIRENT_HAVE_D_NAMLEN | |||
assert (ent->d_namlen == 3); | |||
#endif | |||
#ifdef _D_EXACT_NAMLEN | |||
assert (_D_EXACT_NAMLEN(ent) == 3); | |||
#endif | |||
#ifdef _D_ALLOC_NAMLEN | |||
assert (_D_ALLOC_NAMLEN(ent) > 3); | |||
#endif | |||
found += 8; | |||
} else { | |||
/* Other file */ | |||
fprintf (stderr, "Unexpected file %s\n", ent->d_name); | |||
abort (); | |||
} | |||
} | |||
/* Make sure that all files were found */ | |||
assert (found == 0xf); | |||
closedir (dir); | |||
} | |||
/* Function opendir() fails if directory doesn't exist */ | |||
{ | |||
DIR *dir; | |||
/* Open directory */ | |||
dir = opendir ("tests/invalid"); | |||
assert (dir == NULL); | |||
assert (errno == ENOENT); | |||
} | |||
/* Function opendir() fails if pathname is really a file */ | |||
{ | |||
DIR *dir; | |||
/* Open directory */ | |||
dir = opendir ("tests/1/file"); | |||
assert (dir == NULL); | |||
assert (errno == ENOTDIR); | |||
} | |||
/* Function opendir() fails if pathname is a zero-length string */ | |||
{ | |||
DIR *dir; | |||
/* Open directory */ | |||
dir = opendir (""); | |||
assert (dir == NULL); | |||
assert (errno == ENOENT); | |||
} | |||
/* Rewind of directory stream */ | |||
{ | |||
DIR *dir; | |||
struct dirent *ent; | |||
int found = 0; | |||
/* Open directory */ | |||
dir = opendir ("tests/1"); | |||
assert (dir != NULL); | |||
/* Read entries */ | |||
while ((ent = readdir (dir)) != NULL) { | |||
/* Check each file */ | |||
if (strcmp (ent->d_name, ".") == 0) { | |||
/* Directory itself */ | |||
found += 1; | |||
} else if (strcmp (ent->d_name, "..") == 0) { | |||
/* Parent directory */ | |||
found += 2; | |||
} else if (strcmp (ent->d_name, "file") == 0) { | |||
/* Regular file */ | |||
found += 4; | |||
} else if (strcmp (ent->d_name, "dir") == 0) { | |||
/* Just a directory */ | |||
found += 8; | |||
} else { | |||
/* Other file */ | |||
fprintf (stderr, "Unexpected file %s\n", ent->d_name); | |||
abort (); | |||
} | |||
} | |||
/* Make sure that all files were found */ | |||
assert (found == 0xf); | |||
/* Rewind stream and read entries again */ | |||
rewinddir (dir); | |||
found = 0; | |||
/* Read entries */ | |||
while ((ent = readdir (dir)) != NULL) { | |||
/* Check each file */ | |||
if (strcmp (ent->d_name, ".") == 0) { | |||
/* Directory itself */ | |||
found += 1; | |||
} else if (strcmp (ent->d_name, "..") == 0) { | |||
/* Parent directory */ | |||
found += 2; | |||
} else if (strcmp (ent->d_name, "file") == 0) { | |||
/* Regular file */ | |||
found += 4; | |||
} else if (strcmp (ent->d_name, "dir") == 0) { | |||
/* Just a directory */ | |||
found += 8; | |||
} else { | |||
/* Other file */ | |||
fprintf (stderr, "Unexpected file %s\n", ent->d_name); | |||
abort (); | |||
} | |||
} | |||
/* Make sure that all files were found */ | |||
assert (found == 0xf); | |||
closedir (dir); | |||
} | |||
/* Rewind with intervening change of working directory */ | |||
{ | |||
DIR *dir; | |||
struct dirent *ent; | |||
int found = 0; | |||
int errorcode; | |||
/* Open directory */ | |||
dir = opendir ("tests/1"); | |||
assert (dir != NULL); | |||
/* Read entries */ | |||
while ((ent = readdir (dir)) != NULL) { | |||
/* Check each file */ | |||
if (strcmp (ent->d_name, ".") == 0) { | |||
/* Directory itself */ | |||
found += 1; | |||
} else if (strcmp (ent->d_name, "..") == 0) { | |||
/* Parent directory */ | |||
found += 2; | |||
} else if (strcmp (ent->d_name, "file") == 0) { | |||
/* Regular file */ | |||
found += 4; | |||
} else if (strcmp (ent->d_name, "dir") == 0) { | |||
/* Just a directory */ | |||
found += 8; | |||
} else { | |||
/* Other file */ | |||
fprintf (stderr, "Unexpected file %s\n", ent->d_name); | |||
abort (); | |||
} | |||
} | |||
/* Make sure that all files were found */ | |||
assert (found == 0xf); | |||
/* Change working directory */ | |||
errorcode = chdir ("tests"); | |||
assert (errorcode == 0); | |||
/* Rewind stream and read entries again */ | |||
rewinddir (dir); | |||
found = 0; | |||
/* Read entries */ | |||
while ((ent = readdir (dir)) != NULL) { | |||
/* Check each file */ | |||
if (strcmp (ent->d_name, ".") == 0) { | |||
/* Directory itself */ | |||
found += 1; | |||
} else if (strcmp (ent->d_name, "..") == 0) { | |||
/* Parent directory */ | |||
found += 2; | |||
} else if (strcmp (ent->d_name, "file") == 0) { | |||
/* Regular file */ | |||
found += 4; | |||
} else if (strcmp (ent->d_name, "dir") == 0) { | |||
/* Just a directory */ | |||
found += 8; | |||
} else { | |||
/* Other file */ | |||
fprintf (stderr, "Unexpected file %s\n", ent->d_name); | |||
abort (); | |||
} | |||
} | |||
/* Make sure that all files were found */ | |||
assert (found == 0xf); | |||
/* Restore working directory */ | |||
errorcode = chdir (".."); | |||
assert (errorcode == 0); | |||
closedir (dir); | |||
} | |||
/* Long file name */ | |||
{ | |||
DIR *dir; | |||
struct dirent *ent; | |||
int found = 0; | |||
/* Open directory */ | |||
dir = opendir ("tests/2"); | |||
if (dir == NULL) { | |||
fprintf (stderr, "Directory tests/2 not found\n"); | |||
abort (); | |||
} | |||
/* Read entries */ | |||
while ((ent = readdir (dir)) != NULL) { | |||
/* Check each file */ | |||
if (strcmp (ent->d_name, ".") == 0) { | |||
/* Directory itself */ | |||
found += 1; | |||
} else if (strcmp (ent->d_name, "..") == 0) { | |||
/* Parent directory */ | |||
found += 2; | |||
} else if (strcmp (ent->d_name, "file.txt") == 0) { | |||
/* Regular 8+3 filename */ | |||
#ifdef _DIRENT_HAVE_D_TYPE | |||
assert (ent->d_type == DT_REG); | |||
#endif | |||
#ifdef _DIRENT_HAVE_D_NAMLEN | |||
assert (ent->d_namlen == 8); | |||
#endif | |||
#ifdef _D_EXACT_NAMLEN | |||
assert (_D_EXACT_NAMLEN(ent) == 8); | |||
#endif | |||
#ifdef _D_ALLOC_NAMLEN | |||
assert (_D_ALLOC_NAMLEN(ent) > 8); | |||
#endif | |||
found += 4; | |||
} else if (strcmp (ent->d_name, "Testfile-1.2.3.dat") == 0) { | |||
/* Long file name with multiple dots */ | |||
#ifdef _DIRENT_HAVE_D_TYPE | |||
assert (ent->d_type == DT_REG); | |||
#endif | |||
#ifdef _DIRENT_HAVE_D_NAMLEN | |||
assert (ent->d_namlen == 18); | |||
#endif | |||
#ifdef _D_EXACT_NAMLEN | |||
assert (_D_EXACT_NAMLEN(ent) == 18); | |||
#endif | |||
#ifdef _D_ALLOC_NAMLEN | |||
assert (_D_ALLOC_NAMLEN(ent) > 18); | |||
#endif | |||
found += 8; | |||
} else { | |||
/* Other file */ | |||
fprintf (stderr, "Unexpected file %s\n", ent->d_name); | |||
abort (); | |||
} | |||
} | |||
/* Make sure that all files were found */ | |||
assert (found == 0xf); | |||
closedir (dir); | |||
} | |||
/* Basic directory retrieval with readdir_r */ | |||
{ | |||
DIR *dir; | |||
struct dirent ent[10]; | |||
struct dirent *entry; | |||
size_t i = 0; | |||
size_t n = 0; | |||
int found = 0; | |||
/* Open directory */ | |||
dir = opendir ("tests/1"); | |||
if (dir == NULL) { | |||
fprintf (stderr, "Directory tests/1 not found\n"); | |||
abort (); | |||
} | |||
/* Read entries to table */ | |||
while (readdir_r (dir, &ent[n], &entry) == /*OK*/0 && entry != 0) { | |||
n++; | |||
assert (n <= 4); | |||
} | |||
/* Make sure that we got all the files from directory */ | |||
assert (n == 4); | |||
/* Check entries in memory */ | |||
for (i = 0; i < 4; i++) { | |||
entry = &ent[i]; | |||
/* Check each file */ | |||
if (strcmp (entry->d_name, ".") == 0) { | |||
/* Directory itself */ | |||
#ifdef _DIRENT_HAVE_D_TYPE | |||
assert (entry->d_type == DT_DIR); | |||
#endif | |||
#ifdef _DIRENT_HAVE_D_NAMLEN | |||
assert (entry->d_namlen == 1); | |||
#endif | |||
#ifdef _D_EXACT_NAMLEN | |||
assert (_D_EXACT_NAMLEN(entry) == 1); | |||
#endif | |||
#ifdef _D_ALLOC_NAMLEN | |||
assert (_D_ALLOC_NAMLEN(entry) > 1); | |||
#endif | |||
found += 1; | |||
} else if (strcmp (entry->d_name, "..") == 0) { | |||
/* Parent directory */ | |||
#ifdef _DIRENT_HAVE_D_TYPE | |||
assert (entry->d_type == DT_DIR); | |||
#endif | |||
#ifdef _DIRENT_HAVE_D_NAMLEN | |||
assert (entry->d_namlen == 2); | |||
#endif | |||
#ifdef _D_EXACT_NAMLEN | |||
assert (_D_EXACT_NAMLEN(entry) == 2); | |||
#endif | |||
#ifdef _D_ALLOC_NAMLEN | |||
assert (_D_ALLOC_NAMLEN(entry) > 2); | |||
#endif | |||
found += 2; | |||
} else if (strcmp (entry->d_name, "file") == 0) { | |||
/* Regular file */ | |||
#ifdef _DIRENT_HAVE_D_TYPE | |||
assert (entry->d_type == DT_REG); | |||
#endif | |||
#ifdef _DIRENT_HAVE_D_NAMLEN | |||
assert (entry->d_namlen == 4); | |||
#endif | |||
#ifdef _D_EXACT_NAMLEN | |||
assert (_D_EXACT_NAMLEN(entry) == 4); | |||
#endif | |||
#ifdef _D_ALLOC_NAMLEN | |||
assert (_D_ALLOC_NAMLEN(entry) > 4); | |||
#endif | |||
found += 4; | |||
} else if (strcmp (entry->d_name, "dir") == 0) { | |||
/* Just a directory */ | |||
#ifdef _DIRENT_HAVE_D_TYPE | |||
assert (entry->d_type == DT_DIR); | |||
#endif | |||
#ifdef _DIRENT_HAVE_D_NAMLEN | |||
assert (entry->d_namlen == 3); | |||
#endif | |||
#ifdef _D_EXACT_NAMLEN | |||
assert (_D_EXACT_NAMLEN(entry) == 3); | |||
#endif | |||
#ifdef _D_ALLOC_NAMLEN | |||
assert (_D_ALLOC_NAMLEN(entry) > 3); | |||
#endif | |||
found += 8; | |||
} else { | |||
/* Other file */ | |||
fprintf (stderr, "Unexpected file %s\n", entry->d_name); | |||
abort (); | |||
} | |||
} | |||
/* Make sure that all files were found */ | |||
assert (found == 0xf); | |||
closedir (dir); | |||
} | |||
/* Basic directory retrieval with _wreaddir_r */ | |||
#ifdef WIN32 | |||
{ | |||
_WDIR *dir; | |||
struct _wdirent ent[10]; | |||
struct _wdirent *entry; | |||
size_t i = 0; | |||
size_t n = 0; | |||
int found = 0; | |||
/* Open directory */ | |||
dir = _wopendir (L"tests/1"); | |||
if (dir == NULL) { | |||
fprintf (stderr, "Directory tests/1 not found\n"); | |||
abort (); | |||
} | |||
/* Read entries to table */ | |||
while (_wreaddir_r (dir, &ent[n], &entry) == /*OK*/0 && entry != 0) { | |||
n++; | |||
assert (n <= 4); | |||
} | |||
/* Make sure that we got all the files from directory */ | |||
assert (n == 4); | |||
/* Check entries in memory */ | |||
for (i = 0; i < 4; i++) { | |||
entry = &ent[i]; | |||
/* Check each file */ | |||
if (wcscmp (entry->d_name, L".") == 0) { | |||
/* Directory itself */ | |||
#ifdef _DIRENT_HAVE_D_TYPE | |||
assert (entry->d_type == DT_DIR); | |||
#endif | |||
#ifdef _DIRENT_HAVE_D_NAMLEN | |||
assert (entry->d_namlen == 1); | |||
#endif | |||
#ifdef _D_EXACT_NAMLEN | |||
assert (_D_EXACT_NAMLEN(entry) == 1); | |||
#endif | |||
#ifdef _D_ALLOC_NAMLEN | |||
assert (_D_ALLOC_NAMLEN(entry) > 1); | |||
#endif | |||
found += 1; | |||
} else if (wcscmp (entry->d_name, L"..") == 0) { | |||
/* Parent directory */ | |||
#ifdef _DIRENT_HAVE_D_TYPE | |||
assert (entry->d_type == DT_DIR); | |||
#endif | |||
#ifdef _DIRENT_HAVE_D_NAMLEN | |||
assert (entry->d_namlen == 2); | |||
#endif | |||
#ifdef _D_EXACT_NAMLEN | |||
assert (_D_EXACT_NAMLEN(entry) == 2); | |||
#endif | |||
#ifdef _D_ALLOC_NAMLEN | |||
assert (_D_ALLOC_NAMLEN(entry) > 2); | |||
#endif | |||
found += 2; | |||
} else if (wcscmp (entry->d_name, L"file") == 0) { | |||
/* Regular file */ | |||
#ifdef _DIRENT_HAVE_D_TYPE | |||
assert (entry->d_type == DT_REG); | |||
#endif | |||
#ifdef _DIRENT_HAVE_D_NAMLEN | |||
assert (entry->d_namlen == 4); | |||
#endif | |||
#ifdef _D_EXACT_NAMLEN | |||
assert (_D_EXACT_NAMLEN(entry) == 4); | |||
#endif | |||
#ifdef _D_ALLOC_NAMLEN | |||
assert (_D_ALLOC_NAMLEN(entry) > 4); | |||
#endif | |||
found += 4; | |||
} else if (wcscmp (entry->d_name, L"dir") == 0) { | |||
/* Just a directory */ | |||
#ifdef _DIRENT_HAVE_D_TYPE | |||
assert (entry->d_type == DT_DIR); | |||
#endif | |||
#ifdef _DIRENT_HAVE_D_NAMLEN | |||
assert (entry->d_namlen == 3); | |||
#endif | |||
#ifdef _D_EXACT_NAMLEN | |||
assert (_D_EXACT_NAMLEN(entry) == 3); | |||
#endif | |||
#ifdef _D_ALLOC_NAMLEN | |||
assert (_D_ALLOC_NAMLEN(entry) > 3); | |||
#endif | |||
found += 8; | |||
} else { | |||
/* Other file */ | |||
fprintf (stderr, "Unexpected file\n"); | |||
abort (); | |||
} | |||
} | |||
/* Make sure that all files were found */ | |||
assert (found == 0xf); | |||
_wclosedir (dir); | |||
} | |||
#endif | |||
printf ("OK\n"); | |||
return EXIT_SUCCESS; | |||
} |
@ -1,264 +0,0 @@ | |||
/* | |||
* Make sure that scandir function works OK. | |||
* | |||
* 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 | |||
*/ | |||
/* Silence warning about fopen being insecure */ | |||
#define _CRT_SECURE_NO_WARNINGS | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <sys/stat.h> | |||
#include <dirent.h> | |||
#include <errno.h> | |||
#include <time.h> | |||
#include <limits.h> | |||
#undef NDEBUG | |||
#include <assert.h> | |||
/* Filter and sort functions */ | |||
static int only_readme (const struct dirent *entry); | |||
static int no_directories (const struct dirent *entry); | |||
static int reverse_alpha (const struct dirent **a, const struct dirent **b); | |||
int | |||
main( | |||
int argc, char *argv[]) | |||
{ | |||
struct dirent **files; | |||
int i; | |||
int n; | |||
(void) argc; | |||
(void) argv; | |||
/* Initialize random number generator */ | |||
srand ((unsigned) time (NULL)); | |||
/* Basic scan with simple filter function */ | |||
{ | |||
/* Read directory entries */ | |||
n = scandir ("tests/3", &files, only_readme, alphasort); | |||
assert (n == 1); | |||
/* Make sure that the filter works */ | |||
assert (strcmp (files[0]->d_name, "README.txt") == 0); | |||
/* Release file names */ | |||
for (i = 0; i < n; i++) { | |||
free (files[i]); | |||
} | |||
free (files); | |||
} | |||
/* Basic scan with default sorting function */ | |||
{ | |||
/* Read directory entries in alphabetic order */ | |||
n = scandir ("tests/3", &files, NULL, alphasort); | |||
assert (n == 13); | |||
/* Make sure that we got all the file names in the proper order */ | |||
assert (strcmp (files[0]->d_name, ".") == 0); | |||
assert (strcmp (files[1]->d_name, "..") == 0); | |||
assert (strcmp (files[2]->d_name, "3zero.dat") == 0); | |||
assert (strcmp (files[3]->d_name, "666.dat") == 0); | |||
assert (strcmp (files[4]->d_name, "Qwerty-my-aunt.dat") == 0); | |||
assert (strcmp (files[5]->d_name, "README.txt") == 0); | |||
assert (strcmp (files[6]->d_name, "aaa.dat") == 0); | |||
assert (strcmp (files[7]->d_name, "dirent.dat") == 0); | |||
assert (strcmp (files[8]->d_name, "empty.dat") == 0); | |||
assert (strcmp (files[9]->d_name, "sane-1.12.0.dat") == 0); | |||
assert (strcmp (files[10]->d_name, "sane-1.2.3.dat") == 0); | |||
assert (strcmp (files[11]->d_name, "sane-1.2.4.dat") == 0); | |||
assert (strcmp (files[12]->d_name, "zebra.dat") == 0); | |||
/* Release file names */ | |||
for (i = 0; i < n; i++) { | |||
free (files[i]); | |||
} | |||
free (files); | |||
} | |||
/* Custom filter AND sort function */ | |||
{ | |||
/* Read directory entries in alphabetic order */ | |||
n = scandir ("tests/3", &files, no_directories, reverse_alpha); | |||
assert (n == 11); | |||
/* Make sure that we got all the FILE names in the REVERSE order */ | |||
assert (strcmp (files[0]->d_name, "zebra.dat") == 0); | |||
assert (strcmp (files[1]->d_name, "sane-1.2.4.dat") == 0); | |||
assert (strcmp (files[2]->d_name, "sane-1.2.3.dat") == 0); | |||
assert (strcmp (files[3]->d_name, "sane-1.12.0.dat") == 0); | |||
assert (strcmp (files[4]->d_name, "empty.dat") == 0); | |||
assert (strcmp (files[5]->d_name, "dirent.dat") == 0); | |||
assert (strcmp (files[6]->d_name, "aaa.dat") == 0); | |||
assert (strcmp (files[7]->d_name, "README.txt") == 0); | |||
assert (strcmp (files[8]->d_name, "Qwerty-my-aunt.dat") == 0); | |||
assert (strcmp (files[9]->d_name, "666.dat") == 0); | |||
assert (strcmp (files[10]->d_name, "3zero.dat") == 0); | |||
/* Release file names */ | |||
for (i = 0; i < n; i++) { | |||
free (files[i]); | |||
} | |||
free (files); | |||
} | |||
/* Trying to read from non-existent directory leads to an error */ | |||
{ | |||
files = NULL; | |||
n = scandir ("tests/invalid", &files, NULL, alphasort); | |||
assert (n == -1); | |||
assert (files == NULL); | |||
assert (errno == ENOENT); | |||
} | |||
/* Trying to open file as a directory produces ENOTDIR error */ | |||
{ | |||
files = NULL; | |||
n = scandir ("tests/3/666.dat", &files, NULL, alphasort); | |||
assert (n == -1); | |||
assert (files == NULL); | |||
assert (errno == ENOTDIR); | |||
} | |||
/* Scan large directory */ | |||
{ | |||
char dirname[PATH_MAX+1]; | |||
int i, j; | |||
int ok; | |||
/* Copy name of temporary directory to variable dirname */ | |||
#ifdef WIN32 | |||
i = GetTempPathA (PATH_MAX, dirname); | |||
assert (i > 0); | |||
#else | |||
strcpy (dirname, "/tmp/"); | |||
i = strlen (dirname); | |||
#endif | |||
/* Append random characters to dirname */ | |||
for (j = 0; j < 10; j++) { | |||
char c; | |||
/* Generate random character */ | |||
c = "abcdefghijklmnopqrstuvwxyz"[rand() % 26]; | |||
/* Append character to dirname */ | |||
assert (i < PATH_MAX); | |||
dirname[i++] = c; | |||
} | |||
/* Terminate directory name */ | |||
assert (i < PATH_MAX); | |||
dirname[i] = '\0'; | |||
/* Create directory */ | |||
#ifdef WIN32 | |||
ok = CreateDirectoryA (dirname, NULL); | |||
assert (ok); | |||
#else | |||
ok = mkdir (dirname, 0700); | |||
assert (ok == /*success*/0); | |||
#endif | |||
/* Create one thousand files */ | |||
assert (i + 5 < PATH_MAX); | |||
for (j = 0; j < 1000; j++) { | |||
FILE *fp; | |||
/* Construct file name */ | |||
dirname[i] = '/'; | |||
dirname[i+1] = 'z'; | |||
dirname[i+2] = '0' + ((j / 100) % 10); | |||
dirname[i+3] = '0' + ((j / 10) % 10); | |||
dirname[i+4] = '0' + (j % 10); | |||
dirname[i+5] = '\0'; | |||
/* Create file */ | |||
fp = fopen (dirname, "w"); | |||
assert (fp != NULL); | |||
fclose (fp); | |||
} | |||
/* Cut out the file name part */ | |||
dirname[i] = '\0'; | |||
/* Scan directory */ | |||
n = scandir (dirname, &files, no_directories, alphasort); | |||
assert (n == 1000); | |||
/* Make sure that all 1000 files are read back */ | |||
for (j = 0; j < n; j++) { | |||
char match[100]; | |||
/* Construct file name */ | |||
match[0] = 'z'; | |||
match[1] = '0' + ((j / 100) % 10); | |||
match[2] = '0' + ((j / 10) % 10); | |||
match[3] = '0' + (j % 10); | |||
match[4] = '\0'; | |||
/* Make sure that file name matches that on the disk */ | |||
assert (strcmp (files[j]->d_name, match) == 0); | |||
} | |||
/* Release file names */ | |||
for (j = 0; j < n; j++) { | |||
free (files[j]); | |||
} | |||
free (files); | |||
} | |||
printf ("OK\n"); | |||
return EXIT_SUCCESS; | |||
} | |||
/* Only pass README.txt file */ | |||
static int | |||
only_readme (const struct dirent *entry) | |||
{ | |||
int pass; | |||
if (strcmp (entry->d_name, "README.txt") == 0) { | |||
pass = 1; | |||
} else { | |||
pass = 0; | |||
} | |||
return pass; | |||
} | |||
/* Filter out directories */ | |||
static int | |||
no_directories (const struct dirent *entry) | |||
{ | |||
int pass; | |||
if (entry->d_type != DT_DIR) { | |||
pass = 1; | |||
} else { | |||
pass = 0; | |||
} | |||
return pass; | |||
} | |||
/* Sort in reverse direction */ | |||
static int | |||
reverse_alpha( | |||
const struct dirent **a, const struct dirent **b) | |||
{ | |||
return strcoll ((*b)->d_name, (*a)->d_name); | |||
} |
@ -1,401 +0,0 @@ | |||
/* | |||
* Test program to try unicode file names. | |||
* | |||
* 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 | |||
*/ | |||
/* Silence warning about fopen being insecure */ | |||
#define _CRT_SECURE_NO_WARNINGS | |||
#include <dirent.h> | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <wchar.h> | |||
#include <time.h> | |||
#include <locale.h> | |||
#undef NDEBUG | |||
#include <assert.h> | |||
int | |||
main( | |||
int argc, char *argv[]) | |||
{ | |||
#ifdef WIN32 | |||
wchar_t wpath[MAX_PATH+1]; | |||
char path[MAX_PATH+1]; | |||
DWORD i, j, k, x; | |||
BOOL ok; | |||
HANDLE fh; | |||
_WDIR *wdir; | |||
struct _wdirent *wentry; | |||
DIR *dir; | |||
struct dirent *entry; | |||
char buffer[100]; | |||
FILE *fp; | |||
int counter = 0; | |||
(void) argc; | |||
(void) argv; | |||
/* Initialize random number generator */ | |||
srand (((int) time (NULL)) * 257 + ((int) GetCurrentProcessId ())); | |||
/* Set current locale */ | |||
if (argc > 1) { | |||
printf ("Locale %s\n", argv[1]); | |||
setlocale (LC_ALL, argv[1]); | |||
} else { | |||
setlocale (LC_ALL, ""); | |||
} | |||
/****** CREATE FILE WITH UNICODE FILE NAME ******/ | |||
/* Get path to temporary directory (wide-character and ascii) */ | |||
i = GetTempPathW (MAX_PATH, wpath); | |||
assert (i > 0); | |||
j = GetTempPathA (MAX_PATH, path); | |||
assert (j > 0); | |||
/* Append random directory name */ | |||
for (k = 0; k < 10; k++) { | |||
char c; | |||
/* Generate random character */ | |||
c = "abcdefghijklmnopqrstuvwxyz"[rand() % 26]; | |||
/* Append character to paths */ | |||
assert (i < MAX_PATH && j < MAX_PATH); | |||
wpath[i++] = c; | |||
path[j++] = c; | |||
} | |||
/* Terminate paths */ | |||
assert (i < MAX_PATH && j < MAX_PATH); | |||
wpath[i] = '\0'; | |||
path[j] = '\0'; | |||
/* Remember the end of directory name */ | |||
k = i; | |||
/* Create directory using unicode */ | |||
ok = CreateDirectoryW (wpath, NULL); | |||
if (!ok) { | |||
DWORD e = GetLastError (); | |||
wprintf (L"Cannot create directory %ls (code %u)\n", wpath, e); | |||
abort (); | |||
} | |||
/* Overwrite zero terminator with path separator */ | |||
assert (i < MAX_PATH && j < MAX_PATH); | |||
wpath[i++] = '\\'; | |||
/* Append a few unicode characters */ | |||
assert (i < MAX_PATH); | |||
wpath[i++] = 0x6d4b; | |||
assert (i < MAX_PATH); | |||
wpath[i++] = 0x8bd5; | |||
/* Terminate string */ | |||
assert (i < MAX_PATH); | |||
wpath[i] = '\0'; | |||
/* Create file with unicode */ | |||
fh = CreateFileW( | |||
wpath, | |||
/* Access */ GENERIC_READ | GENERIC_WRITE, | |||
/* Share mode */ 0, | |||
/* Security attributes */ NULL, | |||
/* Creation disposition */ CREATE_NEW, | |||
/* Attributes */ FILE_ATTRIBUTE_NORMAL, | |||
/* Template files */ NULL | |||
); | |||
assert (fh != INVALID_HANDLE_VALUE); | |||
/* Write some data to file */ | |||
ok = WriteFile( | |||
/* File handle */ fh, | |||
/* Pointer to data */ "hep\n", | |||
/* Number of bytes to write */ 4, | |||
/* Number of bytes written */ NULL, | |||
/* Overlapped */ NULL | |||
); | |||
assert (ok); | |||
/* Close file */ | |||
ok = CloseHandle (fh); | |||
assert (ok); | |||
/****** MAKE SURE THAT UNICODE FILE NAME CAN BE READ BY _WREADDIR ******/ | |||
/* Zero terminate wide-character path and open directory stream */ | |||
wpath[k] = '\0'; | |||
wdir = _wopendir (wpath); | |||
if (wdir == NULL) { | |||
wprintf (L"Cannot open directory %ls\n", wpath); | |||
abort (); | |||
} | |||
/* Read through entries */ | |||
counter = 0; | |||
while ((wentry = _wreaddir (wdir)) != NULL) { | |||
/* Skip pseudo directories */ | |||
if (wcscmp (wentry->d_name, L".") == 0) { | |||
continue; | |||
} | |||
if (wcscmp (wentry->d_name, L"..") == 0) { | |||
continue; | |||
} | |||
/* Found a file */ | |||
counter++; | |||
assert (wentry->d_type == DT_REG); | |||
/* Append file name to path */ | |||
i = k; | |||
assert (i < MAX_PATH); | |||
wpath[i++] = '\\'; | |||
x = 0; | |||
while (wentry->d_name[x] != '\0') { | |||
assert (i < MAX_PATH); | |||
wpath[i++] = wentry->d_name[x++]; | |||
} | |||
assert (i < MAX_PATH); | |||
wpath[i] = '\0'; | |||
/* Open file for read */ | |||
fh = CreateFileW( | |||
wpath, | |||
/* Access */ GENERIC_READ, | |||
/* Share mode */ 0, | |||
/* Security attributes */ NULL, | |||
/* Creation disposition */ OPEN_EXISTING, | |||
/* Attributes */ FILE_ATTRIBUTE_NORMAL, | |||
/* Template files */ NULL | |||
); | |||
assert (fh != INVALID_HANDLE_VALUE); | |||
/* Read data from file */ | |||
ok = ReadFile( | |||
/* File handle */ fh, | |||
/* Output buffer */ buffer, | |||
/* Maximum number of bytes to read */ sizeof (buffer) - 1, | |||
/* Number of bytes actually read */ &x, | |||
/* Overlapped */ NULL | |||
); | |||
assert (ok); | |||
/* Make sure that we got the file contents right */ | |||
assert (x == 4); | |||
assert (buffer[0] == 'h'); | |||
assert (buffer[1] == 'e'); | |||
assert (buffer[2] == 'p'); | |||
assert (buffer[3] == '\n'); | |||
/* Close file */ | |||
ok = CloseHandle (fh); | |||
assert (ok); | |||
} | |||
assert (counter == 1); | |||
/* Close directory */ | |||
_wclosedir (wdir); | |||
/****** MAKE SURE THAT UNICODE FILE NAME CAN BE READ BY READDIR ******/ | |||
/* Zero terminate ascii path and open directory stream */ | |||
k = j; | |||
path[k] = '\0'; | |||
dir = opendir (path); | |||
if (dir == NULL) { | |||
fprintf (stderr, "Cannot open directory %s\n", path); | |||
abort (); | |||
} | |||
/* Read through entries */ | |||
counter = 0; | |||
while ((entry = readdir (dir)) != NULL) { | |||
/* Skip pseudo directories */ | |||
if (strcmp (entry->d_name, ".") == 0) { | |||
continue; | |||
} | |||
if (strcmp (entry->d_name, "..") == 0) { | |||
continue; | |||
} | |||
/* Found a file */ | |||
counter++; | |||
assert (entry->d_type == DT_REG); | |||
/* Append file name to path */ | |||
j = k; | |||
assert (j < MAX_PATH); | |||
path[j++] = '\\'; | |||
x = 0; | |||
while (entry->d_name[x] != '\0') { | |||
assert (j < MAX_PATH); | |||
path[j++] = entry->d_name[x++]; | |||
} | |||
assert (j < MAX_PATH); | |||
path[j] = '\0'; | |||
/* Open file for read */ | |||
fp = fopen (path, "r"); | |||
if (!fp) { | |||
fprintf (stderr, "Cannot open file %s\n", path); | |||
abort (); | |||
} | |||
/* Read data from file */ | |||
if (fgets (buffer, sizeof (buffer), fp) == NULL) { | |||
fprintf (stderr, "Cannot read file %s\n", path); | |||
abort (); | |||
} | |||
/* Make sure that we got the file contents right */ | |||
assert (buffer[0] == 'h'); | |||
assert (buffer[1] == 'e'); | |||
assert (buffer[2] == 'p'); | |||
assert (buffer[3] == '\n'); | |||
assert (buffer[4] == '\0'); | |||
/* Close file */ | |||
fclose (fp); | |||
} | |||
assert (counter == 1); | |||
/* Close directory */ | |||
closedir (dir); | |||
/****** CREATE FILE WITH UTF-8 ******/ | |||
/* Append UTF-8 file name (åäö.txt) to path */ | |||
j = k; | |||
path[j++] = '\\'; | |||
path[j++] = 0xc3; | |||
path[j++] = 0xa5; | |||
path[j++] = 0xc3; | |||
path[j++] = 0xa4; | |||
path[j++] = 0xc3; | |||
path[j++] = 0xb6; | |||
path[j++] = 0x2e; | |||
path[j++] = 0x74; | |||
path[j++] = 0x78; | |||
path[j++] = 0x74; | |||
assert (j < MAX_PATH); | |||
path[j] = '\0'; | |||
/* | |||
* Create file. | |||
* | |||
* Be ware that the code below creates a different file depending on the | |||
* current locale! For example, if the current locale is | |||
* english_us.65001, then the file name will be "åäö.txt" (7 characters). | |||
* However, if the current locale is english_us.1252, then the file name | |||
* will be "ÃċÃĊö.txt" (10 characters). | |||
*/ | |||
printf ("Creating %s\n", path); | |||
fp = fopen (path, "w"); | |||
if (!fp) { | |||
fprintf (stderr, "Cannot open file %s\n", path); | |||
abort (); | |||
} | |||
fputs ("hep\n", fp); | |||
fclose (fp); | |||
/* Open directory again */ | |||
path[k] = '\0'; | |||
dir = opendir (path); | |||
if (dir == NULL) { | |||
fprintf (stderr, "Cannot open directory %s\n", path); | |||
abort (); | |||
} | |||
/* Read through entries */ | |||
counter = 0; | |||
while ((entry = readdir (dir)) != NULL) { | |||
/* Skip pseudo directories */ | |||
if (strcmp (entry->d_name, ".") == 0) { | |||
continue; | |||
} | |||
if (strcmp (entry->d_name, "..") == 0) { | |||
continue; | |||
} | |||
/* Found a file */ | |||
counter++; | |||
assert (entry->d_type == DT_REG); | |||
/* Append file name to path */ | |||
j = k; | |||
assert (j < MAX_PATH); | |||
path[j++] = '\\'; | |||
x = 0; | |||
while (entry->d_name[x] != '\0') { | |||
assert (j < MAX_PATH); | |||
path[j++] = entry->d_name[x++]; | |||
} | |||
assert (j < MAX_PATH); | |||
path[j] = '\0'; | |||
/* Print file name for debugging */ | |||
printf ("Opening \"%s\" hex ", path + k + 1); | |||
x = 0; | |||
while (entry->d_name[x] != '\0') { | |||
printf ("0x%02x ", (unsigned) (entry->d_name[x++] & 0xff)); | |||
} | |||
printf ("\n"); | |||
/* Open file for read */ | |||
fp = fopen (path, "r"); | |||
if (!fp) { | |||
fprintf (stderr, "Cannot open file %s\n", path); | |||
abort (); | |||
} | |||
/* Read data from file */ | |||
if (fgets (buffer, sizeof (buffer), fp) == NULL) { | |||
fprintf (stderr, "Cannot read file %s\n", path); | |||
abort (); | |||
} | |||
/* Make sure that we got the file contents right */ | |||
assert (buffer[0] == 'h'); | |||
assert (buffer[1] == 'e'); | |||
assert (buffer[2] == 'p'); | |||
assert (buffer[3] == '\n'); | |||
assert (buffer[4] == '\0'); | |||
/* Close file */ | |||
fclose (fp); | |||
} | |||
assert (counter == 2); | |||
/* Close directory */ | |||
closedir (dir); | |||
#else | |||
/* Linux */ | |||
(void) argc; | |||
(void) argv; | |||
#endif | |||
return EXIT_SUCCESS; | |||
} |