Coverage Report

Created: 2026-08-08 06:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/pigeonhole/src/testsuite/testsuite-arguments.c
Line
Count
Source
1
/* Copyright (c) Pigeonhole authors, see top-level COPYING file */
2
3
#include "lib.h"
4
#include "str.h"
5
#include "str-sanitize.h"
6
#include "array.h"
7
8
#include "sieve-common.h"
9
#include "sieve-ast.h"
10
#include "sieve-commands.h"
11
#include "sieve-code.h"
12
#include "sieve-validator.h"
13
#include "sieve-generator.h"
14
#include "sieve-dump.h"
15
16
#include "testsuite-common.h"
17
#include "testsuite-substitutions.h"
18
#include "testsuite-arguments.h"
19
20
#include <ctype.h>
21
22
/*
23
 * Testsuite string argument
24
 */
25
26
static bool
27
arg_testsuite_string_validate(struct sieve_validator *validator,
28
            struct sieve_ast_argument **arg,
29
            struct sieve_command *context);
30
31
const struct sieve_argument_def testsuite_string_argument = {
32
  .identifier = "@testsuite-string",
33
  .validate = arg_testsuite_string_validate,
34
  .generate = sieve_arg_catenated_string_generate,
35
};
36
37
static bool
38
arg_testsuite_string_validate(struct sieve_validator *valdtr,
39
            struct sieve_ast_argument **arg,
40
            struct sieve_command *cmd)
41
0
{
42
0
  enum { ST_NONE, ST_OPEN, ST_SUBSTITUTION, ST_PARAM, ST_CLOSE } state =
43
0
    ST_NONE;
44
0
  pool_t pool = sieve_ast_pool((*arg)->ast);
45
0
  struct sieve_arg_catenated_string *catstr = NULL;
46
0
  string_t *str = sieve_ast_argument_str(*arg);
47
0
  const char *p, *strstart, *substart = NULL;
48
0
  const char *strval = (const char *) str_data(str);
49
0
  const char *strend = strval + str_len(str);
50
0
  bool result = TRUE;
51
0
  string_t *subs_name = t_str_new(256);
52
0
  string_t *subs_param = t_str_new(256);
53
54
0
  T_BEGIN {
55
    /* Initialize substitution structure */
56
57
0
    p = strval;
58
0
    strstart = p;
59
0
    while (result && p < strend) {
60
0
      switch (state) {
61
      /* Nothing found yet */
62
0
      case ST_NONE:
63
0
        if (*p == '%') {
64
0
          substart = p;
65
0
          state = ST_OPEN;
66
0
          str_truncate(subs_name, 0);
67
0
          str_truncate(subs_param, 0);
68
0
        }
69
0
        p++;
70
0
        break;
71
      /* Got '%' */
72
0
      case ST_OPEN:
73
0
        if (*p == '{') {
74
0
          state = ST_SUBSTITUTION;
75
0
          p++;
76
0
        } else
77
0
          state = ST_NONE;
78
0
        break;
79
80
      /* Got '%{' */
81
0
      case ST_SUBSTITUTION:
82
0
        state = ST_PARAM;
83
84
0
        while (*p != '}' && *p != ':') {
85
0
          if (!i_isalnum(*p)) {
86
0
            state = ST_NONE;
87
0
            break;
88
0
          }
89
0
          str_append_c(subs_name, *p);
90
0
          p++;
91
0
        }
92
0
        break;
93
      /* Got '%{name' */
94
0
      case ST_PARAM:
95
0
        if (*p == ':') {
96
0
          p++;
97
0
          while (*p != '}') {
98
0
            str_append_c(subs_param, *p);
99
0
            p++;
100
0
          }
101
0
        }
102
0
        state = ST_CLOSE;
103
0
        break;
104
      /* Finished parsing param, expecting '}' */
105
0
      case ST_CLOSE:
106
0
        if (*p == '}') {
107
0
          struct sieve_ast_argument *strarg;
108
109
          /* We now know that the substitution is valid */
110
111
0
          if (catstr == NULL)
112
0
            catstr = sieve_arg_catenated_string_create(*arg);
113
114
          /* Add the substring that is before the substitution to the
115
             variable-string AST.
116
           */
117
0
          if (substart > strstart) {
118
0
            string_t *newstr = str_new(pool, substart - strstart);
119
0
            str_append_data(newstr, strstart, substart - strstart);
120
121
0
            strarg = sieve_ast_argument_string_create_raw(
122
0
              (*arg)->ast, newstr, (*arg)->source_line);
123
0
            sieve_arg_catenated_string_add_element(catstr, strarg);
124
125
            /* Give other substitution extensions a chance to do
126
               their work */
127
0
            if (!sieve_validator_argument_activate_super(
128
0
              valdtr, cmd, strarg, FALSE)) {
129
0
              result = FALSE;
130
0
              break;
131
0
            }
132
0
          }
133
134
0
          strarg = testsuite_substitution_argument_create(
135
0
            valdtr, (*arg)->ast, (*arg)->source_line,
136
0
            str_c(subs_name), str_c(subs_param));
137
0
          if (strarg != NULL)
138
0
            sieve_arg_catenated_string_add_element(catstr, strarg);
139
0
          else {
140
0
            sieve_argument_validate_error(
141
0
              valdtr, *arg,
142
0
              "unknown testsuite substitution type '%s'",
143
0
              str_c(subs_name));
144
0
          }
145
146
0
          strstart = p + 1;
147
0
          substart = strstart;
148
0
          p++;
149
0
        }
150
151
        /* Finished, reset for the next substitution */
152
0
        state = ST_NONE;
153
0
      }
154
0
    }
155
0
  } T_END;
156
157
  /* Bail out early if substitution is invalid */
158
0
  if (!result)
159
0
    return FALSE;
160
161
  /* Check whether any substitutions were found */
162
0
  if (catstr == NULL) {
163
    /* No substitutions in this string, pass it on to any other
164
       substution extension.
165
     */
166
0
    return sieve_validator_argument_activate_super(
167
0
      valdtr, cmd, *arg, TRUE);
168
0
  }
169
170
  /* Add the final substring that comes after the last substitution to the
171
     variable-string AST.
172
   */
173
0
  if (strend > strstart) {
174
0
    struct sieve_ast_argument *strarg;
175
0
    string_t *newstr = str_new(pool, strend - strstart);
176
0
    str_append_data(newstr, strstart, strend - strstart);
177
178
0
    strarg = sieve_ast_argument_string_create_raw(
179
0
      (*arg)->ast, newstr, (*arg)->source_line);
180
0
    sieve_arg_catenated_string_add_element(catstr, strarg);
181
182
    /* Give other substitution extensions a chance to do their work.
183
     */
184
0
    if (!sieve_validator_argument_activate_super(valdtr, cmd,
185
0
                   strarg, FALSE))
186
0
      return FALSE;
187
0
  }
188
0
  return TRUE;
189
0
}