/crypto/heimdal/lib/roken/strftime.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 397 lines · 318 code · 23 blank · 56 comment · 19 complexity · 179d7f1fc925a47735041400152b7f78 MD5 · raw file

  1. /*
  2. * Copyright (c) 1999 - 2002 Kungliga Tekniska Hรถgskolan
  3. * (Royal Institute of Technology, Stockholm, Sweden).
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. *
  10. * 1. Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions and the following disclaimer.
  12. *
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in the
  15. * documentation and/or other materials provided with the distribution.
  16. *
  17. * 3. Neither the name of KTH nor the names of its contributors may be
  18. * used to endorse or promote products derived from this software without
  19. * specific prior written permission.
  20. *
  21. * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY
  22. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  24. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE
  25. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  26. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  27. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
  28. * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  29. * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  30. * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  31. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
  32. #include <config.h>
  33. #include "roken.h"
  34. #ifdef TEST_STRPFTIME
  35. #include "strpftime-test.h"
  36. #endif
  37. static const char *abb_weekdays[] = {
  38. "Sun",
  39. "Mon",
  40. "Tue",
  41. "Wed",
  42. "Thu",
  43. "Fri",
  44. "Sat",
  45. };
  46. static const char *full_weekdays[] = {
  47. "Sunday",
  48. "Monday",
  49. "Tuesday",
  50. "Wednesday",
  51. "Thursday",
  52. "Friday",
  53. "Saturday",
  54. };
  55. static const char *abb_month[] = {
  56. "Jan",
  57. "Feb",
  58. "Mar",
  59. "Apr",
  60. "May",
  61. "Jun",
  62. "Jul",
  63. "Aug",
  64. "Sep",
  65. "Oct",
  66. "Nov",
  67. "Dec"
  68. };
  69. static const char *full_month[] = {
  70. "January",
  71. "February",
  72. "Mars",
  73. "April",
  74. "May",
  75. "June",
  76. "July",
  77. "August",
  78. "September",
  79. "October",
  80. "November",
  81. "December"
  82. };
  83. static const char *ampm[] = {
  84. "AM",
  85. "PM"
  86. };
  87. /*
  88. * Convert hour in [0, 24] to [12 1 - 11 12 1 - 11 12]
  89. */
  90. static int
  91. hour_24to12 (int hour)
  92. {
  93. int ret = hour % 12;
  94. if (ret == 0)
  95. ret = 12;
  96. return ret;
  97. }
  98. /*
  99. * Return AM or PM for `hour'
  100. */
  101. static const char *
  102. hour_to_ampm (int hour)
  103. {
  104. return ampm[hour / 12];
  105. }
  106. /*
  107. * Return the week number of `tm' (Sunday being the first day of the week)
  108. * as [0, 53]
  109. */
  110. static int
  111. week_number_sun (const struct tm *tm)
  112. {
  113. return (tm->tm_yday + 7 - (tm->tm_yday % 7 - tm->tm_wday + 7) % 7) / 7;
  114. }
  115. /*
  116. * Return the week number of `tm' (Monday being the first day of the week)
  117. * as [0, 53]
  118. */
  119. static int
  120. week_number_mon (const struct tm *tm)
  121. {
  122. int wday = (tm->tm_wday + 6) % 7;
  123. return (tm->tm_yday + 7 - (tm->tm_yday % 7 - wday + 7) % 7) / 7;
  124. }
  125. /*
  126. * Return the week number of `tm' (Monday being the first day of the
  127. * week) as [01, 53]. Week number one is the one that has four or more
  128. * days in that year.
  129. */
  130. static int
  131. week_number_mon4 (const struct tm *tm)
  132. {
  133. int wday = (tm->tm_wday + 6) % 7;
  134. int w1day = (wday - tm->tm_yday % 7 + 7) % 7;
  135. int ret;
  136. ret = (tm->tm_yday + w1day) / 7;
  137. if (w1day >= 4)
  138. --ret;
  139. if (ret == -1)
  140. ret = 53;
  141. else
  142. ++ret;
  143. return ret;
  144. }
  145. /*
  146. *
  147. */
  148. ROKEN_LIB_FUNCTION size_t ROKEN_LIB_CALL
  149. strftime (char *buf, size_t maxsize, const char *format,
  150. const struct tm *tm)
  151. {
  152. size_t n = 0;
  153. int ret;
  154. while (*format != '\0' && n < maxsize) {
  155. if (*format == '%') {
  156. ++format;
  157. if(*format == 'E' || *format == 'O')
  158. ++format;
  159. switch (*format) {
  160. case 'a' :
  161. ret = snprintf (buf, maxsize - n,
  162. "%s", abb_weekdays[tm->tm_wday]);
  163. break;
  164. case 'A' :
  165. ret = snprintf (buf, maxsize - n,
  166. "%s", full_weekdays[tm->tm_wday]);
  167. break;
  168. case 'h' :
  169. case 'b' :
  170. ret = snprintf (buf, maxsize - n,
  171. "%s", abb_month[tm->tm_mon]);
  172. break;
  173. case 'B' :
  174. ret = snprintf (buf, maxsize - n,
  175. "%s", full_month[tm->tm_mon]);
  176. break;
  177. case 'c' :
  178. ret = snprintf (buf, maxsize - n,
  179. "%d:%02d:%02d %02d:%02d:%02d",
  180. tm->tm_year,
  181. tm->tm_mon + 1,
  182. tm->tm_mday,
  183. tm->tm_hour,
  184. tm->tm_min,
  185. tm->tm_sec);
  186. break;
  187. case 'C' :
  188. ret = snprintf (buf, maxsize - n,
  189. "%02d", (tm->tm_year + 1900) / 100);
  190. break;
  191. case 'd' :
  192. ret = snprintf (buf, maxsize - n,
  193. "%02d", tm->tm_mday);
  194. break;
  195. case 'D' :
  196. ret = snprintf (buf, maxsize - n,
  197. "%02d/%02d/%02d",
  198. tm->tm_mon + 1,
  199. tm->tm_mday,
  200. (tm->tm_year + 1900) % 100);
  201. break;
  202. case 'e' :
  203. ret = snprintf (buf, maxsize - n,
  204. "%2d", tm->tm_mday);
  205. break;
  206. case 'F':
  207. ret = snprintf (buf, maxsize - n,
  208. "%04d-%02d-%02d", tm->tm_year + 1900,
  209. tm->tm_mon + 1, tm->tm_mday);
  210. break;
  211. case 'g':
  212. /* last two digits of week-based year */
  213. abort();
  214. case 'G':
  215. /* week-based year */
  216. abort();
  217. case 'H' :
  218. ret = snprintf (buf, maxsize - n,
  219. "%02d", tm->tm_hour);
  220. break;
  221. case 'I' :
  222. ret = snprintf (buf, maxsize - n,
  223. "%02d",
  224. hour_24to12 (tm->tm_hour));
  225. break;
  226. case 'j' :
  227. ret = snprintf (buf, maxsize - n,
  228. "%03d", tm->tm_yday + 1);
  229. break;
  230. case 'k' :
  231. ret = snprintf (buf, maxsize - n,
  232. "%2d", tm->tm_hour);
  233. break;
  234. case 'l' :
  235. ret = snprintf (buf, maxsize - n,
  236. "%2d",
  237. hour_24to12 (tm->tm_hour));
  238. break;
  239. case 'm' :
  240. ret = snprintf (buf, maxsize - n,
  241. "%02d", tm->tm_mon + 1);
  242. break;
  243. case 'M' :
  244. ret = snprintf (buf, maxsize - n,
  245. "%02d", tm->tm_min);
  246. break;
  247. case 'n' :
  248. ret = snprintf (buf, maxsize - n, "\n");
  249. break;
  250. case 'p' :
  251. ret = snprintf (buf, maxsize - n, "%s",
  252. hour_to_ampm (tm->tm_hour));
  253. break;
  254. case 'r' :
  255. ret = snprintf (buf, maxsize - n,
  256. "%02d:%02d:%02d %s",
  257. hour_24to12 (tm->tm_hour),
  258. tm->tm_min,
  259. tm->tm_sec,
  260. hour_to_ampm (tm->tm_hour));
  261. break;
  262. case 'R' :
  263. ret = snprintf (buf, maxsize - n,
  264. "%02d:%02d",
  265. tm->tm_hour,
  266. tm->tm_min);
  267. break;
  268. case 's' :
  269. ret = snprintf (buf, maxsize - n,
  270. "%d", (int)mktime(rk_UNCONST(tm)));
  271. break;
  272. case 'S' :
  273. ret = snprintf (buf, maxsize - n,
  274. "%02d", tm->tm_sec);
  275. break;
  276. case 't' :
  277. ret = snprintf (buf, maxsize - n, "\t");
  278. break;
  279. case 'T' :
  280. case 'X' :
  281. ret = snprintf (buf, maxsize - n,
  282. "%02d:%02d:%02d",
  283. tm->tm_hour,
  284. tm->tm_min,
  285. tm->tm_sec);
  286. break;
  287. case 'u' :
  288. ret = snprintf (buf, maxsize - n,
  289. "%d", (tm->tm_wday == 0) ? 7 : tm->tm_wday);
  290. break;
  291. case 'U' :
  292. ret = snprintf (buf, maxsize - n,
  293. "%02d", week_number_sun (tm));
  294. break;
  295. case 'V' :
  296. ret = snprintf (buf, maxsize - n,
  297. "%02d", week_number_mon4 (tm));
  298. break;
  299. case 'w' :
  300. ret = snprintf (buf, maxsize - n,
  301. "%d", tm->tm_wday);
  302. break;
  303. case 'W' :
  304. ret = snprintf (buf, maxsize - n,
  305. "%02d", week_number_mon (tm));
  306. break;
  307. case 'x' :
  308. ret = snprintf (buf, maxsize - n,
  309. "%d:%02d:%02d",
  310. tm->tm_year,
  311. tm->tm_mon + 1,
  312. tm->tm_mday);
  313. break;
  314. case 'y' :
  315. ret = snprintf (buf, maxsize - n,
  316. "%02d", (tm->tm_year + 1900) % 100);
  317. break;
  318. case 'Y' :
  319. ret = snprintf (buf, maxsize - n,
  320. "%d", tm->tm_year + 1900);
  321. break;
  322. case 'z':
  323. ret = snprintf (buf, maxsize - n,
  324. "%ld",
  325. #if defined(HAVE_STRUCT_TM_TM_GMTOFF)
  326. (long)tm->tm_gmtoff
  327. #elif defined(HAVE_TIMEZONE)
  328. #ifdef HAVE_ALTZONE
  329. tm->tm_isdst ?
  330. (long)altzone :
  331. #endif
  332. (long)timezone
  333. #else
  334. #error Where in timezone chaos are you?
  335. #endif
  336. );
  337. break;
  338. case 'Z' :
  339. ret = snprintf (buf, maxsize - n,
  340. "%s",
  341. #if defined(HAVE_STRUCT_TM_TM_ZONE)
  342. tm->tm_zone
  343. #elif defined(HAVE_TIMEZONE)
  344. tzname[tm->tm_isdst]
  345. #else
  346. #error what?
  347. #endif
  348. );
  349. break;
  350. case '\0' :
  351. --format;
  352. /* FALLTHROUGH */
  353. case '%' :
  354. ret = snprintf (buf, maxsize - n,
  355. "%%");
  356. break;
  357. default :
  358. ret = snprintf (buf, maxsize - n,
  359. "%%%c", *format);
  360. break;
  361. }
  362. if (ret < 0 || ret >= (int)(maxsize - n))
  363. return 0;
  364. n += ret;
  365. buf += ret;
  366. ++format;
  367. } else {
  368. *buf++ = *format++;
  369. ++n;
  370. }
  371. }
  372. *buf = '\0';
  373. return n;
  374. }