diff options
-rw-r--r-- | scoop.1 | 25 | ||||
-rw-r--r-- | scoop.c | 63 |
2 files changed, 44 insertions, 44 deletions
diff --git a/scoop.1 b/scoop.1 index e4eedfd..fddd749 100644 --- a/scoop.1 +++ b/scoop.1 @@ -8,7 +8,7 @@ . .Sh SYNOPSIS .Nm -.Op Fl Lgpqv +.Op Fl Lgpqsv .Op Fl D Ar date .Op Fl F Ar format .Op Fl N Ar network @@ -27,7 +27,7 @@ .Op Fl w Ar expr .Op Ar search .Nm -.Fl s +.Fl S . .Sh DESCRIPTION The @@ -37,10 +37,6 @@ utility queries the IRC log database, matching events on the intersection of the criteria specified in arguments. -With no arguments, -all events in the database are matched. -Events are output in order -from oldest to newest. . .Pp If standard output is a terminal, @@ -78,6 +74,12 @@ Output timestamps in local time. Match events from .Ar network . . +.It Fl S +Instead of performing a query, +launch the +.Xr sqlite3 1 +shell for the database. +. .It Fl T Ar target Match events .Po @@ -131,6 +133,8 @@ otherwise. . .It Fl g Group events by network and channel or query name. +Implies +.Fl s . . .It Fl h Ar host Match events from users with the hostname @@ -139,6 +143,8 @@ Match events from users with the hostname .It Fl l Ar limit Limit the number of events matched, ordered by most recent. +Implies +.Fl s . . .It Fl m Ar regexp Match events with messages @@ -158,10 +164,9 @@ Match only events from channels. Match only events from queries. . .It Fl s -Instead of performing a query, -launch the -.Xr sqlite3 1 -shell for the database. +Sort the results from oldest to newest. +By default events are output +in the order they appear in the database. . .It Fl t Ar type Match events of diff --git a/scoop.c b/scoop.c index 4c4ee35..3ab6e5d 100644 --- a/scoop.c +++ b/scoop.c @@ -295,7 +295,7 @@ static void regexp(sqlite3_context *ctx, int n, sqlite3_value *args[]) { sqlite3_result_int(ctx, !error); } -static const char *Inner = SQL( +static const char *Query = SQL( SELECT contexts.network, contexts.name AS context, @@ -343,16 +343,6 @@ static const char *Limit = SQL( LIMIT coalesce(:limit, -1) ); -static const char *Outer = SQL( - SELECT * FROM results - ORDER BY time, event -); - -static const char *Group = SQL( - SELECT * FROM results - ORDER BY network, context, time, event -); - static const char *TypeNames[] = { #define X(id, name) [id] = name, ENUM_TYPE @@ -395,35 +385,38 @@ int main(int argc, char *argv[]) { char *path = NULL; bool shell = false; - bool group = false; Format *format = (tty ? formatColor : formatPlain); - int n = 0; - struct Bind binds[argc]; + bool sort = false; + bool group = false; const char *search = NULL; const char *where = NULL; + const char *limit = NULL; - const char *Opts = "D:F:LN:T:a:b:c:d:f:gh:l:m:n:pqst:u:vw:"; + int n = 0; + struct Bind binds[argc]; + const char *Opts = "D:F:LN:ST:a:b:c:d:f:gh:l:m:n:pqst:u:vw:"; for (int opt; 0 < (opt = getopt(argc, argv, Opts));) { switch (opt) { break; case 'D': binds[n++] = Bind(":date", optarg, 0); break; case 'F': binds[n++] = Bind(":format", optarg, 0); break; case 'L': binds[n++] = Bind(":local", NULL, 1); break; case 'N': binds[n++] = Bind(":network", optarg, 0); + break; case 'S': shell = true; break; case 'T': binds[n++] = Bind(":target", optarg, 0); break; case 'a': binds[n++] = Bind(":after", optarg, 0); break; case 'b': binds[n++] = Bind(":before", optarg, 0); break; case 'c': binds[n++] = Bind(":context", optarg, 0); break; case 'd': path = optarg; break; case 'f': format = parseFormat(optarg); - break; case 'g': group = true; + break; case 'g': group = true; sort = true; break; case 'h': binds[n++] = Bind(":host", optarg, 0); - break; case 'l': binds[n++] = Bind(":limit", optarg, 0); + break; case 'l': limit = optarg; sort = true; break; case 'm': binds[n++] = Bind(":regexp", 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 's': sort = true; break; case 't': binds[n++] = Bind(":type", NULL, parseType(optarg)); break; case 'u': binds[n++] = Bind(":user", optarg, 0); break; case 'v': verbose = true; @@ -450,25 +443,27 @@ int main(int argc, char *argv[]) { err(EX_UNAVAILABLE, "sqlite3"); } - int len; char sql[4096]; - if (search) { - len = snprintf( - sql, sizeof(sql), - "WITH results AS (%s AND %s AND %s %s) %s;", - Inner, Search, (where ? where : "true"), Limit, - (group ? Group : Outer) - ); - binds[n++] = Bind(":search", search, 0); - } else { - len = snprintf( - sql, sizeof(sql), - "WITH results AS (%s AND %s %s) %s;", - Inner, (where ? where : "true"), Limit, (group ? Group : Outer) - ); - } + int len = snprintf( + sql, sizeof(sql), + SQL( + WITH results AS ( + %s AND %s AND %s + %s + ) + SELECT * FROM results %s %s %s; + ), + Query, (search ? Search : "true"), (where ? where : "true"), + (limit ? Limit : ""), + (sort ? "ORDER BY" : ""), + (group ? "network, context," : ""), + (sort ? "time, event" : "") + ); assert((size_t)len < sizeof(sql)); + if (search) binds[n++] = Bind(":search", search, 0); + if (limit) binds[n++] = Bind(":limit", limit, 0); + sqlite3_stmt *stmt = dbPrepare(sql); for (int i = 0; i < n; ++i) { if (binds[i].text) { |