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.75M | paralist *pj_mkparam(const char *str) { |
15 | 4.75M | paralist *newitem; |
16 | | |
17 | 4.75M | if ((newitem = (paralist *)malloc(sizeof(paralist) + strlen(str))) != |
18 | 4.75M | nullptr) { |
19 | 4.75M | newitem->used = 0; |
20 | 4.75M | newitem->next = nullptr; |
21 | 4.75M | if (*str == '+') |
22 | 1.78k | ++str; |
23 | 4.75M | (void)strcpy(newitem->param, str); |
24 | 4.75M | } |
25 | 4.75M | return newitem; |
26 | 4.75M | } |
27 | | |
28 | | /* As pj_mkparam, but payload ends at first whitespace, rather than at end of |
29 | | * <str> */ |
30 | 1.56k | paralist *pj_mkparam_ws(const char *str, const char **next_str) { |
31 | 1.56k | paralist *newitem; |
32 | 1.56k | size_t len = 0; |
33 | | |
34 | 1.56k | if (nullptr == str) |
35 | 0 | return nullptr; |
36 | | |
37 | | /* Find start and length of string */ |
38 | 2.83k | while (isspace(*str)) |
39 | 1.26k | str++; |
40 | 1.56k | if (*str == '+') |
41 | 0 | str++; |
42 | 1.56k | bool in_string = false; |
43 | 23.3k | for (; str[len] != '\0'; len++) { |
44 | 23.0k | 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 | 23.0k | } else if (str[len] == '=' && str[len + 1] == '"') { |
51 | 0 | in_string = true; |
52 | 23.0k | } else if (isspace(str[len])) { |
53 | 1.26k | break; |
54 | 1.26k | } |
55 | 23.0k | } |
56 | | |
57 | 1.56k | if (next_str) |
58 | 1.56k | *next_str = str + len; |
59 | | |
60 | | /* Use calloc to automagically 0-terminate the copy */ |
61 | 1.56k | newitem = (paralist *)calloc(1, sizeof(paralist) + len + 1); |
62 | 1.56k | if (nullptr == newitem) |
63 | 0 | return nullptr; |
64 | 1.56k | memcpy(newitem->param, str, len); |
65 | | |
66 | 1.56k | newitem->used = 0; |
67 | 1.56k | newitem->next = nullptr; |
68 | | |
69 | 1.56k | return newitem; |
70 | 1.56k | } |
71 | | |
72 | | /**************************************************************************************/ |
73 | 11.9M | 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 | 11.9M | paralist *next = list; |
90 | 11.9M | const char *c = strchr(parameter, '='); |
91 | 11.9M | size_t len = strlen(parameter); |
92 | 11.9M | if (c) |
93 | 0 | len = c - parameter; |
94 | 11.9M | if (list == nullptr) |
95 | 0 | return nullptr; |
96 | | |
97 | 142M | for (next = list; next; next = next->next) { |
98 | 132M | if (0 == strncmp(parameter, next->param, len) && |
99 | 1.67M | (next->param[len] == '=' || next->param[len] == 0)) { |
100 | 1.56M | next->used = 1; |
101 | 1.56M | return next; |
102 | 1.56M | } |
103 | 130M | if (0 == strcmp(parameter, "step")) |
104 | 0 | return nullptr; |
105 | 130M | } |
106 | | |
107 | 10.3M | return nullptr; |
108 | 11.9M | } |
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 | 7.91M | PROJVALUE pj_param(PJ_CONTEXT *ctx, paralist *pl, const char *opt) { |
131 | | |
132 | 7.91M | int type; |
133 | 7.91M | unsigned l; |
134 | 7.91M | PROJVALUE value = {0}; |
135 | | |
136 | 7.91M | if (ctx == nullptr) |
137 | 0 | ctx = pj_get_default_ctx(); |
138 | | |
139 | 7.91M | type = *opt++; |
140 | | |
141 | 7.91M | if (nullptr == strchr("tbirds", type)) { |
142 | 0 | fprintf(stderr, "invalid request to pj_param, fatal\n"); |
143 | 0 | exit(1); |
144 | 0 | } |
145 | | |
146 | 7.91M | pl = pj_param_exists(pl, opt); |
147 | 7.91M | if (type == 't') { |
148 | 2.17M | value.i = pl != nullptr; |
149 | 2.17M | return value; |
150 | 2.17M | } |
151 | | |
152 | | /* Not found */ |
153 | 5.73M | if (nullptr == pl) { |
154 | | /* Return value after the switch, so that the return path is */ |
155 | | /* taken in all cases */ |
156 | 5.30M | switch (type) { |
157 | 894k | case 'b': |
158 | 895k | case 'i': |
159 | 895k | value.i = 0; |
160 | 895k | break; |
161 | 1.19M | case 'd': |
162 | 1.78M | case 'r': |
163 | 1.78M | value.f = 0.; |
164 | 1.78M | break; |
165 | 2.62M | case 's': |
166 | 2.62M | value.s = nullptr; |
167 | 2.62M | break; |
168 | 5.30M | } |
169 | 5.30M | return value; |
170 | 5.30M | } |
171 | | |
172 | | /* Found parameter - now find its value */ |
173 | 436k | pl->used |= 1; |
174 | 436k | l = (int)strlen(opt); |
175 | 436k | opt = pl->param + l; |
176 | 436k | if (*opt == '=') |
177 | 400k | ++opt; |
178 | | |
179 | 436k | switch (type) { |
180 | 82 | case 'i': /* integer input */ |
181 | 82 | value.i = atoi(opt); |
182 | 535 | for (const char *ptr = opt; *ptr != '\0'; ++ptr) { |
183 | 453 | if (!(*ptr >= '0' && *ptr <= '9')) { |
184 | 220 | proj_context_errno_set(ctx, |
185 | 220 | PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE); |
186 | 220 | value.i = 0; |
187 | 220 | } |
188 | 453 | } |
189 | 82 | break; |
190 | 125k | case 'd': /* simple real input */ |
191 | 125k | value.f = pj_atof(opt); |
192 | 125k | break; |
193 | 53.1k | case 'r': /* degrees input */ |
194 | 53.1k | value.f = dmstor_ctx(ctx, opt, nullptr); |
195 | 53.1k | break; |
196 | 224k | case 's': /* char string */ |
197 | 224k | value.s = (char *)opt; |
198 | 224k | break; |
199 | 32.2k | case 'b': /* boolean */ |
200 | 32.2k | switch (*opt) { |
201 | 14 | case 'F': |
202 | 14 | case 'f': |
203 | 14 | value.i = 0; |
204 | 14 | break; |
205 | 32.0k | case '\0': |
206 | 32.1k | case 'T': |
207 | 32.1k | case 't': |
208 | 32.1k | value.i = 1; |
209 | 32.1k | break; |
210 | 49 | default: |
211 | 49 | proj_context_errno_set(ctx, PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE); |
212 | 49 | value.i = 0; |
213 | 49 | break; |
214 | 32.2k | } |
215 | 32.2k | break; |
216 | 436k | } |
217 | 436k | return value; |
218 | 436k | } |
219 | | |
220 | | /* Parse +t_final parameter with support for "now" keyword */ |
221 | 14.7k | double pj_parse_t_final(PJ *P) { |
222 | 14.7k | if (!pj_param(P->ctx, P->params, "tt_final").i) { |
223 | 14.6k | return 0.0; |
224 | 14.6k | } |
225 | | |
226 | 56 | double t_final = pj_param(P->ctx, P->params, "dt_final").f; |
227 | 56 | if (t_final != 0.0) { |
228 | 3 | return t_final; |
229 | 3 | } |
230 | | |
231 | | /* Check if "now" was specified instead of a numeric value */ |
232 | 53 | const char *t_final_str = pj_param(P->ctx, P->params, "st_final").s; |
233 | 53 | if (!t_final_str || strcmp("now", t_final_str) != 0) { |
234 | 46 | return 0.0; |
235 | 46 | } |
236 | | |
237 | | /* Calculate t_final from current time */ |
238 | 7 | time_t now; |
239 | 7 | struct tm date; |
240 | 7 | time(&now); |
241 | | #ifdef _WIN32 |
242 | | localtime_s(&date, &now); |
243 | | #else |
244 | 7 | localtime_r(&now, &date); |
245 | 7 | #endif |
246 | | |
247 | 7 | const int days_in_year = |
248 | 7 | ((date.tm_year + 1900) % 4 == 0 && |
249 | 0 | ((date.tm_year + 1900) % 100 != 0 || (date.tm_year + 1900) % 400 == 0)) |
250 | 7 | ? 366 |
251 | 7 | : 365; |
252 | | |
253 | 7 | return 1900.0 + date.tm_year + |
254 | 7 | date.tm_yday / static_cast<double>(days_in_year); |
255 | 53 | } |