Coverage Report

Created: 2026-09-03 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/pigeonhole/src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c
Line
Count
Source
1
/* Copyright (c) Pigeonhole authors, see top-level COPYING file */
2
3
/* Extension comparator-i;ascii-numeric
4
 * ------------------------------------
5
 *
6
 * Author: Stephan Bosch
7
 * Specification: RFC 2244
8
 * Implementation: full
9
 * Status: testing
10
 *
11
 */
12
13
#include "sieve-common.h"
14
15
#include "sieve-code.h"
16
#include "sieve-extensions.h"
17
#include "sieve-comparators.h"
18
#include "sieve-validator.h"
19
#include "sieve-generator.h"
20
#include "sieve-interpreter.h"
21
22
#include <ctype.h>
23
24
/*
25
 * Forward declarations
26
 */
27
28
static const struct sieve_operand_def my_comparator_operand;
29
30
const struct sieve_comparator_def i_ascii_numeric_comparator;
31
32
/*
33
 * Extension
34
 */
35
36
static bool
37
ext_cmp_i_ascii_numeric_validator_load(const struct sieve_extension *ext,
38
               struct sieve_validator *validator);
39
40
const struct sieve_extension_def comparator_i_ascii_numeric_extension = {
41
  .name = "comparator-i;ascii-numeric",
42
  .validator_load = ext_cmp_i_ascii_numeric_validator_load,
43
  SIEVE_EXT_DEFINE_OPERAND(my_comparator_operand)
44
};
45
46
static bool
47
ext_cmp_i_ascii_numeric_validator_load(const struct sieve_extension *ext,
48
               struct sieve_validator *validator)
49
0
{
50
0
  sieve_comparator_register(validator, ext, &i_ascii_numeric_comparator);
51
0
  return TRUE;
52
0
}
53
54
/*
55
 * Operand
56
 */
57
58
static const struct sieve_extension_objects ext_comparators =
59
  SIEVE_EXT_DEFINE_COMPARATOR(i_ascii_numeric_comparator);
60
61
static const struct sieve_operand_def my_comparator_operand = {
62
  .name = "comparator-i;ascii-numeric",
63
  .ext_def = &comparator_i_ascii_numeric_extension,
64
  .class = &sieve_comparator_operand_class,
65
  .interface = &ext_comparators,
66
};
67
68
/*
69
 * Comparator
70
 */
71
72
/* Forward declarations */
73
74
static int
75
cmp_i_ascii_numeric_compare(const struct sieve_comparator *cmp,
76
          const char *val1, size_t val1_size,
77
          const char *val2, size_t val2_size);
78
79
/* Comparator object */
80
81
const struct sieve_comparator_def i_ascii_numeric_comparator = {
82
  SIEVE_OBJECT("i;ascii-numeric", &my_comparator_operand, 0),
83
  .flags =
84
    SIEVE_COMPARATOR_FLAG_ORDERING |
85
    SIEVE_COMPARATOR_FLAG_EQUALITY,
86
  .compare = cmp_i_ascii_numeric_compare,
87
};
88
89
/* Comparator implementation */
90
91
static int
92
cmp_i_ascii_numeric_compare(const struct sieve_comparator *cmp ATTR_UNUSED,
93
          const char *val, size_t val_size,
94
          const char *key, size_t key_size)
95
0
{
96
0
  const char *vend = val + val_size;
97
0
  const char *kend = key + key_size;
98
0
  const char *vp = val;
99
0
  const char *kp = key;
100
0
  int digits, i;
101
102
  /* RFC 4790: All input is valid; strings that do not start with a digit
103
     represent positive infinity.
104
   */
105
0
  if (!i_isdigit(*vp)) {
106
0
    if (i_isdigit(*kp)) {
107
      /* Value is greater */
108
0
      return 1;
109
0
    }
110
0
  } else {
111
0
    if (!i_isdigit(*kp)) {
112
      /* Value is less */
113
0
      return -1;
114
0
    }
115
0
  }
116
117
  /* Ignore leading zeros */
118
119
0
  while (*vp == '0' && vp < vend)
120
0
    vp++;
121
0
  while (*kp == '0' && kp < kend)
122
0
    kp++;
123
124
  /* Check whether both numbers are equally long in terms of digits */
125
126
0
  digits = 0;
127
0
  while (vp < vend && kp < kend && i_isdigit(*vp) && i_isdigit(*kp)) {
128
0
    vp++;
129
0
    kp++;
130
0
    digits++;
131
0
  }
132
133
0
  if (vp == vend || !i_isdigit(*vp)) {
134
0
    if (kp != kend && i_isdigit(*kp)) {
135
      /* Value is less */
136
0
      return -1;
137
0
    }
138
0
  } else {
139
    /* Value is greater */
140
0
    return 1;
141
0
  }
142
143
  /* Equally long: compare digits */
144
145
0
  vp -= digits;
146
0
  kp -= digits;
147
0
  i = 0;
148
0
  while (i < digits) {
149
0
    if (*vp > *kp)
150
0
      return 1;
151
0
    else if (*vp < *kp)
152
0
      return -1;
153
154
0
    kp++;
155
0
    vp++;
156
0
    i++;
157
0
  }
158
159
0
  return 0;
160
0
}