Changeset 324d46b in mainline
- Timestamp:
- 2011-07-07T01:32:53Z (14 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 3f466c33
- Parents:
- 08053f7
- Location:
- uspace/lib/posix
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/posix/locale.c
r08053f7 r324d46b 42 42 #include "string.h" 43 43 44 struct _ posix_locale {44 struct __posix_locale { 45 45 int _dummy; 46 46 }; … … 83 83 } 84 84 85 struct posix_lconv * localeconv(void)85 struct posix_lconv *posix_localeconv(void) 86 86 { 87 87 // TODO … … 95 95 return NULL; 96 96 } 97 posix_locale_t copy = malloc(sizeof(struct _ posix_locale));97 posix_locale_t copy = malloc(sizeof(struct __posix_locale)); 98 98 if (copy == NULL) { 99 99 errno = ENOMEM; 100 100 return NULL; 101 101 } 102 memcpy(copy, locobj, sizeof(struct _ posix_locale));102 memcpy(copy, locobj, sizeof(struct __posix_locale)); 103 103 return copy; 104 104 } … … 118 118 } 119 119 // TODO 120 posix_locale_t new = malloc(sizeof(struct _ posix_locale));120 posix_locale_t new = malloc(sizeof(struct __posix_locale)); 121 121 if (new == NULL) { 122 122 errno = ENOMEM; -
uspace/lib/posix/locale.h
r08053f7 r324d46b 38 38 #ifndef NULL 39 39 #define NULL ((void *) 0) 40 #endif 41 42 #ifndef __locale_t_defined 43 #define __locale_t_defined 44 typedef struct __posix_locale *posix_locale_t; 45 #ifndef LIBPOSIX_INTERNAL 46 #define locale_t posix_locale_t 47 #endif 40 48 #endif 41 49 … … 101 109 }; 102 110 103 typedef struct _posix_locale *posix_locale_t;104 105 111 extern char *posix_setlocale(int category, const char *locale); 106 extern struct posix_lconv * localeconv(void);112 extern struct posix_lconv *posix_localeconv(void); 107 113 108 114 /* POSIX Extensions */ … … 115 121 #ifndef LIBPOSIX_INTERNAL 116 122 #define lconv posix_lconv 117 #define locale_t posix_locale_t118 123 119 124 #define setlocale posix_setlocale -
uspace/lib/posix/time.c
r08053f7 r324d46b 36 36 #define LIBPOSIX_INTERNAL 37 37 38 /* Must be first. */ 39 #include "stdbool.h" 40 38 41 #include "internal/common.h" 39 42 #include "time.h" 43 44 #include "ctype.h" 45 #include "errno.h" 40 46 41 47 #include "libc/malloc.h" 42 48 #include "libc/task.h" 43 49 #include "libc/stats.h" 50 51 // TODO: documentation 52 // TODO: test everything in this file 53 54 /* Helper functions ***********************************************************/ 55 56 #define HOURS_PER_DAY (24) 57 #define MINS_PER_HOUR (60) 58 #define SECS_PER_MIN (60) 59 #define MINS_PER_DAY (MINS_PER_HOUR * HOURS_PER_DAY) 60 #define SECS_PER_HOUR (SECS_PER_MIN * MINS_PER_HOUR) 61 #define SECS_PER_DAY (SECS_PER_HOUR * HOURS_PER_DAY) 62 63 static bool _is_leap_year(time_t year) 64 { 65 year += 1900; 66 67 if (year % 400 == 0) 68 return true; 69 if (year % 100 == 0) 70 return false; 71 if (year % 4 == 0) 72 return true; 73 return false; 74 } 75 76 static int _days_in_month(time_t year, time_t mon) 77 { 78 assert(mon >= 0 && mon <= 11); 79 year += 1900; 80 81 static int month_days[] = 82 { 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; 83 84 if (mon == 1) { 85 /* february */ 86 return _is_leap_year(year) ? 29 : 28; 87 } else { 88 return month_days[mon]; 89 } 90 } 91 92 static int _day_of_year(time_t year, time_t mon, time_t mday) 93 { 94 static int mdays[] = 95 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; 96 static int leap_mdays[] = 97 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 }; 98 99 return (_is_leap_year(year) ? leap_mdays[mon] : mdays[mon]) + mday - 1; 100 } 101 102 /* Integer division that rounds to negative infinity. 103 */ 104 static time_t _floor_div(time_t op1, time_t op2) 105 { 106 if (op1 >= 0 || op1 % op2 == 0) { 107 return op1 / op2; 108 } else { 109 return op1 / op2 - 1; 110 } 111 } 112 113 /* Modulo that rounds to negative infinity. 114 */ 115 static time_t _floor_mod(time_t op1, time_t op2) 116 { 117 int div = _floor_div(op1, op2); 118 119 /* (a / b) * b + a % b == a */ 120 /* thus, a % b == a - (a / b) * b */ 121 122 int result = op1 - div * op2; 123 124 /* Some paranoid checking to ensure I didn't make a mistake here. */ 125 assert(result >= 0); 126 assert(result < op2); 127 assert(div * op2 + result == op1); 128 129 return result; 130 } 131 132 static time_t _days_since_epoch(time_t year, time_t mon, time_t mday) 133 { 134 return (year - 70) * 365 + _floor_div(year - 69, 4) - 135 _floor_div(year - 1, 100) + _floor_div(year + 299, 400) + 136 _day_of_year(year, mon, mday); 137 } 138 139 /* Assumes normalized broken-down time. */ 140 static time_t _secs_since_epoch(const struct posix_tm *tm) 141 { 142 return _days_since_epoch(tm->tm_year, tm->tm_mon, tm->tm_mday) * 143 SECS_PER_DAY + tm->tm_hour * SECS_PER_HOUR + 144 tm->tm_min * SECS_PER_MIN + tm->tm_sec; 145 } 146 147 static int _day_of_week(time_t year, time_t mon, time_t mday) 148 { 149 /* 1970-01-01 is Thursday */ 150 return (_days_since_epoch(year, mon, mday) + 4) % 7; 151 } 152 153 struct _long_tm { 154 time_t tm_sec; 155 time_t tm_min; 156 time_t tm_hour; 157 time_t tm_mday; 158 time_t tm_mon; 159 time_t tm_year; 160 int tm_wday; 161 int tm_yday; 162 int tm_isdst; 163 }; 164 165 static void _posix_to_long_tm(struct _long_tm *ltm, struct posix_tm *ptm) 166 { 167 assert(ltm != NULL && ptm != NULL); 168 ltm->tm_sec = ptm->tm_sec; 169 ltm->tm_min = ptm->tm_min; 170 ltm->tm_hour = ptm->tm_hour; 171 ltm->tm_mday = ptm->tm_mday; 172 ltm->tm_mon = ptm->tm_mon; 173 ltm->tm_year = ptm->tm_year; 174 ltm->tm_wday = ptm->tm_wday; 175 ltm->tm_yday = ptm->tm_yday; 176 ltm->tm_isdst = ptm->tm_isdst; 177 } 178 179 static void _long_to_posix_tm(struct posix_tm *ptm, struct _long_tm *ltm) 180 { 181 assert(ltm != NULL && ptm != NULL); 182 // FIXME: the cast should be unnecessary, libarch/common.h brain-damage 183 assert((ltm->tm_year >= (int) INT_MIN) && (ltm->tm_year <= (int) INT_MAX)); 184 185 ptm->tm_sec = ltm->tm_sec; 186 ptm->tm_min = ltm->tm_min; 187 ptm->tm_hour = ltm->tm_hour; 188 ptm->tm_mday = ltm->tm_mday; 189 ptm->tm_mon = ltm->tm_mon; 190 ptm->tm_year = ltm->tm_year; 191 ptm->tm_wday = ltm->tm_wday; 192 ptm->tm_yday = ltm->tm_yday; 193 ptm->tm_isdst = ltm->tm_isdst; 194 } 195 196 static void _normalize_time(struct _long_tm *tm) 197 { 198 // TODO: DST correction 199 200 /* Adjust time. */ 201 tm->tm_min += _floor_div(tm->tm_sec, SECS_PER_MIN); 202 tm->tm_sec = _floor_mod(tm->tm_sec, SECS_PER_MIN); 203 tm->tm_hour += _floor_div(tm->tm_min, MINS_PER_HOUR); 204 tm->tm_min = _floor_mod(tm->tm_min, MINS_PER_HOUR); 205 tm->tm_mday += _floor_div(tm->tm_hour, HOURS_PER_DAY); 206 tm->tm_hour = _floor_mod(tm->tm_hour, HOURS_PER_DAY); 207 208 /* Adjust month. */ 209 tm->tm_year += _floor_div(tm->tm_mon, 12); 210 tm->tm_mon = _floor_mod(tm->tm_mon, 12); 211 212 /* Now the difficult part - days of month. */ 213 /* Slow, but simple. */ 214 // TODO: do this faster 215 216 while (tm->tm_mday < 1) { 217 tm->tm_mon--; 218 if (tm->tm_mon == -1) { 219 tm->tm_mon = 11; 220 tm->tm_year--; 221 } 222 223 tm->tm_mday += _days_in_month(tm->tm_year, tm->tm_mon); 224 } 225 226 while (tm->tm_mday > _days_in_month(tm->tm_year, tm->tm_mon)) { 227 tm->tm_mday -= _days_in_month(tm->tm_year, tm->tm_mon); 228 229 tm->tm_mon++; 230 if (tm->tm_mon == 12) { 231 tm->tm_mon = 0; 232 tm->tm_year++; 233 } 234 } 235 236 /* Calculate the remaining two fields. */ 237 tm->tm_yday = _day_of_year(tm->tm_year, tm->tm_mon, tm->tm_mday); 238 tm->tm_wday = _day_of_week(tm->tm_year, tm->tm_mon, tm->tm_mday); 239 } 240 241 /* Which day the week-based year starts on relative to the first calendar day. 242 * E.g. if the year starts on December 31st, the return value is -1. 243 */ 244 static int _wbyear_offset(int year) 245 { 246 int start_wday = _day_of_week(year, 0, 1); 247 return _floor_mod(4 - start_wday, 7) - 3; 248 } 249 250 /* Returns week-based year of the specified time. 251 * Assumes normalized broken-down time. 252 */ 253 static int _wbyear(const struct posix_tm *tm) 254 { 255 if (tm->tm_yday < _wbyear_offset(tm->tm_year)) { 256 return tm->tm_year - 1; 257 } 258 if (tm->tm_yday > (364 + _is_leap_year(tm->tm_year) + 259 _wbyear_offset(tm->tm_year + 1))) { 260 return tm->tm_year + 1; 261 } 262 return tm->tm_year; 263 } 264 265 /* Number of week in year, when week starts on sunday. 266 */ 267 static int _sun_week_number(const struct posix_tm *tm) 268 { 269 // TODO 270 not_implemented(); 271 } 272 273 /* Number of week in week-based year. 274 */ 275 static int _iso_week_number(const struct posix_tm *tm) 276 { 277 // TODO 278 not_implemented(); 279 } 280 281 /* Number of week in year, when week starts on monday. 282 */ 283 static int _mon_week_number(const struct posix_tm *tm) 284 { 285 // TODO 286 not_implemented(); 287 } 288 289 /******************************************************************************/ 290 291 int posix_daylight; 292 long posix_timezone; 293 char *posix_tzname[2]; 294 295 void posix_tzset(void) 296 { 297 // TODO: read environment 298 posix_tzname[0] = (char *) "GMT"; 299 posix_tzname[1] = (char *) "GMT"; 300 posix_daylight = 0; 301 posix_timezone = 0; 302 } 303 304 double posix_difftime(time_t time1, time_t time0) 305 { 306 return (double) (time1 - time0); 307 } 308 309 /** This function first normalizes the provided broken-down time 310 * (moves all values to their proper bounds) and then tries to 311 * calculate the appropriate time_t representation. 312 * 313 * @param timeptr Broken-down time. 314 * @return time_t representation of the time, undefined value on overflow 315 */ 316 time_t posix_mktime(struct posix_tm *tm) 317 { 318 // TODO: take DST flag into account 319 // TODO: detect overflow 320 321 struct _long_tm ltm; 322 _posix_to_long_tm(<m, tm); 323 _normalize_time(<m); 324 _long_to_posix_tm(tm, <m); 325 326 return _secs_since_epoch(tm); 327 } 44 328 45 329 /** … … 50 334 struct posix_tm *posix_localtime(const time_t *timep) 51 335 { 52 // TODO 53 static struct posix_tm result = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 54 return &result; 336 static struct posix_tm result; 337 return posix_localtime_r(timep, &result); 338 } 339 340 struct posix_tm *posix_localtime_r(const time_t *restrict timer, 341 struct posix_tm *restrict result) 342 { 343 assert(timer != NULL); 344 assert(result != NULL); 345 346 // TODO: deal with timezone 347 // currently assumes system and all times are in GMT 348 349 /* Set epoch and seconds to _long_tm struct and normalize to get 350 * correct values. 351 */ 352 struct _long_tm ltm = { 353 .tm_sec = *timer, 354 .tm_min = 0, 355 .tm_hour = 0, /* 00:00:xx */ 356 .tm_mday = 1, 357 .tm_mon = 0, /* January 1st */ 358 .tm_year = 70, /* 1970 */ 359 }; 360 _normalize_time(<m); 361 362 if (ltm.tm_year < (int) INT_MIN || ltm.tm_year > (int) INT_MAX) { 363 errno = EOVERFLOW; 364 return NULL; 365 } 366 367 _long_to_posix_tm(result, <m); 368 return result; 55 369 } 56 370 … … 60 374 * @return 61 375 */ 62 char *posix_asctime(const struct posix_tm *tm) 63 { 64 // TODO 65 static char result[] = "Sun Jan 01 00:00:00 1900\n"; 66 return result; 376 char *posix_asctime(const struct posix_tm *timeptr) 377 { 378 static char buf[ASCTIME_BUF_LEN]; 379 return posix_asctime_r(timeptr, buf); 380 } 381 382 char *posix_asctime_r(const struct posix_tm *restrict timeptr, 383 char *restrict buf) 384 { 385 assert(timeptr != NULL); 386 assert(buf != NULL); 387 388 static const char *wday[] = { 389 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" 390 }; 391 static const char *mon[] = { 392 "Jan", "Feb", "Mar", "Apr", "May", "Jun", 393 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 394 }; 395 396 snprintf(buf, ASCTIME_BUF_LEN, "%s %s %2d %02d:%02d:%02d %d\n", 397 wday[timeptr->tm_wday], 398 mon[timeptr->tm_mon], 399 timeptr->tm_mday, timeptr->tm_hour, 400 timeptr->tm_min, timeptr->tm_sec, 401 1900 + timeptr->tm_year); 402 403 return buf; 67 404 } 68 405 … … 85 422 * @return 86 423 */ 87 size_t posix_strftime(char *s, size_t maxsize, const char *format, const struct posix_tm *tm) 88 { 89 // TODO 90 if (maxsize >= 1) { 91 *s = '\0'; 92 } 93 return 0; 424 size_t posix_strftime(char *s, size_t maxsize, 425 const char *format, const struct posix_tm *tm) 426 { 427 // TODO: use locale 428 static const char *wday_abbr[] = { 429 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" 430 }; 431 static const char *wday[] = { 432 "Sunday", "Monday", "Tuesday", "Wednesday", 433 "Thursday", "Friday", "Saturday" 434 }; 435 static const char *mon_abbr[] = { 436 "Jan", "Feb", "Mar", "Apr", "May", "Jun", 437 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 438 }; 439 static const char *mon[] = { 440 "January", "February", "March", "April", "May", "June", "July", 441 "August", "September", "October", "November", "December" 442 }; 443 444 if (maxsize < 1) { 445 return 0; 446 } 447 448 char *ptr = s; 449 size_t consumed; 450 size_t remaining = maxsize; 451 452 #define append(...) { \ 453 /* FIXME: this requires POSIX-correct snprintf */ \ 454 /* otherwise it won't work with non-ascii chars */ \ 455 consumed = snprintf(ptr, remaining, __VA_ARGS__); \ 456 if (consumed >= remaining) { \ 457 return 0; \ 458 } \ 459 ptr += consumed; \ 460 remaining -= consumed; \ 461 } 462 463 #define recurse(fmt) { \ 464 consumed = posix_strftime(ptr, remaining, fmt, tm); \ 465 if (consumed == 0) { \ 466 return 0; \ 467 } \ 468 ptr += consumed; \ 469 remaining -= consumed; \ 470 } 471 472 #define TO_12H(hour) (((hour) > 12) ? ((hour) - 12) : \ 473 (((hour) == 0) ? 12 : (hour))) 474 475 while (*format != '\0') { 476 if (*format != '%') { 477 append("%c", *format); 478 format++; 479 continue; 480 } 481 482 format++; 483 if (*format == '0' || *format == '+') { 484 // TODO: padding 485 format++; 486 } 487 while (isdigit(*format)) { 488 // TODO: padding 489 format++; 490 } 491 if (*format == 'O' || *format == 'E') { 492 // TODO: locale's alternative format 493 format++; 494 } 495 496 switch (*format) { 497 case 'a': 498 append("%s", wday_abbr[tm->tm_wday]); break; 499 case 'A': 500 append("%s", wday[tm->tm_wday]); break; 501 case 'b': 502 append("%s", mon_abbr[tm->tm_mon]); break; 503 case 'B': 504 append("%s", mon[tm->tm_mon]); break; 505 case 'c': 506 // TODO: locale-specific datetime format 507 recurse("%Y-%m-%d %H:%M:%S"); break; 508 case 'C': 509 append("%02d", (1900 + tm->tm_year) / 100); break; 510 case 'd': 511 append("%02d", tm->tm_mday); break; 512 case 'D': 513 recurse("%m/%d/%y"); break; 514 case 'e': 515 append("%2d", tm->tm_mday); break; 516 case 'F': 517 recurse("%+4Y-%m-%d"); break; 518 case 'g': 519 append("%02d", _wbyear(tm) % 100); break; 520 case 'G': 521 append("%d", _wbyear(tm)); break; 522 case 'h': 523 recurse("%b"); break; 524 case 'H': 525 append("%02d", tm->tm_hour); break; 526 case 'I': 527 append("%02d", TO_12H(tm->tm_hour)); break; 528 case 'j': 529 append("%03d", tm->tm_yday); break; 530 case 'k': 531 append("%2d", tm->tm_hour); break; 532 case 'l': 533 append("%2d", TO_12H(tm->tm_hour)); break; 534 case 'm': 535 append("%02d", tm->tm_mon); break; 536 case 'M': 537 append("%02d", tm->tm_min); break; 538 case 'n': 539 append("\n"); break; 540 case 'p': 541 append("%s", tm->tm_hour < 12 ? "AM" : "PM"); break; 542 case 'P': 543 append("%s", tm->tm_hour < 12 ? "am" : "PM"); break; 544 case 'r': 545 recurse("%I:%M:%S %p"); break; 546 case 'R': 547 recurse("%H:%M"); break; 548 case 's': 549 append("%ld", _secs_since_epoch(tm)); break; 550 case 'S': 551 append("%02d", tm->tm_sec); break; 552 case 't': 553 append("\t"); break; 554 case 'T': 555 recurse("%H:%M:%S"); break; 556 case 'u': 557 append("%d", (tm->tm_wday == 0) ? 7 : tm->tm_wday); break; 558 case 'U': 559 append("%02d", _sun_week_number(tm)); break; 560 case 'V': 561 append("%02d", _iso_week_number(tm)); break; 562 case 'w': 563 append("%d", tm->tm_wday); break; 564 case 'W': 565 append("%02d", _mon_week_number(tm)); break; 566 case 'x': 567 // TODO: locale-specific date format 568 recurse("%Y-%m-%d"); break; 569 case 'X': 570 // TODO: locale-specific time format 571 recurse("%H:%M:%S"); break; 572 case 'y': 573 append("%02d", tm->tm_year % 100); break; 574 case 'Y': 575 append("%d", 1900 + tm->tm_year); break; 576 case 'z': 577 // TODO: timezone 578 break; 579 case 'Z': 580 // TODO: timezone 581 break; 582 case '%': 583 append("%%"); 584 break; 585 default: 586 /* Invalid specifier, print verbatim. */ 587 while (*format != '%') { 588 format--; 589 } 590 append("%%"); 591 break; 592 } 593 format++; 594 } 595 596 #undef append 597 #undef recurse 598 599 return maxsize - remaining; 94 600 } 95 601 -
uspace/lib/posix/time.h
r08053f7 r324d46b 38 38 39 39 #include "libc/time.h" 40 #include "sys/types.h" 40 41 41 42 #ifndef NULL … … 43 44 #endif 44 45 45 #undef CLOCKS_PER_SEC 46 #define CLOCKS_PER_SEC 1000000L 46 #ifndef CLOCKS_PER_SEC 47 #define CLOCKS_PER_SEC (1000000L) 48 #endif 49 50 #ifndef __locale_t_defined 51 #define __locale_t_defined 52 typedef struct __posix_locale *posix_locale_t; 53 #ifndef LIBPOSIX_INTERNAL 54 #define locale_t posix_locale_t 55 #endif 56 #endif 57 58 #undef ASCTIME_BUF_LEN 59 #define ASCTIME_BUF_LEN 26 60 61 #undef CLOCK_REALTIME 62 #define CLOCK_REALTIME ((posix_clockid_t) 0) 47 63 48 64 struct posix_tm { … … 58 74 }; 59 75 76 // FIXME: should be in sys/types.h 60 77 typedef long posix_clock_t; 61 78 79 struct posix_timespec { 80 time_t tv_sec; /* Seconds. */ 81 long tv_nsec; /* Nanoseconds. */ 82 }; 83 84 struct posix_itimerspec { 85 struct posix_timespec it_interval; /* Timer period. */ 86 struct posix_timespec it_value; /* Timer expiration. */ 87 }; 88 89 /* Timezones */ 90 91 extern int posix_daylight; 92 extern long posix_timezone; 93 extern char *posix_tzname[2]; 94 95 extern void posix_tzset(void); 96 97 /* time_t */ 98 99 extern double posix_difftime(time_t time1, time_t time0); 100 62 101 /* Broken-down Time */ 102 extern time_t posix_mktime(struct posix_tm *timeptr); 63 103 extern struct posix_tm *posix_localtime(const time_t *timep); 64 104 extern struct posix_tm *posix_localtime_r(const time_t *restrict timer, 105 struct posix_tm *restrict result); 65 106 /* Formatting Calendar Time */ 66 extern char *posix_asctime(const struct posix_tm *tm); 107 extern char *posix_asctime(const struct posix_tm *timeptr); 108 extern char *posix_asctime_r(const struct posix_tm *restrict timeptr, 109 char *restrict buf); 67 110 extern char *posix_ctime(const time_t *timep); 68 extern size_t posix_strftime(char *restrict s, size_t maxsize, const char *restrict format, const struct posix_tm *restrict tm); 111 extern size_t posix_strftime(char *restrict s, size_t maxsize, 112 const char *restrict format, const struct posix_tm *restrict tm); 69 113 70 114 /* CPU Time */ 71 115 extern posix_clock_t posix_clock(void); 116 72 117 73 118 #ifndef LIBPOSIX_INTERNAL … … 75 120 76 121 #define clock_t posix_clock_t 122 #define timespec posix_timespec 123 #define itimerspec posix_itimerspec 77 124 125 #define difftime posix_difftime 126 #define mktime posix_mktime 78 127 #define localtime posix_localtime 128 #define localtime_r posix_localtime_r 129 130 #define daylight posix_daylight 131 #define timezone posix_timezone 132 #define tzname posix_tzname 133 #define tzset posix_tzset 79 134 80 135 #define asctime posix_asctime 136 #define asctime_r posix_asctime_r 81 137 #define ctime posix_ctime 82 138 #define strftime posix_strftime
Note:
See TracChangeset
for help on using the changeset viewer.