about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorMichael Vetter <jubalh@iodoru.org>2020-07-21 10:43:14 +0200
committerMichael Vetter <jubalh@iodoru.org>2020-07-21 10:45:29 +0200
commit5a9f76c16aaf58cabb9cf9cb84479a5eec2a24b1 (patch)
tree21ad6b72f1e6f03ea39fa40ef083c66c3452f9b5 /src
parent0077d02c8682826a21852963fd4bf97beee9b105 (diff)
downloadprofani-tty-5a9f76c16aaf58cabb9cf9cb84479a5eec2a24b1.tar.gz
parser.c: Use helper function to reduce duplicate code
`parse_args()` and `parse_args_with_freetext()` shared a lot of common
code.
Let's have a helper function `_parse_args_helper()` for that. The
`with_freetext` parameter will make it behave like
`parse_args_with_freetext()`.

In preparation for https://github.com/profanity-im/profanity/issues/1404
Diffstat (limited to 'src')
-rw-r--r--src/tools/parser.c193
1 files changed, 50 insertions, 143 deletions
diff --git a/src/tools/parser.c b/src/tools/parser.c
index 9818c178..7365f1a3 100644
--- a/src/tools/parser.c
+++ b/src/tools/parser.c
@@ -40,30 +40,8 @@
 
 #include "common.h"
 
