about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--scoop.c74
1 files changed, 34 insertions, 40 deletions
diff --git a/scoop.c b/scoop.c
index 1f031e2..2a78af8 100644
--- a/scoop.c
+++ b/scoop.c
@@ -59,7 +59,7 @@ static const char *Search = SQL(search MATCH :search);
 
 static const char *Limit = SQL(
 	ORDER BY time DESC, event DESC
-	LIMIT :limit
+	LIMIT coalesce(:limit, -1)
 );
 
 static const char *Outer = SQL(
@@ -158,49 +158,47 @@ static const char *TypeNames[] = {
 #undef X
 };
 
-static const enum Type *parseType(const char *input) {
-	static enum Type type;
-	for (type = 0; type < ARRAY_LEN(TypeNames); ++type) {
-		if (!strcmp(input, TypeNames[type])) return &type;
+static enum Type parseType(const char *input) {
+	for (enum Type type = 0; type < ARRAY_LEN(TypeNames); ++type) {
+		if (!strcmp(input, TypeNames[type])) return type;
 	}
 	errx(EX_USAGE, "no such type %s", input);
 }
 
+static struct Bind {
+	const char *param;
+	const char *text;
+	int value;
+} Bind(const char *param, const char *text, int value) {
+	return (struct Bind) { param, text, value };
+}
+
 int main(int argc, char *argv[]) {
 	char *path = NULL;
 	bool shell = false;
+	bool group = false;
 
-	bool public = false;
-	bool query = false;
-	const char *network = NULL;
-	const char *context = NULL;
-	const char *date = NULL;
-	const enum Type *type = NULL;
-	const char *nick = NULL;
-	const char *user = NULL;
-	const char *host = NULL;
-	const char *target = NULL;
+	int n = 0;
+	struct Bind binds[argc];
 	const char *search = NULL;
-	int limit = -1;
-	bool group = false;
 
 	int opt;
 	while (0 < (opt = getopt(argc, argv, "D:N:T:c:d:gh:l:n:pqst:u:v"))) {
 		switch (opt) {
-			break; case 'D': date = optarg;
-			break; case 'N': network = optarg;
-			break; case 'T': target = optarg;
-			break; case 'c': context = optarg;
+			break; case 'D': binds[n++] = Bind(":date", optarg, 0);
+			break; case 'N': binds[n++] = Bind(":network", optarg, 0);
+			break; case 'T': binds[n++] = Bind(":target", optarg, 0);
+			break; case 'c': binds[n++] = Bind(":context", optarg, 0);
 			break; case 'd': path = optarg;
 			break; case 'g': group = true;
-			break; case 'h': host = optarg;
-			break; case 'l': limit = strtol(optarg, NULL, 0);
-			break; case 'n': nick = optarg;
-			break; case 'p': public = true;
-			break; case 'q': query = true;
+			break; case 'h': binds[n++] = Bind(":host", optarg, 0);
+			break; case 'l': binds[n++] = Bind(":limit", optarg, 0);
+			break; case 'n': binds[n++] = Bind(":nick", optarg, 0);
+			break; case 'p': binds[n++] = Bind(":query", NULL, 0);
+			break; case 'q': binds[n++] = Bind(":query", NULL, 1);
 			break; case 's': shell = true;
-			break; case 't': type = parseType(optarg);
-			break; case 'u': user = optarg;
+			break; case 't': binds[n++] = Bind(":type", NULL, parseType(optarg));
+			break; case 'u': binds[n++] = Bind(":user", optarg, 0);
 			break; case 'v': verbose = true;
 			break; default:  return EX_USAGE;
 		}
@@ -254,6 +252,7 @@ int main(int argc, char *argv[]) {
 			"WITH results AS (%s AND %s %s) %s;",
 			Inner, Search, Limit, (group ? Group : Outer)
 		);
+		binds[n++] = Bind(":search", search, 0);
 	} else {
 		snprintf(
 			sql, sizeof(sql),
@@ -263,18 +262,13 @@ int main(int argc, char *argv[]) {
 	}
 
 	sqlite3_stmt *stmt = dbPrepare(sql);
-	dbBindText(stmt, ":network", network);
-	dbBindText(stmt, ":context", context);
-	if (public) dbBindInt(stmt, ":query", false);
-	if (query) dbBindInt(stmt, ":query", true);
-	dbBindText(stmt, ":date", date);
-	if (type) dbBindInt(stmt, ":type", *type);
-	dbBindText(stmt, ":nick", nick);
-	dbBindText(stmt, ":user", user);
-	dbBindText(stmt, ":host", host);
-	dbBindText(stmt, ":target", target);
-	if (search) dbBindText(stmt, ":search", search);
-	dbBindInt(stmt, ":limit", limit);
+	for (int i = 0; i < n; ++i) {
+		if (binds[i].text) {
+			dbBindText(stmt, binds[i].param, binds[i].text);
+		} else {
+			dbBindInt(stmt, binds[i].param, binds[i].value);
+		}
+	}
 
 	if (tty) {
 		dbBindText(stmt, ":open", "\33[7m");