about summary refs log tree commit diff stats
path: root/dirent/examples/dir.c
diff options
context:
space:
mode:
authorRory Bradford <roryrjb@gmail.com>2022-11-19 11:11:26 +0000
committerRory Bradford <roryrjb@gmail.com>2022-11-19 11:18:40 +0000
commit0f92f7352d1964a9859868439e8ded2c4de2111e (patch)
tree14c690402fa28c3b465ec00d2fe767054a1a3331 /dirent/examples/dir.c
parentfbb7c479de91b197c6c501c2023bf564a6a7610f (diff)
downloadrf-0f92f7352d1964a9859868439e8ded2c4de2111e.tar.gz
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 <roryrjb@gmail.com>
Diffstat (limited to 'dirent/examples/dir.c')
-rw-r--r--dirent/examples/dir.c234
1 files changed, 234 insertions, 0 deletions
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       <DIR>               .
+ *     2021-07-20  13:42       <DIR>               ..
+ *     2020-06-21  15:00                       402 desktop.ini
+ *     2020-06-21  15:00       <DIR>               Omat kuvatiedostot
+ *     2020-06-21  15:00       <DIR>               Omat musiikkitiedostot
+ *     2020-06-21  15:00       <DIR>               Omat videotiedostot
+ *     2018-12-21  18:34       <DIR>               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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dirent.h>
+#include <errno.h>
+#include <locale.h>
+#include <time.h>
+#include <sys/stat.h>
+
+#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 = "<DIR>";
+		} else if (S_ISREG(stbuf.st_mode)) {
+			/* Regular file */
+			type = "";
+		} else if (S_ISLNK(stbuf.st_mode)) {
+			/* Link */
+			type = "<LNK>";
+		} else {
+			/* Named pipe, socket, character device or else */
+			type = "<UNK>";
+		}
+
+		/* 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
+