From 0f92f7352d1964a9859868439e8ded2c4de2111e Mon Sep 17 00:00:00 2001 From: Rory Bradford Date: Sat, 19 Nov 2022 11:11:26 +0000 Subject: Full native win32 support This will now compile with MSVC using the make.bat batch file. It does however bring in some additional third party dependencies: ports of dirent and getopt (something I'd ideally like to work on in the future). Signed-off-by: Rory Bradford --- dirent/examples/cat.c | 127 ++++++++++++++++++++++ dirent/examples/dir.c | 234 ++++++++++++++++++++++++++++++++++++++++ dirent/examples/du.c | 199 ++++++++++++++++++++++++++++++++++ dirent/examples/find.c | 184 +++++++++++++++++++++++++++++++ dirent/examples/locate.c | 262 +++++++++++++++++++++++++++++++++++++++++++++ dirent/examples/ls.c | 148 +++++++++++++++++++++++++ dirent/examples/scandir.c | 152 ++++++++++++++++++++++++++ dirent/examples/updatedb.c | 206 +++++++++++++++++++++++++++++++++++ 8 files changed, 1512 insertions(+) create mode 100644 dirent/examples/cat.c create mode 100644 dirent/examples/dir.c create mode 100644 dirent/examples/du.c create mode 100644 dirent/examples/find.c create mode 100644 dirent/examples/locate.c create mode 100644 dirent/examples/ls.c create mode 100644 dirent/examples/scandir.c create mode 100644 dirent/examples/updatedb.c (limited to 'dirent/examples') diff --git a/dirent/examples/cat.c b/dirent/examples/cat.c new file mode 100644 index 0000000..5346922 --- /dev/null +++ b/dirent/examples/cat.c @@ -0,0 +1,127 @@ +/* + * 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 +#include +#include +#include +#include +#include + +static void output_file(const char *fn); +static int _main(int argc, char *argv[]); + +static int +_main(int argc, char *argv[]) +{ + /* 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 */ + int i = 1; + while (i < argc) { + output_file(argv[i]); + i++; + } + return EXIT_SUCCESS; +} + +/* + * Output file to screen + */ +static void +output_file(const char *fn) +{ + /* Open file */ + FILE *fp = fopen(fn, "r"); + if (!fp) { + /* Could not open directory */ + fprintf(stderr, "Cannot open %s (%s)\n", fn, strerror(errno)); + exit(EXIT_FAILURE); + } + + /* Output file to screen */ + size_t n; + do { + /* Read some bytes from file */ + char buffer[4096]; + n = fread(buffer, 1, 4096, fp); + + /* Output bytes to screen */ + fwrite(buffer, 1, n, stdout); + } while (n != 0); + + /* Close file */ + fclose(fp); +} + +/* Stub for converting arguments to UTF-8 on Windows */ +#ifdef _MSC_VER +int +wmain(int argc, wchar_t *argv[]) +{ + /* Select UTF-8 locale */ + setlocale(LC_ALL, ".utf8"); + SetConsoleCP(CP_UTF8); + SetConsoleOutputCP(CP_UTF8); + + /* Allocate memory for multi-byte argv table */ + char **mbargv; + mbargv = (char**) malloc(argc * sizeof(char*)); + if (!mbargv) { + puts("Out of memory"); + exit(3); + } + + /* Convert each argument in argv to UTF-8 */ + for (int i = 0; i < argc; i++) { + size_t n; + wcstombs_s(&n, NULL, 0, argv[i], 0); + + /* Allocate room for ith argument */ + mbargv[i] = (char*) malloc(n + 1); + if (!mbargv[i]) { + puts("Out of memory"); + exit(3); + } + + /* Convert ith argument to utf-8 */ + wcstombs_s(NULL, mbargv[i], n + 1, argv[i], n); + } + + /* Pass UTF-8 converted arguments to the main program */ + int errorcode = _main(argc, mbargv); + + /* Release UTF-8 arguments */ + for (int i = 0; i < argc; i++) { + free(mbargv[i]); + } + + /* Release the argument table */ + free(mbargv); + return errorcode; +} +#else +int +main(int argc, char *argv[]) +{ + return _main(argc, argv); +} +#endif + diff --git a/dirent/examples/dir.c b/dirent/examples/dir.c new file mode 100644 index 0000000..46e38de --- /dev/null +++ b/dirent/examples/dir.c @@ -0,0 +1,234 @@ +/* + * List files with date, type and size. + * + * Compile this file with Visual Studio and run the produced command in + * console with a directory name argument. For example, command + * + * dir "C:\Users\User 1\Documents" + * + * might output something like + * + * Directory of c:\Users\User 1\Documents + * + * 2021-06-06 20:04 . + * 2021-07-20 13:42 .. + * 2020-06-21 15:00 402 desktop.ini + * 2020-06-21 15:00 Omat kuvatiedostot + * 2020-06-21 15:00 Omat musiikkitiedostot + * 2020-06-21 15:00 Omat videotiedostot + * 2018-12-21 18:34 Visual Studio 2017 + * 3 File(s) 402 bytes + * 7 Dir(s) + * + * The dir command provided by this file is only an example: the command + * does not have any fancy options. + * + * Copyright (C) 2006-2012 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 +#include +#include +#include +#include +#include +#include +#include + +#define ERR_MSG_LEN 256 + +static void list_directory(const char* dirname); +static void fail(const char* dirname); +static int _main(int argc, char *argv[]); + +static int +_main(int argc, char* argv[]) +{ + /* For each directory in command line */ + int 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 file sizes in directory */ +static void +list_directory(const char* dirname) +{ + char path[PATH_MAX + 2]; + char *p = path; + char *end = &path[PATH_MAX]; + + /* Copy directory name to path */ + const char *src = dirname; + while (p < end && *src != '\0') { + *p++ = *src++; + } + + /* Get final character of directory name */ + char c = (path < p ? p[-1] : ':'); + + /* Append directory separator if not already there */ + if (c != ':' && c != '/' && c != '\\') + *p++ = '/'; + + /* Print directory name to screen */ + printf("Directory of %s\n\n", dirname); + + /* Open directory stream */ + DIR *dir = opendir(dirname); + if (!dir) { + /* Could not open directory */ + fprintf(stderr, + "Cannot open %s (%s)\n", dirname, strerror(errno)); + exit(EXIT_FAILURE); + } + + /* Loop through file names */ + int filecount = 0; + int dircount = 0; + long long bytecount = 0; + struct dirent *ent; + while ((ent = readdir(dir)) != NULL) { + /* Append file name to path */ + char *q = p; + src = ent->d_name; + while (q < end && *src != '\0') { + *q++ = *src++; + } + *q = '\0'; + + /* Get file properties such as size and modification time */ + struct stat stbuf; + if (stat(path, &stbuf) == /*error*/-1) { + fail(path); + } + + /* Get file type from stat buffer */ + const char *type; + if (S_ISDIR(stbuf.st_mode)) { + /* Directory */ + type = ""; + } else if (S_ISREG(stbuf.st_mode)) { + /* Regular file */ + type = ""; + } else if (S_ISLNK(stbuf.st_mode)) { + /* Link */ + type = ""; + } else { + /* Named pipe, socket, character device or else */ + type = ""; + } + + /* Get last modification date as a string */ + struct tm *tp = localtime(&stbuf.st_mtime); + char mtime[40]; + sprintf(mtime, "%04d-%02d-%02d %02d:%02d", + tp->tm_year + 1900, + tp->tm_mon + 1, + tp->tm_mday, + tp->tm_hour, + tp->tm_min); + + /* Get file size as a string */ + char size[40]; + if (S_ISREG(stbuf.st_mode)) { + sprintf(size, "%lld", (long long) stbuf.st_size); + } else { + size[0] = '\0'; + } + + /* Output file info */ + printf("%-20s %-5s %12s %s\n", + mtime, type, size, ent->d_name); + + /* Compute totals */ + if (S_ISREG(stbuf.st_mode)) { + filecount++; + bytecount += (long long) stbuf.st_size; + } + if (S_ISDIR(stbuf.st_mode)) { + dircount++; + } + } + + /* Output sums */ + printf("%20d File(s) %12lld bytes\n", filecount, bytecount); + printf("%20d Dir(s)\n", dircount); +} + +/* Print error message and exit with error condition */ +static void +fail(const char* msg) +{ + /* Output error message */ + perror(msg); + + /* Exit the program immediately */ + exit(EXIT_FAILURE); +} + +/* Stub for converting arguments to UTF-8 on Windows */ +#ifdef _MSC_VER +int +wmain(int argc, wchar_t *argv[]) +{ + /* Select UTF-8 locale */ + setlocale(LC_ALL, ".utf8"); + SetConsoleCP(CP_UTF8); + SetConsoleOutputCP(CP_UTF8); + + /* Allocate memory for multi-byte argv table */ + char **mbargv; + mbargv = (char**) malloc(argc * sizeof(char*)); + if (!mbargv) { + puts("Out of memory"); + exit(3); + } + + /* Convert each argument in argv to UTF-8 */ + for (int i = 0; i < argc; i++) { + size_t n; + wcstombs_s(&n, NULL, 0, argv[i], 0); + + /* Allocate room for ith argument */ + mbargv[i] = (char*) malloc(n + 1); + if (!mbargv[i]) { + puts("Out of memory"); + exit(3); + } + + /* Convert ith argument to utf-8 */ + wcstombs_s(NULL, mbargv[i], n + 1, argv[i], n); + } + + /* Pass UTF-8 converted arguments to the main program */ + int errorcode = _main(argc, mbargv); + + /* Release UTF-8 arguments */ + for (int i = 0; i < argc; i++) { + free(mbargv[i]); + } + + /* Release the argument table */ + free(mbargv); + return errorcode; +} +#else +int +main(int argc, char *argv[]) +{ + return _main(argc, argv); +} +#endif + diff --git a/dirent/examples/du.c b/dirent/examples/du.c new file mode 100644 index 0000000..a5832c4 --- /dev/null +++ b/dirent/examples/du.c @@ -0,0 +1,199 @@ +/* + * Compute disk usage of files and sub-directories in bytes. + * + * Compile this file with Visual Studio and run the produced command in + * console with a directory name argument. For example, command + * + * du "c:\Program Files" + * + * might produce listing such as + * + * 5204927 7-Zip + * 140046882 CCleaner + * 83140342 CMake + * 2685264 Internet Explorer + * 686314712 LibreOffice + * 214025459 Mozilla Firefox + * 174753900 VideoLAN + * + * If you compare this program to a genuine du command in Linux, then be ware + * directories themselves consume some space in Linux. This program, however, + * only counts the files and hence the size will always be smaller than that + * reported by Linux du. + * + * 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 +#include +#include +#include +#include +#include +#include + +static long long list_directory(const char *dirname, int level); +static int _main(int argc, char *argv[]); + +static int +_main(int argc, char *argv[]) +{ + /* For each directory in command line */ + int i = 1; + while (i < argc) { + list_directory(argv[i], 0); + i++; + } + + /* List current working directory if no arguments on command line */ + if (argc == 1) + list_directory(".", 0); + + return EXIT_SUCCESS; +} + +/* Find files and subdirectories recursively; list their sizes */ +static long long +list_directory(const char *dirname, int level) +{ + char buffer[PATH_MAX + 2]; + char *p = buffer; + char *end = &buffer[PATH_MAX]; + + /* Copy directory name to buffer */ + const char *src = dirname; + while (p < end && *src != '\0') { + *p++ = *src++; + } + *p = '\0'; + + /* Get final character of directory name */ + char c; + if (buffer < p) + c = p[-1]; + else + c = ':'; + + /* Append directory separator if not already there */ + if (c != ':' && c != '/' && c != '\\') + *p++ = '/'; + + /* Open directory stream */ + DIR *dir = opendir(dirname); + if (!dir) { + fprintf(stderr, + "Cannot open %s (%s)\n", dirname, strerror(errno)); + return 0LL; + } + + /* Compute total disk usage of all files and directories */ + struct stat stbuf; + struct dirent *ent; + long long total = 0; + while ((ent = readdir(dir)) != NULL) { + /* Skip pseudo directories . and .. */ + if (strcmp(ent->d_name, ".") == 0 + || strcmp(ent->d_name, "..") == 0) + continue; + + /* Skip links as they consume no space */ + if (ent->d_type == DT_LNK) + continue; + + /* Skip device entries */ + if (ent->d_type != DT_REG && ent->d_type != DT_DIR) + continue; + + /* Append file name to buffer */ + src = ent->d_name; + char *q = p; + while (q < end && *src != '\0') { + *q++ = *src++; + } + *q = '\0'; + + /* Add file size */ + long long size = 0; + if (ent->d_type == DT_REG) { + if (stat(buffer, &stbuf) == /*Error*/-1) { + fprintf(stderr, "Cannot access %s\n", buffer); + continue; + } + size += (long long) stbuf.st_size; + } + + /* Compute size of subdirectories recursively */ + if (ent->d_type == DT_DIR) + size += list_directory(buffer, level + 1); + + /* Update total size of directory */ + total += size; + + /* Output file/directory size in bytes */ + if (level == 0) + printf("%-10lld %s\n", size, ent->d_name); + } + + closedir(dir); + + /* Return total size of directory */ + return total; +} + +/* Stub for converting arguments to UTF-8 on Windows */ +#ifdef _MSC_VER +int +wmain(int argc, wchar_t *argv[]) +{ + /* Select UTF-8 locale */ + setlocale(LC_ALL, ".utf8"); + SetConsoleCP(CP_UTF8); + SetConsoleOutputCP(CP_UTF8); + + /* Allocate memory for multi-byte argv table */ + char **mbargv; + mbargv = (char**) malloc(argc * sizeof(char*)); + if (!mbargv) { + puts("Out of memory"); + exit(3); + } + + /* Convert each argument in argv to UTF-8 */ + for (int i = 0; i < argc; i++) { + size_t n; + wcstombs_s(&n, NULL, 0, argv[i], 0); + + /* Allocate room for ith argument */ + mbargv[i] = (char*) malloc(n + 1); + if (!mbargv[i]) { + puts("Out of memory"); + exit(3); + } + + /* Convert ith argument to utf-8 */ + wcstombs_s(NULL, mbargv[i], n + 1, argv[i], n); + } + + /* Pass UTF-8 converted arguments to the main program */ + int errorcode = _main(argc, mbargv); + + /* Release UTF-8 arguments */ + for (int i = 0; i < argc; i++) { + free(mbargv[i]); + } + + /* Release the argument table */ + free(mbargv); + return errorcode; +} +#else +int +main(int argc, char *argv[]) +{ + return _main(argc, argv); +} +#endif + diff --git a/dirent/examples/find.c b/dirent/examples/find.c new file mode 100644 index 0000000..3e53d49 --- /dev/null +++ b/dirent/examples/find.c @@ -0,0 +1,184 @@ +/* + * List files and directories recursively. + * + * 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 +#include +#include +#include +#include +#include + +static int find_directory(const char *dirname); +static int _main(int argc, char *argv[]); + +int +_main(int argc, char *argv[]) +{ + /* For each directory in command line */ + int i = 1; + while (i < argc) { + if (!find_directory(argv[i])) + 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) +{ + char buffer[PATH_MAX + 2]; + char *p = buffer; + char *end = &buffer[PATH_MAX]; + + /* Copy directory name to buffer */ + const char *src = dirname; + while (p < end && *src != '\0') { + *p++ = *src++; + } + *p = '\0'; + + /* Open directory stream */ + DIR *dir = opendir(dirname); + if (!dir) { + /* Could not open directory */ + fprintf(stderr, + "Cannot open %s (%s)\n", dirname, strerror(errno)); + return /*failure*/ 0; + } + + /* Print all files and directories within the directory */ + struct dirent *ent; + 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); + return /*success*/ 1; +} + +/* Stub for converting arguments to UTF-8 on Windows */ +#ifdef _MSC_VER +int +wmain(int argc, wchar_t *argv[]) +{ + /* Select UTF-8 locale */ + setlocale(LC_ALL, ".utf8"); + SetConsoleCP(CP_UTF8); + SetConsoleOutputCP(CP_UTF8); + + /* Allocate memory for multi-byte argv table */ + char **mbargv; + mbargv = (char**) malloc(argc * sizeof(char*)); + if (!mbargv) { + puts("Out of memory"); + exit(3); + } + + /* Convert each argument in argv to UTF-8 */ + for (int i = 0; i < argc; i++) { + size_t n; + wcstombs_s(&n, NULL, 0, argv[i], 0); + + /* Allocate room for ith argument */ + mbargv[i] = (char*) malloc(n + 1); + if (!mbargv[i]) { + puts("Out of memory"); + exit(3); + } + + /* Convert ith argument to utf-8 */ + wcstombs_s(NULL, mbargv[i], n + 1, argv[i], n); + } + + /* Pass UTF-8 converted arguments to the main program */ + int errorcode = _main(argc, mbargv); + + /* Release UTF-8 arguments */ + for (int i = 0; i < argc; i++) { + free(mbargv[i]); + } + + /* Release the argument table */ + free(mbargv); + return errorcode; +} +#else +int +main(int argc, char *argv[]) +{ + return _main(argc, argv); +} +#endif + diff --git a/dirent/examples/locate.c b/dirent/examples/locate.c new file mode 100644 index 0000000..60bea4d --- /dev/null +++ b/dirent/examples/locate.c @@ -0,0 +1,262 @@ +/* + * Find file name from locatedb database. + * + * 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; + +#ifdef _MSC_VER +int +wmain(int argc, wchar_t *argv[]) +{ + /* Prepare for unicode output */ + _setmode(_fileno(stdout), _O_U16TEXT); + + /* For each pattern in command line */ + int i = 1; + while (i < argc) { + int count = 0; + + /* Find files matching pattern */ + count = db_locate(argv[i]); + + /* Output warning if string is not found */ + if (count == 0) { + wprintf(L"%s not found\n", argv[i]); + } + + i++; + } + + if (argc < 2) { + wprintf(L"Usage: locate pattern\n"); + exit(EXIT_FAILURE); + } + return EXIT_SUCCESS; +} +#else +int +main(int argc, char *argv[]) +{ + printf("locate only works on Microsoft Windows\n"); + return EXIT_SUCCESS; +} +#endif + +/* 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 + /* Locate zero-terminator from fn */ + wchar_t *p = wcschr(fn, '\0'); + + /* Find base name from buffer */ + int done = 0; + 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 */ + int i = 0; + wchar_t base[PATH_MAX + 1]; + while (i < PATH_MAX && p[i] != '\0') { + base[i] = towlower(p[i]); + i++; + } + base[i] = '\0'; + + /* Convert search pattern to lower case */ + i = 0; + wchar_t patt[PATH_MAX + 1]; + 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; + + if (!db) { + wprintf(L"Database not open\n"); + exit(EXIT_SUCCESS); + } + + do { + /* Read wide-character from stream */ + c = fgetwc(db); + + /* 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 */ + done = 1; + ok = 1; + break; + + case /*EOF*/WEOF: + /* End of file */ + done = 1; + if (i == 0) { + /* No data in buffer => return false */ + ok = 0; + } else { + /* Data in buffer => return file name */ + 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) + return; + + /* Open file for writing */ + errno_t 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) + return; + + fclose(db); + db = NULL; +} diff --git a/dirent/examples/ls.c b/dirent/examples/ls.c new file mode 100644 index 0000000..3fb627e --- /dev/null +++ b/dirent/examples/ls.c @@ -0,0 +1,148 @@ +/* + * List contents of a directory. + * + * 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 +#include +#include +#include +#include +#include + +static void list_directory(const char *dirname); +static int _main(int argc, char *argv[]); + +static int +_main(int argc, char *argv[]) +{ + /* For each directory in command line */ + int 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) +{ + /* Open directory stream */ + DIR *dir = opendir(dirname); + if (!dir) { + /* Could not open directory */ + fprintf(stderr, + "Cannot open %s (%s)\n", dirname, strerror(errno)); + exit(EXIT_FAILURE); + } + + /* Print all files and directories within the directory */ + struct dirent *ent; + 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); +} + +/* Stub for converting arguments to UTF-8 on Windows */ +#ifdef _MSC_VER +int +wmain(int argc, wchar_t *argv[]) +{ + /* Select UTF-8 locale */ + setlocale(LC_ALL, ".utf8"); + SetConsoleCP(CP_UTF8); + SetConsoleOutputCP(CP_UTF8); + + /* Allocate memory for multi-byte argv table */ + char **mbargv; + mbargv = (char**) malloc(argc * sizeof(char*)); + if (!mbargv) { + puts("Out of memory"); + exit(3); + } + + /* Convert each argument in argv to UTF-8 */ + for (int i = 0; i < argc; i++) { + size_t n; + wcstombs_s(&n, NULL, 0, argv[i], 0); + + /* Allocate room for ith argument */ + mbargv[i] = (char*) malloc(n + 1); + if (!mbargv[i]) { + puts("Out of memory"); + exit(3); + } + + /* Convert ith argument to utf-8 */ + wcstombs_s(NULL, mbargv[i], n + 1, argv[i], n); + } + + /* Pass UTF-8 converted arguments to the main program */ + int errorcode = _main(argc, mbargv); + + /* Release UTF-8 arguments */ + for (int i = 0; i < argc; i++) { + free(mbargv[i]); + } + + /* Release the argument table */ + free(mbargv); + return errorcode; +} +#else +int +main(int argc, char *argv[]) +{ + return _main(argc, argv); +} +#endif + diff --git a/dirent/examples/scandir.c b/dirent/examples/scandir.c new file mode 100644 index 0000000..65dc11f --- /dev/null +++ b/dirent/examples/scandir.c @@ -0,0 +1,152 @@ +/* + * List contents of a directory in an alphabetical order. + * + * 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 +#include +#include +#include +#include +#include + +static void list_directory(const char *dirname); +static int _main(int argc, char *argv[]); + +static int +_main(int argc, char *argv[]) +{ + /* For each directory in command line */ + int 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) +{ + /* Scan files in directory */ + struct dirent **files; + int n = scandir(dirname, &files, NULL, alphasort); + if (n < 0) { + fprintf(stderr, + "Cannot open %s (%s)\n", dirname, strerror(errno)); + exit(EXIT_FAILURE); + } + + /* Loop through file names */ + for (int i = 0; i < n; i++) { + /* Get pointer to file entry */ + struct dirent *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 (int i = 0; i < n; i++) { + free(files[i]); + } + free(files); +} + +/* Stub for converting arguments to UTF-8 on Windows */ +#ifdef _MSC_VER +int +wmain(int argc, wchar_t *argv[]) +{ + /* Select UTF-8 locale */ + setlocale(LC_ALL, ".utf8"); + SetConsoleCP(CP_UTF8); + SetConsoleOutputCP(CP_UTF8); + + /* Allocate memory for multi-byte argv table */ + char **mbargv; + mbargv = (char**) malloc(argc * sizeof(char*)); + if (!mbargv) { + puts("Out of memory"); + exit(3); + } + + /* Convert each argument in argv to UTF-8 */ + for (int i = 0; i < argc; i++) { + size_t n; + wcstombs_s(&n, NULL, 0, argv[i], 0); + + /* Allocate room for ith argument */ + mbargv[i] = (char*) malloc(n + 1); + if (!mbargv[i]) { + puts("Out of memory"); + exit(3); + } + + /* Convert ith argument to utf-8 */ + wcstombs_s(NULL, mbargv[i], n + 1, argv[i], n); + } + + /* Pass UTF-8 converted arguments to the main program */ + int errorcode = _main(argc, mbargv); + + /* Release UTF-8 arguments */ + for (int i = 0; i < argc; i++) { + free(mbargv[i]); + } + + /* Release the argument table */ + free(mbargv); + return errorcode; +} +#else +int +main(int argc, char *argv[]) +{ + return _main(argc, argv); +} +#endif + diff --git a/dirent/examples/updatedb.c b/dirent/examples/updatedb.c new file mode 100644 index 0000000..c7ec652 --- /dev/null +++ b/dirent/examples/updatedb.c @@ -0,0 +1,206 @@ +/* + * Build database of file and directory names. + * + * 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 +#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 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; + +#ifdef _MSC_VER +int +wmain(int argc, wchar_t *argv[]) +{ + /* Prepare for unicode output */ + _setmode(_fileno(stdout), _O_U16TEXT); + + /* Open locate.db */ + db_open(); + + /* For each directory in command line */ + int i = 1; + while (i < argc) { + /* Scan directory for files */ + int ok = update_directory(argv[i]); + if (!ok) { + wprintf(L"Cannot open directory %s\n", argv[i]); + exit(EXIT_FAILURE); + } + + i++; + } + + /* Use current working directory if no arguments on command line */ + if (argc == 1) + update_directory(L"."); + + db_close(); + return EXIT_SUCCESS; +} +#else +int +main(int argc, char *argv[]) +{ + printf("updatedb only works on Microsoft Windows\n"); + return EXIT_SUCCESS; +} +#endif + +/* Find files recursively */ +static int +update_directory(const wchar_t *dirname) +{ +#ifdef WIN32 + wchar_t buffer[PATH_MAX + 2]; + wchar_t *p = buffer; + wchar_t *end = &buffer[PATH_MAX]; + + /* Copy directory name to buffer */ + const wchar_t *src = dirname; + while (p < end && *src != '\0') { + *p++ = *src++; + } + *p = '\0'; + + /* Open directory stream */ + _WDIR *dir = _wopendir(dirname); + if (!dir) { + /* Cannot open directory */ + return /*failure*/ 0; + } + + /* Print all files and directories within the directory */ + struct _wdirent *ent; + 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); + return /*success*/ 1; +#else + return /*failure*/ 0; +#endif +} + +/* Store file name to locate.db */ +static void +db_store(const wchar_t *dirname) +{ +#ifdef WIN32 + if (!db) { + wprintf(L"Database not open\n"); + exit(EXIT_FAILURE); + } + + /* Output line to file */ + fwprintf(db, L"%s\n", dirname); +#endif +} + +/* Open database file locate.db */ +static void +db_open(void) +{ +#ifdef WIN32 + if (db) + return; + + /* Open file for writing */ + errno_t 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) + return; + + /* Close file */ + fclose(db); + db = NULL; +} -- cgit 1.4.1-2-gfad0