Permalink
Browse files

Implement irc_parse_command().

  • Loading branch information...
1 parent f086261 commit c32c992de440a89ccede547eee8c3901892d1745 @joshthecoder committed Mar 20, 2013
Showing with 182 additions and 2 deletions.
  1. +48 −1 include/irc.h
  2. +19 −1 shmooze.gyp
  3. +51 −0 src/command-lookup.gperf
  4. +8 −0 src/parser.c
  5. +2 −0 test/benchmark-list.h
  6. +42 −0 test/benchmark-parse-messages.c
  7. +2 −0 test/test-list.h
  8. +10 −0 test/test-parse-message.c
View
@@ -9,7 +9,7 @@ typedef struct irc_parser_s irc_parser_t;
struct irc_message_s {
const char* prefix;
const char* command;
- const char* parameters[10];
+ const char* parameters[15];
int parameter_count;
};
@@ -50,4 +50,51 @@ void irc_parser_init(irc_parser_t* parser);
// the number of bytes parsed.
int irc_parser_execute(irc_parser_t* parser, const char* buffer, size_t len);
+typedef enum {
+ IRC_PASS,
+ IRC_NICK,
+ IRC_USER,
+ IRC_SERVER,
+ IRC_OPER,
+ IRC_QUIT,
+ IRC_SQUIT,
+ IRC_JOIN,
+ IRC_PART,
+ IRC_MODE,
+ IRC_TOPIC,
+ IRC_NAMES,
+ IRC_LIST,
+ IRC_INVITE,
+ IRC_KICK,
+ IRC_VERSION,
+ IRC_STATS,
+ IRC_LINKS,
+ IRC_TIME,
+ IRC_CONNECT,
+ IRC_TRACE,
+ IRC_ADMIN,
+ IRC_INFO,
+ IRC_PRIVMSG,
+ IRC_NOTICE,
+ IRC_WHO,
+ IRC_WHOIS,
+ IRC_WHOWAS,
+ IRC_KILL,
+ IRC_PING,
+ IRC_PONG,
+ IRC_ERROR,
+ IRC_AWAY,
+ IRC_REHASH,
+ IRC_RESTART,
+ IRC_SUMMON,
+ IRC_USERS,
+ IRC_WALLOPS,
+ IRC_USERHOST,
+ IRC_ISON,
+ IRC_UNKNOWN
+} irc_command;
+
+// Parse the command type from a buffer containing text.
+irc_command irc_parse_command(const char* buffer, size_t len);
+
#endif
View
@@ -7,10 +7,28 @@
'deps/libuv/uv.gyp:libuv'
],
'include_dirs': [
- 'include'
+ 'include',
+ '>(SHARED_INTERMEDIATE_DIR)'
],
'sources': [
+ 'src/command-lookup.gperf',
'src/parser.c'
+ ],
+ 'rules': [
+ {
+ 'rule_name': 'gperf',
+ 'extension': 'gperf',
+ 'message': 'Generating lookup function from <(RULE_INPUT_PATH)',
+ 'outputs': [
+ '<(SHARED_INTERMEDIATE_DIR)/<(RULE_INPUT_ROOT).c'
+ ],
+ 'action': [
+ 'gperf',
+ '<(RULE_INPUT_PATH)',
+ '--output-file=<(SHARED_INTERMEDIATE_DIR)/<(RULE_INPUT_ROOT).c'
+ ],
+ 'process_outputs_as_sources': 1
+ }
]
},
View
@@ -0,0 +1,51 @@
+%struct-type
+%ignore-case
+%define lookup-function-name irc_lookup_command
+%{
+#include "irc.h"
+%}
+struct irc_command_entry {
+ const char* name;
+ irc_command command;
+};
+%%
+PASS, IRC_PASS
+NICK, IRC_NICK
+USER, IRC_USER
+SERVER, IRC_SERVER
+OPER, IRC_OPER
+QUIT, IRC_QUIT
+SQUIT, IRC_SQUIT
+JOIN, IRC_JOIN
+PART, IRC_PART
+MODE, IRC_MODE
+TOPIC, IRC_TOPIC
+NAMES, IRC_NAMES
+LIST, IRC_LIST
+INVITE, IRC_INVITE
+KICK, IRC_KICK
+VERSION, IRC_VERSION
+STATS, IRC_STATS
+LINKS, IRC_LINKS
+TIME, IRC_TIME
+CONNECT, IRC_CONNECT
+TRACE, IRC_TRACE
+ADMIN, IRC_ADMIN
+INFO, IRC_INFO
+PRIVMSG, IRC_PRIVMSG
+NOTICE, IRC_NOTICE
+WHO, IRC_WHO
+WHOIS, IRC_WHOIS
+WHOWAS, IRC_WHOWAS
+KILL, IRC_KILL
+PING, IRC_PING
+PONG, IRC_PONG
+ERROR, IRC_ERROR
+AWAY, IRC_AWAY
+REHASH, IRC_REHASH
+RESTART, IRC_RESTART
+SUMMON, IRC_SUMMON
+USERS, IRC_USERS
+WALLOPS, IRC_WALLOPS
+USERHOST, IRC_USERHOST
+ISON, IRC_ISON
View
@@ -1,5 +1,8 @@
#include "irc.h"
+// irc_lookup_command() generated by gperf.
+#include "command-lookup.c"
+
enum parser_state {
STATE_START,
STATE_PREFIX,
@@ -151,3 +154,8 @@ int irc_parser_execute(irc_parser_t* parser, const char* buffer, size_t len) {
return bytes_parsed;
}
+irc_command irc_parse_command(const char* buffer, size_t len) {
+ struct irc_command_entry* e = irc_lookup_command(buffer, len);
+ return e ? e->command : IRC_UNKNOWN;
+}
+
View
@@ -1,5 +1,7 @@
BENCHMARK_DECLARE (parse_messages)
+BENCHMARK_DECLARE (parse_commands)
TASK_LIST_START
BENCHMARK_ENTRY (parse_messages)
+ BENCHMARK_ENTRY (parse_commands)
TASK_LIST_END
@@ -42,3 +42,45 @@ BENCHMARK_IMPL(parse_messages) {
return 0;
}
+struct command_test {
+ const char* command;
+ irc_command type;
+ size_t len;
+};
+static struct command_test command_tests[] = {
+ {"PRIVMSG", IRC_PRIVMSG},
+ {"NICK", IRC_NICK},
+ {"USER", IRC_USER},
+ {"NOTICE", IRC_NOTICE},
+ {"JOIN", IRC_JOIN}
+};
+static int count = sizeof(command_tests) / sizeof *command_tests;
+
+BENCHMARK_IMPL(parse_commands) {
+ uv_loop_t* loop = uv_default_loop();
+
+ // Compute lengths of each command.
+ for (int i = 0; i < count; i++) {
+ command_tests[i].len = strlen(command_tests[i].command);
+ }
+
+ uv_update_time(loop);
+ int64_t start_time = uv_now(loop);
+
+ for (int i = 0; i < total_count; i++) {
+ for (int j = 0; j < count; j++) {
+ struct command_test t = command_tests[j];
+ ASSERT(irc_parse_command(t.command, t.len) == t.type);
+ }
+ }
+
+ uv_update_time(loop);
+ int64_t end_time = uv_now(loop);
+
+ LOGF("Parsed %i commands in %lld ms\n",
+ total_count * count, end_time - start_time);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
View
@@ -3,6 +3,7 @@ TEST_DECLARE (parse_message_prefix)
TEST_DECLARE (parse_message_middle)
TEST_DECLARE (parse_message_trailing)
TEST_DECLARE (parse_message_mixed)
+TEST_DECLARE (parse_command)
TEST_DECLARE (parse_illegal_first_byte_whitespace)
@@ -12,6 +13,7 @@ TASK_LIST_START
TEST_ENTRY (parse_message_middle)
TEST_ENTRY (parse_message_trailing)
TEST_ENTRY (parse_message_mixed)
+ TEST_ENTRY (parse_command)
TEST_ENTRY (parse_illegal_first_byte_whitespace)
TASK_LIST_END
View
@@ -102,3 +102,13 @@ TEST_IMPL(parse_message_mixed) {
return 0;
}
+TEST_IMPL(parse_command) {
+ static const char *pass = "PASS",
+ *pass_lc = "pass",
+ *unknown = "FOOBAR";
+ ASSERT(irc_parse_command(pass, strlen(pass)) == IRC_PASS);
+ ASSERT(irc_parse_command(pass_lc, strlen(pass_lc)) == IRC_PASS);
+ ASSERT(irc_parse_command(unknown, strlen(unknown)) == IRC_UNKNOWN);
+ return 0;
+}
+

0 comments on commit c32c992

Please sign in to comment.