Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/c/generic/time.c

    r3e6a98c5 rf9b2cb4c  
    5454#include <malloc.h>
    5555
    56 #define ASCTIME_BUF_LEN 26
     56#define ASCTIME_BUF_LEN  26
     57
     58#define HOURS_PER_DAY  24
     59#define MINS_PER_HOUR  60
     60#define SECS_PER_MIN   60
     61#define USECS_PER_SEC  1000000
     62#define MINS_PER_DAY   (MINS_PER_HOUR * HOURS_PER_DAY)
     63#define SECS_PER_HOUR  (SECS_PER_MIN * MINS_PER_HOUR)
     64#define SECS_PER_DAY   (SECS_PER_HOUR * HOURS_PER_DAY)
    5765
    5866/** Pointer to kernel shared variables with time */
     
    6371} *ktime = NULL;
    6472
    65 /* Helper functions ***********************************************************/
    66 
    67 #define HOURS_PER_DAY (24)
    68 #define MINS_PER_HOUR (60)
    69 #define SECS_PER_MIN (60)
    70 #define MINS_PER_DAY (MINS_PER_HOUR * HOURS_PER_DAY)
    71 #define SECS_PER_HOUR (SECS_PER_MIN * MINS_PER_HOUR)
    72 #define SECS_PER_DAY (SECS_PER_HOUR * HOURS_PER_DAY)
    73 
    74 /**
    75  * Checks whether the year is a leap year.
     73static async_sess_t *clock_conn = NULL;
     74
     75/** Check whether the year is a leap year.
    7676 *
    7777 * @param year Year since 1900 (e.g. for 1970, the value is 70).
     78 *
    7879 * @return true if year is a leap year, false otherwise
    79  */
    80 static bool _is_leap_year(time_t year)
     80 *
     81 */
     82static bool is_leap_year(time_t year)
    8183{
    8284        year += 1900;
    83 
     85       
    8486        if (year % 400 == 0)
    8587                return true;
     88       
    8689        if (year % 100 == 0)
    8790                return false;
     91       
    8892        if (year % 4 == 0)
    8993                return true;
     94       
    9095        return false;
    9196}
    9297
    93 /**
    94  * Returns how many days there are in the given month of the given year.
     98/** How many days there are in the given month
     99 *
     100 * Return how many days there are in the given month of the given year.
    95101 * Note that year is only taken into account if month is February.
    96102 *
    97103 * @param year Year since 1900 (can be negative).
    98  * @param mon Month of the year. 0 for January, 11 for December.
     104 * @param mon  Month of the year. 0 for January, 11 for December.
     105 *
    99106 * @return Number of days in the specified month.
    100  */
    101 static int _days_in_month(time_t year, time_t mon)
    102 {
    103         assert(mon >= 0 && mon <= 11);
    104 
    105         static int month_days[] =
    106                 { 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
    107 
     107 *
     108 */
     109static int days_in_month(time_t year, time_t mon)
     110{
     111        assert(mon >= 0);
     112        assert(mon <= 11);
     113       
     114        static int month_days[] = {
     115                31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
     116        };
     117       
    108118        if (mon == 1) {
     119                /* February */
    109120                year += 1900;
    110                 /* february */
    111                 return _is_leap_year(year) ? 29 : 28;
    112         } else {
    113                 return month_days[mon];
    114         }
    115 }
    116 
    117 /**
    118  * For specified year, month and day of month, returns which day of that year
     121                return is_leap_year(year) ? 29 : 28;
     122        }
     123       
     124        return month_days[mon];
     125}
     126
     127/** Which day of that year it is.
     128 *
     129 * For specified year, month and day of month, return which day of that year
    119130 * it is.
    120131 *
    121132 * For example, given date 2011-01-03, the corresponding expression is:
    122  *     _day_of_year(111, 0, 3) == 2
     133 * day_of_year(111, 0, 3) == 2
    123134 *
    124135 * @param year Year (year 1900 = 0, can be negative).
    125  * @param mon Month (January = 0).
     136 * @param mon  Month (January = 0).
    126137 * @param mday Day of month (First day is 1).
     138 *
    127139 * @return Day of year (First day is 0).
    128  */
    129 static int _day_of_year(time_t year, time_t mon, time_t mday)
    130 {
    131         static int mdays[] =
    132             { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
    133         static int leap_mdays[] =
    134             { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 };
    135 
    136         return (_is_leap_year(year) ? leap_mdays[mon] : mdays[mon]) + mday - 1;
    137 }
    138 
    139 /**
    140  * Integer division that rounds to negative infinity.
    141  * Used by some functions in this file.
     140 *
     141 */
     142static int day_of_year(time_t year, time_t mon, time_t mday)
     143{
     144        static int mdays[] = {
     145                0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
     146        };
     147       
     148        static int leap_mdays[] = {
     149                0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335
     150        };
     151       
     152        return (is_leap_year(year) ? leap_mdays[mon] : mdays[mon]) + mday - 1;
     153}
     154
     155/** Integer division that rounds to negative infinity.
     156 *
     157 * Used by some functions in this module.
    142158 *
    143159 * @param op1 Dividend.
    144160 * @param op2 Divisor.
     161 *
    145162 * @return Rounded quotient.
    146  */
    147 static time_t _floor_div(time_t op1, time_t op2)
    148 {
    149         if (op1 >= 0 || op1 % op2 == 0) {
     163 *
     164 */
     165static time_t floor_div(time_t op1, time_t op2)
     166{
     167        if ((op1 >= 0) || (op1 % op2 == 0))
    150168                return op1 / op2;
    151         } else {
    152                 return op1 / op2 - 1;
    153         }
    154 }
    155 
    156 /**
    157  * Modulo that rounds to negative infinity.
    158  * Used by some functions in this file.
     169       
     170        return op1 / op2 - 1;
     171}
     172
     173/** Modulo that rounds to negative infinity.
     174 *
     175 * Used by some functions in this module.
    159176 *
    160177 * @param op1 Dividend.
    161178 * @param op2 Divisor.
     179 *
    162180 * @return Remainder.
    163  */
    164 static time_t _floor_mod(time_t op1, time_t op2)
    165 {
    166         int div = _floor_div(op1, op2);
    167 
    168         /* (a / b) * b + a % b == a */
    169         /* thus, a % b == a - (a / b) * b */
    170 
    171         int result = op1 - div * op2;
    172        
    173         /* Some paranoid checking to ensure I didn't make a mistake here. */
     181 *
     182 */
     183static time_t floor_mod(time_t op1, time_t op2)
     184{
     185        time_t div = floor_div(op1, op2);
     186       
     187        /*
     188         * (a / b) * b + a % b == a
     189         * Thus: a % b == a - (a / b) * b
     190         */
     191       
     192        time_t result = op1 - div * op2;
     193       
     194        /* Some paranoid checking to ensure there is mistake here. */
    174195        assert(result >= 0);
    175196        assert(result < op2);
     
    179200}
    180201
    181 /**
    182  * Number of days since the Epoch.
     202/** Number of days since the Epoch.
     203 *
    183204 * Epoch is 1970-01-01, which is also equal to day 0.
    184205 *
    185206 * @param year Year (year 1900 = 0, may be negative).
    186  * @param mon Month (January = 0).
     207 * @param mon  Month (January = 0).
    187208 * @param mday Day of month (first day = 1).
     209 *
    188210 * @return Number of days since the Epoch.
    189  */
    190 static time_t _days_since_epoch(time_t year, time_t mon, time_t mday)
    191 {
    192         return (year - 70) * 365 + _floor_div(year - 69, 4) -
    193             _floor_div(year - 1, 100) + _floor_div(year + 299, 400) +
    194             _day_of_year(year, mon, mday);
    195 }
    196 
    197 /**
    198  * Seconds since the Epoch. see also _days_since_epoch().
    199  *
     211 *
     212 */
     213static time_t days_since_epoch(time_t year, time_t mon, time_t mday)
     214{
     215        return (year - 70) * 365 + floor_div(year - 69, 4) -
     216            floor_div(year - 1, 100) + floor_div(year + 299, 400) +
     217            day_of_year(year, mon, mday);
     218}
     219
     220/** Seconds since the Epoch.
     221 *
     222 * See also days_since_epoch().
     223 *
    200224 * @param tm Normalized broken-down time.
     225 *
    201226 * @return Number of seconds since the epoch, not counting leap seconds.
    202  */
    203 static time_t _secs_since_epoch(const struct tm *tm)
    204 {
    205         return _days_since_epoch(tm->tm_year, tm->tm_mon, tm->tm_mday) *
     227 *
     228 */
     229static time_t secs_since_epoch(const struct tm *tm)
     230{
     231        return days_since_epoch(tm->tm_year, tm->tm_mon, tm->tm_mday) *
    206232            SECS_PER_DAY + tm->tm_hour * SECS_PER_HOUR +
    207233            tm->tm_min * SECS_PER_MIN + tm->tm_sec;
    208234}
    209235
    210 /**
    211  * Which day of week the specified date is.
    212  *
     236/** Which day of week the specified date is.
     237 *
    213238 * @param year Year (year 1900 = 0).
    214  * @param mon Month (January = 0).
     239 * @param mon  Month (January = 0).
    215240 * @param mday Day of month (first = 1).
     241 *
    216242 * @return Day of week (Sunday = 0).
    217  */
    218 static int _day_of_week(time_t year, time_t mon, time_t mday)
     243 *
     244 */
     245static time_t day_of_week(time_t year, time_t mon, time_t mday)
    219246{
    220247        /* 1970-01-01 is Thursday */
    221         return _floor_mod((_days_since_epoch(year, mon, mday) + 4), 7);
    222 }
    223 
    224 /**
    225  * Normalizes the broken-down time and optionally adds specified amount of
    226  * seconds.
    227  * 
     248        return floor_mod(days_since_epoch(year, mon, mday) + 4, 7);
     249}
     250
     251/** Normalize the broken-down time.
     252 *
     253 * Optionally add specified amount of seconds.
     254 *
    228255 * @param tm Broken-down time to normalize.
    229  * @param sec_add Seconds to add.
     256 * @param tv Timeval to add.
     257 *
    230258 * @return 0 on success, -1 on overflow
    231  */
    232 static int _normalize_time(struct tm *tm, time_t sec_add)
     259 *
     260 */
     261static int normalize_tm_tv(struct tm *tm, const struct timeval *tv)
    233262{
    234263        // TODO: DST correction
    235 
     264       
    236265        /* Set initial values. */
    237         time_t sec = tm->tm_sec + sec_add;
     266        time_t usec = tm->tm_usec + tv->tv_usec;
     267        time_t sec = tm->tm_sec + tv->tv_sec;
    238268        time_t min = tm->tm_min;
    239269        time_t hour = tm->tm_hour;
     
    241271        time_t mon = tm->tm_mon;
    242272        time_t year = tm->tm_year;
    243 
     273       
    244274        /* Adjust time. */
    245         min += _floor_div(sec, SECS_PER_MIN);
    246         sec = _floor_mod(sec, SECS_PER_MIN);
    247         hour += _floor_div(min, MINS_PER_HOUR);
    248         min = _floor_mod(min, MINS_PER_HOUR);
    249         day += _floor_div(hour, HOURS_PER_DAY);
    250         hour = _floor_mod(hour, HOURS_PER_DAY);
    251 
     275        sec += floor_div(usec, USECS_PER_SEC);
     276        usec = floor_mod(usec, USECS_PER_SEC);
     277        min += floor_div(sec, SECS_PER_MIN);
     278        sec = floor_mod(sec, SECS_PER_MIN);
     279        hour += floor_div(min, MINS_PER_HOUR);
     280        min = floor_mod(min, MINS_PER_HOUR);
     281        day += floor_div(hour, HOURS_PER_DAY);
     282        hour = floor_mod(hour, HOURS_PER_DAY);
     283       
    252284        /* Adjust month. */
    253         year += _floor_div(mon, 12);
    254         mon = _floor_mod(mon, 12);
    255 
     285        year += floor_div(mon, 12);
     286        mon = floor_mod(mon, 12);
     287       
    256288        /* Now the difficult part - days of month. */
    257289       
    258290        /* First, deal with whole cycles of 400 years = 146097 days. */
    259         year += _floor_div(day, 146097) * 400;
    260         day = _floor_mod(day, 146097);
     291        year += floor_div(day, 146097) * 400;
     292        day = floor_mod(day, 146097);
    261293       
    262294        /* Then, go in one year steps. */
     
    264296                /* January and February. */
    265297                while (day > 365) {
    266                         day -= _is_leap_year(year) ? 366 : 365;
     298                        day -= is_leap_year(year) ? 366 : 365;
    267299                        year++;
    268300                }
     
    270302                /* Rest of the year. */
    271303                while (day > 365) {
    272                         day -= _is_leap_year(year + 1) ? 366 : 365;
     304                        day -= is_leap_year(year + 1) ? 366 : 365;
    273305                        year++;
    274306                }
     
    276308       
    277309        /* Finally, finish it off month per month. */
    278         while (day >= _days_in_month(year, mon)) {
    279                 day -= _days_in_month(year, mon);
     310        while (day >= days_in_month(year, mon)) {
     311                day -= days_in_month(year, mon);
    280312                mon++;
     313               
    281314                if (mon >= 12) {
    282315                        mon -= 12;
     
    286319       
    287320        /* Calculate the remaining two fields. */
    288         tm->tm_yday = _day_of_year(year, mon, day + 1);
    289         tm->tm_wday = _day_of_week(year, mon, day + 1);
     321        tm->tm_yday = day_of_year(year, mon, day + 1);
     322        tm->tm_wday = day_of_week(year, mon, day + 1);
    290323       
    291324        /* And put the values back to the struct. */
     325        tm->tm_usec = (int) usec;
    292326        tm->tm_sec = (int) sec;
    293327        tm->tm_min = (int) min;
     
    296330        tm->tm_mon = (int) mon;
    297331       
    298         /* Casts to work around libc brain-damage. */
    299         if (year > ((int)INT_MAX) || year < ((int)INT_MIN)) {
    300                 tm->tm_year = (year < 0) ? ((int)INT_MIN) : ((int)INT_MAX);
     332        /* Casts to work around POSIX brain-damage. */
     333        if (year > ((int) INT_MAX) || year < ((int) INT_MIN)) {
     334                tm->tm_year = (year < 0) ? ((int) INT_MIN) : ((int) INT_MAX);
    301335                return -1;
    302336        }
     
    306340}
    307341
    308 /**
    309  * Which day the week-based year starts on, relative to the first calendar day.
    310  * E.g. if the year starts on December 31st, the return value is -1.
     342static int normalize_tm_time(struct tm *tm, time_t time)
     343{
     344        struct timeval tv = {
     345                .tv_sec = time,
     346                .tv_usec = 0
     347        };
     348
     349        return normalize_tm_tv(tm, &tv);
     350}
     351
     352
     353/** Which day the week-based year starts on.
     354 *
     355 * Relative to the first calendar day. E.g. if the year starts
     356 * on December 31st, the return value is -1.
    311357 *
    312358 * @param Year since 1900.
     359 *
    313360 * @return Offset of week-based year relative to calendar year.
    314  */
    315 static int _wbyear_offset(int year)
    316 {
    317         int start_wday = _day_of_week(year, 0, 1);
    318         return _floor_mod(4 - start_wday, 7) - 3;
    319 }
    320 
    321 /**
    322  * Returns week-based year of the specified time.
     361 *
     362 */
     363static int wbyear_offset(int year)
     364{
     365        int start_wday = day_of_week(year, 0, 1);
     366       
     367        return floor_mod(4 - start_wday, 7) - 3;
     368}
     369
     370/** Week-based year of the specified time.
    323371 *
    324372 * @param tm Normalized broken-down time.
     373 *
    325374 * @return Week-based year.
    326  */
    327 static int _wbyear(const struct tm *tm)
    328 {
    329         int day = tm->tm_yday - _wbyear_offset(tm->tm_year);
     375 *
     376 */
     377static int wbyear(const struct tm *tm)
     378{
     379        int day = tm->tm_yday - wbyear_offset(tm->tm_year);
     380       
    330381        if (day < 0) {
    331382                /* Last week of previous year. */
    332383                return tm->tm_year - 1;
    333384        }
    334         if (day > 364 + _is_leap_year(tm->tm_year)) {
     385       
     386        if (day > 364 + is_leap_year(tm->tm_year)) {
    335387                /* First week of next year. */
    336388                return tm->tm_year + 1;
    337389        }
     390       
    338391        /* All the other days are in the calendar year. */
    339392        return tm->tm_year;
    340393}
    341394
    342 /**
    343  * Week number of the year, assuming weeks start on sunday.
     395/** Week number of the year (assuming weeks start on Sunday).
     396 *
    344397 * The first Sunday of January is the first day of week 1;
    345398 * days in the new year before this are in week 0.
    346399 *
    347400 * @param tm Normalized broken-down time.
     401 *
    348402 * @return The week number (0 - 53).
    349  */
    350 static int _sun_week_number(const struct tm *tm)
    351 {
    352         int first_day = (7 - _day_of_week(tm->tm_year, 0, 1)) % 7;
     403 *
     404 */
     405static int sun_week_number(const struct tm *tm)
     406{
     407        int first_day = (7 - day_of_week(tm->tm_year, 0, 1)) % 7;
     408       
    353409        return (tm->tm_yday - first_day + 7) / 7;
    354410}
    355411
    356 /**
    357  * Week number of the year, assuming weeks start on monday.
    358  * If the week containing January 1st has four or more days in the new year,
    359  * then it is considered week 1. Otherwise, it is the last week of the previous
    360  * year, and the next week is week 1. Both January 4th and the first Thursday
     412/** Week number of the year (assuming weeks start on Monday).
     413 *
     414 * If the week containing January 1st has four or more days
     415 * in the new year, then it is considered week 1. Otherwise,
     416 * it is the last week of the previous year, and the next week
     417 * is week 1. Both January 4th and the first Thursday
    361418 * of January are always in week 1.
    362419 *
    363420 * @param tm Normalized broken-down time.
     421 *
    364422 * @return The week number (1 - 53).
    365  */
    366 static int _iso_week_number(const struct tm *tm)
    367 {
    368         int day = tm->tm_yday - _wbyear_offset(tm->tm_year);
     423 *
     424 */
     425static int iso_week_number(const struct tm *tm)
     426{
     427        int day = tm->tm_yday - wbyear_offset(tm->tm_year);
     428       
    369429        if (day < 0) {
    370430                /* Last week of previous year. */
    371431                return 53;
    372432        }
    373         if (day > 364 + _is_leap_year(tm->tm_year)) {
     433       
     434        if (day > 364 + is_leap_year(tm->tm_year)) {
    374435                /* First week of next year. */
    375436                return 1;
    376437        }
     438       
    377439        /* All the other days give correct answer. */
    378440        return (day / 7 + 1);
    379441}
    380442
    381 /**
    382  * Week number of the year, assuming weeks start on monday.
     443/** Week number of the year (assuming weeks start on Monday).
     444 *
    383445 * The first Monday of January is the first day of week 1;
    384  * days in the new year before this are in week 0. 
     446 * days in the new year before this are in week 0.
    385447 *
    386448 * @param tm Normalized broken-down time.
     449 *
    387450 * @return The week number (0 - 53).
    388  */
    389 static int _mon_week_number(const struct tm *tm)
    390 {
    391         int first_day = (1 - _day_of_week(tm->tm_year, 0, 1)) % 7;
     451 *
     452 */
     453static int mon_week_number(const struct tm *tm)
     454{
     455        int first_day = (1 - day_of_week(tm->tm_year, 0, 1)) % 7;
     456       
    392457        return (tm->tm_yday - first_day + 7) / 7;
    393458}
    394459
    395 /******************************************************************************/
    396 
     460static void tv_normalize(struct timeval *tv)
     461{
     462        while (tv->tv_usec > USECS_PER_SEC) {
     463                tv->tv_sec++;
     464                tv->tv_usec -= USECS_PER_SEC;
     465        }
     466        while (tv->tv_usec < 0) {
     467                tv->tv_sec--;
     468                tv->tv_usec += USECS_PER_SEC;
     469        }
     470}
    397471
    398472/** Add microseconds to given timeval.
     
    402476 *
    403477 */
    404 void tv_add(struct timeval *tv, suseconds_t usecs)
    405 {
    406         tv->tv_sec += usecs / 1000000;
    407         tv->tv_usec += usecs % 1000000;
    408        
    409         if (tv->tv_usec > 1000000) {
    410                 tv->tv_sec++;
    411                 tv->tv_usec -= 1000000;
    412         }
    413 }
    414 
    415 /** Subtract two timevals.
     478void tv_add_diff(struct timeval *tv, suseconds_t usecs)
     479{
     480        tv->tv_sec += usecs / USECS_PER_SEC;
     481        tv->tv_usec += usecs % USECS_PER_SEC;
     482        tv_normalize(tv);
     483}
     484
     485/** Add two timevals.
    416486 *
    417487 * @param tv1 First timeval.
    418488 * @param tv2 Second timeval.
     489 */
     490void tv_add(struct timeval *tv1, struct timeval *tv2)
     491{
     492        tv1->tv_sec += tv2->tv_sec;
     493        tv1->tv_usec += tv2->tv_usec;
     494        tv_normalize(tv1);
     495}
     496
     497/** Subtract two timevals.
     498 *
     499 * @param tv1 First timeval.
     500 * @param tv2 Second timeval.
    419501 *
    420502 * @return Difference between tv1 and tv2 (tv1 - tv2) in
     
    422504 *
    423505 */
    424 suseconds_t tv_sub(struct timeval *tv1, struct timeval *tv2)
     506suseconds_t tv_sub_diff(struct timeval *tv1, struct timeval *tv2)
    425507{
    426508        return (tv1->tv_usec - tv2->tv_usec) +
    427             ((tv1->tv_sec - tv2->tv_sec) * 1000000);
     509            ((tv1->tv_sec - tv2->tv_sec) * USECS_PER_SEC);
     510}
     511
     512/** Subtract two timevals.
     513 *
     514 * @param tv1 First timeval.
     515 * @param tv2 Second timeval.
     516 *
     517 */
     518void tv_sub(struct timeval *tv1, struct timeval *tv2)
     519{
     520        tv1->tv_sec -= tv2->tv_sec;
     521        tv1->tv_usec -= tv2->tv_usec;
     522        tv_normalize(tv1);
    428523}
    429524
     
    468563}
    469564
    470 /** Get time of day
     565/** Get time of day.
    471566 *
    472567 * The time variables are memory mapped (read-only) from kernel which
     
    482577 *
    483578 */
    484 int gettimeofday(struct timeval *tv, struct timezone *tz)
    485 {
    486         int rc;
    487         struct tm t;
    488         category_id_t cat_id;
    489         size_t svc_cnt;
    490         service_id_t *svc_ids = NULL;
    491         service_id_t svc_id;
    492         char *svc_name = NULL;
    493 
    494         static async_sess_t *clock_conn = NULL;
    495 
     579void gettimeofday(struct timeval *tv, struct timezone *tz)
     580{
    496581        if (tz) {
    497582                tz->tz_minuteswest = 0;
    498583                tz->tz_dsttime = DST_NONE;
    499584        }
    500 
     585       
    501586        if (clock_conn == NULL) {
    502                 rc = loc_category_get_id("clock", &cat_id, IPC_FLAG_BLOCKING);
     587                category_id_t cat_id;
     588                int rc = loc_category_get_id("clock", &cat_id, IPC_FLAG_BLOCKING);
    503589                if (rc != EOK)
    504                         goto ret_uptime;
    505 
     590                        goto fallback;
     591               
     592                service_id_t *svc_ids;
     593                size_t svc_cnt;
    506594                rc = loc_category_get_svcs(cat_id, &svc_ids, &svc_cnt);
    507595                if (rc != EOK)
    508                         goto ret_uptime;
    509 
     596                        goto fallback;
     597               
    510598                if (svc_cnt == 0)
    511                         goto ret_uptime;
    512 
     599                        goto fallback;
     600               
     601                char *svc_name;
    513602                rc = loc_service_get_name(svc_ids[0], &svc_name);
     603                free(svc_ids);
    514604                if (rc != EOK)
    515                         goto ret_uptime;
    516 
     605                        goto fallback;
     606               
     607                service_id_t svc_id;
    517608                rc = loc_service_get_id(svc_name, &svc_id, 0);
     609                free(svc_name);
    518610                if (rc != EOK)
    519                         goto ret_uptime;
    520 
    521                 clock_conn = loc_service_connect(EXCHANGE_SERIALIZE,
    522                     svc_id, IPC_FLAG_BLOCKING);
     611                        goto fallback;
     612               
     613                clock_conn = loc_service_connect(svc_id, INTERFACE_DDF,
     614                    IPC_FLAG_BLOCKING);
    523615                if (!clock_conn)
    524                         goto ret_uptime;
    525         }
    526 
    527         rc = clock_dev_time_get(clock_conn, &t);
     616                        goto fallback;
     617        }
     618       
     619        struct tm time;
     620        int rc = clock_dev_time_get(clock_conn, &time);
    528621        if (rc != EOK)
    529                 goto ret_uptime;
    530 
    531         tv->tv_usec = 0;
    532         tv->tv_sec = mktime(&t);
    533 
    534         free(svc_name);
    535         free(svc_ids);
    536 
    537         return EOK;
    538 
    539 ret_uptime:
    540 
    541         free(svc_name);
    542         free(svc_ids);
    543 
    544         return getuptime(tv);
    545 }
    546 
    547 int getuptime(struct timeval *tv)
     622                goto fallback;
     623       
     624        tv->tv_usec = time.tm_usec;
     625        tv->tv_sec = mktime(&time);
     626       
     627        return;
     628       
     629fallback:
     630        getuptime(tv);
     631}
     632
     633void getuptime(struct timeval *tv)
    548634{
    549635        if (ktime == NULL) {
     
    552638                if (rc != EOK) {
    553639                        errno = rc;
    554                         return -1;
     640                        goto fallback;
    555641                }
    556642               
    557                 void *addr;
    558                 rc = physmem_map((void *) faddr, 1,
    559                     AS_AREA_READ | AS_AREA_CACHEABLE, &addr);
     643                void *addr = AS_AREA_ANY;
     644                rc = physmem_map(faddr, 1, AS_AREA_READ | AS_AREA_CACHEABLE,
     645                    &addr);
    560646                if (rc != EOK) {
    561647                        as_area_destroy(addr);
    562648                        errno = rc;
    563                         return -1;
     649                        goto fallback;
    564650                }
    565651               
     
    580666        } else
    581667                tv->tv_sec = s1;
    582 
    583         return 0;
     668       
     669        return;
     670       
     671fallback:
     672        tv->tv_sec = 0;
     673        tv->tv_usec = 0;
    584674}
    585675
     
    587677{
    588678        struct timeval tv;
    589         if (gettimeofday(&tv, NULL))
    590                 return (time_t) -1;
     679        gettimeofday(&tv, NULL);
    591680       
    592681        if (tloc)
     
    631720}
    632721
    633 /**
    634  * This function first normalizes the provided broken-down time
    635  * (moves all values to their proper bounds) and then tries to
    636  * calculate the appropriate time_t representation.
     722/** Get time from broken-down time.
     723 *
     724 * First normalize the provided broken-down time
     725 * (moves all values to their proper bounds) and
     726 * then try to calculate the appropriate time_t
     727 * representation.
    637728 *
    638729 * @param tm Broken-down time.
    639  * @return time_t representation of the time, undefined value on overflow.
     730 *
     731 * @return time_t representation of the time.
     732 * @return Undefined value on overflow.
     733 *
    640734 */
    641735time_t mktime(struct tm *tm)
     
    643737        // TODO: take DST flag into account
    644738        // TODO: detect overflow
    645 
    646         _normalize_time(tm, 0);
    647         return _secs_since_epoch(tm);
    648 }
    649 
    650 /**
    651  * Convert time and date to a string, based on a specified format and
    652  * current locale.
    653  *
    654  * @param s Buffer to write string to.
     739       
     740        normalize_tm_time(tm, 0);
     741        return secs_since_epoch(tm);
     742}
     743
     744/*
     745 * FIXME: This requires POSIX-correct snprintf.
     746 *        Otherwise it won't work with non-ASCII chars.
     747 */
     748#define APPEND(...) \
     749        { \
     750                consumed = snprintf(ptr, remaining, __VA_ARGS__); \
     751                if (consumed >= remaining) \
     752                        return 0; \
     753                \
     754                ptr += consumed; \
     755                remaining -= consumed; \
     756        }
     757
     758#define RECURSE(fmt) \
     759        { \
     760                consumed = strftime(ptr, remaining, fmt, tm); \
     761                if (consumed == 0) \
     762                        return 0; \
     763                \
     764                ptr += consumed; \
     765                remaining -= consumed; \
     766        }
     767
     768#define TO_12H(hour) \
     769        (((hour) > 12) ? ((hour) - 12) : \
     770            (((hour) == 0) ? 12 : (hour)))
     771
     772/** Convert time and date to a string.
     773 *
     774 * @param s       Buffer to write string to.
    655775 * @param maxsize Size of the buffer.
    656  * @param format Format of the output.
    657  * @param tm Broken-down time to format.
     776 * @param format  Format of the output.
     777 * @param tm      Broken-down time to format.
     778 *
    658779 * @return Number of bytes written.
     780 *
    659781 */
    660782size_t strftime(char *restrict s, size_t maxsize,
     
    664786        assert(format != NULL);
    665787        assert(tm != NULL);
    666 
     788       
    667789        // TODO: use locale
     790       
    668791        static const char *wday_abbr[] = {
    669792                "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
    670793        };
     794       
    671795        static const char *wday[] = {
    672796                "Sunday", "Monday", "Tuesday", "Wednesday",
    673797                "Thursday", "Friday", "Saturday"
    674798        };
     799       
    675800        static const char *mon_abbr[] = {
    676801                "Jan", "Feb", "Mar", "Apr", "May", "Jun",
    677802                "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
    678803        };
     804       
    679805        static const char *mon[] = {
    680806                "January", "February", "March", "April", "May", "June", "July",
     
    682808        };
    683809       
    684         if (maxsize < 1) {
     810        if (maxsize < 1)
    685811                return 0;
    686         }
    687812       
    688813        char *ptr = s;
     
    690815        size_t remaining = maxsize;
    691816       
    692         #define append(...) { \
    693                 /* FIXME: this requires POSIX-correct snprintf */ \
    694                 /*        otherwise it won't work with non-ascii chars */ \
    695                 consumed = snprintf(ptr, remaining, __VA_ARGS__); \
    696                 if (consumed >= remaining) { \
    697                         return 0; \
    698                 } \
    699                 ptr += consumed; \
    700                 remaining -= consumed; \
    701         }
    702        
    703         #define recurse(fmt) { \
    704                 consumed = strftime(ptr, remaining, fmt, tm); \
    705                 if (consumed == 0) { \
    706                         return 0; \
    707                 } \
    708                 ptr += consumed; \
    709                 remaining -= consumed; \
    710         }
    711        
    712         #define TO_12H(hour) (((hour) > 12) ? ((hour) - 12) : \
    713             (((hour) == 0) ? 12 : (hour)))
    714        
    715817        while (*format != '\0') {
    716818                if (*format != '%') {
    717                         append("%c", *format);
     819                        APPEND("%c", *format);
    718820                        format++;
    719821                        continue;
     
    721823               
    722824                format++;
    723                 if (*format == '0' || *format == '+') {
     825                if ((*format == '0') || (*format == '+')) {
    724826                        // TODO: padding
    725827                        format++;
    726828                }
     829               
    727830                while (isdigit(*format)) {
    728831                        // TODO: padding
    729832                        format++;
    730833                }
    731                 if (*format == 'O' || *format == 'E') {
     834               
     835                if ((*format == 'O') || (*format == 'E')) {
    732836                        // TODO: locale's alternative format
    733837                        format++;
     
    736840                switch (*format) {
    737841                case 'a':
    738                         append("%s", wday_abbr[tm->tm_wday]); break;
     842                        APPEND("%s", wday_abbr[tm->tm_wday]);
     843                        break;
    739844                case 'A':
    740                         append("%s", wday[tm->tm_wday]); break;
     845                        APPEND("%s", wday[tm->tm_wday]);
     846                        break;
    741847                case 'b':
    742                         append("%s", mon_abbr[tm->tm_mon]); break;
     848                        APPEND("%s", mon_abbr[tm->tm_mon]);
     849                        break;
    743850                case 'B':
    744                         append("%s", mon[tm->tm_mon]); break;
     851                        APPEND("%s", mon[tm->tm_mon]);
     852                        break;
    745853                case 'c':
    746854                        // TODO: locale-specific datetime format
    747                         recurse("%Y-%m-%d %H:%M:%S"); break;
     855                        RECURSE("%Y-%m-%d %H:%M:%S");
     856                        break;
    748857                case 'C':
    749                         append("%02d", (1900 + tm->tm_year) / 100); break;
     858                        APPEND("%02d", (1900 + tm->tm_year) / 100);
     859                        break;
    750860                case 'd':
    751                         append("%02d", tm->tm_mday); break;
     861                        APPEND("%02d", tm->tm_mday);
     862                        break;
    752863                case 'D':
    753                         recurse("%m/%d/%y"); break;
     864                        RECURSE("%m/%d/%y");
     865                        break;
    754866                case 'e':
    755                         append("%2d", tm->tm_mday); break;
     867                        APPEND("%2d", tm->tm_mday);
     868                        break;
    756869                case 'F':
    757                         recurse("%+4Y-%m-%d"); break;
     870                        RECURSE("%+4Y-%m-%d");
     871                        break;
    758872                case 'g':
    759                         append("%02d", _wbyear(tm) % 100); break;
     873                        APPEND("%02d", wbyear(tm) % 100);
     874                        break;
    760875                case 'G':
    761                         append("%d", _wbyear(tm)); break;
     876                        APPEND("%d", wbyear(tm));
     877                        break;
    762878                case 'h':
    763                         recurse("%b"); break;
     879                        RECURSE("%b");
     880                        break;
    764881                case 'H':
    765                         append("%02d", tm->tm_hour); break;
     882                        APPEND("%02d", tm->tm_hour);
     883                        break;
    766884                case 'I':
    767                         append("%02d", TO_12H(tm->tm_hour)); break;
     885                        APPEND("%02d", TO_12H(tm->tm_hour));
     886                        break;
    768887                case 'j':
    769                         append("%03d", tm->tm_yday); break;
     888                        APPEND("%03d", tm->tm_yday);
     889                        break;
    770890                case 'k':
    771                         append("%2d", tm->tm_hour); break;
     891                        APPEND("%2d", tm->tm_hour);
     892                        break;
    772893                case 'l':
    773                         append("%2d", TO_12H(tm->tm_hour)); break;
     894                        APPEND("%2d", TO_12H(tm->tm_hour));
     895                        break;
    774896                case 'm':
    775                         append("%02d", tm->tm_mon); break;
     897                        APPEND("%02d", tm->tm_mon);
     898                        break;
    776899                case 'M':
    777                         append("%02d", tm->tm_min); break;
     900                        APPEND("%02d", tm->tm_min);
     901                        break;
    778902                case 'n':
    779                         append("\n"); break;
     903                        APPEND("\n");
     904                        break;
    780905                case 'p':
    781                         append("%s", tm->tm_hour < 12 ? "AM" : "PM"); break;
     906                        APPEND("%s", tm->tm_hour < 12 ? "AM" : "PM");
     907                        break;
    782908                case 'P':
    783                         append("%s", tm->tm_hour < 12 ? "am" : "PM"); break;
     909                        APPEND("%s", tm->tm_hour < 12 ? "am" : "PM");
     910                        break;
    784911                case 'r':
    785                         recurse("%I:%M:%S %p"); break;
     912                        RECURSE("%I:%M:%S %p");
     913                        break;
    786914                case 'R':
    787                         recurse("%H:%M"); break;
     915                        RECURSE("%H:%M");
     916                        break;
    788917                case 's':
    789                         append("%ld", _secs_since_epoch(tm)); break;
     918                        APPEND("%ld", secs_since_epoch(tm));
     919                        break;
    790920                case 'S':
    791                         append("%02d", tm->tm_sec); break;
     921                        APPEND("%02d", tm->tm_sec);
     922                        break;
    792923                case 't':
    793                         append("\t"); break;
     924                        APPEND("\t");
     925                        break;
    794926                case 'T':
    795                         recurse("%H:%M:%S"); break;
     927                        RECURSE("%H:%M:%S");
     928                        break;
    796929                case 'u':
    797                         append("%d", (tm->tm_wday == 0) ? 7 : tm->tm_wday);
     930                        APPEND("%d", (tm->tm_wday == 0) ? 7 : tm->tm_wday);
    798931                        break;
    799932                case 'U':
    800                         append("%02d", _sun_week_number(tm)); break;
     933                        APPEND("%02d", sun_week_number(tm));
     934                        break;
    801935                case 'V':
    802                         append("%02d", _iso_week_number(tm)); break;
     936                        APPEND("%02d", iso_week_number(tm));
     937                        break;
    803938                case 'w':
    804                         append("%d", tm->tm_wday); break;
     939                        APPEND("%d", tm->tm_wday);
     940                        break;
    805941                case 'W':
    806                         append("%02d", _mon_week_number(tm)); break;
     942                        APPEND("%02d", mon_week_number(tm));
     943                        break;
    807944                case 'x':
    808945                        // TODO: locale-specific date format
    809                         recurse("%Y-%m-%d"); break;
     946                        RECURSE("%Y-%m-%d");
     947                        break;
    810948                case 'X':
    811949                        // TODO: locale-specific time format
    812                         recurse("%H:%M:%S"); break;
     950                        RECURSE("%H:%M:%S");
     951                        break;
    813952                case 'y':
    814                         append("%02d", tm->tm_year % 100); break;
     953                        APPEND("%02d", tm->tm_year % 100);
     954                        break;
    815955                case 'Y':
    816                         append("%d", 1900 + tm->tm_year); break;
     956                        APPEND("%d", 1900 + tm->tm_year);
     957                        break;
    817958                case 'z':
    818959                        // TODO: timezone
     
    822963                        break;
    823964                case '%':
    824                         append("%%");
     965                        APPEND("%%");
    825966                        break;
    826967                default:
    827968                        /* Invalid specifier, print verbatim. */
    828                         while (*format != '%') {
     969                        while (*format != '%')
    829970                                format--;
    830                         }
    831                         append("%%");
     971                       
     972                        APPEND("%%");
    832973                        break;
    833974                }
     975               
    834976                format++;
    835977        }
    836978       
    837         #undef append
    838         #undef recurse
    839        
    840979        return maxsize - remaining;
    841980}
    842981
    843 
    844 /** Converts a time value to a broken-down UTC time
    845  *
    846  * @param time    Time to convert
    847  * @param result  Structure to store the result to
    848  *
    849  * @return        EOK or a negative error code
     982/** Convert a time value to a broken-down UTC time/
     983 *
     984 * @param time   Time to convert
     985 * @param result Structure to store the result to
     986 *
     987 * @return EOK or a negative error code
     988 *
    850989 */
    851990int time_utc2tm(const time_t time, struct tm *restrict result)
    852991{
    853992        assert(result != NULL);
    854 
     993       
    855994        /* Set result to epoch. */
     995        result->tm_usec = 0;
    856996        result->tm_sec = 0;
    857997        result->tm_min = 0;
     
    8601000        result->tm_mon = 0;
    8611001        result->tm_year = 70; /* 1970 */
    862 
    863         if (_normalize_time(result, time) == -1)
     1002       
     1003        if (normalize_tm_time(result, time) == -1)
    8641004                return EOVERFLOW;
    865 
     1005       
    8661006        return EOK;
    8671007}
    8681008
    869 /** Converts a time value to a null terminated string of the form
    870  *  "Wed Jun 30 21:49:08 1993\n" expressed in UTC.
    871  *
    872  * @param time   Time to convert.
    873  * @param buf    Buffer to store the string to, must be at least
    874  *               ASCTIME_BUF_LEN bytes long.
    875  *
    876  * @return       EOK or a negative error code.
     1009/** Convert a time value to a NULL-terminated string.
     1010 *
     1011 * The format is "Wed Jun 30 21:49:08 1993\n" expressed in UTC.
     1012 *
     1013 * @param time Time to convert.
     1014 * @param buf  Buffer to store the string to, must be at least
     1015 *             ASCTIME_BUF_LEN bytes long.
     1016 *
     1017 * @return EOK or a negative error code.
     1018 *
    8771019 */
    8781020int time_utc2str(const time_t time, char *restrict buf)
    8791021{
    880         struct tm t;
    881         int r;
    882 
    883         if ((r = time_utc2tm(time, &t)) != EOK)
    884                 return r;
    885 
    886         time_tm2str(&t, buf);
     1022        struct tm tm;
     1023        int ret = time_utc2tm(time, &tm);
     1024        if (ret != EOK)
     1025                return ret;
     1026       
     1027        time_tm2str(&tm, buf);
    8871028        return EOK;
    8881029}
    8891030
    890 
    891 /**
    892  * Converts broken-down time to a string in format
    893  * "Sun Jan 1 00:00:00 1970\n". (Obsolete)
     1031/** Convert broken-down time to a NULL-terminated string.
     1032 *
     1033 * The format is "Sun Jan 1 00:00:00 1970\n". (Obsolete)
    8941034 *
    8951035 * @param timeptr Broken-down time structure.
    896  * @param buf     Buffer to store string to, must be at least ASCTIME_BUF_LEN
    897  *                bytes long.
     1036 * @param buf     Buffer to store string to, must be at least
     1037 *                ASCTIME_BUF_LEN bytes long.
     1038 *
    8981039 */
    8991040void time_tm2str(const struct tm *restrict timeptr, char *restrict buf)
     
    9011042        assert(timeptr != NULL);
    9021043        assert(buf != NULL);
    903 
     1044       
    9041045        static const char *wday[] = {
    9051046                "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
    9061047        };
     1048       
    9071049        static const char *mon[] = {
    9081050                "Jan", "Feb", "Mar", "Apr", "May", "Jun",
    9091051                "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
    9101052        };
    911 
     1053       
    9121054        snprintf(buf, ASCTIME_BUF_LEN, "%s %s %2d %02d:%02d:%02d %d\n",
    9131055            wday[timeptr->tm_wday],
     
    9181060}
    9191061
    920 /**
    921  * Converts a time value to a broken-down local time, expressed relative
    922  * to the user's specified timezone.
    923  *
    924  * @param timer     Time to convert.
    925  * @param result    Structure to store the result to.
    926  *
    927  * @return          EOK on success or a negative error code.
    928  */
    929 int time_local2tm(const time_t time, struct tm *restrict result)
    930 {
    931         // TODO: deal with timezone
    932         // currently assumes system and all times are in GMT
    933 
     1062/** Converts a time value to a broken-down local time.
     1063 *
     1064 * Time is expressed relative to the user's specified timezone.
     1065 *
     1066 * @param tv     Timeval to convert.
     1067 * @param result Structure to store the result to.
     1068 *
     1069 * @return EOK on success or a negative error code.
     1070 *
     1071 */
     1072int time_tv2tm(const struct timeval *tv, struct tm *restrict result)
     1073{
     1074        // TODO: Deal with timezones.
     1075        //       Currently assumes system and all times are in UTC
     1076       
    9341077        /* Set result to epoch. */
     1078        result->tm_usec = 0;
    9351079        result->tm_sec = 0;
    9361080        result->tm_min = 0;
     
    9391083        result->tm_mon = 0;
    9401084        result->tm_year = 70; /* 1970 */
    941 
    942         if (_normalize_time(result, time) == -1)
     1085       
     1086        if (normalize_tm_tv(result, tv) == -1)
    9431087                return EOVERFLOW;
    944 
     1088       
    9451089        return EOK;
    9461090}
    9471091
    948 /**
    949  * Converts the calendar time to a null terminated string
    950  * of the form "Wed Jun 30 21:49:08 1993\n" expressed relative to the
     1092/** Converts a time value to a broken-down local time.
     1093 *
     1094 * Time is expressed relative to the user's specified timezone.
     1095 *
     1096 * @param timer  Time to convert.
     1097 * @param result Structure to store the result to.
     1098 *
     1099 * @return EOK on success or a negative error code.
     1100 *
     1101 */
     1102int time_local2tm(const time_t time, struct tm *restrict result)
     1103{
     1104        struct timeval tv = {
     1105                .tv_sec = time,
     1106                .tv_usec = 0
     1107        };
     1108
     1109        return time_tv2tm(&tv, result);
     1110}
     1111
     1112/** Convert the calendar time to a NULL-terminated string.
     1113 *
     1114 * The format is "Wed Jun 30 21:49:08 1993\n" expressed relative to the
    9511115 * user's specified timezone.
    952  *
    953  * @param timer  Time to convert.
    954  * @param buf    Buffer to store the string to. Must be at least
    955  *               ASCTIME_BUF_LEN bytes long.
    956  *
    957  * @return       EOK on success or a negative error code.
     1116 *
     1117 * @param timer Time to convert.
     1118 * @param buf   Buffer to store the string to. Must be at least
     1119 *              ASCTIME_BUF_LEN bytes long.
     1120 *
     1121 * @return EOK on success or a negative error code.
     1122 *
    9581123 */
    9591124int time_local2str(const time_t time, char *buf)
    9601125{
    9611126        struct tm loctime;
    962         int r;
    963 
    964         if ((r = time_local2tm(time, &loctime)) != EOK)
    965                 return r;
    966 
     1127        int ret = time_local2tm(time, &loctime);
     1128        if (ret != EOK)
     1129                return ret;
     1130       
    9671131        time_tm2str(&loctime, buf);
    968 
    9691132        return EOK;
    9701133}
    9711134
    972 /**
    973  * Calculate the difference between two times, in seconds.
    974  *
     1135/** Calculate the difference between two times, in seconds.
     1136 *
    9751137 * @param time1 First time.
    9761138 * @param time0 Second time.
    977  * @return Time in seconds.
     1139 *
     1140 * @return Time difference in seconds.
     1141 *
    9781142 */
    9791143double difftime(time_t time1, time_t time0)
Note: See TracChangeset for help on using the changeset viewer.