about summary refs log tree commit diff
path: root/scoop.c
diff options
context:
space:
mode:
Diffstat (limited to 'scoop.c')
-rw-r--r--scoop.c96
1 files changed, 77 insertions, 19 deletions
diff --git a/scoop.c b/scoop.c
index 8c113d5..73aeb89 100644
--- a/scoop.c
+++ b/scoop.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2019  C. McEnroe <june@causal.agency>
+/* Copyright (C) 2019  June McEnroe <june@causal.agency>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -245,6 +245,7 @@ static void regexpFree(void *_regex) {
 	free(regex);
 }
 
+static int regexpFlags = REG_EXTENDED | REG_NOSUB;
 static void regexp(sqlite3_context *ctx, int n, sqlite3_value *args[]) {
 	assert(n == 2);
 	if (sqlite3_value_type(args[0]) == SQLITE_NULL) {
@@ -267,7 +268,7 @@ static void regexp(sqlite3_context *ctx, int n, sqlite3_value *args[]) {
 
 		int error = regcomp(
 			regex, (const char *)sqlite3_value_text(args[0]),
-			REG_EXTENDED | REG_NOSUB
+			regexpFlags
 		);
 		if (error) {
 			char msg[256];
@@ -283,7 +284,9 @@ static void regexp(sqlite3_context *ctx, int n, sqlite3_value *args[]) {
 	sqlite3_result_int(ctx, !error);
 }
 
-static char select[4096] = SQL(
+enum { QueryCap = 4096 };
+
+static char select[QueryCap] = SQL(
 	SELECT
 		events.event,
 		contexts.network,
@@ -306,8 +309,6 @@ static char select[4096] = SQL(
 		events.target,
 );
 
-enum { QueryCap = 4096 };
-
 static char from[QueryCap] = SQL(
 	FROM events
 	JOIN contexts USING (context)
@@ -344,6 +345,14 @@ static enum Type parseType(const char *input) {
 	errx(EX_USAGE, "no such type %s", input);
 }
 
+static int parseTypes(char *list) {
+	int mask = 0;
+	while (list) {
+		mask |= 1 << parseType(strsep(&list, ","));
+	}
+	return mask;
+}
+
 int main(int argc, char *argv[]) {
 	bool tty = isatty(STDOUT_FILENO);
 
@@ -353,20 +362,33 @@ int main(int argc, char *argv[]) {
 
 	bool sort = false;
 	bool group = false;
+	bool reverse = false;
 	const char *limit = NULL;
 
 	int n = 0;
-	struct Bind binds[argc + 2];
-	const char *Opts = "D:F:LN:ST:a:b:c:d:f:gh:l:m:n:pqst:u:vw:";
+	struct Bind *binds = calloc(argc + 2, sizeof(*binds));
+	if (!binds) err(EX_OSERR, "calloc");
+
+	const char *Opts = "D:F:LN:ST:a:b:c:d:f:gh:il:m:n:pqrst:u:vw:";
 	for (int opt; 0 < (opt = getopt(argc, argv, Opts));) {
 		switch (opt) {
 			break; case 'D': {
 				append(
 					where,
 					SQL(
-						AND events.time >= strftime('%s', :date, 'start of day')
-						AND events.time
-							< strftime('%s', :date, 'start of day', '+1 day')
+						AND events.time >=
+						CASE WHEN :local THEN
+							strftime('%s', :date, 'start of day', 'utc')
+						ELSE
+							strftime('%s', :date, 'start of day')
+						END
+						AND events.time <
+						CASE WHEN :local THEN
+							strftime('%s', :date, 'start of day', '+1 day',
+								'utc')
+						ELSE
+							strftime('%s', :date, 'start of day', '+1 day')
+						END
 					)
 				);
 				binds[n++] = Bind(":date", optarg, 0);
@@ -389,11 +411,29 @@ int main(int argc, char *argv[]) {
 				binds[n++] = Bind(":target", optarg, 0);
 			}
 			break; case 'a': {
-				append(where, SQL(AND events.time >= strftime('%s', :after)));
+				append(
+					where,
+					SQL(
+						AND events.time >=
+						CASE WHEN :local
+						THEN strftime('%s', :after, 'utc')
+						ELSE strftime('%s', :after)
+						END
+					)
+				);
 				binds[n++] = Bind(":after", optarg, 0);
 			}
 			break; case 'b': {
-				append(where, SQL(AND events.time < strftime('%s', :before)));
+				append(
+					where,
+					SQL(
+						AND events.time <
+						CASE WHEN :local
+						THEN strftime('%s', :before, 'utc')
+						ELSE strftime('%s', :before)
+						END
+					)
+				);
 				binds[n++] = Bind(":before", optarg, 0);
 			}
 			break; case 'c': {
@@ -414,6 +454,9 @@ int main(int argc, char *argv[]) {
 				append(where, SQL(AND names.host = :host));
 				binds[n++] = Bind(":host", optarg, 0);
 			}
+			break; case 'i': {
+				regexpFlags |= REG_ICASE;
+			}
 			break; case 'l': {
 				limit = optarg;
 				sort = true;
@@ -434,12 +477,15 @@ int main(int argc, char *argv[]) {
 				append(where, SQL(AND contexts.query = :query));
 				binds[n++] = Bind(":query", NULL, 1);
 			}
+			break; case 'r': {
+				reverse = true;
+			}
 			break; case 's': {
 				sort = true;
 			}
 			break; case 't': {
-				append(where, SQL(AND events.type = :type));
-				binds[n++] = Bind(":type", NULL, parseType(optarg));
+				append(where, SQL(AND (1 << events.type) & :types));
+				binds[n++] = Bind(":types", NULL, parseTypes(optarg));
 			}
 			break; case 'u': {
 				append(where, SQL(AND names.user = :user));
@@ -456,7 +502,8 @@ int main(int argc, char *argv[]) {
 		}
 	}
 
-	if (optind < argc) {
+	bool search = (optind < argc);
+	if (search) {
 		append(select, SQL(highlight(search, 6, :open, :close)));
 		append(from, SQL(JOIN search ON search.rowid = events.event));
 		append(where, SQL(AND search MATCH :search));
@@ -474,11 +521,15 @@ int main(int argc, char *argv[]) {
 	}
 
 	if (limit) {
-		append(where, SQL(ORDER BY time DESC, event DESC LIMIT :limit));
+		if (search) {
+			append(where, SQL(ORDER BY search.rowid DESC LIMIT :limit));
+		} else {
+			append(where, SQL(ORDER BY event DESC LIMIT :limit));
+		}
 		binds[n++] = Bind(":limit", limit, 0);
 	}
 
-	dbFind(path, SQLITE_OPEN_READWRITE);
+	dbFind(path, SQLITE_OPEN_READONLY);
 	if (dbVersion() != DatabaseVersion) {
 		errx(EX_CONFIG, "database out of date; migrate with litterbox -m");
 	}
@@ -503,9 +554,15 @@ int main(int argc, char *argv[]) {
 			SQL(
 				WITH results AS (%s %s %s)
 				SELECT * FROM results
-				ORDER BY %s time, event;
+				ORDER BY %s time %s, event %s;
 			),
-			select, from, where, (group ? "network, context," : "")
+			select, from, where, (group ? "network, context," : ""),
+			(reverse ? "DESC" : ""), (reverse ? "DESC" : "")
+		);
+	} else if (reverse) {
+		len = asprintf(
+			&query, "%s %s %s ORDER BY %s DESC;",
+			select, from, where, (search ? "search.rowid" : "event")
 		);
 	} else {
 		len = asprintf(&query, "%s %s %s;", select, from, where);
@@ -522,6 +579,7 @@ int main(int argc, char *argv[]) {
 			dbBindInt(stmt, binds[i].param, binds[i].value);
 		}
 	}
+	free(binds);
 
 	if (verbose) {
 		char *expand = sqlite3_expanded_sql(stmt);