summaryrefslogtreecommitdiff
path: root/src/sp_config_utils.c
blob: dbe6793a07f3f29afcf352fc38c28e7888a3db7b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#include "php_snuffleupagus.h"

int parse_keywords(sp_config_functions *funcs, char *line) {
  int value_len = 0;
  const char *original_line = line;
  for (size_t i = 0; funcs[i].func; i++) {
    if (!strncmp(funcs[i].token, line, strlen(funcs[i].token))) {
      line += strlen(funcs[i].token);
      value_len = funcs[i].func(line, funcs[i].token, funcs[i].retval) + 1;
      if (value_len == 0) {  // bad parameter
        return -1;
      }
      line += value_len;
      i = -1;  // we start the loop again
    }
  }
  while (*line == ';' || *line == '\t' || *line == ' ') {
    line++;
  }

  if (*line == '#') {
    return 0;
  }

  if (*line) {
    sp_log_err("config", "Trailing chars '%s' at the end of '%s' on line %zu",
               line, original_line, sp_line_no);
    return -1;
  }
  return 0;
}

zend_string *get_param(size_t *consumed, char *restrict line, sp_type type,
                       const char *restrict keyword) {
  enum { IN_ESCAPE, NONE } state = NONE;
  char *original_line = line;
  size_t j = 0;

  zend_string *ret = NULL;
  if (NULL == line || '\0' == *line) {
    goto err;
  }

  ret = zend_string_alloc(strlen(line) + 1, 1);

  /* The first char of a string is always '"', since they MUST be quoted. */
  if ('"' == *line) {
    line++;
  } else {
    goto err;
  }

  for (size_t i = 0; line[i] && j < strlen(original_line) - 2; i++) {
    switch (line[i]) {
      case '"':
        /* A double quote at this point is either:
          - at the very end of the string.
          - escaped
          */
        if ((state == NONE) && (line[i + 1] == SP_TOKEN_END_PARAM)) {
          /* The `+2` if for
           1. the terminal double-quote
           2. the SP_TOKEN_END_PARAM
           */
          *consumed = i + 2;
          // Make sure that the string we return is the right size,
          // as it can be smaller than strlen(line)
          ret = zend_string_truncate(ret, j, 1);
          // truncate does not add a \0
          ZSTR_VAL(ret)[ZSTR_LEN(ret)] = 0;
          return ret;
        } else if (state == IN_ESCAPE) {
          break;  // we're on an escped double quote
        } else {
          goto err;
        }
      case '\\':
        if (state == NONE) {
          state = IN_ESCAPE;
          continue;
        }
      default:
        break;
    }
    if (state == IN_ESCAPE) {
      state = NONE;
    }
    ZSTR_VAL(ret)[j++] = line[i];
  }
err:
  if (0 == j) {
    sp_log_err("error", "A valid string as parameter is expected on line %zu",
               sp_line_no);
  } else {
    sp_log_err("error",
               "There is an issue with the parsing of '%s': it doesn't look "
               "like a valid string on line %zu",
               original_line ? original_line : "NULL", sp_line_no);
  }
  line = NULL;
  return NULL;
}

zend_always_inline sp_list_node *parse_functions_list(char *value) {
  static const char *sep = ">";

  if (NULL == strchr(value, sep[0])) {
    return NULL;
  }

  sp_list_node *list = NULL;
  char *tmp = strdup(value);
  char *function_name;
  char *next_token = tmp;
  while ((function_name = strtok_r(NULL, sep, &next_token))) {
    list = sp_list_prepend(list, strdup(function_name));
  }
  free(tmp);

  return list;
}