Replace shift with a great variadic function
I am disappointed in the lack of compiler attributes for type-checking variadic functions.
This commit is contained in:
		
							parent
							
								
									05fe4ece20
								
							
						
					
					
						commit
						fc113c8ef9
					
				
							
								
								
									
										218
									
								
								handle.c
									
									
									
									
									
								
							
							
						
						
									
										218
									
								
								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 {
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user