strptime.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627
  1. // ATTN! this is port of FreeBSD LIBC code to Win32 - just for convenience.
  2. // Locale is ignored!!!
  3. /*
  4. * Powerdog Industries kindly requests feedback from anyone modifying
  5. * this function:
  6. *
  7. * Date: Thu, 05 Jun 1997 23:17:17 -0400
  8. * From: Kevin Ruddy <kevin.ruddy@powerdog.com>
  9. * To: James FitzGibbon <james@nexis.net>
  10. * Subject: Re: Use of your strptime(3) code (fwd)
  11. *
  12. * The reason for the "no mod" clause was so that modifications would
  13. * come back and we could integrate them and reissue so that a wider
  14. * audience could use it (thereby spreading the wealth). This has
  15. * made it possible to get strptime to work on many operating systems.
  16. * I'm not sure why that's "plain unacceptable" to the FreeBSD team.
  17. *
  18. * Anyway, you can change it to "with or without modification" as
  19. * you see fit. Enjoy.
  20. *
  21. * Kevin Ruddy
  22. * Powerdog Industries, Inc.
  23. */
  24. /*
  25. * Copyright (c) 1994 Powerdog Industries. All rights reserved.
  26. *
  27. * Redistribution and use in source and binary forms, with or without
  28. * modification, are permitted provided that the following conditions
  29. * are met:
  30. * 1. Redistributions of source code must retain the above copyright
  31. * notice, this list of conditions and the following disclaimer.
  32. * 2. Redistributions in binary form must reproduce the above copyright
  33. * notice, this list of conditions and the following disclaimer
  34. * in the documentation and/or other materials provided with the
  35. * distribution.
  36. * 3. All advertising materials mentioning features or use of this
  37. * software must display the following acknowledgement:
  38. * This product includes software developed by Powerdog Industries.
  39. * 4. The name of Powerdog Industries may not be used to endorse or
  40. * promote products derived from this software without specific prior
  41. * written permission.
  42. *
  43. * THIS SOFTWARE IS PROVIDED BY POWERDOG INDUSTRIES ``AS IS'' AND ANY
  44. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  45. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  46. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE POWERDOG INDUSTRIES BE
  47. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  48. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  49. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
  50. * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  51. * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
  52. * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
  53. * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  54. */
  55. #include <util/system/compat.h>
  56. #include "systime.h"
  57. #ifdef _win32_
  58. #ifndef lint
  59. #ifndef NOID
  60. static char copyright[] =
  61. "@(#) Copyright (c) 1994 Powerdog Industries. All rights reserved.";
  62. static char sccsid[] = "@(#)strptime.c 0.1 (Powerdog) 94/03/27";
  63. #endif /* !defined NOID */
  64. #endif /* not lint */
  65. //__FBSDID("$FreeBSD: src/lib/libc/stdtime/strptime.c,v 1.35 2003/11/17 04:19:15 nectar Exp $");
  66. //#include "namespace.h"
  67. #include <time.h>
  68. #include <ctype.h>
  69. #include <errno.h>
  70. #include <stdlib.h>
  71. #include <string.h>
  72. //#include <pthread.h>
  73. //#include "un-namespace.h"
  74. //#include "libc_private.h"
  75. // ******************* #include "timelocal.h" *********************
  76. struct lc_time_T {
  77. const char* mon[12];
  78. const char* month[12];
  79. const char* wday[7];
  80. const char* weekday[7];
  81. const char* X_fmt;
  82. const char* x_fmt;
  83. const char* c_fmt;
  84. const char* am;
  85. const char* pm;
  86. const char* date_fmt;
  87. const char* alt_month[12];
  88. const char* md_order;
  89. const char* ampm_fmt;
  90. };
  91. // ******************* timelocal.c ******************
  92. /*-
  93. * Copyright (c) 2001 Alexey Zelkin <phantom@FreeBSD.org>
  94. * Copyright (c) 1997 FreeBSD Inc.
  95. * All rights reserved.
  96. */
  97. static const struct lc_time_T _C_time_locale = {
  98. {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
  99. "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"},
  100. {"January", "February", "March", "April", "May", "June",
  101. "July", "August", "September", "October", "November", "December"},
  102. {"Sun", "Mon", "Tue", "Wed",
  103. "Thu", "Fri", "Sat"},
  104. {"Sunday", "Monday", "Tuesday", "Wednesday",
  105. "Thursday", "Friday", "Saturday"},
  106. /* X_fmt */
  107. "%H:%M:%S",
  108. /*
  109. * x_fmt
  110. * Since the C language standard calls for
  111. * "date, using locale's date format," anything goes.
  112. * Using just numbers (as here) makes Quakers happier;
  113. * it's also compatible with SVR4.
  114. */
  115. "%m/%d/%y",
  116. /*
  117. * c_fmt
  118. */
  119. "%a %b %e %H:%M:%S %Y",
  120. /* am */
  121. "AM",
  122. /* pm */
  123. "PM",
  124. /* date_fmt */
  125. "%a %b %e %H:%M:%S %Z %Y",
  126. /* alt_month
  127. * Standalone months forms for %OB
  128. */
  129. {
  130. "January", "February", "March", "April", "May", "June",
  131. "July", "August", "September", "October", "November", "December"},
  132. /* md_order
  133. * Month / day order in dates
  134. */
  135. "md",
  136. /* ampm_fmt
  137. * To determine 12-hour clock format time (empty, if N/A)
  138. */
  139. "%I:%M:%S %p"};
  140. struct lc_time_T*
  141. __get_current_time_locale(void)
  142. {
  143. return /*(_time_using_locale
  144. ? &_time_locale
  145. :*/
  146. (struct lc_time_T*)&_C_time_locale /*)*/;
  147. }
  148. // ******************* strptime.c *******************
  149. static char* _strptime(const char*, const char*, struct tm*, int*);
  150. #define asizeof(a) (sizeof(a) / sizeof((a)[0]))
  151. #if defined(_MSC_VER) && (_MSC_VER >= 1900)
  152. #define tzname _tzname
  153. #endif
  154. static char*
  155. _strptime(const char* buf, const char* fmt, struct tm* tm, int* GMTp)
  156. {
  157. char c;
  158. const char* ptr;
  159. int i;
  160. size_t len = 0;
  161. int Ealternative, Oalternative;
  162. struct lc_time_T* tptr = __get_current_time_locale();
  163. ptr = fmt;
  164. while (*ptr != 0) {
  165. if (*buf == 0)
  166. break;
  167. c = *ptr++;
  168. if (c != '%') {
  169. if (isspace((unsigned char)c))
  170. while (*buf != 0 && isspace((unsigned char)*buf))
  171. ++buf;
  172. else if (c != *buf++)
  173. return 0;
  174. continue;
  175. }
  176. Ealternative = 0;
  177. Oalternative = 0;
  178. label:
  179. c = *ptr++;
  180. switch (c) {
  181. case 0:
  182. case '%':
  183. if (*buf++ != '%')
  184. return 0;
  185. break;
  186. case '+':
  187. buf = _strptime(buf, tptr->date_fmt, tm, GMTp);
  188. if (buf == 0)
  189. return 0;
  190. break;
  191. case 'C':
  192. if (!isdigit((unsigned char)*buf))
  193. return 0;
  194. /* XXX This will break for 3-digit centuries. */
  195. len = 2;
  196. for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
  197. i *= 10;
  198. i += *buf - '0';
  199. --len;
  200. }
  201. if (i < 19)
  202. return 0;
  203. tm->tm_year = i * 100 - 1900;
  204. break;
  205. case 'c':
  206. buf = _strptime(buf, tptr->c_fmt, tm, GMTp);
  207. if (buf == 0)
  208. return 0;
  209. break;
  210. case 'D':
  211. buf = _strptime(buf, "%m/%d/%y", tm, GMTp);
  212. if (buf == 0)
  213. return 0;
  214. break;
  215. case 'E':
  216. if (Ealternative || Oalternative)
  217. break;
  218. ++Ealternative;
  219. goto label;
  220. case 'O':
  221. if (Ealternative || Oalternative)
  222. break;
  223. ++Oalternative;
  224. goto label;
  225. case 'F':
  226. buf = _strptime(buf, "%Y-%m-%d", tm, GMTp);
  227. if (buf == 0)
  228. return 0;
  229. break;
  230. case 'R':
  231. buf = _strptime(buf, "%H:%M", tm, GMTp);
  232. if (buf == 0)
  233. return 0;
  234. break;
  235. case 'r':
  236. buf = _strptime(buf, tptr->ampm_fmt, tm, GMTp);
  237. if (buf == 0)
  238. return 0;
  239. break;
  240. case 'T':
  241. buf = _strptime(buf, "%H:%M:%S", tm, GMTp);
  242. if (buf == 0)
  243. return 0;
  244. break;
  245. case 'X':
  246. buf = _strptime(buf, tptr->X_fmt, tm, GMTp);
  247. if (buf == 0)
  248. return 0;
  249. break;
  250. case 'x':
  251. buf = _strptime(buf, tptr->x_fmt, tm, GMTp);
  252. if (buf == 0)
  253. return 0;
  254. break;
  255. case 'j':
  256. if (!isdigit((unsigned char)*buf))
  257. return 0;
  258. len = 3;
  259. for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
  260. i *= 10;
  261. i += *buf - '0';
  262. --len;
  263. }
  264. if (i < 1 || i > 366)
  265. return 0;
  266. tm->tm_yday = i - 1;
  267. break;
  268. case 'M':
  269. case 'S':
  270. if (*buf == 0 || isspace((unsigned char)*buf))
  271. break;
  272. if (!isdigit((unsigned char)*buf))
  273. return 0;
  274. len = 2;
  275. for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
  276. i *= 10;
  277. i += *buf - '0';
  278. --len;
  279. }
  280. if (c == 'M') {
  281. if (i > 59)
  282. return 0;
  283. tm->tm_min = i;
  284. } else {
  285. if (i > 60)
  286. return 0;
  287. tm->tm_sec = i;
  288. }
  289. if (*buf != 0 && isspace((unsigned char)*buf))
  290. while (*ptr != 0 && !isspace((unsigned char)*ptr))
  291. ++ptr;
  292. break;
  293. case 'H':
  294. case 'I':
  295. case 'k':
  296. case 'l':
  297. /*
  298. * Of these, %l is the only specifier explicitly
  299. * documented as not being zero-padded. However,
  300. * there is no harm in allowing zero-padding.
  301. *
  302. * XXX The %l specifier may gobble one too many
  303. * digits if used incorrectly.
  304. */
  305. if (!isdigit((unsigned char)*buf))
  306. return 0;
  307. len = 2;
  308. for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
  309. i *= 10;
  310. i += *buf - '0';
  311. --len;
  312. }
  313. if (c == 'H' || c == 'k') {
  314. if (i > 23)
  315. return 0;
  316. } else if (i > 12)
  317. return 0;
  318. tm->tm_hour = i;
  319. if (*buf != 0 && isspace((unsigned char)*buf))
  320. while (*ptr != 0 && !isspace((unsigned char)*ptr))
  321. ++ptr;
  322. break;
  323. case 'p':
  324. /*
  325. * XXX This is bogus if parsed before hour-related
  326. * specifiers.
  327. */
  328. len = strlen(tptr->am);
  329. if (strnicmp(buf, tptr->am, len) == 0) {
  330. if (tm->tm_hour > 12)
  331. return 0;
  332. if (tm->tm_hour == 12)
  333. tm->tm_hour = 0;
  334. buf += len;
  335. break;
  336. }
  337. len = strlen(tptr->pm);
  338. if (strnicmp(buf, tptr->pm, len) == 0) {
  339. if (tm->tm_hour > 12)
  340. return 0;
  341. if (tm->tm_hour != 12)
  342. tm->tm_hour += 12;
  343. buf += len;
  344. break;
  345. }
  346. return 0;
  347. case 'A':
  348. case 'a':
  349. for (i = 0; i < asizeof(tptr->weekday); i++) {
  350. len = strlen(tptr->weekday[i]);
  351. if (strnicmp(buf, tptr->weekday[i],
  352. len) == 0)
  353. break;
  354. len = strlen(tptr->wday[i]);
  355. if (strnicmp(buf, tptr->wday[i],
  356. len) == 0)
  357. break;
  358. }
  359. if (i == asizeof(tptr->weekday))
  360. return 0;
  361. tm->tm_wday = i;
  362. buf += len;
  363. break;
  364. case 'U':
  365. case 'W':
  366. /*
  367. * XXX This is bogus, as we can not assume any valid
  368. * information present in the tm structure at this
  369. * point to calculate a real value, so just check the
  370. * range for now.
  371. */
  372. if (!isdigit((unsigned char)*buf))
  373. return 0;
  374. len = 2;
  375. for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
  376. i *= 10;
  377. i += *buf - '0';
  378. --len;
  379. }
  380. if (i > 53)
  381. return 0;
  382. if (*buf != 0 && isspace((unsigned char)*buf))
  383. while (*ptr != 0 && !isspace((unsigned char)*ptr))
  384. ++ptr;
  385. break;
  386. case 'w':
  387. if (!isdigit((unsigned char)*buf))
  388. return 0;
  389. i = *buf - '0';
  390. if (i > 6)
  391. return 0;
  392. tm->tm_wday = i;
  393. if (*buf != 0 && isspace((unsigned char)*buf))
  394. while (*ptr != 0 && !isspace((unsigned char)*ptr))
  395. ++ptr;
  396. break;
  397. case 'd':
  398. case 'e':
  399. /*
  400. * The %e specifier is explicitly documented as not
  401. * being zero-padded but there is no harm in allowing
  402. * such padding.
  403. *
  404. * XXX The %e specifier may gobble one too many
  405. * digits if used incorrectly.
  406. */
  407. if (!isdigit((unsigned char)*buf))
  408. return 0;
  409. len = 2;
  410. for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
  411. i *= 10;
  412. i += *buf - '0';
  413. --len;
  414. }
  415. if (i > 31)
  416. return 0;
  417. tm->tm_mday = i;
  418. if (*buf != 0 && isspace((unsigned char)*buf))
  419. while (*ptr != 0 && !isspace((unsigned char)*ptr))
  420. ++ptr;
  421. break;
  422. case 'B':
  423. case 'b':
  424. case 'h':
  425. for (i = 0; i < asizeof(tptr->month); i++) {
  426. if (Oalternative) {
  427. if (c == 'B') {
  428. len = strlen(tptr->alt_month[i]);
  429. if (strnicmp(buf,
  430. tptr->alt_month[i],
  431. len) == 0)
  432. break;
  433. }
  434. } else {
  435. len = strlen(tptr->month[i]);
  436. if (strnicmp(buf, tptr->month[i],
  437. len) == 0)
  438. break;
  439. len = strlen(tptr->mon[i]);
  440. if (strnicmp(buf, tptr->mon[i],
  441. len) == 0)
  442. break;
  443. }
  444. }
  445. if (i == asizeof(tptr->month))
  446. return 0;
  447. tm->tm_mon = i;
  448. buf += len;
  449. break;
  450. case 'm':
  451. if (!isdigit((unsigned char)*buf))
  452. return 0;
  453. len = 2;
  454. for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
  455. i *= 10;
  456. i += *buf - '0';
  457. --len;
  458. }
  459. if (i < 1 || i > 12)
  460. return 0;
  461. tm->tm_mon = i - 1;
  462. if (*buf != 0 && isspace((unsigned char)*buf))
  463. while (*ptr != 0 && !isspace((unsigned char)*ptr))
  464. ++ptr;
  465. break;
  466. case 's': {
  467. char* cp;
  468. int sverrno;
  469. long n;
  470. time_t t;
  471. sverrno = errno;
  472. errno = 0;
  473. n = strtol(buf, &cp, 10);
  474. if (errno == ERANGE || (long)(t = n) != n) {
  475. errno = sverrno;
  476. return 0;
  477. }
  478. errno = sverrno;
  479. buf = cp;
  480. GmTimeR(&t, tm);
  481. *GMTp = 1;
  482. } break;
  483. case 'Y':
  484. case 'y':
  485. if (*buf == 0 || isspace((unsigned char)*buf))
  486. break;
  487. if (!isdigit((unsigned char)*buf))
  488. return 0;
  489. len = (c == 'Y') ? 4 : 2;
  490. for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
  491. i *= 10;
  492. i += *buf - '0';
  493. --len;
  494. }
  495. if (c == 'Y')
  496. i -= 1900;
  497. if (c == 'y' && i < 69)
  498. i += 100;
  499. if (i < 0)
  500. return 0;
  501. tm->tm_year = i;
  502. if (*buf != 0 && isspace((unsigned char)*buf))
  503. while (*ptr != 0 && !isspace((unsigned char)*ptr))
  504. ++ptr;
  505. break;
  506. case 'Z': {
  507. const char* cp;
  508. char* zonestr;
  509. for (cp = buf; *cp && isupper((unsigned char)*cp); ++cp) { /*empty*/
  510. }
  511. if (cp - buf) {
  512. zonestr = (char*)alloca(cp - buf + 1);
  513. strncpy(zonestr, buf, cp - buf);
  514. zonestr[cp - buf] = '\0';
  515. tzset();
  516. if (0 == strcmp(zonestr, "GMT")) {
  517. *GMTp = 1;
  518. } else if (0 == strcmp(zonestr, tzname[0])) {
  519. tm->tm_isdst = 0;
  520. } else if (0 == strcmp(zonestr, tzname[1])) {
  521. tm->tm_isdst = 1;
  522. } else {
  523. return 0;
  524. }
  525. buf += cp - buf;
  526. }
  527. } break;
  528. }
  529. }
  530. return (char*)buf;
  531. }
  532. char* strptime(const char* buf, const char* fmt, struct tm* tm)
  533. {
  534. char* ret;
  535. int gmt;
  536. gmt = 0;
  537. ret = _strptime(buf, fmt, tm, &gmt);
  538. if (ret && gmt) {
  539. time_t t = timegm(tm);
  540. localtime_r(&t, tm);
  541. }
  542. return (ret);
  543. }
  544. #endif //_win32_