summary refs log tree commit diff stats
path: root/neols.c
diff options
context:
space:
mode:
Diffstat (limited to 'neols.c')
-rw-r--r--neols.c148
1 files changed, 148 insertions, 0 deletions
diff --git a/neols.c b/neols.c
new file mode 100644
index 0000000..06dc66e
--- /dev/null
+++ b/neols.c
@@ -0,0 +1,148 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "shared.h"
+
+/* A majority of lines in files.json
+are less than 80 characters long. */
+#define GUESS 80
+/* Each informative line has 6 spaces,
+a quote, then the data type, then a quote,
+then a colon, then a space, then a quote,
+then the data, terminated by a quote.
+The length of the data type's name plus
+11 characters precedes the data on each line. */
+#define PREFIX 11
+
+void
+stripquote(char *str)
+{
+	int i;
+	for (i = 0; str[i] != '\0'; ++i)
+		if (str[i] == '"') {
+			str[i] = '\0';
+			break;
+		}
+}
+
+int
+dircmp(char *dir, char *str)
+{
+	int slashes = 0, i;
+	for (i = 0; str[i] != '\0'; ++i)
+		if (str[i] == '/')
+			++slashes;
+	if (dir == NULL) {
+		if (! slashes)
+			return 1;
+		return 0;
+	}
+
+	int diff = 0, dirslashes = 0, dirlen = 0;
+	for (i = 0; dir[i] != '\0'; ++i) {
+		if (dir[i] != str[i]) {
+			diff = 1;
+			break;
+		}
+		if (dir[i] == '/')
+			++dirslashes;
+		++dirlen;
+	}
+	if (diff)
+		return 0;
+
+	/* Account for a trailing slash. */
+	if (dir[dirlen - 1] == '/')
+		--dirslashes;
+	if (slashes - dirslashes < 2)
+		return 1;
+	return 0;
+}
+
+void
+printentry(int long_format, int size, char *path, int is_directory,
+	char *sha1_hash, char *updated_at)
+{
+	if (long_format) {
+		/* The longest 31-bit int is 10 digits.
+		If the file size is larger, there's worse problems. */
+		printf("%10d ", size);
+		int i;
+		for (i = 0; i < 20; ++i)
+			putchar(updated_at[5 + i]);
+		putchar(' ');
+	}
+	printf("%s", path);
+	if (is_directory)
+		putchar('/');
+	putchar('\n');
+}
+
+char *infn = "files.json";
+/* neols [-l] [wildcard] */
+int
+main(int argc, char **argv)
+{
+	FILE *in = fopen(infn, "r");
+	if (in == NULL) {
+		puts("files.json isn't in the working directory.");
+		return 1;
+	}
+	int i;
+	int long_format = 0;
+	char *dir = NULL;
+	for (i = 1; i < argc; ++i) {
+		if (strcmp(argv[i], "-l") == 0)
+			long_format = 1;
+		else
+			dir = argv[i];
+	}
+	char *line;
+	/* The various statistics related to each entry are stored,
+	one entry at a time. A path may be any size, so each line need
+	be handled by realloc. */
+	char *path = NULL, *updated_at = NULL, *sha1_hash = NULL;
+	int is_directory = 0, size = 0;
+	int end, len;
+	for (end = 0; ! end;) {
+		line = storeline(in, &end, &len, GUESS);
+		/* Only on lines terminating an entry, '}' is the
+		fifth character. The ninth character of each data
+		line is unique. */
+		if (line[4] == '}') {
+			char *p = path + PREFIX + strlen("size");
+			if (dircmp(dir, p)) {
+				printentry(long_format, size, p,
+					is_directory, sha1_hash + PREFIX
+					+ strlen("sha1_hash"),
+					updated_at + PREFIX +
+					strlen("updated_at"));
+			}
+			free(path);
+			free(updated_at);
+			free(sha1_hash);
+			sha1_hash = NULL;
+			size = 0;
+			free(line);
+		} else if (line[8] == 'a') {
+			path = line;
+			stripquote(path + strlen("path") + PREFIX);
+		} else if (line[8] == 's') {
+			if (strstr(line, "false") == 0)
+				is_directory = 1;
+			else
+				is_directory = 0;
+			free(line);
+		} else if (line[8] == 'i') {
+			line[len - 1] = '\0';
+			size = atoi(line + PREFIX + strlen("size"));
+			free(line);
+		} else if (line[8] == 'p') {
+			updated_at = line;
+			stripquote(updated_at);
+		} else if (line[8] == 'h') {
+			sha1_hash = line;
+		}
+	}
+	return 0;
+}