Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1167 lines
38 KiB

  1. /***
  2. *strftime.c - String Format Time
  3. *
  4. * Copyright (c) 1988-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. *
  8. *Revision History:
  9. * 03-09-89 JCR Initial version.
  10. * 03-15-89 JCR Changed day/month strings from all caps to leading cap
  11. * 06-20-89 JCR Removed _LOAD_DGROUP code
  12. * 03-20-90 GJF Replaced _LOAD_DS with _CALLTYPE1, added #include
  13. * <cruntime.h>, removed #include <register.h> and
  14. * removed some leftover 16-bit support. Also, fixed
  15. * the copyright.
  16. * 03-23-90 GJF Made static functions _CALLTYPE4.
  17. * 07-23-90 SBM Compiles cleanly with -W3 (removed unreferenced
  18. * variable)
  19. * 08-13-90 SBM Compiles cleanly with -W3 with new build of compiler
  20. * 10-04-90 GJF New-style function declarators.
  21. * 01-22-91 GJF ANSI naming.
  22. * 08-15-91 MRM Calls tzset() to set timezone info in case of %z.
  23. * 08-16-91 MRM Put appropriate header file for tzset().
  24. * 10-10-91 ETC Locale support under _INTL switch.
  25. * 12-18-91 ETC Use localized time strings structure.
  26. * 02-10-93 CFW Ported to Cuda tree, change _CALLTYPE4 to _CRTAPI3.
  27. * 02-16-93 CFW Massive changes: bug fixes & enhancements.
  28. * 03-08-93 CFW Changed _expand to _expandtime.
  29. * 03-09-93 CFW Handle string literals inside format strings.
  30. * 03-09-93 CFW Alternate form cleanup.
  31. * 03-17-93 CFW Change *count > 0, to *count != 0, *count is unsigned.
  32. * 03-22-93 CFW Change "C" locale time format specifier to 24-hour.
  33. * 03-30-93 GJF Call _tzset instead of __tzset (which no longer
  34. * exists).
  35. * 04-06-93 SKS Replace _CRTAPI* with __cdecl
  36. * 04-14-93 CFW Disable _alternate_form for 'X' specifier, fix count bug.
  37. * 04-28-93 CFW Fix bug in '%c' handling.
  38. * 07-15-93 GJF Call __tzset() in place of _tzset().
  39. * 09-15-93 CFW Use ANSI conformant "__" names.
  40. * 04-11-94 GJF Made definitions of __lc_time_c, _alternate_form and
  41. * _no_lead_zeros conditional on ndef DLL_FOR_WIN32S.
  42. * 09-06-94 CFW Remove _INTL switch.
  43. * 02-13-95 GJF Appended Mac version of source file (somewhat cleaned
  44. * up), with appropriate #ifdef-s.
  45. * 09-26-95 GJF New locking macro, and scheme, for functions which
  46. * reference the locale.
  47. * 02-22-96 JWM Merge in PlumHall mods.
  48. * 06-17-96 SKS Enable new Plum-Hall code for _MAC as well as _WIN32
  49. * 07-10-97 GJF Made __lc_time_c selectany. Also, removed unnecessary
  50. * init to 0 for globals, cleaned up the formatting a bit,
  51. * added a few __cdecls and detailed old (and no longer
  52. * used as of 6/17/96 change) Mac version.
  53. * 08-21-97 GJF Added support for AM/PM type suffix to time string.
  54. * 09-10-98 GJF Added support for per-thread locale info.
  55. * 03-04-99 GJF Added refcount field to __lc_time_c.
  56. * 05-17-99 PML Remove all Macintosh support.
  57. * 08-30-99 PML Don't overflow buffer on leadbyte in _store_winword.
  58. * 03-17-00 PML Corrected _Gettnames to also copy ww_timefmt (VS7#9374)
  59. * 09-07-00 PML Remove dependency on libcp.lib/xlocinfo.h (vs7#159463)
  60. * 03-25-01 PML Use GetDateFormat/GetTimeFormat in _store_winword for
  61. * calendar types other than the basic type 1, localized
  62. * Gregorian (vs7#196892) Also fix formatting for leading
  63. * zero suppression in fields, which was busted for %c,
  64. * %x, %X.
  65. * 12-11-01 BWT Replace _getptd with _getptd_noexit - we can return 0/ENOMEM
  66. * here instead of exiting.
  67. * 02-25-02 BWT Early exit expandtime if NULL is passed in as the timeptr
  68. *
  69. *******************************************************************************/
  70. #include <cruntime.h>
  71. #include <internal.h>
  72. #include <mtdll.h>
  73. #include <time.h>
  74. #include <locale.h>
  75. #include <setlocal.h>
  76. #include <ctype.h>
  77. #include <stdlib.h>
  78. #include <string.h>
  79. #include <dbgint.h>
  80. #include <malloc.h>
  81. #include <errno.h>
  82. /* Prototypes for local routines */
  83. static void __cdecl _expandtime(
  84. #ifdef _MT
  85. pthreadlocinfo ptloci,
  86. #endif
  87. char specifier,
  88. const struct tm *tmptr,
  89. char **out,
  90. size_t *count,
  91. struct __lc_time_data *lc_time,
  92. unsigned alternate_form);
  93. static void __cdecl _store_str (char *in, char **out, size_t *count);
  94. static void __cdecl _store_num (int num, int digits, char **out, size_t *count,
  95. unsigned no_lead_zeros);
  96. static void __cdecl _store_number (int num, char **out, size_t *count);
  97. static void __cdecl _store_winword (
  98. #ifdef _MT
  99. pthreadlocinfo ptloci,
  100. #endif
  101. int field_code,
  102. const struct tm *tmptr,
  103. char **out,
  104. size_t *count,
  105. struct __lc_time_data *lc_time);
  106. size_t __cdecl _Strftime (
  107. char *string,
  108. size_t maxsize,
  109. const char *format,
  110. const struct tm *timeptr,
  111. void *lc_time_arg
  112. );
  113. #ifdef _MT
  114. size_t __cdecl _Strftime_mt (pthreadlocinfo ptloci, char *string, size_t maxsize,
  115. const char *format, const struct tm *timeptr, void *lc_time_arg);
  116. #endif
  117. /* LC_TIME data for local "C" */
  118. __declspec(selectany) struct __lc_time_data __lc_time_c = {
  119. {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"},
  120. {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
  121. "Friday", "Saturday", },
  122. {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug",
  123. "Sep", "Oct", "Nov", "Dec"},
  124. {"January", "February", "March", "April", "May", "June",
  125. "July", "August", "September", "October",
  126. "November", "December"},
  127. {"AM", "PM"},
  128. { "MM/dd/yy" },
  129. { "dddd, MMMM dd, yyyy" },
  130. { "HH:mm:ss" },
  131. 0x0409,
  132. 1,
  133. #ifdef _MT
  134. 0
  135. #endif
  136. };
  137. /* Pointer to the current LC_TIME data structure. */
  138. struct __lc_time_data *__lc_time_curr = &__lc_time_c;
  139. /* Codes for __lc_time_data ww_* fields for _store_winword */
  140. #define WW_SDATEFMT 0
  141. #define WW_LDATEFMT 1
  142. #define WW_TIMEFMT 2
  143. #define TIME_SEP ':'
  144. /* get a copy of the current day names */
  145. char * __cdecl _Getdays (
  146. void
  147. )
  148. {
  149. const struct __lc_time_data *pt = __lc_time_curr;
  150. size_t n, len = 0;
  151. char *p;
  152. for (n = 0; n < 7; ++n)
  153. len += strlen(pt->wday_abbr[n]) + strlen(pt->wday[n]) + 2;
  154. p = (char *)_malloc_crt(len + 1);
  155. if (p != 0) {
  156. char *s = p;
  157. for (n = 0; n < 7; ++n) {
  158. *s++ = TIME_SEP;
  159. s += strlen(strcpy(s, pt->wday_abbr[n]));
  160. *s++ = TIME_SEP;
  161. s += strlen(strcpy(s, pt->wday[n]));
  162. }
  163. *s++ = '\0';
  164. }
  165. return (p);
  166. }
  167. /* get a copy of the current month names */
  168. char * __cdecl _Getmonths (
  169. void
  170. )
  171. {
  172. const struct __lc_time_data *pt = __lc_time_curr;
  173. size_t n, len = 0;
  174. char *p;
  175. for (n = 0; n < 12; ++n)
  176. len += strlen(pt->month_abbr[n]) + strlen(pt->month[n]) + 2;
  177. p = (char *)_malloc_crt(len + 1);
  178. if (p != 0) {
  179. char *s = p;
  180. for (n = 0; n < 12; ++n) {
  181. *s++ = TIME_SEP;
  182. s += strlen(strcpy(s, pt->month_abbr[n]));
  183. *s++ = TIME_SEP;
  184. s += strlen(strcpy(s, pt->month[n]));
  185. }
  186. *s++ = '\0';
  187. }
  188. return (p);
  189. }
  190. /* get a copy of the current time locale information */
  191. void * __cdecl _Gettnames (
  192. void
  193. )
  194. {
  195. const struct __lc_time_data *pt = __lc_time_curr;
  196. size_t n, len = 0;
  197. void *p;
  198. for (n = 0; n < 7; ++n)
  199. len += strlen(pt->wday_abbr[n]) + strlen(pt->wday[n]) + 2;
  200. for (n = 0; n < 12; ++n)
  201. len += strlen(pt->month_abbr[n]) + strlen(pt->month[n]) + 2;
  202. len += strlen(pt->ampm[0]) + strlen(pt->ampm[1]) + 2;
  203. len += strlen(pt->ww_sdatefmt) + 1;
  204. len += strlen(pt->ww_ldatefmt) + 1;
  205. len += strlen(pt->ww_timefmt) + 1;
  206. p = _malloc_crt(sizeof (*pt) + len);
  207. if (p != 0) {
  208. struct __lc_time_data *pn = (struct __lc_time_data *)p;
  209. char *s = (char *)p + sizeof (*pt);
  210. memcpy(p, __lc_time_curr, sizeof (*pt));
  211. for (n = 0; n < 7; ++n) {
  212. pn->wday_abbr[n] = s;
  213. s += strlen(strcpy(s, pt->wday_abbr[n])) + 1;
  214. pn->wday[n] = s;
  215. s += strlen(strcpy(s, pt->wday[n])) + 1;
  216. }
  217. for (n = 0; n < 12; ++n) {
  218. pn->month_abbr[n] = s;
  219. s += strlen(strcpy(s, pt->month_abbr[n])) + 1;
  220. pn->month[n] = s;
  221. s += strlen(strcpy(s, pt->month[n])) + 1;
  222. }
  223. pn->ampm[0] = s;
  224. s += strlen(strcpy(s, pt->ampm[0])) + 1;
  225. pn->ampm[1] = s;
  226. s += strlen(strcpy(s, pt->ampm[1])) + 1;
  227. pn->ww_sdatefmt = s;
  228. s += strlen(strcpy(s, pt->ww_sdatefmt)) + 1;
  229. pn->ww_ldatefmt = s;
  230. s += strlen(strcpy(s, pt->ww_ldatefmt)) + 1;
  231. pn->ww_timefmt = s;
  232. strcpy(s, pt->ww_timefmt);
  233. }
  234. return (p);
  235. }
  236. /***
  237. *size_t strftime(string, maxsize, format, timeptr) - Format a time string
  238. *
  239. *Purpose:
  240. * Place characters into the user's output buffer expanding time
  241. * format directives as described in the user's control string.
  242. * Use the supplied 'tm' structure for time data when expanding
  243. * the format directives.
  244. * [ANSI]
  245. *
  246. *Entry:
  247. * char *string = pointer to output string
  248. * size_t maxsize = max length of string
  249. * const char *format = format control string
  250. * const struct tm *timeptr = pointer to tb data structure
  251. *
  252. *Exit:
  253. * !0 = If the total number of resulting characters including the
  254. * terminating null is not more than 'maxsize', then return the
  255. * number of chars placed in the 'string' array (not including the
  256. * null terminator).
  257. *
  258. * 0 = Otherwise, return 0 and the contents of the string are
  259. * indeterminate.
  260. *
  261. *Exceptions:
  262. *
  263. *******************************************************************************/
  264. size_t __cdecl strftime (
  265. char *string,
  266. size_t maxsize,
  267. const char *format,
  268. const struct tm *timeptr
  269. )
  270. {
  271. return (_Strftime(string, maxsize, format, timeptr, 0));
  272. }
  273. /***
  274. *size_t _Strftime(string, maxsize, format,
  275. * timeptr, lc_time) - Format a time string for a given locale
  276. *
  277. *Purpose:
  278. * Place characters into the user's output buffer expanding time
  279. * format directives as described in the user's control string.
  280. * Use the supplied 'tm' structure for time data when expanding
  281. * the format directives. use the locale information at lc_time.
  282. * [ANSI]
  283. *
  284. *Entry:
  285. * char *string = pointer to output string
  286. * size_t maxsize = max length of string
  287. * const char *format = format control string
  288. * const struct tm *timeptr = pointer to tb data structure
  289. * struct __lc_time_data *lc_time = pointer to locale-specific info
  290. * (passed as void * to avoid type mismatch with C++)
  291. *
  292. *Exit:
  293. * !0 = If the total number of resulting characters including the
  294. * terminating null is not more than 'maxsize', then return the
  295. * number of chars placed in the 'string' array (not including the
  296. * null terminator).
  297. *
  298. * 0 = Otherwise, return 0 and the contents of the string are
  299. * indeterminate.
  300. *
  301. *Exceptions:
  302. *
  303. *******************************************************************************/
  304. size_t __cdecl _Strftime (
  305. char *string,
  306. size_t maxsize,
  307. const char *format,
  308. const struct tm *timeptr,
  309. void *lc_time_arg
  310. )
  311. {
  312. #ifdef _MT
  313. pthreadlocinfo ptloci;
  314. _ptiddata ptd = _getptd_noexit();
  315. if (!ptd) {
  316. errno = ENOMEM;
  317. return 0;
  318. }
  319. ptloci = ptd->ptlocinfo;
  320. if ( ptloci != __ptlocinfo )
  321. ptloci = __updatetlocinfo();
  322. return _Strftime_mt(ptloci, string, maxsize, format, timeptr,
  323. lc_time_arg);
  324. }
  325. size_t __cdecl _Strftime_mt (
  326. pthreadlocinfo ptloci,
  327. char *string,
  328. size_t maxsize,
  329. const char *format,
  330. const struct tm *timeptr,
  331. void *lc_time_arg
  332. )
  333. {
  334. #endif
  335. unsigned alternate_form;
  336. struct __lc_time_data *lc_time;
  337. size_t left; /* space left in output string */
  338. #ifdef _MT
  339. lc_time = lc_time_arg == 0 ? ptloci->lc_time_curr :
  340. #else
  341. lc_time = lc_time_arg == 0 ? __lc_time_curr :
  342. #endif
  343. (struct __lc_time_data *)lc_time_arg;
  344. /* Copy maxsize into temp. */
  345. left = maxsize;
  346. /* Copy the input string to the output string expanding the format
  347. designations appropriately. Stop copying when one of the following
  348. is true: (1) we hit a null char in the input stream, or (2) there's
  349. no room left in the output stream. */
  350. while (left > 0)
  351. {
  352. switch(*format)
  353. {
  354. case('\0'):
  355. /* end of format input string */
  356. goto done;
  357. case('%'):
  358. /* Format directive. Take appropriate action based
  359. on format control character. */
  360. if (!timeptr) {
  361. return 0;
  362. }
  363. format++; /* skip over % char */
  364. /* process flags */
  365. alternate_form = 0;
  366. if (*format == '#')
  367. {
  368. alternate_form = 1;
  369. format++;
  370. }
  371. #ifdef _MT
  372. _expandtime (ptloci, *format, timeptr, &string,
  373. #else
  374. _expandtime (*format, timeptr, &string,
  375. #endif
  376. &left,lc_time, alternate_form);
  377. format++; /* skip format char */
  378. break;
  379. default:
  380. /* store character, bump pointers, dec the char count */
  381. if (isleadbyte((int)(*format)) && left > 1)
  382. {
  383. *string++ = *format++;
  384. left--;
  385. }
  386. *string++ = *format++;
  387. left--;
  388. break;
  389. }
  390. }
  391. /* All done. See if we terminated because we hit a null char or because
  392. we ran out of space */
  393. done:
  394. if (left > 0) {
  395. /* Store a terminating null char and return the number of chars
  396. we stored in the output string. */
  397. *string = '\0';
  398. return(maxsize-left);
  399. }
  400. else
  401. return(0);
  402. }
  403. /***
  404. *_expandtime() - Expand the conversion specifier
  405. *
  406. *Purpose:
  407. * Expand the given strftime conversion specifier using the time struct
  408. * and store it in the supplied buffer.
  409. *
  410. * The expansion is locale-dependent.
  411. *
  412. * *** For internal use with strftime() only ***
  413. *
  414. *Entry:
  415. * char specifier = strftime conversion specifier to expand
  416. * const struct tm *tmptr = pointer to time/date structure
  417. * char **string = address of pointer to output string
  418. * size_t *count = address of char count (space in output area)
  419. * struct __lc_time_data *lc_time = pointer to locale-specific info
  420. *
  421. *Exit:
  422. * none
  423. *
  424. *Exceptions:
  425. *
  426. *******************************************************************************/
  427. static void __cdecl _expandtime (
  428. #ifdef _MT
  429. pthreadlocinfo ptloci,
  430. #endif
  431. char specifier,
  432. const struct tm *timeptr,
  433. char **string,
  434. size_t *left,
  435. struct __lc_time_data *lc_time,
  436. unsigned alternate_form
  437. )
  438. {
  439. unsigned temp; /* temps */
  440. int wdaytemp;
  441. /* Use a copy of the appropriate __lc_time_data pointer. This
  442. should prevent the necessity of locking/unlocking in mthread
  443. code (if we can guarantee that the various __lc_time data
  444. structures are always in the same segment). contents of time
  445. strings structure can now change, so thus we do use locking */
  446. switch(specifier) { /* switch on specifier */
  447. case('a'): /* abbreviated weekday name */
  448. _store_str((char *)(lc_time->wday_abbr[timeptr->tm_wday]),
  449. string, left);
  450. break;
  451. case('A'): /* full weekday name */
  452. _store_str((char *)(lc_time->wday[timeptr->tm_wday]),
  453. string, left);
  454. break;
  455. case('b'): /* abbreviated month name */
  456. _store_str((char *)(lc_time->month_abbr[timeptr->tm_mon]),
  457. string, left);
  458. break;
  459. case('B'): /* full month name */
  460. _store_str((char *)(lc_time->month[timeptr->tm_mon]),
  461. string, left);
  462. break;
  463. case('c'): /* date and time display */
  464. if (alternate_form)
  465. {
  466. _store_winword(
  467. #ifdef _MT
  468. ptloci,
  469. #endif
  470. WW_LDATEFMT, timeptr, string, left, lc_time);
  471. if (*left == 0)
  472. return;
  473. *(*string)++=' ';
  474. (*left)--;
  475. _store_winword(
  476. #ifdef _MT
  477. ptloci,
  478. #endif
  479. WW_TIMEFMT, timeptr, string, left, lc_time);
  480. }
  481. else {
  482. _store_winword(
  483. #ifdef _MT
  484. ptloci,
  485. #endif
  486. WW_SDATEFMT, timeptr, string, left, lc_time);
  487. if (*left == 0)
  488. return;
  489. *(*string)++=' ';
  490. (*left)--;
  491. _store_winword(
  492. #ifdef _MT
  493. ptloci,
  494. #endif
  495. WW_TIMEFMT, timeptr, string, left, lc_time);
  496. }
  497. break;
  498. case('d'): /* mday in decimal (01-31) */
  499. /* pass alternate_form as the no leading zeros flag */
  500. _store_num(timeptr->tm_mday, 2, string, left,
  501. alternate_form);
  502. break;
  503. case('H'): /* 24-hour decimal (00-23) */
  504. /* pass alternate_form as the no leading zeros flag */
  505. _store_num(timeptr->tm_hour, 2, string, left,
  506. alternate_form);
  507. break;
  508. case('I'): /* 12-hour decimal (01-12) */
  509. if (!(temp = timeptr->tm_hour%12))
  510. temp=12;
  511. /* pass alternate_form as the no leading zeros flag */
  512. _store_num(temp, 2, string, left, alternate_form);
  513. break;
  514. case('j'): /* yday in decimal (001-366) */
  515. /* pass alternate_form as the no leading zeros flag */
  516. _store_num(timeptr->tm_yday+1, 3, string, left,
  517. alternate_form);
  518. break;
  519. case('m'): /* month in decimal (01-12) */
  520. /* pass alternate_form as the no leading zeros flag */
  521. _store_num(timeptr->tm_mon+1, 2, string, left,
  522. alternate_form);
  523. break;
  524. case('M'): /* minute in decimal (00-59) */
  525. /* pass alternate_form as the no leading zeros flag */
  526. _store_num(timeptr->tm_min, 2, string, left,
  527. alternate_form);
  528. break;
  529. case('p'): /* AM/PM designation */
  530. if (timeptr->tm_hour <= 11)
  531. _store_str((char *)(lc_time->ampm[0]), string, left);
  532. else
  533. _store_str((char *)(lc_time->ampm[1]), string, left);
  534. break;
  535. case('S'): /* secs in decimal (00-59) */
  536. /* pass alternate_form as the no leading zeros flag */
  537. _store_num(timeptr->tm_sec, 2, string, left,
  538. alternate_form);
  539. break;
  540. case('U'): /* sunday week number (00-53) */
  541. wdaytemp = timeptr->tm_wday;
  542. goto weeknum; /* join common code */
  543. case('w'): /* week day in decimal (0-6) */
  544. /* pass alternate_form as the no leading zeros flag */
  545. _store_num(timeptr->tm_wday, 1, string, left,
  546. alternate_form);
  547. break;
  548. case('W'): /* monday week number (00-53) */
  549. if (timeptr->tm_wday == 0) /* monday based */
  550. wdaytemp = 6;
  551. else
  552. wdaytemp = timeptr->tm_wday-1;
  553. weeknum:
  554. if (timeptr->tm_yday < wdaytemp)
  555. temp = 0;
  556. else {
  557. temp = timeptr->tm_yday/7;
  558. if ((timeptr->tm_yday%7) >= wdaytemp)
  559. temp++;
  560. }
  561. /* pass alternate_form as the no leading zeros flag */
  562. _store_num(temp, 2, string, left, alternate_form);
  563. break;
  564. case('x'): /* date display */
  565. if (alternate_form)
  566. {
  567. _store_winword(
  568. #ifdef _MT
  569. ptloci,
  570. #endif
  571. WW_LDATEFMT, timeptr, string, left, lc_time);
  572. }
  573. else
  574. {
  575. _store_winword(
  576. #ifdef _MT
  577. ptloci,
  578. #endif
  579. WW_SDATEFMT, timeptr, string, left, lc_time);
  580. }
  581. break;
  582. case('X'): /* time display */
  583. _store_winword(
  584. #ifdef _MT
  585. ptloci,
  586. #endif
  587. WW_TIMEFMT, timeptr, string, left, lc_time);
  588. break;
  589. case('y'): /* year w/o century (00-99) */
  590. temp = timeptr->tm_year%100;
  591. /* pass alternate_form as the no leading zeros flag */
  592. _store_num(temp, 2, string, left, alternate_form);
  593. break;
  594. case('Y'): /* year w/ century */
  595. temp = (((timeptr->tm_year/100)+19)*100) +
  596. (timeptr->tm_year%100);
  597. /* pass alternate_form as the no leading zeros flag */
  598. _store_num(temp, 4, string, left, alternate_form);
  599. break;
  600. case('Z'): /* time zone name, if any */
  601. case('z'): /* time zone name, if any */
  602. #ifdef _POSIX_
  603. tzset(); /* Set time zone info */
  604. _store_str(tzname[((timeptr->tm_isdst)?1:0)],
  605. string, left);
  606. #else
  607. __tzset(); /* Set time zone info */
  608. _store_str(_tzname[((timeptr->tm_isdst)?1:0)],
  609. string, left);
  610. #endif
  611. break;
  612. case('%'): /* percent sign */
  613. *(*string)++ = '%';
  614. (*left)--;
  615. break;
  616. default: /* unknown format directive */
  617. /* ignore the directive and continue */
  618. /* [ANSI: Behavior is undefined.] */
  619. break;
  620. } /* end % switch */
  621. }
  622. /***
  623. *_store_str() - Copy a time string
  624. *
  625. *Purpose:
  626. * Copy the supplied time string into the output string until
  627. * (1) we hit a null in the time string, or (2) the given count
  628. * goes to 0.
  629. *
  630. * *** For internal use with strftime() only ***
  631. *
  632. *Entry:
  633. * char *in = pointer to null terminated time string
  634. * char **out = address of pointer to output string
  635. * size_t *count = address of char count (space in output area)
  636. *
  637. *Exit:
  638. * none
  639. *Exceptions:
  640. *
  641. *******************************************************************************/
  642. static void __cdecl _store_str (
  643. char *in,
  644. char **out,
  645. size_t *count
  646. )
  647. {
  648. while ((*count != 0) && (*in != '\0')) {
  649. *(*out)++ = *in++;
  650. (*count)--;
  651. }
  652. }
  653. /***
  654. *_store_num() - Convert a number to ascii and copy it
  655. *
  656. *Purpose:
  657. * Convert the supplied number to decimal and store
  658. * in the output buffer. Update both the count and
  659. * buffer pointers.
  660. *
  661. * *** For internal use with strftime() only ***
  662. *
  663. *Entry:
  664. * int num = pointer to integer value
  665. * int digits = # of ascii digits to put into string
  666. * char **out = address of pointer to output string
  667. * size_t *count = address of char count (space in output area)
  668. * unsigned no_lead_zeros = flag indicating that padding by leading
  669. * zeros is not necessary
  670. *
  671. *Exit:
  672. * none
  673. *Exceptions:
  674. *
  675. *******************************************************************************/
  676. static void __cdecl _store_num (
  677. int num,
  678. int digits,
  679. char **out,
  680. size_t *count,
  681. unsigned no_lead_zeros
  682. )
  683. {
  684. int temp = 0;
  685. if (no_lead_zeros) {
  686. _store_number (num, out, count);
  687. return;
  688. }
  689. if ((size_t)digits < *count) {
  690. for (digits--; (digits+1); digits--) {
  691. (*out)[digits] = (char)('0' + num % 10);
  692. num /= 10;
  693. temp++;
  694. }
  695. *out += temp;
  696. *count -= temp;
  697. }
  698. else
  699. *count = 0;
  700. }
  701. /***
  702. *_store_number() - Convert positive integer to string
  703. *
  704. *Purpose:
  705. * Convert positive integer to a string and store it in the output
  706. * buffer with no null terminator. Update both the count and
  707. * buffer pointers.
  708. *
  709. * Differs from _store_num in that the precision is not specified,
  710. * and no leading zeros are added.
  711. *
  712. * *** For internal use with strftime() only ***
  713. *
  714. * Created from xtoi.c
  715. *
  716. *Entry:
  717. * int num = pointer to integer value
  718. * char **out = address of pointer to output string
  719. * size_t *count = address of char count (space in output area)
  720. *
  721. *Exit:
  722. * none
  723. *
  724. *Exceptions:
  725. * The buffer is filled until it is out of space. There is no
  726. * way to tell beforehand (as in _store_num) if the buffer will
  727. * run out of space.
  728. *
  729. *******************************************************************************/
  730. static void __cdecl _store_number (
  731. int num,
  732. char **out,
  733. size_t *count
  734. )
  735. {
  736. char *p; /* pointer to traverse string */
  737. char *firstdig; /* pointer to first digit */
  738. char temp; /* temp char */
  739. p = *out;
  740. /* put the digits in the buffer in reverse order */
  741. if (*count > 1)
  742. {
  743. do {
  744. *p++ = (char) (num % 10 + '0');
  745. (*count)--;
  746. } while ((num/=10) > 0 && *count > 1);
  747. }
  748. firstdig = *out; /* firstdig points to first digit */
  749. *out = p; /* return pointer to next space */
  750. p--; /* p points to last digit */
  751. /* reverse the buffer */
  752. do {
  753. temp = *p;
  754. *p-- = *firstdig;
  755. *firstdig++ = temp; /* swap *p and *firstdig */
  756. } while (firstdig < p); /* repeat until halfway */
  757. }
  758. /***
  759. *_store_winword() - Store date/time in WinWord format
  760. *
  761. *Purpose:
  762. * Format the date/time in the supplied WinWord format
  763. * and store it in the supplied buffer.
  764. *
  765. * *** For internal use with strftime() only ***
  766. *
  767. * For simple localized Gregorian calendars (calendar type 1), the WinWord
  768. * format is converted token by token to strftime conversion specifiers.
  769. * _expandtime is then called to do the work. The WinWord format is
  770. * expected to be a character string (not wide-chars).
  771. *
  772. * For other calendar types, the Win32 APIs GetDateFormat/GetTimeFormat
  773. * are instead used to do all formatting, so that this routine doesn't
  774. * have to know about era/period strings, year offsets, etc.
  775. *
  776. *
  777. *Entry:
  778. * int field_code = code for ww_* field with format
  779. * const struct tm *tmptr = pointer to time/date structure
  780. * char **out = address of pointer to output string
  781. * size_t *count = address of char count (space in output area)
  782. * struct __lc_time_data *lc_time = pointer to locale-specific info
  783. *
  784. *Exit:
  785. * none
  786. *
  787. *Exceptions:
  788. *
  789. *******************************************************************************/
  790. static void __cdecl _store_winword (
  791. #ifdef _MT
  792. pthreadlocinfo ptloci,
  793. #endif
  794. int field_code,
  795. const struct tm *tmptr,
  796. char **out,
  797. size_t *count,
  798. struct __lc_time_data *lc_time
  799. )
  800. {
  801. const char *format;
  802. char specifier;
  803. const char *p;
  804. int repeat;
  805. char *ampmstr;
  806. unsigned no_lead_zeros;
  807. switch (field_code)
  808. {
  809. case WW_SDATEFMT:
  810. format = lc_time->ww_sdatefmt;
  811. break;
  812. case WW_LDATEFMT:
  813. format = lc_time->ww_ldatefmt;
  814. break;
  815. case WW_TIMEFMT:
  816. default:
  817. format = lc_time->ww_timefmt;
  818. break;
  819. }
  820. if (lc_time->ww_caltype != 1)
  821. {
  822. /* We have something other than the basic Gregorian calendar */
  823. SYSTEMTIME SystemTime;
  824. int cch;
  825. int (WINAPI * FormatFunc)(LCID, DWORD, const SYSTEMTIME *,
  826. LPCSTR, LPSTR, int);
  827. if (field_code != WW_TIMEFMT)
  828. FormatFunc = GetDateFormat;
  829. else
  830. FormatFunc = GetTimeFormat;
  831. SystemTime.wYear = (WORD)(tmptr->tm_year + 1900);
  832. SystemTime.wMonth = (WORD)(tmptr->tm_mon + 1);
  833. SystemTime.wDay = (WORD)(tmptr->tm_mday);
  834. SystemTime.wHour = (WORD)(tmptr->tm_hour);
  835. SystemTime.wMinute = (WORD)(tmptr->tm_min);
  836. SystemTime.wSecond = (WORD)(tmptr->tm_sec);
  837. SystemTime.wMilliseconds = 0;
  838. /* Find buffer size required */
  839. cch = FormatFunc(lc_time->ww_lcid, 0, &SystemTime,
  840. format, NULL, 0);
  841. if (cch != 0)
  842. {
  843. int malloc_flag = 0;
  844. char *buffer;
  845. /* Allocate buffer, first try stack, then heap */
  846. __try
  847. {
  848. buffer = (char *)_alloca(cch);
  849. }
  850. __except (EXCEPTION_EXECUTE_HANDLER)
  851. {
  852. _resetstkoflw();
  853. buffer = NULL;
  854. }
  855. if (buffer == NULL)
  856. {
  857. buffer = (char *)_malloc_crt(cch);
  858. if (buffer != NULL)
  859. malloc_flag = 1;
  860. }
  861. if (buffer != NULL)
  862. {
  863. /* Do actual date/time formatting */
  864. cch = FormatFunc(lc_time->ww_lcid, 0, &SystemTime,
  865. format, buffer, cch);
  866. /* Copy to output buffer */
  867. p = buffer;
  868. while (--cch > 0 && *count > 0) {
  869. *(*out)++ = *p++;
  870. (*count)--;
  871. }
  872. if (malloc_flag)
  873. _free_crt(buffer);
  874. return;
  875. }
  876. }
  877. /* In case of error, just fall through to localized Gregorian */
  878. }
  879. while (*format && *count != 0)
  880. {
  881. specifier = 0; /* indicate no match */
  882. no_lead_zeros = 0; /* default is print leading zeros */
  883. /* count the number of repetitions of this character */
  884. for (repeat=0, p=format; *p++ == *format; repeat++);
  885. /* leave p pointing to the beginning of the next token */
  886. p--;
  887. /* switch on ascii format character and determine specifier */
  888. switch (*format)
  889. {
  890. case 'M':
  891. switch (repeat)
  892. {
  893. case 1: no_lead_zeros = 1; /* fall thru */
  894. case 2: specifier = 'm'; break;
  895. case 3: specifier = 'b'; break;
  896. case 4: specifier = 'B'; break;
  897. } break;
  898. case 'd':
  899. switch (repeat)
  900. {
  901. case 1: no_lead_zeros = 1; /* fall thru */
  902. case 2: specifier = 'd'; break;
  903. case 3: specifier = 'a'; break;
  904. case 4: specifier = 'A'; break;
  905. } break;
  906. case 'y':
  907. switch (repeat)
  908. {
  909. case 2: specifier = 'y'; break;
  910. case 4: specifier = 'Y'; break;
  911. } break;
  912. case 'h':
  913. switch (repeat)
  914. {
  915. case 1: no_lead_zeros = 1; /* fall thru */
  916. case 2: specifier = 'I'; break;
  917. } break;
  918. case 'H':
  919. switch (repeat)
  920. {
  921. case 1: no_lead_zeros = 1; /* fall thru */
  922. case 2: specifier = 'H'; break;
  923. } break;
  924. case 'm':
  925. switch (repeat)
  926. {
  927. case 1: no_lead_zeros = 1; /* fall thru */
  928. case 2: specifier = 'M'; break;
  929. } break;
  930. case 's': /* for compatibility; not strictly WinWord */
  931. switch (repeat)
  932. {
  933. case 1: no_lead_zeros = 1; /* fall thru */
  934. case 2: specifier = 'S'; break;
  935. } break;
  936. case 'A':
  937. case 'a':
  938. if (!__ascii_stricmp(format, "am/pm"))
  939. p = format + 5;
  940. else if (!__ascii_stricmp(format, "a/p"))
  941. p = format + 3;
  942. specifier = 'p';
  943. break;
  944. case 't': /* t or tt time marker suffix */
  945. if ( tmptr->tm_hour <= 11 )
  946. ampmstr = lc_time->ampm[0];
  947. else
  948. ampmstr = lc_time->ampm[1];
  949. if ( (repeat == 1) && (*count > 0) ) {
  950. if (
  951. #ifdef _MT
  952. __isleadbyte_mt(ptloci, (int)*ampmstr) &&
  953. #else
  954. isleadbyte((int)*ampmstr) &&
  955. #endif
  956. (*count > 1) )
  957. {
  958. *(*out)++ = *ampmstr++;
  959. (*count)--;
  960. }
  961. *(*out)++ = *ampmstr++;
  962. (*count)--;
  963. } else {
  964. while (*ampmstr != 0 && *count > 0) {
  965. if (isleadbyte((int)*ampmstr) && *count > 1) {
  966. *(*out)++ = *ampmstr++;
  967. (*count)--;
  968. }
  969. *(*out)++ = *ampmstr++;
  970. (*count)--;
  971. }
  972. }
  973. format = p;
  974. continue;
  975. case '\'': /* literal string */
  976. if (repeat & 1) /* odd number */
  977. {
  978. format += repeat;
  979. while (*format && *count != 0)
  980. {
  981. if (*format == '\'')
  982. {
  983. format++;
  984. break;
  985. }
  986. #ifdef _MT
  987. if ( __isleadbyte_mt(ptloci, (int)*format) &&
  988. #else
  989. if ( isleadbyte((int)*format) &&
  990. #endif
  991. (*count > 1) )
  992. {
  993. *(*out)++ = *format++;
  994. (*count)--;
  995. }
  996. *(*out)++ = *format++;
  997. (*count)--;
  998. }
  999. }
  1000. else { /* even number */
  1001. format += repeat;
  1002. }
  1003. continue;
  1004. default: /* non-control char, print it */
  1005. break;
  1006. } /* switch */
  1007. /* expand specifier, or copy literal if specifier not found */
  1008. if (specifier)
  1009. {
  1010. _expandtime(
  1011. #ifdef _MT
  1012. ptloci,
  1013. #endif
  1014. specifier, tmptr, out, count,
  1015. lc_time, no_lead_zeros);
  1016. format = p; /* bump format up to the next token */
  1017. } else {
  1018. #ifdef _MT
  1019. if (__isleadbyte_mt(ptloci, (int)*format) &&
  1020. #else
  1021. if (isleadbyte((int)*format) &&
  1022. #endif
  1023. (*count > 1))
  1024. {
  1025. *(*out)++ = *format++;
  1026. (*count)--;
  1027. }
  1028. *(*out)++ = *format++;
  1029. (*count)--;
  1030. }
  1031. } /* while */
  1032. }