Ignore:
File:
1 edited

Legend:

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

    rf9b2cb4c r3e6a98c5  
    5454#include <malloc.h>
    5555
    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)
     56#define ASCTIME_BUF_LEN 26
    6557
    6658/** Pointer to kernel shared variables with time */
     
    7163} *ktime = NULL;
    7264
    73 static async_sess_t *clock_conn = NULL;
    74 
    75 /** Check whether the year is a leap year.
     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.
    7676 *
    7777 * @param year Year since 1900 (e.g. for 1970, the value is 70).
    78  *
    7978 * @return true if year is a leap year, false otherwise
    80  *
    81  */
    82 static bool is_leap_year(time_t year)
     79 */
     80static bool _is_leap_year(time_t year)
    8381{
    8482        year += 1900;
    85        
     83
    8684        if (year % 400 == 0)
    8785                return true;
    88        
    8986        if (year % 100 == 0)
    9087                return false;
    91        
    9288        if (year % 4 == 0)
    9389                return true;
    94        
    9590        return false;
    9691}
    9792
    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.
     93/**
     94 * Returns how many days there are in the given month of the given year.
    10195 * Note that year is only taken into account if month is February.
    10296 *
    10397 * @param year Year since 1900 (can be negative).
    104  * @param mon  Month of the year. 0 for January, 11 for December.
    105  *
     98 * @param mon Month of the year. 0 for January, 11 for December.
    10699 * @return Number of days in the specified month.
    107  *
    108  */
    109 static 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        
     100 */
     101static 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
    118108        if (mon == 1) {
    119                 /* February */
    120109                year += 1900;
    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
     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
    130119 * it is.
    131120 *
    132121 * For example, given date 2011-01-03, the corresponding expression is:
    133  * day_of_year(111, 0, 3) == 2
     122 *     _day_of_year(111, 0, 3) == 2
    134123 *
    135124 * @param year Year (year 1900 = 0, can be negative).
    136  * @param mon  Month (January = 0).
     125 * @param mon Month (January = 0).
    137126 * @param mday Day of month (First day is 1).
    138  *
    139127 * @return Day of year (First day is 0).
    140  *
    141  */
    142 static 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.
     128 */
     129static 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.
    158142 *
    159143 * @param op1 Dividend.
    160144 * @param op2 Divisor.
    161  *
    162145 * @return Rounded quotient.
    163  *
    164  */
    165 static time_t floor_div(time_t op1, time_t op2)
    166 {
    167         if ((op1 >= 0) || (op1 % op2 == 0))
     146 */
     147static time_t _floor_div(time_t op1, time_t op2)
     148{
     149        if (op1 >= 0 || op1 % op2 == 0) {
    168150                return op1 / op2;
    169        
    170         return op1 / op2 - 1;
    171 }
    172 
    173 /** Modulo that rounds to negative infinity.
    174  *
    175  * Used by some functions in this module.
     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.
    176159 *
    177160 * @param op1 Dividend.
    178161 * @param op2 Divisor.
    179  *
    180162 * @return Remainder.
    181  *
    182  */
    183 static 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. */
     163 */
     164static 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. */
    195174        assert(result >= 0);
    196175        assert(result < op2);
     
    200179}
    201180
    202 /** Number of days since the Epoch.
    203  *
     181/**
     182 * Number of days since the Epoch.
    204183 * Epoch is 1970-01-01, which is also equal to day 0.
    205184 *
    206185 * @param year Year (year 1900 = 0, may be negative).
    207  * @param mon  Month (January = 0).
     186 * @param mon Month (January = 0).
    208187 * @param mday Day of month (first day = 1).
    209  *
    210188 * @return Number of days since the Epoch.
    211  *
    212  */
    213 static 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  *
     189 */
     190static 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 *
    224200 * @param tm Normalized broken-down time.
    225  *
    226201 * @return Number of seconds since the epoch, not counting leap seconds.
    227  *
    228  */
    229 static time_t secs_since_epoch(const struct tm *tm)
    230 {
    231         return days_since_epoch(tm->tm_year, tm->tm_mon, tm->tm_mday) *
     202 */
     203static time_t _secs_since_epoch(const struct tm *tm)
     204{
     205        return _days_since_epoch(tm->tm_year, tm->tm_mon, tm->tm_mday) *
    232206            SECS_PER_DAY + tm->tm_hour * SECS_PER_HOUR +
    233207            tm->tm_min * SECS_PER_MIN + tm->tm_sec;
    234208}
    235209
    236 /** Which day of week the specified date is.
    237  *
     210/**
     211 * Which day of week the specified date is.
     212 *
    238213 * @param year Year (year 1900 = 0).
    239  * @param mon  Month (January = 0).
     214 * @param mon Month (January = 0).
    240215 * @param mday Day of month (first = 1).
    241  *
    242216 * @return Day of week (Sunday = 0).
    243  *
    244  */
    245 static time_t day_of_week(time_t year, time_t mon, time_t mday)
     217 */
     218static int _day_of_week(time_t year, time_t mon, time_t mday)
    246219{
    247220        /* 1970-01-01 is Thursday */
    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  *
     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 * 
    255228 * @param tm Broken-down time to normalize.
    256  * @param tv Timeval to add.
    257  *
     229 * @param sec_add Seconds to add.
    258230 * @return 0 on success, -1 on overflow
    259  *
    260  */
    261 static int normalize_tm_tv(struct tm *tm, const struct timeval *tv)
     231 */
     232static int _normalize_time(struct tm *tm, time_t sec_add)
    262233{
    263234        // TODO: DST correction
    264        
     235
    265236        /* Set initial values. */
    266         time_t usec = tm->tm_usec + tv->tv_usec;
    267         time_t sec = tm->tm_sec + tv->tv_sec;
     237        time_t sec = tm->tm_sec + sec_add;
    268238        time_t min = tm->tm_min;
    269239        time_t hour = tm->tm_hour;
     
    271241        time_t mon = tm->tm_mon;
    272242        time_t year = tm->tm_year;
    273        
     243
    274244        /* Adjust time. */
    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        
     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
    284252        /* Adjust month. */
    285         year += floor_div(mon, 12);
    286         mon = floor_mod(mon, 12);
    287        
     253        year += _floor_div(mon, 12);
     254        mon = _floor_mod(mon, 12);
     255
    288256        /* Now the difficult part - days of month. */
    289257       
    290258        /* First, deal with whole cycles of 400 years = 146097 days. */
    291         year += floor_div(day, 146097) * 400;
    292         day = floor_mod(day, 146097);
     259        year += _floor_div(day, 146097) * 400;
     260        day = _floor_mod(day, 146097);
    293261       
    294262        /* Then, go in one year steps. */
     
    296264                /* January and February. */
    297265                while (day > 365) {
    298                         day -= is_leap_year(year) ? 366 : 365;
     266                        day -= _is_leap_year(year) ? 366 : 365;
    299267                        year++;
    300268                }
     
    302270                /* Rest of the year. */
    303271                while (day > 365) {
    304                         day -= is_leap_year(year + 1) ? 366 : 365;
     272                        day -= _is_leap_year(year + 1) ? 366 : 365;
    305273                        year++;
    306274                }
     
    308276       
    309277        /* Finally, finish it off month per month. */
    310         while (day >= days_in_month(year, mon)) {
    311                 day -= days_in_month(year, mon);
     278        while (day >= _days_in_month(year, mon)) {
     279                day -= _days_in_month(year, mon);
    312280                mon++;
    313                
    314281                if (mon >= 12) {
    315282                        mon -= 12;
     
    319286       
    320287        /* Calculate the remaining two fields. */
    321         tm->tm_yday = day_of_year(year, mon, day + 1);
    322         tm->tm_wday = day_of_week(year, mon, day + 1);
     288        tm->tm_yday = _day_of_year(year, mon, day + 1);
     289        tm->tm_wday = _day_of_week(year, mon, day + 1);
    323290       
    324291        /* And put the values back to the struct. */
    325         tm->tm_usec = (int) usec;
    326292        tm->tm_sec = (int) sec;
    327293        tm->tm_min = (int) min;
     
    330296        tm->tm_mon = (int) mon;
    331297       
    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);
     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);
    335301                return -1;
    336302        }
     
    340306}
    341307
    342 static 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.
     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.
    357311 *
    358312 * @param Year since 1900.
    359  *
    360313 * @return Offset of week-based year relative to calendar year.
    361  *
    362  */
    363 static 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.
     314 */
     315static 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.
    371323 *
    372324 * @param tm Normalized broken-down time.
    373  *
    374325 * @return Week-based year.
    375  *
    376  */
    377 static int wbyear(const struct tm *tm)
    378 {
    379         int day = tm->tm_yday - wbyear_offset(tm->tm_year);
    380        
     326 */
     327static int _wbyear(const struct tm *tm)
     328{
     329        int day = tm->tm_yday - _wbyear_offset(tm->tm_year);
    381330        if (day < 0) {
    382331                /* Last week of previous year. */
    383332                return tm->tm_year - 1;
    384333        }
    385        
    386         if (day > 364 + is_leap_year(tm->tm_year)) {
     334        if (day > 364 + _is_leap_year(tm->tm_year)) {
    387335                /* First week of next year. */
    388336                return tm->tm_year + 1;
    389337        }
    390        
    391338        /* All the other days are in the calendar year. */
    392339        return tm->tm_year;
    393340}
    394341
    395 /** Week number of the year (assuming weeks start on Sunday).
    396  *
     342/**
     343 * Week number of the year, assuming weeks start on sunday.
    397344 * The first Sunday of January is the first day of week 1;
    398345 * days in the new year before this are in week 0.
    399346 *
    400347 * @param tm Normalized broken-down time.
    401  *
    402348 * @return The week number (0 - 53).
    403  *
    404  */
    405 static int sun_week_number(const struct tm *tm)
    406 {
    407         int first_day = (7 - day_of_week(tm->tm_year, 0, 1)) % 7;
    408        
     349 */
     350static int _sun_week_number(const struct tm *tm)
     351{
     352        int first_day = (7 - _day_of_week(tm->tm_year, 0, 1)) % 7;
    409353        return (tm->tm_yday - first_day + 7) / 7;
    410354}
    411355
    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
     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
    418361 * of January are always in week 1.
    419362 *
    420363 * @param tm Normalized broken-down time.
    421  *
    422364 * @return The week number (1 - 53).
    423  *
    424  */
    425 static int iso_week_number(const struct tm *tm)
    426 {
    427         int day = tm->tm_yday - wbyear_offset(tm->tm_year);
    428        
     365 */
     366static int _iso_week_number(const struct tm *tm)
     367{
     368        int day = tm->tm_yday - _wbyear_offset(tm->tm_year);
    429369        if (day < 0) {
    430370                /* Last week of previous year. */
    431371                return 53;
    432372        }
    433        
    434         if (day > 364 + is_leap_year(tm->tm_year)) {
     373        if (day > 364 + _is_leap_year(tm->tm_year)) {
    435374                /* First week of next year. */
    436375                return 1;
    437376        }
    438        
    439377        /* All the other days give correct answer. */
    440378        return (day / 7 + 1);
    441379}
    442380
    443 /** Week number of the year (assuming weeks start on Monday).
    444  *
     381/**
     382 * Week number of the year, assuming weeks start on monday.
    445383 * The first Monday of January is the first day of week 1;
    446  * days in the new year before this are in week 0.
     384 * days in the new year before this are in week 0. 
    447385 *
    448386 * @param tm Normalized broken-down time.
    449  *
    450387 * @return The week number (0 - 53).
    451  *
    452  */
    453 static int mon_week_number(const struct tm *tm)
    454 {
    455         int first_day = (1 - day_of_week(tm->tm_year, 0, 1)) % 7;
    456        
     388 */
     389static int _mon_week_number(const struct tm *tm)
     390{
     391        int first_day = (1 - _day_of_week(tm->tm_year, 0, 1)) % 7;
    457392        return (tm->tm_yday - first_day + 7) / 7;
    458393}
    459394
    460 static 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 }
     395/******************************************************************************/
     396
    471397
    472398/** Add microseconds to given timeval.
     
    476402 *
    477403 */
    478 void 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.
     404void 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.
    486416 *
    487417 * @param tv1 First timeval.
    488418 * @param tv2 Second timeval.
    489  */
    490 void 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.
     419 *
     420 * @return Difference between tv1 and tv2 (tv1 - tv2) in
     421 *         microseconds.
     422 *
     423 */
     424suseconds_t tv_sub(struct timeval *tv1, struct timeval *tv2)
     425{
     426        return (tv1->tv_usec - tv2->tv_usec) +
     427            ((tv1->tv_sec - tv2->tv_sec) * 1000000);
     428}
     429
     430/** Decide if one timeval is greater than the other.
     431 *
     432 * @param t1 First timeval.
     433 * @param t2 Second timeval.
     434 *
     435 * @return True if tv1 is greater than tv2.
     436 * @return False otherwise.
     437 *
     438 */
     439int tv_gt(struct timeval *tv1, struct timeval *tv2)
     440{
     441        if (tv1->tv_sec > tv2->tv_sec)
     442                return true;
     443       
     444        if ((tv1->tv_sec == tv2->tv_sec) && (tv1->tv_usec > tv2->tv_usec))
     445                return true;
     446       
     447        return false;
     448}
     449
     450/** Decide if one timeval is greater than or equal to the other.
    498451 *
    499452 * @param tv1 First timeval.
    500453 * @param tv2 Second timeval.
    501454 *
    502  * @return Difference between tv1 and tv2 (tv1 - tv2) in
    503  *         microseconds.
    504  *
    505  */
    506 suseconds_t tv_sub_diff(struct timeval *tv1, struct timeval *tv2)
    507 {
    508         return (tv1->tv_usec - tv2->tv_usec) +
    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  */
    518 void 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);
    523 }
    524 
    525 /** Decide if one timeval is greater than the other.
    526  *
    527  * @param t1 First timeval.
    528  * @param t2 Second timeval.
    529  *
    530  * @return True if tv1 is greater than tv2.
     455 * @return True if tv1 is greater than or equal to tv2.
    531456 * @return False otherwise.
    532457 *
    533458 */
    534 int tv_gt(struct timeval *tv1, struct timeval *tv2)
     459int tv_gteq(struct timeval *tv1, struct timeval *tv2)
    535460{
    536461        if (tv1->tv_sec > tv2->tv_sec)
    537462                return true;
    538463       
    539         if ((tv1->tv_sec == tv2->tv_sec) && (tv1->tv_usec > tv2->tv_usec))
    540                 return true;
    541        
    542         return false;
    543 }
    544 
    545 /** Decide if one timeval is greater than or equal to the other.
    546  *
    547  * @param tv1 First timeval.
    548  * @param tv2 Second timeval.
    549  *
    550  * @return True if tv1 is greater than or equal to tv2.
    551  * @return False otherwise.
    552  *
    553  */
    554 int tv_gteq(struct timeval *tv1, struct timeval *tv2)
    555 {
    556         if (tv1->tv_sec > tv2->tv_sec)
    557                 return true;
    558        
    559464        if ((tv1->tv_sec == tv2->tv_sec) && (tv1->tv_usec >= tv2->tv_usec))
    560465                return true;
     
    563468}
    564469
    565 /** Get time of day.
     470/** Get time of day
    566471 *
    567472 * The time variables are memory mapped (read-only) from kernel which
     
    577482 *
    578483 */
    579 void gettimeofday(struct timeval *tv, struct timezone *tz)
    580 {
     484int 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
    581496        if (tz) {
    582497                tz->tz_minuteswest = 0;
    583498                tz->tz_dsttime = DST_NONE;
    584499        }
    585        
     500
    586501        if (clock_conn == NULL) {
    587                 category_id_t cat_id;
    588                 int rc = loc_category_get_id("clock", &cat_id, IPC_FLAG_BLOCKING);
     502                rc = loc_category_get_id("clock", &cat_id, IPC_FLAG_BLOCKING);
    589503                if (rc != EOK)
    590                         goto fallback;
    591                
    592                 service_id_t *svc_ids;
    593                 size_t svc_cnt;
     504                        goto ret_uptime;
     505
    594506                rc = loc_category_get_svcs(cat_id, &svc_ids, &svc_cnt);
    595507                if (rc != EOK)
    596                         goto fallback;
    597                
     508                        goto ret_uptime;
     509
    598510                if (svc_cnt == 0)
    599                         goto fallback;
    600                
    601                 char *svc_name;
     511                        goto ret_uptime;
     512
    602513                rc = loc_service_get_name(svc_ids[0], &svc_name);
    603                 free(svc_ids);
    604514                if (rc != EOK)
    605                         goto fallback;
    606                
    607                 service_id_t svc_id;
     515                        goto ret_uptime;
     516
    608517                rc = loc_service_get_id(svc_name, &svc_id, 0);
    609                 free(svc_name);
    610518                if (rc != EOK)
    611                         goto fallback;
    612                
    613                 clock_conn = loc_service_connect(svc_id, INTERFACE_DDF,
    614                     IPC_FLAG_BLOCKING);
     519                        goto ret_uptime;
     520
     521                clock_conn = loc_service_connect(EXCHANGE_SERIALIZE,
     522                    svc_id, IPC_FLAG_BLOCKING);
    615523                if (!clock_conn)
    616                         goto fallback;
    617         }
    618        
    619         struct tm time;
    620         int rc = clock_dev_time_get(clock_conn, &time);
     524                        goto ret_uptime;
     525        }
     526
     527        rc = clock_dev_time_get(clock_conn, &t);
    621528        if (rc != EOK)
    622                 goto fallback;
    623        
    624         tv->tv_usec = time.tm_usec;
    625         tv->tv_sec = mktime(&time);
    626        
    627         return;
    628        
    629 fallback:
    630         getuptime(tv);
    631 }
    632 
    633 void getuptime(struct timeval *tv)
     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
     539ret_uptime:
     540
     541        free(svc_name);
     542        free(svc_ids);
     543
     544        return getuptime(tv);
     545}
     546
     547int getuptime(struct timeval *tv)
    634548{
    635549        if (ktime == NULL) {
     
    638552                if (rc != EOK) {
    639553                        errno = rc;
    640                         goto fallback;
     554                        return -1;
    641555                }
    642556               
    643                 void *addr = AS_AREA_ANY;
    644                 rc = physmem_map(faddr, 1, AS_AREA_READ | AS_AREA_CACHEABLE,
    645                     &addr);
     557                void *addr;
     558                rc = physmem_map((void *) faddr, 1,
     559                    AS_AREA_READ | AS_AREA_CACHEABLE, &addr);
    646560                if (rc != EOK) {
    647561                        as_area_destroy(addr);
    648562                        errno = rc;
    649                         goto fallback;
     563                        return -1;
    650564                }
    651565               
     
    666580        } else
    667581                tv->tv_sec = s1;
    668        
    669         return;
    670        
    671 fallback:
    672         tv->tv_sec = 0;
    673         tv->tv_usec = 0;
     582
     583        return 0;
    674584}
    675585
     
    677587{
    678588        struct timeval tv;
    679         gettimeofday(&tv, NULL);
     589        if (gettimeofday(&tv, NULL))
     590                return (time_t) -1;
    680591       
    681592        if (tloc)
     
    720631}
    721632
    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.
     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.
    728637 *
    729638 * @param tm Broken-down time.
    730  *
    731  * @return time_t representation of the time.
    732  * @return Undefined value on overflow.
    733  *
     639 * @return time_t representation of the time, undefined value on overflow.
    734640 */
    735641time_t mktime(struct tm *tm)
     
    737643        // TODO: take DST flag into account
    738644        // TODO: detect overflow
    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.
     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.
    775655 * @param maxsize Size of the buffer.
    776  * @param format  Format of the output.
    777  * @param tm      Broken-down time to format.
    778  *
     656 * @param format Format of the output.
     657 * @param tm Broken-down time to format.
    779658 * @return Number of bytes written.
    780  *
    781659 */
    782660size_t strftime(char *restrict s, size_t maxsize,
     
    786664        assert(format != NULL);
    787665        assert(tm != NULL);
    788        
     666
    789667        // TODO: use locale
    790        
    791668        static const char *wday_abbr[] = {
    792669                "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
    793670        };
    794        
    795671        static const char *wday[] = {
    796672                "Sunday", "Monday", "Tuesday", "Wednesday",
    797673                "Thursday", "Friday", "Saturday"
    798674        };
    799        
    800675        static const char *mon_abbr[] = {
    801676                "Jan", "Feb", "Mar", "Apr", "May", "Jun",
    802677                "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
    803678        };
    804        
    805679        static const char *mon[] = {
    806680                "January", "February", "March", "April", "May", "June", "July",
     
    808682        };
    809683       
    810         if (maxsize < 1)
     684        if (maxsize < 1) {
    811685                return 0;
     686        }
    812687       
    813688        char *ptr = s;
     
    815690        size_t remaining = maxsize;
    816691       
     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       
    817715        while (*format != '\0') {
    818716                if (*format != '%') {
    819                         APPEND("%c", *format);
     717                        append("%c", *format);
    820718                        format++;
    821719                        continue;
     
    823721               
    824722                format++;
    825                 if ((*format == '0') || (*format == '+')) {
     723                if (*format == '0' || *format == '+') {
    826724                        // TODO: padding
    827725                        format++;
    828726                }
    829                
    830727                while (isdigit(*format)) {
    831728                        // TODO: padding
    832729                        format++;
    833730                }
    834                
    835                 if ((*format == 'O') || (*format == 'E')) {
     731                if (*format == 'O' || *format == 'E') {
    836732                        // TODO: locale's alternative format
    837733                        format++;
     
    840736                switch (*format) {
    841737                case 'a':
    842                         APPEND("%s", wday_abbr[tm->tm_wday]);
    843                         break;
     738                        append("%s", wday_abbr[tm->tm_wday]); break;
    844739                case 'A':
    845                         APPEND("%s", wday[tm->tm_wday]);
    846                         break;
     740                        append("%s", wday[tm->tm_wday]); break;
    847741                case 'b':
    848                         APPEND("%s", mon_abbr[tm->tm_mon]);
    849                         break;
     742                        append("%s", mon_abbr[tm->tm_mon]); break;
    850743                case 'B':
    851                         APPEND("%s", mon[tm->tm_mon]);
    852                         break;
     744                        append("%s", mon[tm->tm_mon]); break;
    853745                case 'c':
    854746                        // TODO: locale-specific datetime format
    855                         RECURSE("%Y-%m-%d %H:%M:%S");
    856                         break;
     747                        recurse("%Y-%m-%d %H:%M:%S"); break;
    857748                case 'C':
    858                         APPEND("%02d", (1900 + tm->tm_year) / 100);
    859                         break;
     749                        append("%02d", (1900 + tm->tm_year) / 100); break;
    860750                case 'd':
    861                         APPEND("%02d", tm->tm_mday);
    862                         break;
     751                        append("%02d", tm->tm_mday); break;
    863752                case 'D':
    864                         RECURSE("%m/%d/%y");
    865                         break;
     753                        recurse("%m/%d/%y"); break;
    866754                case 'e':
    867                         APPEND("%2d", tm->tm_mday);
    868                         break;
     755                        append("%2d", tm->tm_mday); break;
    869756                case 'F':
    870                         RECURSE("%+4Y-%m-%d");
    871                         break;
     757                        recurse("%+4Y-%m-%d"); break;
    872758                case 'g':
    873                         APPEND("%02d", wbyear(tm) % 100);
    874                         break;
     759                        append("%02d", _wbyear(tm) % 100); break;
    875760                case 'G':
    876                         APPEND("%d", wbyear(tm));
    877                         break;
     761                        append("%d", _wbyear(tm)); break;
    878762                case 'h':
    879                         RECURSE("%b");
    880                         break;
     763                        recurse("%b"); break;
    881764                case 'H':
    882                         APPEND("%02d", tm->tm_hour);
    883                         break;
     765                        append("%02d", tm->tm_hour); break;
    884766                case 'I':
    885                         APPEND("%02d", TO_12H(tm->tm_hour));
    886                         break;
     767                        append("%02d", TO_12H(tm->tm_hour)); break;
    887768                case 'j':
    888                         APPEND("%03d", tm->tm_yday);
    889                         break;
     769                        append("%03d", tm->tm_yday); break;
    890770                case 'k':
    891                         APPEND("%2d", tm->tm_hour);
    892                         break;
     771                        append("%2d", tm->tm_hour); break;
    893772                case 'l':
    894                         APPEND("%2d", TO_12H(tm->tm_hour));
    895                         break;
     773                        append("%2d", TO_12H(tm->tm_hour)); break;
    896774                case 'm':
    897                         APPEND("%02d", tm->tm_mon);
    898                         break;
     775                        append("%02d", tm->tm_mon); break;
    899776                case 'M':
    900                         APPEND("%02d", tm->tm_min);
    901                         break;
     777                        append("%02d", tm->tm_min); break;
    902778                case 'n':
    903                         APPEND("\n");
    904                         break;
     779                        append("\n"); break;
    905780                case 'p':
    906                         APPEND("%s", tm->tm_hour < 12 ? "AM" : "PM");
    907                         break;
     781                        append("%s", tm->tm_hour < 12 ? "AM" : "PM"); break;
    908782                case 'P':
    909                         APPEND("%s", tm->tm_hour < 12 ? "am" : "PM");
    910                         break;
     783                        append("%s", tm->tm_hour < 12 ? "am" : "PM"); break;
    911784                case 'r':
    912                         RECURSE("%I:%M:%S %p");
    913                         break;
     785                        recurse("%I:%M:%S %p"); break;
    914786                case 'R':
    915                         RECURSE("%H:%M");
    916                         break;
     787                        recurse("%H:%M"); break;
    917788                case 's':
    918                         APPEND("%ld", secs_since_epoch(tm));
    919                         break;
     789                        append("%ld", _secs_since_epoch(tm)); break;
    920790                case 'S':
    921                         APPEND("%02d", tm->tm_sec);
    922                         break;
     791                        append("%02d", tm->tm_sec); break;
    923792                case 't':
    924                         APPEND("\t");
    925                         break;
     793                        append("\t"); break;
    926794                case 'T':
    927                         RECURSE("%H:%M:%S");
    928                         break;
     795                        recurse("%H:%M:%S"); break;
    929796                case 'u':
    930                         APPEND("%d", (tm->tm_wday == 0) ? 7 : tm->tm_wday);
     797                        append("%d", (tm->tm_wday == 0) ? 7 : tm->tm_wday);
    931798                        break;
    932799                case 'U':
    933                         APPEND("%02d", sun_week_number(tm));
    934                         break;
     800                        append("%02d", _sun_week_number(tm)); break;
    935801                case 'V':
    936                         APPEND("%02d", iso_week_number(tm));
    937                         break;
     802                        append("%02d", _iso_week_number(tm)); break;
    938803                case 'w':
    939                         APPEND("%d", tm->tm_wday);
    940                         break;
     804                        append("%d", tm->tm_wday); break;
    941805                case 'W':
    942                         APPEND("%02d", mon_week_number(tm));
    943                         break;
     806                        append("%02d", _mon_week_number(tm)); break;
    944807                case 'x':
    945808                        // TODO: locale-specific date format
    946                         RECURSE("%Y-%m-%d");
    947                         break;
     809                        recurse("%Y-%m-%d"); break;
    948810                case 'X':
    949811                        // TODO: locale-specific time format
    950                         RECURSE("%H:%M:%S");
    951                         break;
     812                        recurse("%H:%M:%S"); break;
    952813                case 'y':
    953                         APPEND("%02d", tm->tm_year % 100);
    954                         break;
     814                        append("%02d", tm->tm_year % 100); break;
    955815                case 'Y':
    956                         APPEND("%d", 1900 + tm->tm_year);
    957                         break;
     816                        append("%d", 1900 + tm->tm_year); break;
    958817                case 'z':
    959818                        // TODO: timezone
     
    963822                        break;
    964823                case '%':
    965                         APPEND("%%");
     824                        append("%%");
    966825                        break;
    967826                default:
    968827                        /* Invalid specifier, print verbatim. */
    969                         while (*format != '%')
     828                        while (*format != '%') {
    970829                                format--;
    971                        
    972                         APPEND("%%");
     830                        }
     831                        append("%%");
    973832                        break;
    974833                }
    975                
    976834                format++;
    977835        }
    978836       
     837        #undef append
     838        #undef recurse
     839       
    979840        return maxsize - remaining;
    980841}
    981842
    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  *
     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
    989850 */
    990851int time_utc2tm(const time_t time, struct tm *restrict result)
    991852{
    992853        assert(result != NULL);
    993        
     854
    994855        /* Set result to epoch. */
    995         result->tm_usec = 0;
    996856        result->tm_sec = 0;
    997857        result->tm_min = 0;
     
    1000860        result->tm_mon = 0;
    1001861        result->tm_year = 70; /* 1970 */
    1002        
    1003         if (normalize_tm_time(result, time) == -1)
     862
     863        if (_normalize_time(result, time) == -1)
    1004864                return EOVERFLOW;
    1005        
     865
    1006866        return EOK;
    1007867}
    1008868
    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  *
     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.
    1019877 */
    1020878int time_utc2str(const time_t time, char *restrict buf)
    1021879{
    1022         struct tm tm;
    1023         int ret = time_utc2tm(time, &tm);
    1024         if (ret != EOK)
    1025                 return ret;
    1026        
    1027         time_tm2str(&tm, buf);
     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);
    1028887        return EOK;
    1029888}
    1030889
    1031 /** Convert broken-down time to a NULL-terminated string.
    1032  *
    1033  * The format is "Sun Jan 1 00:00:00 1970\n". (Obsolete)
     890
     891/**
     892 * Converts broken-down time to a string in format
     893 * "Sun Jan 1 00:00:00 1970\n". (Obsolete)
    1034894 *
    1035895 * @param timeptr Broken-down time structure.
    1036  * @param buf     Buffer to store string to, must be at least
    1037  *                ASCTIME_BUF_LEN bytes long.
    1038  *
     896 * @param buf     Buffer to store string to, must be at least ASCTIME_BUF_LEN
     897 *                bytes long.
    1039898 */
    1040899void time_tm2str(const struct tm *restrict timeptr, char *restrict buf)
     
    1042901        assert(timeptr != NULL);
    1043902        assert(buf != NULL);
    1044        
     903
    1045904        static const char *wday[] = {
    1046905                "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
    1047906        };
    1048        
    1049907        static const char *mon[] = {
    1050908                "Jan", "Feb", "Mar", "Apr", "May", "Jun",
    1051909                "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
    1052910        };
    1053        
     911
    1054912        snprintf(buf, ASCTIME_BUF_LEN, "%s %s %2d %02d:%02d:%02d %d\n",
    1055913            wday[timeptr->tm_wday],
     
    1060918}
    1061919
    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  */
    1072 int 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        
     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 */
     929int 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
    1077934        /* Set result to epoch. */
    1078         result->tm_usec = 0;
    1079935        result->tm_sec = 0;
    1080936        result->tm_min = 0;
     
    1083939        result->tm_mon = 0;
    1084940        result->tm_year = 70; /* 1970 */
    1085        
    1086         if (normalize_tm_tv(result, tv) == -1)
     941
     942        if (_normalize_time(result, time) == -1)
    1087943                return EOVERFLOW;
    1088        
     944
    1089945        return EOK;
    1090946}
    1091947
    1092 /** Converts a time value to a broken-down local time.
    1093  *
    1094  * Time is expressed relative to the user's specified timezone.
    1095  *
     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
     951 * user's specified timezone.
     952 *
    1096953 * @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  */
    1102 int 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
    1115  * user's specified timezone.
    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  *
     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.
    1123958 */
    1124959int time_local2str(const time_t time, char *buf)
    1125960{
    1126961        struct tm loctime;
    1127         int ret = time_local2tm(time, &loctime);
    1128         if (ret != EOK)
    1129                 return ret;
    1130        
     962        int r;
     963
     964        if ((r = time_local2tm(time, &loctime)) != EOK)
     965                return r;
     966
    1131967        time_tm2str(&loctime, buf);
     968
    1132969        return EOK;
    1133970}
    1134971
    1135 /** Calculate the difference between two times, in seconds.
    1136  *
     972/**
     973 * Calculate the difference between two times, in seconds.
     974 *
    1137975 * @param time1 First time.
    1138976 * @param time0 Second time.
    1139  *
    1140  * @return Time difference in seconds.
    1141  *
     977 * @return Time in seconds.
    1142978 */
    1143979double difftime(time_t time1, time_t time0)
Note: See TracChangeset for help on using the changeset viewer.