Coverage Report

Created: 2026-02-26 07:07

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/PROJ/src/param.cpp
Line
Count
Source
1
/* put parameters in linked list and retrieve */
2
3
#include <ctype.h>
4
#include <stddef.h>
5
#include <stdio.h>
6
#include <stdlib.h>
7
#include <string.h>
8
9
#include "proj.h"
10
#include "proj_internal.h"
11
12
/* create parameter list entry */
13
3.16M
paralist *pj_mkparam(const char *str) {
14
3.16M
    paralist *newitem;
15
16
3.16M
    if ((newitem = (paralist *)malloc(sizeof(paralist) + strlen(str))) !=
17
3.16M
        nullptr) {
18
3.16M
        newitem->used = 0;
19
3.16M
        newitem->next = nullptr;
20
3.16M
        if (*str == '+')
21
833
            ++str;
22
3.16M
        (void)strcpy(newitem->param, str);
23
3.16M
    }
24
3.16M
    return newitem;
25
3.16M
}
26
27
/* As pj_mkparam, but payload ends at first whitespace, rather than at end of
28
 * <str> */
29
1.13k
paralist *pj_mkparam_ws(const char *str, const char **next_str) {
30
1.13k
    paralist *newitem;
31
1.13k
    size_t len = 0;
32
33
1.13k
    if (nullptr == str)
34
0
        return nullptr;
35
36
    /* Find start and length of string */
37
2.06k
    while (isspace(*str))
38
924
        str++;
39
1.13k
    if (*str == '+')
40
0
        str++;
41
1.13k
    bool in_string = false;
42
16.9k
    for (; str[len] != '\0'; len++) {
43
16.7k
        if (in_string) {
44
0
            if (str[len] == '"' && str[len + 1] == '"') {
45
0
                len++;
46
0
            } else if (str[len] == '"') {
47
0
                in_string = false;
48
0
            }
49
16.7k
        } else if (str[len] == '=' && str[len + 1] == '"') {
50
0
            in_string = true;
51
16.7k
        } else if (isspace(str[len])) {
52
924
            break;
53
924
        }
54
16.7k
    }
55
56
1.13k
    if (next_str)
57
1.13k
        *next_str = str + len;
58
59
    /* Use calloc to automagically 0-terminate the copy */
60
1.13k
    newitem = (paralist *)calloc(1, sizeof(paralist) + len + 1);
61
1.13k
    if (nullptr == newitem)
62
0
        return nullptr;
63
1.13k
    memcpy(newitem->param, str, len);
64
65
1.13k
    newitem->used = 0;
66
1.13k
    newitem->next = nullptr;
67
68
1.13k
    return newitem;
69
1.13k
}
70
71
/**************************************************************************************/
72
8.71M
paralist *pj_param_exists(paralist *list, const char *parameter) {
73
    /***************************************************************************************
74
        Determine whether a given parameter exists in a paralist. If it does,
75
    return a pointer to the corresponding list element - otherwise return 0.
76
77
        In support of the pipeline syntax, the search is terminated once a
78
    "+step" list element is reached, in which case a 0 is returned, unless the
79
    parameter searched for is actually "step", in which case a pointer to the
80
    "step" list element is returned.
81
82
        This function is equivalent to the pj_param (...) call with the "opt"
83
    argument set to the parameter name preceeeded by a 't'. But by using this
84
    one, one avoids writing the code allocating memory for a new copy of
85
    parameter name, and prepending the t (for compile time known names, this is
86
    obviously not an issue).
87
    ***************************************************************************************/
88
8.71M
    paralist *next = list;
89
8.71M
    const char *c = strchr(parameter, '=');
90
8.71M
    size_t len = strlen(parameter);
91
8.71M
    if (c)
92
0
        len = c - parameter;
93
8.71M
    if (list == nullptr)
94
0
        return nullptr;
95
96
93.8M
    for (next = list; next; next = next->next) {
97
86.2M
        if (0 == strncmp(parameter, next->param, len) &&
98
1.23M
            (next->param[len] == '=' || next->param[len] == 0)) {
99
1.14M
            next->used = 1;
100
1.14M
            return next;
101
1.14M
        }
102
85.1M
        if (0 == strcmp(parameter, "step"))
103
0
            return nullptr;
104
85.1M
    }
105
106
7.57M
    return nullptr;
107
8.71M
}
108
109
/************************************************************************/
110
/*                              pj_param()                              */
111
/*                                                                      */
112
/*      Test for presence or get parameter value.  The first            */
113
/*      character in `opt' is a parameter type which can take the       */
114
/*      values:                                                         */
115
/*                                                                      */
116
/*       `t' - test for presence, return TRUE/FALSE in PROJVALUE.i      */
117
/*       `i' - integer value returned in PROJVALUE.i                    */
118
/*       `d' - simple valued real input returned in PROJVALUE.f         */
119
/*       `r' - degrees (DMS translation applied), returned as           */
120
/*             radians in PROJVALUE.f                                   */
121
/*       `s' - string returned in PROJVALUE.s                           */
122
/*       `b' - test for t/T/f/F, return in PROJVALUE.i                  */
123
/*                                                                      */
124
/*      Search is terminated when "step" is found, in which case        */
125
/*      0 is returned, unless "step" was the target searched for.       */
126
/*                                                                      */
127
/************************************************************************/
128
129
5.79M
PROJVALUE pj_param(PJ_CONTEXT *ctx, paralist *pl, const char *opt) {
130
131
5.79M
    int type;
132
5.79M
    unsigned l;
133
5.79M
    PROJVALUE value = {0};
134
135
5.79M
    if (ctx == nullptr)
136
0
        ctx = pj_get_default_ctx();
137
138
5.79M
    type = *opt++;
139
140
5.79M
    if (nullptr == strchr("tbirds", type)) {
141
0
        fprintf(stderr, "invalid request to pj_param, fatal\n");
142
0
        exit(1);
143
0
    }
144
145
5.79M
    pl = pj_param_exists(pl, opt);
146
5.79M
    if (type == 't') {
147
1.61M
        value.i = pl != nullptr;
148
1.61M
        return value;
149
1.61M
    }
150
151
    /* Not found */
152
4.18M
    if (nullptr == pl) {
153
        /* Return value after the switch, so that the return path is */
154
        /* taken in all cases */
155
3.86M
        switch (type) {
156
647k
        case 'b':
157
647k
        case 'i':
158
647k
            value.i = 0;
159
647k
            break;
160
877k
        case 'd':
161
1.30M
        case 'r':
162
1.30M
            value.f = 0.;
163
1.30M
            break;
164
1.91M
        case 's':
165
1.91M
            value.s = nullptr;
166
1.91M
            break;
167
3.86M
        }
168
3.86M
        return value;
169
3.86M
    }
170
171
    /* Found parameter - now find its value */
172
316k
    pl->used |= 1;
173
316k
    l = (int)strlen(opt);
174
316k
    opt = pl->param + l;
175
316k
    if (*opt == '=')
176
288k
        ++opt;
177
178
316k
    switch (type) {
179
73
    case 'i': /* integer input */
180
73
        value.i = atoi(opt);
181
479
        for (const char *ptr = opt; *ptr != '\0'; ++ptr) {
182
406
            if (!(*ptr >= '0' && *ptr <= '9')) {
183
142
                proj_context_errno_set(ctx,
184
142
                                       PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE);
185
142
                value.i = 0;
186
142
            }
187
406
        }
188
73
        break;
189
89.7k
    case 'd': /* simple real input */
190
89.7k
        value.f = pj_atof(opt);
191
89.7k
        break;
192
39.0k
    case 'r': /* degrees input */
193
39.0k
        value.f = dmstor_ctx(ctx, opt, nullptr);
194
39.0k
        break;
195
162k
    case 's': /* char string */
196
162k
        value.s = (char *)opt;
197
162k
        break;
198
25.1k
    case 'b': /* boolean */
199
25.1k
        switch (*opt) {
200
14
        case 'F':
201
14
        case 'f':
202
14
            value.i = 0;
203
14
            break;
204
25.0k
        case '\0':
205
25.0k
        case 'T':
206
25.0k
        case 't':
207
25.0k
            value.i = 1;
208
25.0k
            break;
209
40
        default:
210
40
            proj_context_errno_set(ctx, PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE);
211
40
            value.i = 0;
212
40
            break;
213
25.1k
        }
214
25.1k
        break;
215
316k
    }
216
316k
    return value;
217
316k
}