Line | Count | Source |
1 | | /* put parameters in linked list and retrieve */ |
2 | | |
3 | | #include <ctime> |
4 | | #include <ctype.h> |
5 | | #include <stddef.h> |
6 | | #include <stdio.h> |
7 | | #include <stdlib.h> |
8 | | #include <string.h> |
9 | | |
10 | | #include "proj.h" |
11 | | #include "proj_internal.h" |
12 | | |
13 | | /* create parameter list entry */ |
14 | 4.74M | paralist *pj_mkparam(const char *str) { |
15 | 4.74M | paralist *newitem; |
16 | | |
17 | 4.74M | if ((newitem = (paralist *)malloc(sizeof(paralist) + strlen(str))) != |
18 | 4.74M | nullptr) { |
19 | 4.74M | newitem->used = 0; |
20 | 4.74M | newitem->next = nullptr; |
21 | 4.74M | if (*str == '+') |
22 | 1.05k | ++str; |
23 | 4.74M | (void)strcpy(newitem->param, str); |
24 | 4.74M | } |
25 | 4.74M | return newitem; |
26 | 4.74M | } |
27 | | |
28 | | /* As pj_mkparam, but payload ends at first whitespace, rather than at end of |
29 | | * <str> */ |
30 | 1.64k | paralist *pj_mkparam_ws(const char *str, const char **next_str) { |
31 | 1.64k | paralist *newitem; |
32 | 1.64k | size_t len = 0; |
33 | | |
34 | 1.64k | if (nullptr == str) |
35 | 0 | return nullptr; |
36 | | |
37 | | /* Find start and length of string */ |
38 | 2.95k | while (isspace(*str)) |
39 | 1.31k | str++; |
40 | 1.64k | if (*str == '+') |
41 | 0 | str++; |
42 | 1.64k | bool in_string = false; |
43 | 24.5k | for (; str[len] != '\0'; len++) { |
44 | 24.2k | if (in_string) { |
45 | 0 | if (str[len] == '"' && str[len + 1] == '"') { |
46 | 0 | len++; |
47 | 0 | } else if (str[len] == '"') { |
48 | 0 | in_string = false; |
49 | 0 | } |
50 | 24.2k | } else if (str[len] == '=' && str[len + 1] == '"') { |
51 | 0 | in_string = true; |
52 | 24.2k | } else if (isspace(str[len])) { |
53 | 1.31k | break; |
54 | 1.31k | } |
55 | 24.2k | } |
56 | | |
57 | 1.64k | if (next_str) |
58 | 1.64k | *next_str = str + len; |
59 | | |
60 | | /* Use calloc to automagically 0-terminate the copy */ |
61 | 1.64k | newitem = (paralist *)calloc(1, sizeof(paralist) + len + 1); |
62 | 1.64k | if (nullptr == newitem) |
63 | 0 | return nullptr; |
64 | 1.64k | memcpy(newitem->param, str, len); |
65 | | |
66 | 1.64k | newitem->used = 0; |
67 | 1.64k | newitem->next = nullptr; |
68 | | |
69 | 1.64k | return newitem; |
70 | 1.64k | } |
71 | | |
72 | | /**************************************************************************************/ |
73 | 12.7M | paralist *pj_param_exists(paralist *list, const char *parameter) { |
74 | | /*************************************************************************************** |
75 | | Determine whether a given parameter exists in a paralist. If it does, |
76 | | return a pointer to the corresponding list element - otherwise return 0. |
77 | | |
78 | | In support of the pipeline syntax, the search is terminated once a |
79 | | "+step" list element is reached, in which case a 0 is returned, unless the |
80 | | parameter searched for is actually "step", in which case a pointer to the |
81 | | "step" list element is returned. |
82 | | |
83 | | This function is equivalent to the pj_param (...) call with the "opt" |
84 | | argument set to the parameter name preceeeded by a 't'. But by using this |
85 | | one, one avoids writing the code allocating memory for a new copy of |
86 | | parameter name, and prepending the t (for compile time known names, this is |
87 | | obviously not an issue). |
88 | | ***************************************************************************************/ |
89 | 12.7M | paralist *next = list; |
90 | 12.7M | const char *c = strchr(parameter, '='); |
91 | 12.7M | size_t len = strlen(parameter); |
92 | 12.7M | if (c) |
93 | 0 | len = c - parameter; |
94 | 12.7M | if (list == nullptr) |
95 | 0 | return nullptr; |
96 | | |
97 | 138M | for (next = list; next; next = next->next) { |
98 | 127M | if (0 == strncmp(parameter, next->param, len) && |
99 | 1.77M | (next->param[len] == '=' || next->param[len] == 0)) { |
100 | 1.64M | next->used = 1; |
101 | 1.64M | return next; |
102 | 1.64M | } |
103 | 125M | if (0 == strcmp(parameter, "step")) |
104 | 0 | return nullptr; |
105 | 125M | } |
106 | | |
107 | 11.0M | return nullptr; |
108 | 12.7M | } |
109 | | |
110 | | /************************************************************************/ |
111 | | /* pj_param() */ |
112 | | /* */ |
113 | | /* Test for presence or get parameter value. The first */ |
114 | | /* character in `opt' is a parameter type which can take the */ |
115 | | /* values: */ |
116 | | /* */ |
117 | | /* `t' - test for presence, return TRUE/FALSE in PROJVALUE.i */ |
118 | | /* `i' - integer value returned in PROJVALUE.i */ |
119 | | /* `d' - simple valued real input returned in PROJVALUE.f */ |
120 | | /* `r' - degrees (DMS translation applied), returned as */ |
121 | | /* radians in PROJVALUE.f */ |
122 | | /* `s' - string returned in PROJVALUE.s */ |
123 | | /* `b' - test for t/T/f/F, return in PROJVALUE.i */ |
124 | | /* */ |
125 | | /* Search is terminated when "step" is found, in which case */ |
126 | | /* 0 is returned, unless "step" was the target searched for. */ |
127 | | /* */ |
128 | | /************************************************************************/ |
129 | | |
130 | 8.39M | PROJVALUE pj_param(PJ_CONTEXT *ctx, paralist *pl, const char *opt) { |
131 | | |
132 | 8.39M | int type; |
133 | 8.39M | unsigned l; |
134 | 8.39M | PROJVALUE value = {0}; |
135 | | |
136 | 8.39M | if (ctx == nullptr) |
137 | 0 | ctx = pj_get_default_ctx(); |
138 | | |
139 | 8.39M | type = *opt++; |
140 | | |
141 | 8.39M | if (nullptr == strchr("tbirds", type)) { |
142 | 0 | fprintf(stderr, "invalid request to pj_param, fatal\n"); |
143 | 0 | exit(1); |
144 | 0 | } |
145 | | |
146 | 8.39M | pl = pj_param_exists(pl, opt); |
147 | 8.39M | if (type == 't') { |
148 | 2.29M | value.i = pl != nullptr; |
149 | 2.29M | return value; |
150 | 2.29M | } |
151 | | |
152 | | /* Not found */ |
153 | 6.10M | if (nullptr == pl) { |
154 | | /* Return value after the switch, so that the return path is */ |
155 | | /* taken in all cases */ |
156 | 5.63M | switch (type) { |
157 | 957k | case 'b': |
158 | 957k | case 'i': |
159 | 957k | value.i = 0; |
160 | 957k | break; |
161 | 1.26M | case 'd': |
162 | 1.88M | case 'r': |
163 | 1.88M | value.f = 0.; |
164 | 1.88M | break; |
165 | 2.78M | case 's': |
166 | 2.78M | value.s = nullptr; |
167 | 2.78M | break; |
168 | 5.63M | } |
169 | 5.63M | return value; |
170 | 5.63M | } |
171 | | |
172 | | /* Found parameter - now find its value */ |
173 | 466k | pl->used |= 1; |
174 | 466k | l = (int)strlen(opt); |
175 | 466k | opt = pl->param + l; |
176 | 466k | if (*opt == '=') |
177 | 430k | ++opt; |
178 | | |
179 | 466k | switch (type) { |
180 | 73 | case 'i': /* integer input */ |
181 | 73 | value.i = atoi(opt); |
182 | 875 | for (const char *ptr = opt; *ptr != '\0'; ++ptr) { |
183 | 802 | if (!(*ptr >= '0' && *ptr <= '9')) { |
184 | 572 | proj_context_errno_set(ctx, |
185 | 572 | PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE); |
186 | 572 | value.i = 0; |
187 | 572 | } |
188 | 802 | } |
189 | 73 | break; |
190 | 124k | case 'd': /* simple real input */ |
191 | 124k | value.f = pj_atof(opt); |
192 | 124k | break; |
193 | 61.0k | case 'r': /* degrees input */ |
194 | 61.0k | value.f = dmstor_ctx(ctx, opt, nullptr); |
195 | 61.0k | break; |
196 | 248k | case 's': /* char string */ |
197 | 248k | value.s = (char *)opt; |
198 | 248k | break; |
199 | 32.3k | case 'b': /* boolean */ |
200 | 32.3k | switch (*opt) { |
201 | 13 | case 'F': |
202 | 13 | case 'f': |
203 | 13 | value.i = 0; |
204 | 13 | break; |
205 | 32.2k | case '\0': |
206 | 32.2k | case 'T': |
207 | 32.2k | case 't': |
208 | 32.2k | value.i = 1; |
209 | 32.2k | break; |
210 | 50 | default: |
211 | 50 | proj_context_errno_set(ctx, PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE); |
212 | 50 | value.i = 0; |
213 | 50 | break; |
214 | 32.3k | } |
215 | 32.3k | break; |
216 | 466k | } |
217 | 466k | return value; |
218 | 466k | } |
219 | | |
220 | | /* Parse +t_final parameter with support for "now" keyword */ |
221 | 20.3k | double pj_parse_t_final(PJ *P) { |
222 | 20.3k | if (!pj_param(P->ctx, P->params, "tt_final").i) { |
223 | 20.2k | return 0.0; |
224 | 20.2k | } |
225 | | |
226 | 47 | double t_final = pj_param(P->ctx, P->params, "dt_final").f; |
227 | 47 | if (t_final != 0.0) { |
228 | 5 | return t_final; |
229 | 5 | } |
230 | | |
231 | | /* Check if "now" was specified instead of a numeric value */ |
232 | 42 | const char *t_final_str = pj_param(P->ctx, P->params, "st_final").s; |
233 | 42 | if (!t_final_str || strcmp("now", t_final_str) != 0) { |
234 | 29 | return 0.0; |
235 | 29 | } |
236 | | |
237 | | /* Calculate t_final from current time */ |
238 | 13 | time_t now; |
239 | 13 | struct tm date; |
240 | 13 | time(&now); |
241 | | #ifdef _WIN32 |
242 | | localtime_s(&date, &now); |
243 | | #else |
244 | 13 | localtime_r(&now, &date); |
245 | 13 | #endif |
246 | | |
247 | 13 | const int days_in_year = |
248 | 13 | ((date.tm_year + 1900) % 4 == 0 && |
249 | 0 | ((date.tm_year + 1900) % 100 != 0 || (date.tm_year + 1900) % 400 == 0)) |
250 | 13 | ? 366 |
251 | 13 | : 365; |
252 | | |
253 | 13 | return 1900.0 + date.tm_year + |
254 | 13 | date.tm_yday / static_cast<double>(days_in_year); |
255 | 42 | } |