Coverage Report

Created: 2026-01-10 06:18

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/git/parse.c
Line
Count
Source
1
#include "git-compat-util.h"
2
#include "gettext.h"
3
#include "parse.h"
4
5
static uintmax_t get_unit_factor(const char *end)
6
0
{
7
0
  if (!*end)
8
0
    return 1;
9
0
  else if (!strcasecmp(end, "k"))
10
0
    return 1024;
11
0
  else if (!strcasecmp(end, "m"))
12
0
    return 1024 * 1024;
13
0
  else if (!strcasecmp(end, "g"))
14
0
    return 1024 * 1024 * 1024;
15
0
  return 0;
16
0
}
17
18
int git_parse_signed(const char *value, intmax_t *ret, intmax_t max)
19
0
{
20
0
  if (value && *value) {
21
0
    char *end;
22
0
    intmax_t val;
23
0
    intmax_t factor;
24
25
0
    if (max < 0)
26
0
      BUG("max must be a positive integer");
27
28
0
    errno = 0;
29
0
    val = strtoimax(value, &end, 0);
30
0
    if (errno == ERANGE)
31
0
      return 0;
32
0
    if (end == value) {
33
0
      errno = EINVAL;
34
0
      return 0;
35
0
    }
36
0
    factor = get_unit_factor(end);
37
0
    if (!factor) {
38
0
      errno = EINVAL;
39
0
      return 0;
40
0
    }
41
0
    if ((val < 0 && (-max - 1) / factor > val) ||
42
0
        (val > 0 && max / factor < val)) {
43
0
      errno = ERANGE;
44
0
      return 0;
45
0
    }
46
0
    val *= factor;
47
0
    *ret = val;
48
0
    return 1;
49
0
  }
50
0
  errno = EINVAL;
51
0
  return 0;
52
0
}
53
54
int git_parse_unsigned(const char *value, uintmax_t *ret, uintmax_t max)
55
0
{
56
0
  if (value && *value) {
57
0
    char *end;
58
0
    uintmax_t val;
59
0
    uintmax_t factor;
60
61
    /* negative values would be accepted by strtoumax */
62
0
    if (strchr(value, '-')) {
63
0
      errno = EINVAL;
64
0
      return 0;
65
0
    }
66
0
    errno = 0;
67
0
    val = strtoumax(value, &end, 0);
68
0
    if (errno == ERANGE)
69
0
      return 0;
70
0
    if (end == value) {
71
0
      errno = EINVAL;
72
0
      return 0;
73
0
    }
74
0
    factor = get_unit_factor(end);
75
0
    if (!factor) {
76
0
      errno = EINVAL;
77
0
      return 0;
78
0
    }
79
0
    if (unsigned_mult_overflows(factor, val) ||
80
0
        factor * val > max) {
81
0
      errno = ERANGE;
82
0
      return 0;
83
0
    }
84
0
    val *= factor;
85
0
    *ret = val;
86
0
    return 1;
87
0
  }
88
0
  errno = EINVAL;
89
0
  return 0;
90
0
}
91
92
int git_parse_int(const char *value, int *ret)
93
0
{
94
0
  intmax_t tmp;
95
0
  if (!git_parse_signed(value, &tmp, maximum_signed_value_of_type(int)))
96
0
    return 0;
97
0
  *ret = tmp;
98
0
  return 1;
99
0
}
100
101
int git_parse_int64(const char *value, int64_t *ret)
102
0
{
103
0
  intmax_t tmp;
104
0
  if (!git_parse_signed(value, &tmp, maximum_signed_value_of_type(int64_t)))
105
0
    return 0;
106
0
  *ret = tmp;
107
0
  return 1;
108
0
}
109
110
int git_parse_ulong(const char *value, unsigned long *ret)
111
0
{
112
0
  uintmax_t tmp;
113
0
  if (!git_parse_unsigned(value, &tmp, maximum_unsigned_value_of_type(long)))
114
0
    return 0;
115
0
  *ret = tmp;
116
0
  return 1;
117
0
}
118
119
int git_parse_ssize_t(const char *value, ssize_t *ret)
120
0
{
121
0
  intmax_t tmp;
122
0
  if (!git_parse_signed(value, &tmp, maximum_signed_value_of_type(ssize_t)))
123
0
    return 0;
124
0
  *ret = tmp;
125
0
  return 1;
126
0
}
127
128
int git_parse_double(const char *value, double *ret)
129
0
{
130
0
  char *end;
131
0
  double val;
132
0
  uintmax_t factor;
133
134
0
  if (!value || !*value) {
135
0
    errno = EINVAL;
136
0
    return 0;
137
0
  }
138
139
0
  errno = 0;
140
0
  val = strtod(value, &end);
141
0
  if (errno == ERANGE)
142
0
    return 0;
143
0
  if (end == value) {
144
0
    errno = EINVAL;
145
0
    return 0;
146
0
  }
147
0
  factor = get_unit_factor(end);
148
0
  if (!factor) {
149
0
    errno = EINVAL;
150
0
    return 0;
151
0
  }
152
0
  val *= factor;
153
0
  *ret = val;
154
0
  return 1;
155
0
}
156
157
int git_parse_maybe_bool_text(const char *value)
158
0
{
159
0
  if (!value)
160
0
    return 1;
161
0
  if (!*value)
162
0
    return 0;
163
0
  if (!strcasecmp(value, "true")
164
0
      || !strcasecmp(value, "yes")
165
0
      || !strcasecmp(value, "on"))
166
0
    return 1;
167
0
  if (!strcasecmp(value, "false")
168
0
      || !strcasecmp(value, "no")
169
0
      || !strcasecmp(value, "off"))
170
0
    return 0;
171
0
  return -1;
172
0
}
173
174
int git_parse_maybe_bool(const char *value)
175
0
{
176
0
  int v = git_parse_maybe_bool_text(value);
177
0
  if (0 <= v)
178
0
    return v;
179
0
  if (git_parse_int(value, &v))
180
0
    return !!v;
181
0
  return -1;
182
0
}
183
184
/*
185
 * Parse environment variable 'k' as a boolean (in various
186
 * possible spellings); if missing, use the default value 'def'.
187
 */
188
int git_env_bool(const char *k, int def)
189
0
{
190
0
  const char *v = getenv(k);
191
0
  int val;
192
0
  if (!v)
193
0
    return def;
194
0
  val = git_parse_maybe_bool(v);
195
0
  if (val < 0)
196
0
    die(_("bad boolean environment value '%s' for '%s'"),
197
0
        v, k);
198
0
  return val;
199
0
}
200
201
/*
202
 * Parse environment variable 'k' as ulong with possibly a unit
203
 * suffix; if missing, use the default value 'val'.
204
 */
205
unsigned long git_env_ulong(const char *k, unsigned long val)
206
1
{
207
1
  const char *v = getenv(k);
208
1
  if (v && !git_parse_ulong(v, &val))
209
0
    die(_("failed to parse %s"), k);
210
1
  return val;
211
1
}