File: | src/mod/xml_int/mod_xml_rpc/../../../../libs/xmlrpc-c/src/parse_datetime.c |
Location: | line 464, column 24 |
Description: | Passed-by-value struct argument contains uninitialized data (e.g., field: 'Y') |
1 | #include "xmlrpc_config.h" | |||
2 | ||||
3 | #include <stdlib.h> | |||
4 | #include <assert.h> | |||
5 | #include <ctype.h> | |||
6 | #include <string.h> | |||
7 | ||||
8 | #if HAVE_REGEX1 | |||
9 | #include <sys/types.h> /* Missing from regex.h in GNU libc */ | |||
10 | #include <regex.h> | |||
11 | #endif | |||
12 | ||||
13 | #include "bool.h" | |||
14 | ||||
15 | #include "xmlrpc-c/base.h" | |||
16 | #include "xmlrpc-c/base_int.h" | |||
17 | #include "xmlrpc-c/util.h" | |||
18 | ||||
19 | #include "parse_datetime.h" | |||
20 | ||||
21 | ||||
22 | ||||
23 | #if HAVE_REGEX1 | |||
24 | ||||
25 | static unsigned int | |||
26 | digitStringValue(const char * const string, | |||
27 | regmatch_t const match) { | |||
28 | /*---------------------------------------------------------------------------- | |||
29 | Return the numerical value of the decimal whole number substring of | |||
30 | 'string' identified by 'match'. E.g. if 'string' is 'abc34d' and | |||
31 | 'match' says start at 3 and end at 5, we return 34. | |||
32 | -----------------------------------------------------------------------------*/ | |||
33 | unsigned int i; | |||
34 | unsigned int accum; | |||
35 | ||||
36 | assert(match.rm_so >= 0)((match.rm_so >= 0) ? (void) (0) : __assert_fail ("match.rm_so >= 0" , "../../../../libs/xmlrpc-c/src/parse_datetime.c", 36, __PRETTY_FUNCTION__ )); | |||
37 | assert(match.rm_eo >= 0)((match.rm_eo >= 0) ? (void) (0) : __assert_fail ("match.rm_eo >= 0" , "../../../../libs/xmlrpc-c/src/parse_datetime.c", 37, __PRETTY_FUNCTION__ )); | |||
38 | ||||
39 | for (i = match.rm_so, accum = 0; i < (unsigned)match.rm_eo; ++i) { | |||
40 | accum *= 10; | |||
41 | assert(isdigit(string[i]))((((*__ctype_b_loc ())[(int) ((string[i]))] & (unsigned short int) _ISdigit)) ? (void) (0) : __assert_fail ("((*__ctype_b_loc ())[(int) ((string[i]))] & (unsigned short int) _ISdigit)" , "../../../../libs/xmlrpc-c/src/parse_datetime.c", 41, __PRETTY_FUNCTION__ )); | |||
42 | accum += string[i] - '0'; | |||
43 | } | |||
44 | return accum; | |||
45 | } | |||
46 | #endif /* HAVE_REGEX */ | |||
47 | ||||
48 | ||||
49 | ||||
50 | #if HAVE_REGEX1 | |||
51 | ||||
52 | static unsigned int | |||
53 | digitStringMillionths(const char * const string, | |||
54 | regmatch_t const match) { | |||
55 | /*---------------------------------------------------------------------------- | |||
56 | Return the number of millionths represented by the digits after the | |||
57 | decimal point in a decimal string, where thse digits are the substring | |||
58 | of 'string' identified by 'match'. E.g. if the substring is | |||
59 | 34, we return 340,000. | |||
60 | -----------------------------------------------------------------------------*/ | |||
61 | unsigned int i; | |||
62 | unsigned int accum; | |||
63 | ||||
64 | assert(match.rm_so >= 0)((match.rm_so >= 0) ? (void) (0) : __assert_fail ("match.rm_so >= 0" , "../../../../libs/xmlrpc-c/src/parse_datetime.c", 64, __PRETTY_FUNCTION__ )); | |||
65 | assert(match.rm_eo >= 0)((match.rm_eo >= 0) ? (void) (0) : __assert_fail ("match.rm_eo >= 0" , "../../../../libs/xmlrpc-c/src/parse_datetime.c", 65, __PRETTY_FUNCTION__ )); | |||
66 | ||||
67 | for (i = match.rm_so, accum = 0; i < (unsigned)match.rm_so+6; ++i) { | |||
68 | accum *= 10; | |||
69 | if (i < (unsigned)match.rm_eo) { | |||
70 | assert(isdigit(string[i]))((((*__ctype_b_loc ())[(int) ((string[i]))] & (unsigned short int) _ISdigit)) ? (void) (0) : __assert_fail ("((*__ctype_b_loc ())[(int) ((string[i]))] & (unsigned short int) _ISdigit)" , "../../../../libs/xmlrpc-c/src/parse_datetime.c", 70, __PRETTY_FUNCTION__ )); | |||
71 | accum += string[i] - '0'; | |||
72 | } | |||
73 | } | |||
74 | return accum; | |||
75 | } | |||
76 | #endif /* HAVE_REGEX */ | |||
77 | ||||
78 | ||||
79 | #if HAVE_REGEX1 | |||
80 | ||||
81 | static void | |||
82 | subParseDtRegex_standard(regmatch_t * const matches, | |||
83 | const char * const datetimeString, | |||
84 | xmlrpc_datetime * const dtP) { | |||
85 | ||||
86 | dtP->Y = digitStringValue(datetimeString, matches[1]); | |||
87 | dtP->M = digitStringValue(datetimeString, matches[2]); | |||
88 | dtP->D = digitStringValue(datetimeString, matches[3]); | |||
89 | dtP->h = digitStringValue(datetimeString, matches[4]); | |||
90 | dtP->m = digitStringValue(datetimeString, matches[5]); | |||
91 | dtP->s = digitStringValue(datetimeString, matches[6]); | |||
92 | ||||
93 | if (matches[7].rm_so == -1) | |||
94 | dtP->u = 0; | |||
95 | else | |||
96 | dtP->u = digitStringMillionths(datetimeString, matches[7]); | |||
97 | } | |||
98 | ||||
99 | ||||
100 | ||||
101 | static void | |||
102 | subParseDtRegex_standardtzd(regmatch_t * const matches, | |||
103 | const char * const datetimeString, | |||
104 | xmlrpc_datetime * const dtP) { | |||
105 | ||||
106 | dtP->Y = digitStringValue(datetimeString, matches[1]); | |||
107 | dtP->M = digitStringValue(datetimeString, matches[2]); | |||
108 | dtP->D = digitStringValue(datetimeString, matches[3]); | |||
109 | dtP->h = digitStringValue(datetimeString, matches[4]); | |||
110 | dtP->m = digitStringValue(datetimeString, matches[5]); | |||
111 | dtP->s = digitStringValue(datetimeString, matches[6]); | |||
112 | } | |||
113 | ||||
114 | #endif /* HAVE_REGEX */ | |||
115 | ||||
116 | ||||
117 | #if HAVE_REGEX1 | |||
118 | ||||
119 | typedef void (*regparsefunc_t)(regmatch_t * const matches, | |||
120 | const char * const datetimeString, | |||
121 | xmlrpc_datetime * const dtP); | |||
122 | ||||
123 | ||||
124 | struct regexParser { | |||
125 | const char * const regex; | |||
126 | regparsefunc_t func; | |||
127 | }; | |||
128 | ||||
129 | static const struct regexParser iso8601Regex[] | |||
130 | ||||
131 | /* Each entry of this table is instructions for recognizing and parsing | |||
132 | some form of a "dateTime.iso8601" XML element. | |||
133 | ||||
134 | (Note that we recognize far more than just the XML-RPC standard | |||
135 | dateTime.iso8601). | |||
136 | */ | |||
137 | ||||
138 | = { | |||
139 | { | |||
140 | /* Examples: | |||
141 | YYYYMMDD[T]HHMMSS | |||
142 | YYYY-MM-DD[T]HH:MM:SS | |||
143 | YYYY-MM-DD[T]HH:MM:SS.ssss | |||
144 | */ | |||
145 | ||||
146 | "^([0-9]{4})\\-?([0-9]{2})\\-?([0-9]{2})T" | |||
147 | "([0-9]{2}):?([0-9]{2}):?([0-9]{2})\\.?([0-9]+)?$", | |||
148 | subParseDtRegex_standard | |||
149 | }, | |||
150 | ||||
151 | { | |||
152 | /* Examples: | |||
153 | YYYYMMDD[T]HHMMSS[Z] | |||
154 | YYYYMMDD[T]HHMMSS[+-]hh | |||
155 | YYYYMMDD[T]HHMMSS[+-]hhmm | |||
156 | */ | |||
157 | ||||
158 | "^([0-9]{4})\\-?([0-9]{2})\\-?([0-9]{2})T" | |||
159 | "([0-9]{2}):?([0-9]{2}):?([0-9]{2})[Z\\+\\-]([0-9]{2,4})?$", | |||
160 | subParseDtRegex_standardtzd | |||
161 | }, | |||
162 | { NULL((void*)0), NULL((void*)0) } | |||
163 | }; | |||
164 | #endif /* HAVE_REGEX */ | |||
165 | ||||
166 | ||||
167 | ||||
168 | #if HAVE_REGEX1 | |||
169 | static void | |||
170 | parseDtRegex(xmlrpc_env * const envP, | |||
171 | const char * const datetimeString, | |||
172 | xmlrpc_datetime * const dtP) { | |||
173 | ||||
174 | unsigned int i; | |||
175 | const struct regexParser * parserP; | |||
176 | /* The parser that matches 'datetimeString'. Null if no match yet | |||
177 | found. | |||
178 | */ | |||
179 | regmatch_t matches[1024]; | |||
180 | ||||
181 | for (i = 0, parserP = NULL((void*)0); iso8601Regex[i].regex && !parserP; ++i) { | |||
182 | const struct regexParser * const thisParserP = &iso8601Regex[i]; | |||
183 | ||||
184 | regex_t re; | |||
185 | int status; | |||
186 | ||||
187 | status = regcomp(&re, thisParserP->regex, REG_ICASE(1 << 1) | REG_EXTENDED1); | |||
188 | ||||
189 | /* Our regex is valid, so it must have compiled: */ | |||
190 | assert(status == 0)((status == 0) ? (void) (0) : __assert_fail ("status == 0", "../../../../libs/xmlrpc-c/src/parse_datetime.c" , 190, __PRETTY_FUNCTION__)); | |||
191 | { | |||
192 | int status; | |||
193 | ||||
194 | status = regexec(&re, datetimeString, ARRAY_SIZE(matches)(sizeof(matches)/sizeof(matches[0])), | |||
195 | matches, 0); | |||
196 | ||||
197 | if (status == 0) { | |||
198 | assert(matches[0].rm_so != -1)((matches[0].rm_so != -1) ? (void) (0) : __assert_fail ("matches[0].rm_so != -1" , "../../../../libs/xmlrpc-c/src/parse_datetime.c", 198, __PRETTY_FUNCTION__ )); /* Match of whole regex */ | |||
199 | ||||
200 | parserP = thisParserP; | |||
201 | } | |||
202 | regfree(&re); | |||
203 | } | |||
204 | } | |||
205 | ||||
206 | if (parserP) { | |||
207 | parserP->func(matches, datetimeString, dtP); | |||
208 | } else { | |||
209 | xmlrpc_env_set_fault_formatted( | |||
210 | envP, XMLRPC_PARSE_ERROR(-503), | |||
211 | "value '%s' is not of any form we recognize " | |||
212 | "for a <dateTime.iso8601> element", | |||
213 | datetimeString); | |||
214 | } | |||
215 | ||||
216 | } | |||
217 | #endif /* HAVE_REGEX */ | |||
218 | ||||
219 | ||||
220 | ||||
221 | static __inline__ void | |||
222 | parseDtNoRegex(xmlrpc_env * const envP, | |||
223 | const char * const datetimeString, | |||
224 | xmlrpc_datetime * const dtP) { | |||
225 | ||||
226 | unsigned int const dtStrlen = strlen(datetimeString); | |||
227 | ||||
228 | char year[4+1]; | |||
229 | char month[2+1]; | |||
230 | char day[2+1]; | |||
231 | char hour[2+1]; | |||
232 | char minute[2+1]; | |||
233 | char second[2+1]; | |||
234 | ||||
235 | if (dtStrlen < 17 || dtStrlen == 18 || dtStrlen > 24) | |||
236 | xmlrpc_faultf(envP, "could not parse date, size incompatible: '%d'", | |||
237 | dtStrlen); | |||
238 | else { | |||
239 | year[0] = datetimeString[ 0]; | |||
240 | year[1] = datetimeString[ 1]; | |||
241 | year[2] = datetimeString[ 2]; | |||
242 | year[3] = datetimeString[ 3]; | |||
243 | year[4] = '\0'; | |||
244 | ||||
245 | month[0] = datetimeString[ 4]; | |||
246 | month[1] = datetimeString[ 5]; | |||
247 | month[2] = '\0'; | |||
248 | ||||
249 | day[0] = datetimeString[ 6]; | |||
250 | day[1] = datetimeString[ 7]; | |||
251 | day[2] = '\0'; | |||
252 | ||||
253 | assert(datetimeString[ 8] == 'T')((datetimeString[ 8] == 'T') ? (void) (0) : __assert_fail ("datetimeString[ 8] == 'T'" , "../../../../libs/xmlrpc-c/src/parse_datetime.c", 253, __PRETTY_FUNCTION__ )); | |||
254 | ||||
255 | hour[0] = datetimeString[ 9]; | |||
256 | hour[1] = datetimeString[10]; | |||
257 | hour[2] = '\0'; | |||
258 | ||||
259 | assert(datetimeString[11] == ':')((datetimeString[11] == ':') ? (void) (0) : __assert_fail ("datetimeString[11] == ':'" , "../../../../libs/xmlrpc-c/src/parse_datetime.c", 259, __PRETTY_FUNCTION__ )); | |||
260 | ||||
261 | minute[0] = datetimeString[12]; | |||
262 | minute[1] = datetimeString[13]; | |||
263 | minute[2] = '\0'; | |||
264 | ||||
265 | assert(datetimeString[14] == ':')((datetimeString[14] == ':') ? (void) (0) : __assert_fail ("datetimeString[14] == ':'" , "../../../../libs/xmlrpc-c/src/parse_datetime.c", 265, __PRETTY_FUNCTION__ )); | |||
266 | ||||
267 | second[0] = datetimeString[15]; | |||
268 | second[1] = datetimeString[16]; | |||
269 | second[2] = '\0'; | |||
270 | ||||
271 | if (dtStrlen > 17) { | |||
272 | unsigned int const pad = 24 - dtStrlen; | |||
273 | unsigned int i; | |||
274 | ||||
275 | dtP->u = atoi(&datetimeString[18]); | |||
276 | for (i = 0; i < pad; ++i) | |||
277 | dtP->u *= 10; | |||
278 | } else | |||
279 | dtP->u = 0; | |||
280 | ||||
281 | dtP->Y = atoi(year); | |||
282 | dtP->M = atoi(month); | |||
283 | dtP->D = atoi(day); | |||
284 | dtP->h = atoi(hour); | |||
285 | dtP->m = atoi(minute); | |||
286 | dtP->s = atoi(second); | |||
287 | } | |||
288 | } | |||
289 | ||||
290 | ||||
291 | ||||
292 | static void | |||
293 | validateFirst17(xmlrpc_env * const envP, | |||
294 | const char * const dt) { | |||
295 | /*---------------------------------------------------------------------------- | |||
296 | Assuming 'dt' is at least 17 characters long, validate that the first | |||
297 | 17 characters are a valid XML-RPC datetime, e.g. | |||
298 | "20080628T16:35:02" | |||
299 | -----------------------------------------------------------------------------*/ | |||
300 | unsigned int i; | |||
301 | ||||
302 | for (i = 0; i < 8 && !envP->fault_occurred; ++i) | |||
303 | if (!isdigit(dt[i])((*__ctype_b_loc ())[(int) ((dt[i]))] & (unsigned short int ) _ISdigit)) | |||
304 | xmlrpc_env_set_fault_formatted( | |||
305 | envP, XMLRPC_PARSE_ERROR(-503), "Not a digit: '%c'", dt[i]); | |||
306 | ||||
307 | if (dt[8] != 'T') | |||
308 | xmlrpc_env_set_fault_formatted( | |||
309 | envP, XMLRPC_PARSE_ERROR(-503), "9th character is '%c', not 'T'", | |||
310 | dt[8]); | |||
311 | if (!isdigit(dt[9])((*__ctype_b_loc ())[(int) ((dt[9]))] & (unsigned short int ) _ISdigit)) | |||
312 | xmlrpc_env_set_fault_formatted( | |||
313 | envP, XMLRPC_PARSE_ERROR(-503), "Not a digit: '%c'", dt[9]); | |||
314 | if (!isdigit(dt[10])((*__ctype_b_loc ())[(int) ((dt[10]))] & (unsigned short int ) _ISdigit)) | |||
315 | xmlrpc_env_set_fault_formatted( | |||
316 | envP, XMLRPC_PARSE_ERROR(-503), "Not a digit: '%c'", dt[10]); | |||
317 | if (dt[11] != ':') | |||
318 | xmlrpc_env_set_fault_formatted( | |||
319 | envP, XMLRPC_PARSE_ERROR(-503), "Not a colon: '%c'", dt[11]); | |||
320 | if (!isdigit(dt[12])((*__ctype_b_loc ())[(int) ((dt[12]))] & (unsigned short int ) _ISdigit)) | |||
321 | xmlrpc_env_set_fault_formatted( | |||
322 | envP, XMLRPC_PARSE_ERROR(-503), "Not a digit: '%c'", dt[12]); | |||
323 | if (!isdigit(dt[13])((*__ctype_b_loc ())[(int) ((dt[13]))] & (unsigned short int ) _ISdigit)) | |||
324 | xmlrpc_env_set_fault_formatted( | |||
325 | envP, XMLRPC_PARSE_ERROR(-503), "Not a digit: '%c'", dt[13]); | |||
326 | if (dt[14] != ':') | |||
327 | xmlrpc_env_set_fault_formatted( | |||
328 | envP, XMLRPC_PARSE_ERROR(-503), "Not a colon: '%c'", dt[14]); | |||
329 | if (!isdigit(dt[15])((*__ctype_b_loc ())[(int) ((dt[15]))] & (unsigned short int ) _ISdigit)) | |||
330 | xmlrpc_env_set_fault_formatted( | |||
331 | envP, XMLRPC_PARSE_ERROR(-503), "Not a digit: '%c'", dt[15]); | |||
332 | if (!isdigit(dt[16])((*__ctype_b_loc ())[(int) ((dt[16]))] & (unsigned short int ) _ISdigit)) | |||
333 | xmlrpc_env_set_fault_formatted( | |||
334 | envP, XMLRPC_PARSE_ERROR(-503), "Not a digit: '%c'", dt[16]); | |||
335 | } | |||
336 | ||||
337 | ||||
338 | ||||
339 | static void | |||
340 | validateFractionalSeconds(xmlrpc_env * const envP, | |||
341 | const char * const dt) { | |||
342 | /*---------------------------------------------------------------------------- | |||
343 | Validate the fractional seconds part of the XML-RPC datetime string | |||
344 | 'dt', if any. That's the decimal point and everything following | |||
345 | it. | |||
346 | -----------------------------------------------------------------------------*/ | |||
347 | if (strlen(dt) > 17) { | |||
348 | if (dt[17] != '.') { | |||
349 | xmlrpc_env_set_fault_formatted( | |||
350 | envP, XMLRPC_PARSE_ERROR(-503), | |||
351 | "'%c' where only a period is valid", dt[17]); | |||
352 | } else { | |||
353 | if (dt[18] == '\0') | |||
354 | xmlrpc_env_set_fault_formatted( | |||
355 | envP, XMLRPC_PARSE_ERROR(-503), "Nothing after decimal point"); | |||
356 | else { | |||
357 | unsigned int i; | |||
358 | for (i = 18; dt[i] != '\0' && !envP->fault_occurred; ++i) { | |||
359 | if (!isdigit(dt[i])((*__ctype_b_loc ())[(int) ((dt[i]))] & (unsigned short int ) _ISdigit)) | |||
360 | xmlrpc_env_set_fault_formatted( | |||
361 | envP, XMLRPC_PARSE_ERROR(-503), | |||
362 | "Non-digit in fractional seconds: '%c'", dt[i]); | |||
363 | } | |||
364 | } | |||
365 | } | |||
366 | } | |||
367 | } | |||
368 | ||||
369 | ||||
370 | ||||
371 | static __inline__ void | |||
372 | validateFormatNoRegex(xmlrpc_env * const envP, | |||
373 | const char * const dt) { | |||
374 | ||||
375 | if (strlen(dt) < 17) | |||
376 | xmlrpc_env_set_fault_formatted( | |||
377 | envP, XMLRPC_PARSE_ERROR(-503), | |||
378 | "Invalid length of %u of datetime. " | |||
379 | "Must be at least 17 characters", | |||
380 | (unsigned)strlen(dt)); | |||
381 | else { | |||
382 | validateFirst17(envP, dt); | |||
383 | ||||
384 | validateFractionalSeconds(envP, dt); | |||
385 | } | |||
386 | } | |||
387 | ||||
388 | ||||
389 | ||||
390 | static void | |||
391 | validateXmlrpcDatetimeSome(xmlrpc_env * const envP, | |||
392 | xmlrpc_datetime const dt) { | |||
393 | /*---------------------------------------------------------------------------- | |||
394 | Type xmlrpc_datetime is defined such that it can represent a nonexistent | |||
395 | datetime such as February 30. | |||
396 | ||||
397 | Validate that 'dt' doesn't have glaring invalidities such as Hour 25. | |||
398 | We leave the possibility of more subtle invalidity such as February 30. | |||
399 | -----------------------------------------------------------------------------*/ | |||
400 | ||||
401 | if (dt.M < 1 || dt.M > 12) | |||
402 | xmlrpc_env_set_fault_formatted( | |||
403 | envP, XMLRPC_PARSE_ERROR(-503), | |||
404 | "Month of year value %u is not in the range 1-12", dt.M); | |||
405 | else if (dt.D < 1 || dt.D > 31) | |||
406 | xmlrpc_env_set_fault_formatted( | |||
407 | envP, XMLRPC_PARSE_ERROR(-503), | |||
408 | "Day of month value %u is not in the range 1-31", dt.D); | |||
409 | else if (dt.h > 23) | |||
410 | xmlrpc_env_set_fault_formatted( | |||
411 | envP, XMLRPC_PARSE_ERROR(-503), | |||
412 | "Hour of day value %u is not in the range 0-23", dt.h); | |||
413 | else if (dt.m > 59) | |||
414 | xmlrpc_env_set_fault_formatted( | |||
415 | envP, XMLRPC_PARSE_ERROR(-503), | |||
416 | "Minute of hour value %u is not in the range 0-59", dt.m); | |||
417 | else if (dt.s > 59) | |||
418 | xmlrpc_env_set_fault_formatted( | |||
419 | envP, XMLRPC_PARSE_ERROR(-503), | |||
420 | "Second of minute value %u is not in the range 0-59", dt.s); | |||
421 | else if (dt.u > 999999) | |||
422 | xmlrpc_env_set_fault_formatted( | |||
423 | envP, XMLRPC_PARSE_ERROR(-503), | |||
424 | "Microsecond of second value %u is not in the range 0-1M", dt.u); | |||
425 | } | |||
426 | ||||
427 | ||||
428 | ||||
429 | void | |||
430 | xmlrpc_parseDatetime(xmlrpc_env * const envP, | |||
431 | const char * const datetimeString, | |||
432 | xmlrpc_value ** const valuePP) { | |||
433 | /*---------------------------------------------------------------------------- | |||
434 | Parse the content of a <datetime.iso8601> XML-RPC XML element, e.g. | |||
435 | "20000301T00:00:00". | |||
436 | ||||
437 | 'str' is that content. | |||
438 | ||||
439 | Example of the format we parse: "19980717T14:08:55" | |||
440 | Note that this is not quite ISO 8601. It's a bizarre combination of | |||
441 | two ISO 8601 formats. | |||
442 | ||||
443 | Note that Xmlrpc-c recognizes various extensions of the XML-RPC | |||
444 | <datetime.iso8601> element type. | |||
445 | ||||
446 | 'str' may not be valid XML-RPC (with extensions). In that case we fail | |||
447 | with fault code XMLRPC_PARSE_ERROR. | |||
448 | -----------------------------------------------------------------------------*/ | |||
449 | xmlrpc_datetime dt; | |||
450 | ||||
451 | #if HAVE_REGEX1 | |||
452 | parseDtRegex(envP, datetimeString, &dt); | |||
453 | #else | |||
454 | /* Note: validation is not as strong without regex */ | |||
455 | validateFormatNoRegex(envP, datetimeString); | |||
456 | if (!envP->fault_occurred) | |||
457 | parseDtNoRegex(envP, datetimeString, &dt); | |||
458 | #endif | |||
459 | ||||
460 | if (!envP->fault_occurred) { | |||
| ||||
461 | validateXmlrpcDatetimeSome(envP, dt); | |||
462 | ||||
463 | if (!envP->fault_occurred) | |||
464 | *valuePP = xmlrpc_datetime_new(envP, dt); | |||
| ||||
465 | } | |||
466 | } |