Coverage Report

Created: 2026-07-30 06:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/pigeonhole/src/lib-sieve/tst-allof.c
Line
Count
Source
1
/* Copyright (c) Pigeonhole authors, see top-level COPYING file */
2
3
#include "sieve-common.h"
4
#include "sieve-commands.h"
5
#include "sieve-validator.h"
6
#include "sieve-generator.h"
7
#include "sieve-binary.h"
8
#include "sieve-code.h"
9
#include "sieve-binary.h"
10
11
/*
12
 * Allof test
13
 *
14
 * Syntax
15
 *   allof <tests: test-list>
16
 */
17
18
static bool
19
tst_allof_generate(const struct sieve_codegen_env *cgenv,
20
       struct sieve_command *ctx, struct sieve_jumplist *jumps,
21
       bool jump_true);
22
static bool
23
tst_allof_validate_const(struct sieve_validator *valdtr,
24
       struct sieve_command *tst, int *const_current,
25
       int const_new);
26
27
const struct sieve_command_def tst_allof = {
28
  .identifier = "allof",
29
  .type = SCT_TEST,
30
  .positional_args = 0,
31
  .subtests = 2,
32
  .block_allowed = FALSE,
33
  .block_required = FALSE,
34
  .validate_const = tst_allof_validate_const,
35
  .control_generate = tst_allof_generate
36
};
37
38
/*
39
 * Code validation
40
 */
41
42
static bool
43
tst_allof_validate_const(struct sieve_validator *valdtr ATTR_UNUSED,
44
       struct sieve_command *tst ATTR_UNUSED,
45
       int *const_current, int const_next)
46
0
{
47
0
  if (const_next == 0) {
48
0
    *const_current = 0;
49
0
    return FALSE;
50
0
  }
51
52
0
  if (*const_current != -1)
53
0
    *const_current = const_next;
54
0
  return TRUE;
55
0
}
56
57
/*
58
 * Code generation
59
 */
60
61
static bool
62
tst_allof_generate(const struct sieve_codegen_env *cgenv,
63
       struct sieve_command *ctx, struct sieve_jumplist *jumps,
64
       bool jump_true)
65
0
{
66
0
  struct sieve_binary_block *sblock = cgenv->sblock;
67
0
  struct sieve_ast_node *test;
68
0
  struct sieve_jumplist false_jumps;
69
70
0
  if (sieve_ast_test_count(ctx->ast_node) > 1) {
71
0
    if (jump_true) {
72
      /* Prepare jumplist */
73
0
      sieve_jumplist_init_temp(&false_jumps, sblock);
74
0
    }
75
76
0
    test = sieve_ast_test_first(ctx->ast_node);
77
0
    while (test != NULL) {
78
0
      bool result;
79
80
      /* If this test list must jump on false, all sub-tests
81
         can simply add their jumps to the caller's jump list,
82
         otherwise this test redirects all false jumps to the
83
         end of the currently generated code. This is just
84
         after a final jump to the true case
85
       */
86
0
      if (jump_true) {
87
0
        result = sieve_generate_test(
88
0
          cgenv, test, &false_jumps, FALSE);
89
0
      } else {
90
0
        result = sieve_generate_test(
91
0
          cgenv, test, jumps, FALSE);
92
0
      }
93
94
0
      if (!result)
95
0
        return FALSE;
96
97
0
      test = sieve_ast_test_next(test);
98
0
    }
99
100
0
    if (jump_true) {
101
      /* All tests succeeded, jump to case TRUE */
102
0
      sieve_operation_emit(cgenv->sblock, NULL,
103
0
               &sieve_jmp_operation);
104
0
      sieve_jumplist_add(
105
0
        jumps, sieve_binary_emit_offset(sblock, 0));
106
107
      /* All false exits jump here */
108
0
      sieve_jumplist_resolve(&false_jumps);
109
0
    }
110
0
  } else {
111
    /* Script author is being inefficient; we can optimize the allof
112
       test away */
113
0
    test = sieve_ast_test_first(ctx->ast_node);
114
0
    sieve_generate_test(cgenv, test, jumps, jump_true);
115
0
  }
116
117
0
  return TRUE;
118
0
}