summaryrefslogtreecommitdiff
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;
+}