Line | Count | Source (jump to first uncovered line) |
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 | 1.25M | paralist *pj_mkparam(const char *str) { |
14 | 1.25M | paralist *newitem; |
15 | | |
16 | 1.25M | if ((newitem = (paralist *)malloc(sizeof(paralist) + strlen(str))) != |
17 | 1.25M | nullptr) { |
18 | 1.25M | newitem->used = 0; |
19 | 1.25M | newitem->next = nullptr; |
20 | 1.25M | if (*str == '+') |
21 | 82 | ++str; |
22 | 1.25M | (void)strcpy(newitem->param, str); |
23 | 1.25M | } |
24 | 1.25M | return newitem; |
25 | 1.25M | } |
26 | | |
27 | | /* As pj_mkparam, but payload ends at first whitespace, rather than at end of |
28 | | * <str> */ |
29 | 334 | paralist *pj_mkparam_ws(const char *str, const char **next_str) { |
30 | 334 | paralist *newitem; |
31 | 334 | size_t len = 0; |
32 | | |
33 | 334 | if (nullptr == str) |
34 | 0 | return nullptr; |
35 | | |
36 | | /* Find start and length of string */ |
37 | 518 | while (isspace(*str)) |
38 | 184 | str++; |
39 | 334 | if (*str == '+') |
40 | 334 | str++; |
41 | 334 | bool in_string = false; |
42 | 3.16k | for (; str[len] != '\0'; len++) { |
43 | 3.01k | 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 | 3.01k | } else if (str[len] == '=' && str[len + 1] == '"') { |
50 | 0 | in_string = true; |
51 | 3.01k | } else if (isspace(str[len])) { |
52 | 184 | break; |
53 | 184 | } |
54 | 3.01k | } |
55 | | |
56 | 334 | if (next_str) |
57 | 334 | *next_str = str + len; |
58 | | |
59 | | /* Use calloc to automagically 0-terminate the copy */ |
60 | 334 | newitem = (paralist *)calloc(1, sizeof(paralist) + len + 1); |
61 | 334 | if (nullptr == newitem) |
62 | 0 | return nullptr; |
63 | 334 | memcpy(newitem->param, str, len); |
64 | | |
65 | 334 | newitem->used = 0; |
66 | 334 | newitem->next = nullptr; |
67 | | |
68 | 334 | return newitem; |
69 | 334 | } |
70 | | |
71 | | /**************************************************************************************/ |
72 | 3.34M | 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 | 3.34M | paralist *next = list; |
89 | 3.34M | const char *c = strchr(parameter, '='); |
90 | 3.34M | size_t len = strlen(parameter); |
91 | 3.34M | if (c) |
92 | 0 | len = c - parameter; |
93 | 3.34M | if (list == nullptr) |
94 | 0 | return nullptr; |
95 | | |
96 | 39.5M | for (next = list; next; next = next->next) { |
97 | 36.6M | if (0 == strncmp(parameter, next->param, len) && |
98 | 36.6M | (next->param[len] == '=' || next->param[len] == 0)) { |
99 | 440k | next->used = 1; |
100 | 440k | return next; |
101 | 440k | } |
102 | 36.1M | if (0 == strcmp(parameter, "step")) |
103 | 0 | return nullptr; |
104 | 36.1M | } |
105 | | |
106 | 2.90M | return nullptr; |
107 | 3.34M | } |
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 | 2.12M | PROJVALUE pj_param(PJ_CONTEXT *ctx, paralist *pl, const char *opt) { |
130 | | |
131 | 2.12M | int type; |
132 | 2.12M | unsigned l; |
133 | 2.12M | PROJVALUE value = {0}; |
134 | | |
135 | 2.12M | if (ctx == nullptr) |
136 | 0 | ctx = pj_get_default_ctx(); |
137 | | |
138 | 2.12M | type = *opt++; |
139 | | |
140 | 2.12M | if (nullptr == strchr("tbirds", type)) { |
141 | 0 | fprintf(stderr, "invalid request to pj_param, fatal\n"); |
142 | 0 | exit(1); |
143 | 0 | } |
144 | | |
145 | 2.12M | pl = pj_param_exists(pl, opt); |
146 | 2.12M | if (type == 't') { |
147 | 521k | value.i = pl != nullptr; |
148 | 521k | return value; |
149 | 521k | } |
150 | | |
151 | | /* Not found */ |
152 | 1.59M | if (nullptr == pl) { |
153 | | /* Return value after the switch, so that the return path is */ |
154 | | /* taken in all cases */ |
155 | 1.50M | switch (type) { |
156 | 213k | case 'b': |
157 | 213k | case 'i': |
158 | 213k | value.i = 0; |
159 | 213k | break; |
160 | 357k | case 'd': |
161 | 537k | case 'r': |
162 | 537k | value.f = 0.; |
163 | 537k | break; |
164 | 751k | case 's': |
165 | 751k | value.s = nullptr; |
166 | 751k | break; |
167 | 1.50M | } |
168 | 1.50M | return value; |
169 | 1.50M | } |
170 | | |
171 | | /* Found parameter - now find its value */ |
172 | 97.2k | pl->used |= 1; |
173 | 97.2k | l = (int)strlen(opt); |
174 | 97.2k | opt = pl->param + l; |
175 | 97.2k | if (*opt == '=') |
176 | 87.1k | ++opt; |
177 | | |
178 | 97.2k | switch (type) { |
179 | 622 | case 'i': /* integer input */ |
180 | 622 | value.i = atoi(opt); |
181 | 1.92k | for (const char *ptr = opt; *ptr != '\0'; ++ptr) { |
182 | 1.30k | if (!(*ptr >= '0' && *ptr <= '9')) { |
183 | 534 | proj_context_errno_set(ctx, |
184 | 534 | PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE); |
185 | 534 | value.i = 0; |
186 | 534 | } |
187 | 1.30k | } |
188 | 622 | break; |
189 | 23.0k | case 'd': /* simple real input */ |
190 | 23.0k | value.f = pj_atof(opt); |
191 | 23.0k | break; |
192 | 14.8k | case 'r': /* degrees input */ |
193 | 14.8k | value.f = dmstor_ctx(ctx, opt, nullptr); |
194 | 14.8k | break; |
195 | 51.0k | case 's': /* char string */ |
196 | 51.0k | value.s = (char *)opt; |
197 | 51.0k | break; |
198 | 7.64k | case 'b': /* boolean */ |
199 | 7.64k | switch (*opt) { |
200 | 73 | case 'F': |
201 | 440 | case 'f': |
202 | 440 | value.i = 0; |
203 | 440 | break; |
204 | 6.37k | case '\0': |
205 | 6.41k | case 'T': |
206 | 6.42k | case 't': |
207 | 6.42k | value.i = 1; |
208 | 6.42k | break; |
209 | 779 | default: |
210 | 779 | proj_context_errno_set(ctx, PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE); |
211 | 779 | value.i = 0; |
212 | 779 | break; |
213 | 7.64k | } |
214 | 7.64k | break; |
215 | 97.2k | } |
216 | 97.2k | return value; |
217 | 97.2k | } |