aboutsummaryrefslogtreecommitdiffstats
path: root/src/blogc-git-receiver/shell-command-parser.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/blogc-git-receiver/shell-command-parser.c')
-rw-r--r--src/blogc-git-receiver/shell-command-parser.c125
1 files changed, 125 insertions, 0 deletions
diff --git a/src/blogc-git-receiver/shell-command-parser.c b/src/blogc-git-receiver/shell-command-parser.c
new file mode 100644
index 0000000..cc8c537
--- /dev/null
+++ b/src/blogc-git-receiver/shell-command-parser.c
@@ -0,0 +1,125 @@
+/*
+ * blogc: A blog compiler.
+ * Copyright (C) 2015-2016 Rafael G. Martins <rafael@rafaelmartins.eng.br>
+ *
+ * This program can be distributed under the terms of the BSD License.
+ * See the file LICENSE.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "../common/utils.h"
+#include "shell-command-parser.h"
+
+typedef enum {
+ START_COMMAND = 1,
+ START_REPO,
+ START_REPO2,
+ REPO,
+ START_ESCAPED,
+} command_state_t;
+
+
+char*
+bgr_shell_command_parse(const char *command)
+{
+ command_state_t state = START_COMMAND;
+ size_t start = 0;
+ size_t command_len = strlen(command);
+
+ bc_string_t *rv = bc_string_new();
+
+ for (size_t current = 0; current < command_len; current++) {
+
+ char c = command[current];
+
+ switch (state) {
+ case START_COMMAND:
+ if (c == ' ') {
+ if (((current == 16) &&
+ (0 == strncmp("git-receive-pack", command, 16))) ||
+ ((current == 15) &&
+ (0 == strncmp("git-upload-pack", command, 15))) ||
+ ((current == 18) &&
+ (0 == strncmp("git-upload-archive", command, 18))))
+ {
+ state = START_REPO;
+ break;
+ }
+ goto error;
+ }
+ break;
+
+ case START_REPO:
+ if (c == '\'') { // never saw git using double-quotes
+ state = START_REPO2;
+ break;
+ }
+ if (c == '\\') { // escaped ! or '
+ state = START_ESCAPED;
+ break;
+ }
+ goto error;
+
+ case START_REPO2:
+ if (c == '\'') {
+ state = START_REPO;
+ break;
+ }
+ start = current;
+ if (rv->len == 0 && c == '/') { // no absolute urls
+ start = current + 1;
+ }
+ state = REPO;
+ break;
+
+ case START_ESCAPED:
+ if (c == '!' || c == '\'') {
+ bc_string_append_c(rv, c);
+ state = START_REPO;
+ break;
+ }
+ goto error;
+
+ case REPO:
+ if (c == '\'') {
+ bc_string_append_len(rv, command + start, current - start);
+ state = START_REPO;
+ break;
+ }
+ break;
+ }
+ }
+
+ if (rv->len > 0)
+ return bc_string_free(rv, false);
+
+error:
+ bc_string_free(rv, true);
+ return NULL;
+}
+
+
+char*
+bgr_shell_quote(const char *command)
+{
+ // this does not really belongs here, but function is very small
+ bc_string_t *rv = bc_string_new();
+ bc_string_append_c(rv, '\'');
+ if (command != NULL) {
+ for (size_t i = 0; i < strlen(command); i++) {
+ switch (command[i]) {
+ case '!':
+ bc_string_append(rv, "'\\!'");
+ break;
+ case '\'':
+ bc_string_append(rv, "'\\''");
+ break;
+ default:
+ bc_string_append_c(rv, command[i]);
+ }
+ }
+ }
+ bc_string_append_c(rv, '\'');
+ return bc_string_free(rv, false);
+}