-/*
- * Take a full line of input and return an array of strings representing
- * the arguments of a command.
- * If the number of arguments found is less than min, or more than max
- * NULL is returned.
- *
- * inp - The line of input
- * min - The minimum allowed number of arguments
- * max - The maximum allowed number of arguments
- *
- * Returns - An NULL terminated array of strings representing the arguments
- * of the command, or NULL if the validation fails.
- *
- * E.g. the following input line:
- *
- * /cmd arg1 arg2
- *
- * Will return a pointer to the following array:
- *
- * { "arg1", "arg2", NULL }
- *
- */
-gchar**
-parse_args(const char* const inp, int min, int max, gboolean* result)
+static gchar**
+_parse_args_helper(const char* const inp, int min, int max, gboolean* result, gboolean with_freetext)
 {
     if (inp == NULL) {
         *result = FALSE;
@@ -76,9 +54,11 @@ parse_args(const char* const inp, int min, int max, gboolean* result)
 
     int inp_size = g_utf8_strlen(copy, -1);
     gboolean in_token = FALSE;
+    gboolean in_freetext = FALSE;
     gboolean in_quotes = FALSE;
     char* token_start = &copy[0];
     int token_size = 0;
+    int num_tokens = 0;
     GSList* tokens = NULL;
 
     // add tokens to GSList
@@ -92,13 +72,22 @@ parse_args(const char* const inp, int min, int max, gboolean* result)
                 continue;
             } else {
                 in_token = TRUE;
-                if (curr_uni == '"') {
+                if (with_freetext) {
+                    num_tokens++;
+                }
+                if (with_freetext && (num_tokens == max + 1) && (curr_uni != '"')) {
+                    in_freetext = TRUE;
+                } else if (curr_uni == '"') {
                     in_quotes = TRUE;
                     i++;
                     gchar* next_ch = g_utf8_next_char(curr_ch);
                     gunichar next_uni = g_utf8_get_char(next_ch);
                     token_start = next_ch;
                     token_size += g_unichar_to_utf8(next_uni, NULL);
+                }
+                if (curr_uni == '"') {
+                    gchar* next_ch = g_utf8_next_char(curr_ch);
+                    token_start = next_ch;
                 } else {
                     token_start = curr_ch;
                     token_size += g_unichar_to_utf8(curr_uni, NULL);
@@ -113,15 +102,19 @@ parse_args(const char* const inp, int min, int max, gboolean* result)
                     in_token = FALSE;
                     in_quotes = FALSE;
                 } else {
-                    token_size += g_unichar_to_utf8(curr_uni, NULL);
+                    if (curr_uni != '"') {
+                        token_size += g_unichar_to_utf8(curr_uni, NULL);
+                    }
                 }
             } else {
-                if (curr_uni == ' ') {
+                if (with_freetext && in_freetext) {
+                    token_size += g_unichar_to_utf8(curr_uni, NULL);
+                } else if (curr_uni == ' ') {
                     tokens = g_slist_append(tokens, g_strndup(token_start,
                                                               token_size));
                     token_size = 0;
                     in_token = FALSE;
-                } else {
+                } else if (curr_uni != '"') {
                     token_size += g_unichar_to_utf8(curr_uni, NULL);
                 }
             }
@@ -171,6 +164,34 @@ parse_args(const char* const inp, int min, int max, gboolean* result)
 
 /*
  * Take a full line of input and return an array of strings representing
+ * the arguments of a command.
+ * If the number of arguments found is less than min, or more than max
+ * NULL is returned.
+ *
+ * inp - The line of input
+ * min - The minimum allowed number of arguments
+ * max - The maximum allowed number of arguments
+ *
+ * Returns - An NULL terminated array of strings representing the arguments
+ * of the command, or NULL if the validation fails.
+ *
+ * E.g. the following input line:
+ *
+ * /cmd arg1 arg2
+ *
+ * Will return a pointer to the following array:
+ *
+ * { "arg1", "arg2", NULL }
+ *
+ */
+gchar**
+parse_args(const char* const inp, int min, int max, gboolean* result)
+{
+    return _parse_args_helper(inp, min, max, result, FALSE);
+}
+
+/*
+ * Take a full line of input and return an array of strings representing
  * the arguments of a command.  This function handles when the last parameter
  * to the command is free text e.g.
  *
@@ -198,121 +219,7 @@ parse_args(const char* const inp, int min, int max, gboolean* result)
 gchar**
 parse_args_with_freetext(const char* const inp, int min, int max, gboolean* result)
 {
-    if (inp == NULL) {
-        *result = FALSE;
-        return NULL;
-    }
-
-    // copy and strip input of leading/trailing whitespace
-    char* copy = strdup(inp);
-    g_strstrip(copy);
-
-    int inp_size = g_utf8_strlen(copy, -1);
-    gboolean in_token = FALSE;
-    gboolean in_freetext = FALSE;
-    gboolean in_quotes = FALSE;
-    char* token_start = &copy[0];
-    int token_size = 0;
-    int num_tokens = 0;
-    GSList* tokens = NULL;
-
-    // add tokens to GSList
-    int i;
-    for (i = 0; i < inp_size; i++) {
-        gchar* curr_ch = g_utf8_offset_to_pointer(copy, i);
-        gunichar curr_uni = g_utf8_get_char(curr_ch);
-
-        if (!in_token) {
-            if (curr_uni == ' ') {
-                continue;
-            } else {
-                in_token = TRUE;
-                num_tokens++;
-                if ((num_tokens == max + 1) && (curr_uni != '"')) {
-                    in_freetext = TRUE;
-                } else if (curr_uni == '"') {
-                    in_quotes = TRUE;
-                    i++;
-                    gchar* next_ch = g_utf8_next_char(curr_ch);
-                    gunichar next_uni = g_utf8_get_char(next_ch);
-                    token_start = next_ch;
-                    token_size += g_unichar_to_utf8(next_uni, NULL);
-                }
-                if (curr_uni == '"') {
-                    gchar* next_ch = g_utf8_next_char(curr_ch);
-                    token_start = next_ch;
-                } else {
-                    token_start = curr_ch;
-                    token_size += g_unichar_to_utf8(curr_uni, NULL);
-                }
-            }
-        } else {
-            if (in_quotes) {
-                if (curr_uni == '"') {
-                    tokens = g_slist_append(tokens, g_strndup(token_start,
-                                                              token_size));
-                    token_size = 0;
-                    in_token = FALSE;
-                    in_quotes = FALSE;
-                } else {
-                    if (curr_uni != '"') {
-                        token_size += g_unichar_to_utf8(curr_uni, NULL);
-                    }
-                }
-            } else {
-                if (in_freetext) {
-                    token_size += g_unichar_to_utf8(curr_uni, NULL);
-                } else if (curr_uni == ' ') {
-                    tokens = g_slist_append(tokens, g_strndup(token_start,
-                                                              token_size));
-                    token_size = 0;
-                    in_token = FALSE;
-                } else if (curr_uni != '"') {
-                    token_size += g_unichar_to_utf8(curr_uni, NULL);
-                }
-            }
-        }
-    }
-
-    if (in_token) {
-        tokens = g_slist_append(tokens, g_strndup(token_start, token_size));
-    }
-
-    free(copy);
-
-    int num = g_slist_length(tokens) - 1;
-
-    // if num args not valid return NULL
-    if ((num < min) || (num > max)) {
-        g_slist_free_full(tokens, free);
-        *result = FALSE;
-        return NULL;
-
-        // if min allowed is 0 and 0 found, return empty char* array
-    } else if (min == 0 && num == 0) {
-        g_slist_free_full(tokens, free);
-        gchar** args = malloc((num + 1) * sizeof(*args));
-        args[0] = NULL;
-        *result = TRUE;
-        return args;
-
-        // 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) {
-            args[arg_count++] = strdup(token->data);
-            token = g_slist_next(token);
-        }
-
-        args[arg_count] = NULL;
-        g_slist_free_full(tokens, free);
-        *result = TRUE;
-        return args;
-    }
+    return _parse_args_helper(inp, min, max, result, TRUE);
 }
 
 int