Replace shift with a great variadic function
I am disappointed in the lack of compiler attributes for type-checking variadic functions.master
parent
05fe4ece20
commit
fc113c8ef9
208
handle.c
208
handle.c
|
@ -15,6 +15,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <err.h>
|
#include <err.h>
|
||||||
|
#include <stdarg.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -32,15 +33,8 @@ static int color(const char *s) {
|
||||||
return (x == 1) ? 0 : x;
|
return (x == 1) ? 0 : x;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef void (*Handler)(char *prefix, char *params);
|
static char *paramField(char **params) {
|
||||||
|
|
||||||
static char *prift(char **prefix) {
|
|
||||||
return strsep(prefix, "!@");
|
|
||||||
}
|
|
||||||
|
|
||||||
static char *shift(char **params) {
|
|
||||||
char *rest = *params;
|
char *rest = *params;
|
||||||
if (!rest) errx(EX_PROTOCOL, "unexpected eol");
|
|
||||||
if (rest[0] == ':') {
|
if (rest[0] == ':') {
|
||||||
*params = NULL;
|
*params = NULL;
|
||||||
return &rest[1];
|
return &rest[1];
|
||||||
|
@ -48,24 +42,59 @@ static char *shift(char **params) {
|
||||||
return strsep(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) {
|
static void handlePing(char *prefix, char *params) {
|
||||||
(void)prefix;
|
(void)prefix;
|
||||||
ircFmt("PONG %s\r\n", params);
|
ircFmt("PONG %s\r\n", params);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle432(char *prefix, char *params) {
|
static void handle432(char *prefix, char *params) {
|
||||||
(void)prefix;
|
char *mesg;
|
||||||
shift(¶ms);
|
shift(prefix, NULL, NULL, NULL, params, 1, 0, &mesg);
|
||||||
shift(¶ms);
|
|
||||||
char *mesg = shift(¶ms);
|
|
||||||
uiLog(L"You can't use that name here");
|
uiLog(L"You can't use that name here");
|
||||||
uiFmt("Sheriff says, \"%s\"", mesg);
|
uiFmt("Sheriff says, \"%s\"", mesg);
|
||||||
uiLog(L"Type /nick <name> to choose a new one");
|
uiLog(L"Type /nick <name> to choose a new one");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle001(char *prefix, char *params) {
|
static void handle001(char *prefix, char *params) {
|
||||||
(void)prefix;
|
char *nick;
|
||||||
char *nick = shift(¶ms);
|
shift(prefix, NULL, NULL, NULL, params, 1, 0, &nick);
|
||||||
if (strcmp(nick, chat.nick)) {
|
if (strcmp(nick, chat.nick)) {
|
||||||
free(chat.nick);
|
free(chat.nick);
|
||||||
chat.nick = strdup(nick);
|
chat.nick = strdup(nick);
|
||||||
|
@ -74,27 +103,23 @@ static void handle001(char *prefix, char *params) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handleJoin(char *prefix, char *params) {
|
static void handleJoin(char *prefix, char *params) {
|
||||||
char *nick = prift(&prefix);
|
char *nick, *user, *chan;
|
||||||
char *user = prift(&prefix);
|
shift(prefix, &nick, &user, NULL, params, 1, 0, &chan);
|
||||||
char *chan = shift(¶ms);
|
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)) {
|
if (!strcmp(nick, chat.nick) && strcmp(user, chat.user)) {
|
||||||
free(chat.user);
|
free(chat.user);
|
||||||
chat.user = strdup(user);
|
chat.user = strdup(user);
|
||||||
}
|
}
|
||||||
tabTouch(nick);
|
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) {
|
static void handlePart(char *prefix, char *params) {
|
||||||
char *nick = prift(&prefix);
|
char *nick, *user, *chan, *mesg;
|
||||||
char *user = prift(&prefix);
|
shift(prefix, &nick, &user, NULL, params, 1, 1, &chan, &mesg);
|
||||||
char *chan = shift(¶ms);
|
if (mesg) {
|
||||||
tabRemove(nick);
|
|
||||||
if (params) {
|
|
||||||
char *mesg = shift(¶ms);
|
|
||||||
uiFmt(
|
uiFmt(
|
||||||
"\3%d%s\3 leaves \3%d%s\3, \"%s\"",
|
"\3%d%s\3 leaves \3%d%s\3, \"%s\"",
|
||||||
color(user), nick, color(chan), chan, mesg
|
color(user), nick, color(chan), chan, mesg
|
||||||
|
@ -105,14 +130,13 @@ static void handlePart(char *prefix, char *params) {
|
||||||
color(user), nick, color(chan), chan
|
color(user), nick, color(chan), chan
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
tabRemove(nick);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handleQuit(char *prefix, char *params) {
|
static void handleQuit(char *prefix, char *params) {
|
||||||
char *nick = prift(&prefix);
|
char *nick, *user, *mesg;
|
||||||
char *user = prift(&prefix);
|
shift(prefix, &nick, &user, NULL, params, 0, 1, &mesg);
|
||||||
tabRemove(nick);
|
if (mesg) {
|
||||||
if (params) {
|
|
||||||
char *mesg = shift(¶ms);
|
|
||||||
char *quot = (mesg[0] == '"') ? "" : "\"";
|
char *quot = (mesg[0] == '"') ? "" : "\"";
|
||||||
uiFmt(
|
uiFmt(
|
||||||
"\3%d%s\3 leaves, %s%s%s",
|
"\3%d%s\3 leaves, %s%s%s",
|
||||||
|
@ -121,51 +145,51 @@ static void handleQuit(char *prefix, char *params) {
|
||||||
} else {
|
} else {
|
||||||
uiFmt("\3%d%s\3 leaves", color(user), nick);
|
uiFmt("\3%d%s\3 leaves", color(user), nick);
|
||||||
}
|
}
|
||||||
|
tabRemove(nick);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handleKick(char *prefix, char *params) {
|
static void handleKick(char *prefix, char *params) {
|
||||||
char *nick = prift(&prefix);
|
char *nick, *user, *chan, *kick, *mesg;
|
||||||
char *user = prift(&prefix);
|
shift(prefix, &nick, &user, NULL, params, 2, 1, &chan, &kick, &mesg);
|
||||||
char *chan = shift(¶ms);
|
if (mesg) {
|
||||||
char *kick = shift(¶ms);
|
|
||||||
char *mesg = shift(¶ms);
|
|
||||||
tabRemove(nick);
|
|
||||||
uiFmt(
|
uiFmt(
|
||||||
"\3%d%s\3 kicks \3%d%s\3 out of \3%d%s\3, \"%s\"",
|
"\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
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle332(char *prefix, char *params) {
|
static void handle332(char *prefix, char *params) {
|
||||||
(void)prefix;
|
char *chan, *topic;
|
||||||
shift(¶ms);
|
shift(prefix, NULL, NULL, NULL, params, 3, 0, NULL, &chan, &topic);
|
||||||
char *chan = shift(¶ms);
|
|
||||||
char *topic = shift(¶ms);
|
|
||||||
urlScan(topic);
|
|
||||||
uiTopicStr(topic);
|
|
||||||
uiFmt(
|
uiFmt(
|
||||||
"The sign in \3%d%s\3 reads, \"%s\"",
|
"The sign in \3%d%s\3 reads, \"%s\"",
|
||||||
color(chan), chan, topic
|
color(chan), chan, topic
|
||||||
);
|
);
|
||||||
|
urlScan(topic);
|
||||||
|
uiTopicStr(topic);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handleTopic(char *prefix, char *params) {
|
static void handleTopic(char *prefix, char *params) {
|
||||||
char *nick = prift(&prefix);
|
char *nick, *user, *chan, *topic;
|
||||||
char *user = prift(&prefix);
|
shift(prefix, &nick, &user, NULL, params, 2, 0, &chan, &topic);
|
||||||
char *chan = shift(¶ms);
|
|
||||||
char *topic = shift(¶ms);
|
|
||||||
urlScan(topic);
|
|
||||||
uiTopicStr(topic);
|
|
||||||
uiFmt(
|
uiFmt(
|
||||||
"\3%d%s\3 places a new sign in \3%d%s\3, \"%s\"",
|
"\3%d%s\3 places a new sign in \3%d%s\3, \"%s\"",
|
||||||
color(user), nick, color(chan), chan, topic
|
color(user), nick, color(chan), chan, topic
|
||||||
);
|
);
|
||||||
|
urlScan(topic);
|
||||||
|
uiTopicStr(topic);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle366(char *prefix, char *params) {
|
static void handle366(char *prefix, char *params) {
|
||||||
(void)prefix;
|
char *chan;
|
||||||
shift(¶ms);
|
shift(prefix, NULL, NULL, NULL, params, 2, 0, NULL, &chan);
|
||||||
char *chan = shift(¶ms);
|
|
||||||
ircFmt("WHO %s\r\n", chan);
|
ircFmt("WHO %s\r\n", chan);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,14 +199,11 @@ static struct {
|
||||||
} who;
|
} who;
|
||||||
|
|
||||||
static void handle352(char *prefix, char *params) {
|
static void handle352(char *prefix, char *params) {
|
||||||
(void)prefix;
|
char *user, *nick;
|
||||||
shift(¶ms);
|
shift(
|
||||||
shift(¶ms);
|
prefix, NULL, NULL, NULL,
|
||||||
char *user = shift(¶ms);
|
params, 6, 0, NULL, NULL, &user, NULL, NULL, &nick
|
||||||
shift(¶ms);
|
);
|
||||||
shift(¶ms);
|
|
||||||
char *nick = shift(¶ms);
|
|
||||||
tabTouch(nick);
|
|
||||||
size_t cap = sizeof(who.buf) - who.len;
|
size_t cap = sizeof(who.buf) - who.len;
|
||||||
int len = snprintf(
|
int len = snprintf(
|
||||||
&who.buf[who.len], cap,
|
&who.buf[who.len], cap,
|
||||||
|
@ -190,65 +211,74 @@ static void handle352(char *prefix, char *params) {
|
||||||
(who.len ? ", " : ""), color(user), nick
|
(who.len ? ", " : ""), color(user), nick
|
||||||
);
|
);
|
||||||
if ((size_t)len < cap) who.len += len;
|
if ((size_t)len < cap) who.len += len;
|
||||||
|
tabTouch(nick);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle315(char *prefix, char *params) {
|
static void handle315(char *prefix, char *params) {
|
||||||
(void)prefix;
|
char *chan;
|
||||||
shift(¶ms);
|
shift(prefix, NULL, NULL, NULL, params, 2, 0, NULL, &chan);
|
||||||
char *chan = shift(¶ms);
|
|
||||||
who.len = 0;
|
|
||||||
uiFmt(
|
uiFmt(
|
||||||
"In \3%d%s\3 are %s",
|
"In \3%d%s\3 are %s",
|
||||||
color(chan), chan, who.buf
|
color(chan), chan, who.buf
|
||||||
);
|
);
|
||||||
|
who.len = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handleNick(char *prefix, char *params) {
|
static void handleNick(char *prefix, char *params) {
|
||||||
char *prev = prift(&prefix);
|
char *prev, *user, *next;
|
||||||
char *user = prift(&prefix);
|
shift(prefix, &prev, &user, NULL, params, 1, 0, &next);
|
||||||
char *next = shift(¶ms);
|
uiFmt(
|
||||||
|
"\3%d%s\3 is now known as \3%d%s\3",
|
||||||
|
color(user), prev, color(user), next
|
||||||
|
);
|
||||||
if (!strcmp(user, chat.user)) {
|
if (!strcmp(user, chat.user)) {
|
||||||
free(chat.nick);
|
free(chat.nick);
|
||||||
chat.nick = strdup(next);
|
chat.nick = strdup(next);
|
||||||
}
|
}
|
||||||
tabReplace(prev, 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(
|
uiFmt(
|
||||||
"\3%d%s\3 is now known as \3%d%s\3",
|
"* \3%d%s\3 %s",
|
||||||
color(user), prev, color(user), next
|
color(user), nick, params
|
||||||
);
|
);
|
||||||
|
if (strcmp(user, chat.user)) tabTouch(nick);
|
||||||
|
urlScan(params);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handlePrivmsg(char *prefix, char *params) {
|
static void handlePrivmsg(char *prefix, char *params) {
|
||||||
char *nick = prift(&prefix);
|
char *nick, *user, *mesg;
|
||||||
char *user = prift(&prefix);
|
shift(prefix, &nick, &user, NULL, params, 2, 0, NULL, &mesg);
|
||||||
shift(¶ms);
|
if (mesg[0] == '\1') {
|
||||||
char *mesg = shift(¶ms);
|
handleCTCP(nick, user, mesg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
bool self = !strcmp(user, chat.user);
|
bool self = !strcmp(user, chat.user);
|
||||||
bool ping = !strncasecmp(mesg, chat.nick, strlen(chat.nick));
|
bool ping = !strncasecmp(mesg, chat.nick, strlen(chat.nick));
|
||||||
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(
|
uiFmt(
|
||||||
"%c%c\3%d%s\17%c %s",
|
"%c%c\3%d%s\17%c %s",
|
||||||
self["<["], ping["\17\26"], color(user), nick, self[">]"], mesg
|
self["<["], ping["\17\26"], color(user), nick, self[">]"], mesg
|
||||||
);
|
);
|
||||||
}
|
if (!self) tabTouch(nick);
|
||||||
|
if (ping) uiBeep();
|
||||||
|
urlScan(mesg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handleNotice(char *prefix, char *params) {
|
static void handleNotice(char *prefix, char *params) {
|
||||||
char *nick = prift(&prefix);
|
char *nick, *user, *chan, *mesg;
|
||||||
char *user = prift(&prefix);
|
shift(prefix, &nick, &user, NULL, params, 2, 0, &chan, &mesg);
|
||||||
char *chan = shift(¶ms);
|
if (strcmp(chan, chat.chan)) return;
|
||||||
char *mesg = shift(¶ms);
|
uiFmt(
|
||||||
if (strcmp(chat.chan, chan)) return;
|
"-\3%d%s\3- %s",
|
||||||
|
color(user), nick, mesg
|
||||||
|
);
|
||||||
tabTouch(nick);
|
tabTouch(nick);
|
||||||
urlScan(mesg);
|
urlScan(mesg);
|
||||||
uiFmt("-\3%d%s\3- %s", color(user), nick, mesg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct {
|
static const struct {
|
||||||
|
|
Loading…
Reference in New Issue