diff options
author | Curtis McEnroe | 2018-08-09 17:37:14 -0400 |
---|---|---|
committer | Curtis McEnroe | 2018-08-09 17:37:14 -0400 |
commit | fc113c8ef9b11c968f9cf6d3e44803ad6895f64f (patch) | |
tree | d05cd884fbe0843f3a94061fd9a99d9e9e684cdc /handle.c | |
parent | 05fe4ece20a8333d91850b812a6d8bdc45726ae4 (diff) |
Replace shift with a great variadic function
I am disappointed in the lack of compiler attributes for type-checking variadic functions.
Diffstat (limited to 'handle.c')
-rw-r--r-- | handle.c | 218 |
1 files changed, 124 insertions, 94 deletions
diff --git a/handle.c b/handle.c index 4389ff8..ed1ba35 100644 --- a/handle.c +++ b/handle.c @@ -15,6 +15,7 @@ */ #include <err.h> +#include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -32,15 +33,8 @@ static int color(const char *s) { return (x == 1) ? 0 : x; } -typedef void (*Handler)(char *prefix, char *params); - -static char *prift(char **prefix) { - return strsep(prefix, "!@"); -} - -static char *shift(char **params) { +static char *paramField(char **params) { char *rest = *params; - if (!rest) errx(EX_PROTOCOL, "unexpected eol"); if (rest[0] == ':') { *params = NULL; return &rest[1]; @@ -48,24 +42,59 @@ static char *shift(char **params) { return strsep(params, " "); } +static void shift( + char *prefix, char **nick, char **user, char **host, + char *params, size_t req, size_t opt, /* (char **) */ ... +) { + char *field; + if (prefix) { + field = strsep(&prefix, "!"); + if (nick) *nick = field; + field = strsep(&prefix, "@"); + if (user) *user = field; + if (host) *host = prefix; + } + + va_list ap; + va_start(ap, opt); + for (size_t i = 0; i < req; ++i) { + if (!params) { + va_end(ap); + errx(EX_PROTOCOL, "%zu params required, found %zu", req, i); + } + field = paramField(¶ms); + char **param = va_arg(ap, char **); + if (param) *param = field; + } + for (size_t i = 0; i < opt; ++i) { + char **param = va_arg(ap, char **); + if (params) { + *param = paramField(¶ms); + } else { + *param = NULL; + } + } + va_end(ap); +} + +typedef void (*Handler)(char *prefix, char *params); + static void handlePing(char *prefix, char *params) { (void)prefix; ircFmt("PONG %s\r\n", params); } static void handle432(char *prefix, char *params) { - (void)prefix; - shift(¶ms); - shift(¶ms); - char *mesg = shift(¶ms); + char *mesg; + shift(prefix, NULL, NULL, NULL, params, 1, 0, &mesg); uiLog(L"You can't use that name here"); uiFmt("Sheriff says, \"%s\"", mesg); uiLog(L"Type /nick <name> to choose a new one"); } static void handle001(char *prefix, char *params) { - (void)prefix; - char *nick = shift(¶ms); + char *nick; + shift(prefix, NULL, NULL, NULL, params, 1, 0, &nick); if (strcmp(nick, chat.nick)) { free(chat.nick); chat.nick = strdup(nick); @@ -74,27 +103,23 @@ static void handle001(char *prefix, char *params) { } static void handleJoin(char *prefix, char *params) { - char *nick = prift(&prefix); - char *user = prift(&prefix); - char *chan = shift(¶ms); + char *nick, *user, *chan; + shift(prefix, &nick, &user, NULL, params, 1, 0, &chan); + uiFmt( + "\3%d%s\3 arrives in \3%d%s\3", + color(user), nick, color(chan), chan + ); if (!strcmp(nick, chat.nick) && strcmp(user, chat.user)) { free(chat.user); chat.user = strdup(user); } tabTouch(nick); - uiFmt( - "\3%d%s\3 arrives in \3%d%s\3", - color(user), nick, color(chan), chan - ); } static void handlePart(char *prefix, char *params) { - char *nick = prift(&prefix); - char *user = prift(&prefix); - char *chan = shift(¶ms); - tabRemove(nick); - if (params) { - char *mesg = shift(¶ms); + char *nick, *user, *chan, *mesg; + shift(prefix, &nick, &user, NULL, params, 1, 1, &chan, &mesg); + if (mesg) { uiFmt( "\3%d%s\3 leaves \3%d%s\3, \"%s\"", color(user), nick, color(chan), chan, mesg @@ -105,14 +130,13 @@ static void handlePart(char *prefix, char *params) { color(user), nick, color(chan), chan ); } + tabRemove(nick); } static void handleQuit(char *prefix, char *params) { - char *nick = prift(&prefix); - char *user = prift(&prefix); - tabRemove(nick); - if (params) { - char *mesg = shift(¶ms); + char *nick, *user, *mesg; + shift(prefix, &nick, &user, NULL, params, 0, 1, &mesg); + if (mesg) { char *quot = (mesg[0] == '"') ? "" : "\""; uiFmt( "\3%d%s\3 leaves, %s%s%s", @@ -121,51 +145,51 @@ static void handleQuit(char *prefix, char *params) { } else { uiFmt("\3%d%s\3 leaves", color(user), nick); } + tabRemove(nick); } static void handleKick(char *prefix, char *params) { - char *nick = prift(&prefix); - char *user = prift(&prefix); - char *chan = shift(¶ms); - char *kick = shift(¶ms); - char *mesg = shift(¶ms); + char *nick, *user, *chan, *kick, *mesg; + shift(prefix, &nick, &user, NULL, params, 2, 1, &chan, &kick, &mesg); + if (mesg) { + uiFmt( + "\3%d%s\3 kicks \3%d%s\3 out of \3%d%s\3, \"%s\"", + color(user), nick, color(kick), kick, color(chan), chan, mesg + ); + } else { + uiFmt( + "\3%d%s\3 kicks \3%d%s\3 out of \3%d%s\3", + color(user), nick, color(kick), kick, color(chan), chan + ); + } tabRemove(nick); - uiFmt( - "\3%d%s\3 kicks \3%d%s\3 out of \3%d%s\3, \"%s\"", - color(user), nick, color(kick), kick, color(chan), chan, mesg - ); } static void handle332(char *prefix, char *params) { - (void)prefix; - shift(¶ms); - char *chan = shift(¶ms); - char *topic = shift(¶ms); - urlScan(topic); - uiTopicStr(topic); + char *chan, *topic; + shift(prefix, NULL, NULL, NULL, params, 3, 0, NULL, &chan, &topic); uiFmt( "The sign in \3%d%s\3 reads, \"%s\"", color(chan), chan, topic ); + urlScan(topic); + uiTopicStr(topic); } static void handleTopic(char *prefix, char *params) { - char *nick = prift(&prefix); - char *user = prift(&prefix); - char *chan = shift(¶ms); - char *topic = shift(¶ms); - urlScan(topic); - uiTopicStr(topic); + char *nick, *user, *chan, *topic; + shift(prefix, &nick, &user, NULL, params, 2, 0, &chan, &topic); uiFmt( "\3%d%s\3 places a new sign in \3%d%s\3, \"%s\"", color(user), nick, color(chan), chan, topic ); + urlScan(topic); + uiTopicStr(topic); } static void handle366(char *prefix, char *params) { - (void)prefix; - shift(¶ms); - char *chan = shift(¶ms); + char *chan; + shift(prefix, NULL, NULL, NULL, params, 2, 0, NULL, &chan); ircFmt("WHO %s\r\n", chan); } @@ -175,14 +199,11 @@ static struct { } who; static void handle352(char *prefix, char *params) { - (void)prefix; - shift(¶ms); - shift(¶ms); - char *user = shift(¶ms); - shift(¶ms); - shift(¶ms); - char *nick = shift(¶ms); - tabTouch(nick); + char *user, *nick; + shift( + prefix, NULL, NULL, NULL, + params, 6, 0, NULL, NULL, &user, NULL, NULL, &nick + ); size_t cap = sizeof(who.buf) - who.len; int len = snprintf( &who.buf[who.len], cap, @@ -190,65 +211,74 @@ static void handle352(char *prefix, char *params) { (who.len ? ", " : ""), color(user), nick ); if ((size_t)len < cap) who.len += len; + tabTouch(nick); } static void handle315(char *prefix, char *params) { - (void)prefix; - shift(¶ms); - char *chan = shift(¶ms); - who.len = 0; + char *chan; + shift(prefix, NULL, NULL, NULL, params, 2, 0, NULL, &chan); uiFmt( "In \3%d%s\3 are %s", color(chan), chan, who.buf ); + who.len = 0; } static void handleNick(char *prefix, char *params) { - char *prev = prift(&prefix); - char *user = prift(&prefix); - char *next = shift(¶ms); + char *prev, *user, *next; + shift(prefix, &prev, &user, NULL, params, 1, 0, &next); + uiFmt( + "\3%d%s\3 is now known as \3%d%s\3", + color(user), prev, color(user), next + ); if (!strcmp(user, chat.user)) { free(chat.nick); chat.nick = strdup(next); } tabReplace(prev, next); +} + +static void handleCTCP(char *nick, char *user, char *mesg) { + mesg = &mesg[1]; + char *ctcp = strsep(&mesg, " "); + char *params = strsep(&mesg, "\1"); + if (strcmp(ctcp, "ACTION")) return; uiFmt( - "\3%d%s\3 is now known as \3%d%s\3", - color(user), prev, color(user), next + "* \3%d%s\3 %s", + color(user), nick, params ); + if (strcmp(user, chat.user)) tabTouch(nick); + urlScan(params); } static void handlePrivmsg(char *prefix, char *params) { - char *nick = prift(&prefix); - char *user = prift(&prefix); - shift(¶ms); - char *mesg = shift(¶ms); + char *nick, *user, *mesg; + shift(prefix, &nick, &user, NULL, params, 2, 0, NULL, &mesg); + if (mesg[0] == '\1') { + handleCTCP(nick, user, mesg); + return; + } bool self = !strcmp(user, chat.user); bool ping = !strncasecmp(mesg, chat.nick, strlen(chat.nick)); + uiFmt( + "%c%c\3%d%s\17%c %s", + self["<["], ping["\17\26"], color(user), nick, self[">]"], mesg + ); if (!self) tabTouch(nick); - urlScan(mesg); if (ping) uiBeep(); - if (mesg[0] == '\1') { - strsep(&mesg, " "); - char *action = strsep(&mesg, "\1"); - uiFmt("* \3%d%s\3 %s", color(user), nick, action); - } else { - uiFmt( - "%c%c\3%d%s\17%c %s", - self["<["], ping["\17\26"], color(user), nick, self[">]"], mesg - ); - } + urlScan(mesg); } static void handleNotice(char *prefix, char *params) { - char *nick = prift(&prefix); - char *user = prift(&prefix); - char *chan = shift(¶ms); - char *mesg = shift(¶ms); - if (strcmp(chat.chan, chan)) return; + char *nick, *user, *chan, *mesg; + shift(prefix, &nick, &user, NULL, params, 2, 0, &chan, &mesg); + if (strcmp(chan, chat.chan)) return; + uiFmt( + "-\3%d%s\3- %s", + color(user), nick, mesg + ); tabTouch(nick); urlScan(mesg); - uiFmt("-\3%d%s\3- %s", color(user), nick, mesg); } static const struct { |