From 824eaa1678043afd8e31e4de529aaf61165295d7 Mon Sep 17 00:00:00 2001 From: James Booth Date: Sun, 18 Nov 2012 00:07:00 +0000 Subject: [PATCH] Added parser module --- Makefile.am | 4 +- src/command.c | 44 ++++----------- src/contact_list.c | 2 - src/parser.c | 96 +++++++++++++++++++++++++++++++++ src/parser.h | 30 +++++++++++ tests/test_parser.c | 127 ++++++++++++++++++++++++++++++++++++++++++++ tests/testsuite.c | 1 + tests/testsuite.h | 1 + 8 files changed, 266 insertions(+), 39 deletions(-) create mode 100644 src/parser.c create mode 100644 src/parser.h create mode 100644 tests/test_parser.c diff --git a/Makefile.am b/Makefile.am index 66304e99..e0e3b01b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -8,14 +8,14 @@ profanity_SOURCES = src/command.c src/contact.c src/history.c src/jabber.h \ src/main.c src/profanity.h src/prof_history.h src/chat_log.c \ src/chat_log.h src/tinyurl.c src/tinyurl.h src/chat_session.c \ src/chat_session.h src/release.c src/release.h src/room_chat.c \ - src/room_chat.h src/stanza.c src/stanza.h + src/room_chat.h src/stanza.c src/stanza.h src/parser.c src/parser.h TESTS = tests/testsuite check_PROGRAMS = tests/testsuite tests_testsuite_SOURCES = tests/test_contact_list.c src/contact_list.c src/contact.c \ tests/test_common.c tests/test_prof_history.c src/prof_history.c src/common.c \ tests/test_prof_autocomplete.c src/prof_autocomplete.c tests/testsuite.c \ - src/log.c + tests/test_parser.c src/parser.c tests_testsuite_LDADD = -lheadunit -lstdc++ man_MANS = docs/profanity.1 diff --git a/src/command.c b/src/command.c index a02c77e9..160c8091 100644 --- a/src/command.c +++ b/src/command.c @@ -36,6 +36,7 @@ #include "history.h" #include "jabber.h" #include "log.h" +#include "parser.h" #include "preferences.h" #include "prof_autocomplete.h" #include "tinyurl.h" @@ -835,7 +836,7 @@ _cmd_connect(const char * const inp, struct cmd_help_t help) { gboolean result = FALSE; int num_args = 0; - gchar **args = _cmd_parse_args(inp, 1, 1, &num_args); + gchar **args = parse_args(inp, 1, 1, &num_args); if (args == NULL) { cons_show("Usage: %s", help.usage); @@ -882,7 +883,7 @@ _cmd_sub(const char * const inp, struct cmd_help_t help) { gboolean result = FALSE; int num_args = 0; - gchar **args = _cmd_parse_args(inp, 1, 2, &num_args); + gchar **args = parse_args(inp, 1, 2, &num_args); if (args == NULL) { cons_show("Usage: %s", help.usage); @@ -1220,7 +1221,7 @@ _cmd_info(const char * const inp, struct cmd_help_t help) { gboolean result = FALSE; int num_args = 0; - gchar **args = _cmd_parse_args(inp, 1, 1, &num_args); + gchar **args = parse_args(inp, 1, 1, &num_args); if (args == NULL) { cons_show("Usage: %s", help.usage); @@ -1252,7 +1253,7 @@ _cmd_join(const char * const inp, struct cmd_help_t help) { gboolean result = FALSE; int num_args = 0; - gchar **args = _cmd_parse_args(inp, 1, 2, &num_args); + gchar **args = parse_args(inp, 1, 2, &num_args); if (args == NULL) { cons_show("Usage: %s", help.usage); @@ -1296,7 +1297,7 @@ _cmd_tiny(const char * const inp, struct cmd_help_t help) { gboolean result = FALSE; int num_args = 0; - gchar **args = _cmd_parse_args(inp, 1, 1, &num_args); + gchar **args = parse_args(inp, 1, 1, &num_args); if (args == NULL) { cons_show("Usage: %s", help.usage); @@ -1401,7 +1402,7 @@ _cmd_set_notify(const char * const inp, struct cmd_help_t help) { gboolean result = FALSE; int num_args = 0; - gchar **args = _cmd_parse_args(inp, 2, 2, &num_args); + gchar **args = parse_args(inp, 2, 2, &num_args); if (args == NULL) { cons_show("Usage: %s", help.usage); @@ -1463,7 +1464,7 @@ _cmd_set_log(const char * const inp, struct cmd_help_t help) { gboolean result = FALSE; int num_args = 0; - gchar **args = _cmd_parse_args(inp, 2, 2, &num_args); + gchar **args = parse_args(inp, 2, 2, &num_args); if (args == NULL) { cons_show("Usage: %s", help.usage); @@ -1496,7 +1497,7 @@ _cmd_set_priority(const char * const inp, struct cmd_help_t help) { gboolean result = FALSE; int num_args = 0; - gchar **args = _cmd_parse_args(inp, 1, 1, &num_args); + gchar **args = parse_args(inp, 1, 1, &num_args); if (args == NULL) { cons_show("Usage: %s", help.usage); @@ -1805,30 +1806,3 @@ _strtoi(char *str, int *saveptr, int min, int max) return 0; } - -gchar ** -_cmd_parse_args(const char * const inp, int min, int max, int *num) -{ - char *copy = strdup(inp); - gchar **args = NULL; - g_strstrip(copy); - gchar **split = g_strsplit(copy, " ", 0); - *num = g_strv_length(split) - 1; - - if ((*num < min) || (*num > max)) { - g_strfreev(split); - free(copy); - return NULL; - } else { - args = malloc((*num + 1) * sizeof(*args)); - int i; - for (i = 0; i < *num; i++) { - args[i] = strdup(split[i+1]); - } - args[i] = NULL; - g_strfreev(split); - free(copy); - - return args; - } -} diff --git a/src/contact_list.c b/src/contact_list.c index d05d7412..714750dd 100644 --- a/src/contact_list.c +++ b/src/contact_list.c @@ -25,7 +25,6 @@ #include #include "contact.h" -#include "log.h" #include "prof_autocomplete.h" static PAutocomplete ac; @@ -80,7 +79,6 @@ contact_list_update_contact(const char * const jid, const char * const presence, PContact contact = g_hash_table_lookup(contacts, jid); if (contact == NULL) { - log_warning("Contact not in list: %s", jid); return FALSE; } diff --git a/src/parser.c b/src/parser.c new file mode 100644 index 00000000..5034c215 --- /dev/null +++ b/src/parser.c @@ -0,0 +1,96 @@ +/* + * parser.c + * + * Copyright (C) 2012 James Booth + * + * This file is part of Profanity. + * + * Profanity is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Profanity is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Profanity. If not, see . + * + */ + +#include +#include + +#include + +gchar ** +parse_args(const char * const inp, int min, int max, int *num) +{ + if (inp == NULL) { + *num = 0; + return NULL; + } + + // copy and strip input of leading/trailing whitepsace + char *copy = strdup(inp); + g_strstrip(copy); + + int inp_size = strlen(copy); + gboolean in_token = FALSE; + char *token_start = ©[0]; + int token_size = 0; + GSList *tokens = NULL; + + // add tokens to GSList + int i; + for (i = 0; i <= inp_size; i++) { + if (!in_token) { + if (copy[i] == ' ') { + continue; + } else { + in_token = TRUE; + token_start = ©[i]; + token_size++; + } + } else { + if (copy[i] == ' ' || copy[i] == '\0') { + tokens = g_slist_append(tokens, g_strndup(token_start, + token_size)); + token_size = 0; + in_token = FALSE; + } else { + token_size++; + } + } + } + + *num = g_slist_length(tokens) - 1; + + // if num args not valid return NULL + if ((*num < min) || (*num > max)) { + g_slist_free_full(tokens, free); + free(copy); + *num = 0; + return NULL; + + // otherwise return args array + } else { + gchar **args = malloc((*num + 1) * sizeof(*args)); + GSList *token = tokens; + token = g_slist_next(token); + int arg_count = 0; + + while (token != NULL) { + args[arg_count++] = strdup(token->data); + token = g_slist_next(token); + } + + args[arg_count] = NULL; + g_slist_free_full(tokens, free); + free(copy); + + return args; + } +} diff --git a/src/parser.h b/src/parser.h new file mode 100644 index 00000000..a0442f33 --- /dev/null +++ b/src/parser.h @@ -0,0 +1,30 @@ +/* + * parser.h + * + * Copyright (C) 2012 James Booth + * + * This file is part of Profanity. + * + * Profanity is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Profanity is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Profanity. If not, see . + * + */ + +#ifndef PARSER_H +#define PARSER_H + +#include + +gchar** parse_args(const char * const inp, int min, int max, int *num); + +#endif diff --git a/tests/test_parser.c b/tests/test_parser.c new file mode 100644 index 00000000..40d4fc28 --- /dev/null +++ b/tests/test_parser.c @@ -0,0 +1,127 @@ +#include +#include +#include +#include "parser.h" + +void +parse_null_returns_null(void) +{ + char *inp = NULL; + int num = 0; + gchar **result = parse_args(inp, 1, 2, &num); + + assert_is_null(result); + g_strfreev(result); +} + +void +parse_empty_returns_null(void) +{ + char *inp = ""; + int num = 0; + gchar **result = parse_args(inp, 1, 2, &num); + + assert_is_null(result); + g_strfreev(result); +} + +void +parse_space_returns_null(void) +{ + char *inp = " "; + int num = 0; + gchar **result = parse_args(inp, 1, 2, &num); + + assert_is_null(result); + g_strfreev(result); +} + +void +parse_cmd_no_args_returns_null(void) +{ + char *inp = "/cmd"; + int num = 0; + gchar **result = parse_args(inp, 1, 2, &num); + + assert_is_null(result); + g_strfreev(result); +} + +void +parse_cmd_with_space_returns_null(void) +{ + char *inp = "/cmd "; + int num = 0; + gchar **result = parse_args(inp, 1, 2, &num); + + assert_is_null(result); + g_strfreev(result); +} + +void +parse_cmd_one_arg(void) +{ + char *inp = "/cmd arg1"; + int num = 0; + gchar **result = parse_args(inp, 1, 2, &num); + + assert_int_equals(1, num); + assert_string_equals("arg1", result[0]); + g_strfreev(result); +} + +void +parse_cmd_two_args(void) +{ + char *inp = "/cmd arg1 arg2"; + int num = 0; + gchar **result = parse_args(inp, 1, 2, &num); + + assert_int_equals(2, num); + assert_string_equals("arg1", result[0]); + assert_string_equals("arg2", result[1]); + g_strfreev(result); +} + +void +parse_cmd_three_args(void) +{ + char *inp = "/cmd arg1 arg2 arg3"; + int num = 0; + gchar **result = parse_args(inp, 3, 3, &num); + + assert_int_equals(3, num); + assert_string_equals("arg1", result[0]); + assert_string_equals("arg2", result[1]); + assert_string_equals("arg3", result[2]); + g_strfreev(result); +} + +void +parse_cmd_three_args_with_spaces(void) +{ + char *inp = " /cmd arg1 arg2 arg3 "; + int num = 0; + gchar **result = parse_args(inp, 3, 3, &num); + + assert_int_equals(3, num); + assert_string_equals("arg1", result[0]); + assert_string_equals("arg2", result[1]); + assert_string_equals("arg3", result[2]); + g_strfreev(result); +} + +void +register_parser_tests(void) +{ + TEST_MODULE("parser tests"); + TEST(parse_null_returns_null); + TEST(parse_empty_returns_null); + TEST(parse_space_returns_null); + TEST(parse_cmd_no_args_returns_null); + TEST(parse_cmd_with_space_returns_null); + TEST(parse_cmd_one_arg); + TEST(parse_cmd_two_args); + TEST(parse_cmd_three_args); + TEST(parse_cmd_three_args_with_spaces); +} diff --git a/tests/testsuite.c b/tests/testsuite.c index e7a23005..7c1b81dc 100644 --- a/tests/testsuite.c +++ b/tests/testsuite.c @@ -7,6 +7,7 @@ int main(void) register_contact_list_tests(); register_common_tests(); register_prof_autocomplete_tests(); + register_parser_tests(); run_suite(); return 0; } diff --git a/tests/testsuite.h b/tests/testsuite.h index 45145c9b..029cd48c 100644 --- a/tests/testsuite.h +++ b/tests/testsuite.h @@ -5,5 +5,6 @@ void register_prof_history_tests(void); void register_contact_list_tests(void); void register_common_tests(void); void register_prof_autocomplete_tests(void); +void register_parser_tests(void); #endif