Fork us on GitHub Follow us on Facebook Follow us on Twitter

Changeset f7ea5400 in mainline


Ignore:
Timestamp:
2012-08-15T17:52:09Z (9 years ago)
Author:
Maurizio Lombardi <m.lombardi85@…>
Branches:
lfn, master
Children:
16639bb
Parents:
9dec6d4
Message:

Replace the gmtime(), asctime() localtime() and ctime() with a new set of reentrant functions.
The former will be kept in the posix library for compatibility reasons.

Location:
uspace
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • uspace/drv/time/cmos-rtc/cmos-rtc.c

    r9dec6d4 rf7ea5400  
    301301
    302302                time_t cur_time = boottime + uptime_get();
    303                 *t = *gmtime(&cur_time);
    304                 return EOK;
     303                return localtime2tm(cur_time, t);
    305304        }
    306305
  • uspace/lib/c/generic/time.c

    r9dec6d4 rf7ea5400  
    841841}
    842842
    843 struct tm *gmtime(const time_t *timer)
    844 {
    845         assert(timer != NULL);
    846 
    847         static struct tm result;
     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
     850 */
     851int utctime2tm(const time_t time, struct tm *restrict result)
     852{
     853        assert(result != NULL);
    848854
    849855        /* Set result to epoch. */
    850         result.tm_sec = 0;
    851         result.tm_min = 0;
    852         result.tm_hour = 0;
    853         result.tm_mday = 1;
    854         result.tm_mon = 0;
    855         result.tm_year = 70; /* 1970 */
    856 
    857         if (_normalize_time(&result, *timer) == -1) {
    858                 errno = EOVERFLOW;
    859                 return NULL;
    860         }
    861 
    862         return &result;
    863 }
     856        result->tm_sec = 0;
     857        result->tm_min = 0;
     858        result->tm_hour = 0;
     859        result->tm_mday = 1;
     860        result->tm_mon = 0;
     861        result->tm_year = 70; /* 1970 */
     862
     863        if (_normalize_time(result, time) == -1)
     864                return EOVERFLOW;
     865
     866        return EOK;
     867}
     868
     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.
     877 */
     878int utctime2str(const time_t time, char *restrict buf)
     879{
     880        struct tm t;
     881        int r;
     882
     883        if ((r = utctime2tm(time, &t)) != EOK)
     884                return r;
     885
     886        tm2str(&t, buf);
     887        return EOK;
     888}
     889
    864890
    865891/**
     
    868894 *
    869895 * @param timeptr Broken-down time structure.
    870  * @return Pointer to a statically allocated string.
    871  */
    872 char *asctime(const struct tm *timeptr)
    873 {
    874         static char buf[ASCTIME_BUF_LEN];
    875 
     896 * @param buf     Buffer to store string to, must be at least ASCTIME_BUF_LEN
     897 *                bytes long.
     898 */
     899void tm2str(const struct tm *restrict timeptr, char *restrict buf)
     900{
    876901        assert(timeptr != NULL);
     902        assert(buf != NULL);
    877903
    878904        static const char *wday[] = {
     
    890916            timeptr->tm_min, timeptr->tm_sec,
    891917            1900 + timeptr->tm_year);
    892 
    893         return buf;
    894 
    895 }
    896 
    897 /**
    898  * Converts a time value to a broken-down local time.
    899  *
    900  * @param timer Time to convert.
    901  * @return Normalized broken-down time in local timezone, NULL on overflow.
    902  */
    903 struct tm *localtime(const time_t *timer)
     918}
     919
     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 localtime2tm(const time_t time, struct tm *restrict result)
    904930{
    905931        // TODO: deal with timezone
    906932        // currently assumes system and all times are in GMT
    907933
    908         static struct tm result;
    909 
    910934        /* Set result to epoch. */
    911         result.tm_sec = 0;
    912         result.tm_min = 0;
    913         result.tm_hour = 0;
    914         result.tm_mday = 1;
    915         result.tm_mon = 0;
    916         result.tm_year = 70; /* 1970 */
    917 
    918         if (_normalize_time(&result, *timer) == -1) {
    919                 errno = EOVERFLOW;
    920                 return NULL;
    921         }
    922 
    923         return &result;
    924 }
    925 
    926 /**
    927  * Equivalent to asctime(localtime(clock)).
     935        result->tm_sec = 0;
     936        result->tm_min = 0;
     937        result->tm_hour = 0;
     938        result->tm_mday = 1;
     939        result->tm_mon = 0;
     940        result->tm_year = 70; /* 1970 */
     941
     942        if (_normalize_time(result, time) == -1)
     943                return EOVERFLOW;
     944
     945        return EOK;
     946}
     947
     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.
    928952 *
    929  * @param timer Time to convert.
    930  * @return Pointer to a statically allocated string holding the date.
    931  */
    932 char *ctime(const time_t *timer)
    933 {
    934         struct tm *loctime = localtime(timer);
    935         if (loctime == NULL) {
    936                 return NULL;
    937         }
    938         return asctime(loctime);
     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.
     958 */
     959int localtime2str(const time_t time, char *buf)
     960{
     961        struct tm loctime;
     962        int r;
     963
     964        if ((r = localtime2tm(time, &loctime)) != EOK)
     965                return r;
     966
     967        tm2str(&loctime, buf);
     968
     969        return EOK;
    939970}
    940971
  • uspace/lib/c/include/sys/time.h

    r9dec6d4 rf7ea5400  
    8181
    8282extern time_t mktime(struct tm *tm);
    83 extern struct tm *gmtime(const time_t *timer);
    84 extern char *asctime(const struct tm *timeptr);
    85 extern struct tm *localtime(const time_t *timer);
    86 extern char *ctime(const time_t *timer);
     83extern int utctime2tm(const time_t time, struct tm *result);
     84extern int utctime2str(const time_t time, char *buf);
     85extern void tm2str(const struct tm *timeptr, char *buf);
     86extern int localtime2tm(const time_t time, struct tm *result);
     87extern int localtime2str(const time_t time, char *buf);
    8788extern double difftime(time_t time1, time_t time0);
    8889extern size_t strftime(char *restrict s, size_t maxsize,
  • uspace/lib/posix/time.c

    r9dec6d4 rf7ea5400  
    6161 */
    6262
    63 
    64 
    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.
    76  *
    77  * @param year Year since 1900 (e.g. for 1970, the value is 70).
    78  * @return true if year is a leap year, false otherwise
    79  */
    80 static bool _is_leap_year(time_t year)
    81 {
    82         year += 1900;
    83 
    84         if (year % 400 == 0)
    85                 return true;
    86         if (year % 100 == 0)
    87                 return false;
    88         if (year % 4 == 0)
    89                 return true;
    90         return false;
    91 }
    92 
    93 /**
    94  * Returns how many days there are in the given month of the given year.
    95  * Note that year is only taken into account if month is February.
    96  *
    97  * @param year Year since 1900 (can be negative).
    98  * @param mon Month of the year. 0 for January, 11 for December.
    99  * @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 
    108         if (mon == 1) {
    109                 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
    119  * it is.
    120  *
    121  * For example, given date 2011-01-03, the corresponding expression is:
    122  *     _day_of_year(111, 0, 3) == 2
    123  *
    124  * @param year Year (year 1900 = 0, can be negative).
    125  * @param mon Month (January = 0).
    126  * @param mday Day of month (First day is 1).
    127  * @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.
    142  *
    143  * @param op1 Dividend.
    144  * @param op2 Divisor.
    145  * @return Rounded quotient.
    146  */
    147 static time_t _floor_div(time_t op1, time_t op2)
    148 {
    149         if (op1 >= 0 || op1 % op2 == 0) {
    150                 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.
    159  *
    160  * @param op1 Dividend.
    161  * @param op2 Divisor.
    162  * @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. */
    174         assert(result >= 0);
    175         assert(result < op2);
    176         assert(div * op2 + result == op1);
    177        
    178         return result;
    179 }
    180 
    181 /**
    182  * Number of days since the Epoch.
    183  * Epoch is 1970-01-01, which is also equal to day 0.
    184  *
    185  * @param year Year (year 1900 = 0, may be negative).
    186  * @param mon Month (January = 0).
    187  * @param mday Day of month (first day = 1).
    188  * @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  * Which day of week the specified date is.
    199  *
    200  * @param year Year (year 1900 = 0).
    201  * @param mon Month (January = 0).
    202  * @param mday Day of month (first = 1).
    203  * @return Day of week (Sunday = 0).
    204  */
    205 static int _day_of_week(time_t year, time_t mon, time_t mday)
    206 {
    207         /* 1970-01-01 is Thursday */
    208         return _floor_mod((_days_since_epoch(year, mon, mday) + 4), 7);
    209 }
    210 
    211 /**
    212  * Normalizes the broken-down time and optionally adds specified amount of
    213  * seconds.
    214  *
    215  * @param tm Broken-down time to normalize.
    216  * @param sec_add Seconds to add.
    217  * @return 0 on success, -1 on overflow
    218  */
    219 static int _normalize_time(struct tm *tm, time_t sec_add)
    220 {
    221         // TODO: DST correction
    222 
    223         /* Set initial values. */
    224         time_t sec = tm->tm_sec + sec_add;
    225         time_t min = tm->tm_min;
    226         time_t hour = tm->tm_hour;
    227         time_t day = tm->tm_mday - 1;
    228         time_t mon = tm->tm_mon;
    229         time_t year = tm->tm_year;
    230 
    231         /* Adjust time. */
    232         min += _floor_div(sec, SECS_PER_MIN);
    233         sec = _floor_mod(sec, SECS_PER_MIN);
    234         hour += _floor_div(min, MINS_PER_HOUR);
    235         min = _floor_mod(min, MINS_PER_HOUR);
    236         day += _floor_div(hour, HOURS_PER_DAY);
    237         hour = _floor_mod(hour, HOURS_PER_DAY);
    238 
    239         /* Adjust month. */
    240         year += _floor_div(mon, 12);
    241         mon = _floor_mod(mon, 12);
    242 
    243         /* Now the difficult part - days of month. */
    244        
    245         /* First, deal with whole cycles of 400 years = 146097 days. */
    246         year += _floor_div(day, 146097) * 400;
    247         day = _floor_mod(day, 146097);
    248        
    249         /* Then, go in one year steps. */
    250         if (mon <= 1) {
    251                 /* January and February. */
    252                 while (day > 365) {
    253                         day -= _is_leap_year(year) ? 366 : 365;
    254                         year++;
    255                 }
    256         } else {
    257                 /* Rest of the year. */
    258                 while (day > 365) {
    259                         day -= _is_leap_year(year + 1) ? 366 : 365;
    260                         year++;
    261                 }
    262         }
    263        
    264         /* Finally, finish it off month per month. */
    265         while (day >= _days_in_month(year, mon)) {
    266                 day -= _days_in_month(year, mon);
    267                 mon++;
    268                 if (mon >= 12) {
    269                         mon -= 12;
    270                         year++;
    271                 }
    272         }
    273        
    274         /* Calculate the remaining two fields. */
    275         tm->tm_yday = _day_of_year(year, mon, day + 1);
    276         tm->tm_wday = _day_of_week(year, mon, day + 1);
    277        
    278         /* And put the values back to the struct. */
    279         tm->tm_sec = (int) sec;
    280         tm->tm_min = (int) min;
    281         tm->tm_hour = (int) hour;
    282         tm->tm_mday = (int) day + 1;
    283         tm->tm_mon = (int) mon;
    284        
    285         /* Casts to work around libc brain-damage. */
    286         if (year > ((int)INT_MAX) || year < ((int)INT_MIN)) {
    287                 tm->tm_year = (year < 0) ? ((int)INT_MIN) : ((int)INT_MAX);
    288                 return -1;
    289         }
    290        
    291         tm->tm_year = (int) year;
    292         return 0;
    293 }
    294 
    295 /******************************************************************************/
    296 
    29763int posix_daylight;
    29864long posix_timezone;
     
    32187    struct tm *restrict result)
    32288{
    323         assert(timer != NULL);
    324         assert(result != NULL);
    325 
    326         /* Set result to epoch. */
    327         result->tm_sec = 0;
    328         result->tm_min = 0;
    329         result->tm_hour = 0;
    330         result->tm_mday = 1;
    331         result->tm_mon = 0;
    332         result->tm_year = 70; /* 1970 */
    333 
    334         if (_normalize_time(result, *timer) == -1) {
    335                 errno = EOVERFLOW;
     89        int rc = utctime2tm(*timer, result);
     90        if (rc != EOK) {
     91                errno = rc;
    33692                return NULL;
    33793        }
    33894
    33995        return result;
     96}
     97
     98/**
     99 * Converts a time value to a broken-down UTC time.
     100 * (non reentrant version)
     101 *
     102 * @param timep  Time to convert
     103 * @return       Pointer to a statically allocated structure that stores
     104 *               the result, NULL in case of error.
     105 */
     106struct tm *posix_gmtime(const time_t *restrict timep)
     107{
     108        static struct tm result;
     109
     110        return posix_gmtime_r(timep, &result);
    340111}
    341112
     
    353124        // currently assumes system and all times are in GMT
    354125        return posix_gmtime_r(timer, result);
     126}
     127
     128/**
     129 * Converts a time value to a broken-down local time.
     130 * (non reentrant version)
     131 *
     132 * @param timep    Time to convert.
     133 * @return         Pointer to a statically allocated structure that stores
     134 *                 the result, NULL in case of error.
     135 */
     136struct tm *posix_localtime(const time_t *restrict timep)
     137{
     138        static struct tm result;
     139
     140        return posix_localtime_r(timep, &result);
    355141}
    356142
     
    367153    char *restrict buf)
    368154{
    369         assert(timeptr != NULL);
    370         assert(buf != NULL);
    371 
    372         static const char *wday[] = {
    373                 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
    374         };
    375         static const char *mon[] = {
    376                 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
    377                 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
    378         };
    379 
    380         snprintf(buf, ASCTIME_BUF_LEN, "%s %s %2d %02d:%02d:%02d %d\n",
    381             wday[timeptr->tm_wday],
    382             mon[timeptr->tm_mon],
    383             timeptr->tm_mday, timeptr->tm_hour,
    384             timeptr->tm_min, timeptr->tm_sec,
    385             1900 + timeptr->tm_year);
    386 
     155        tm2str(timeptr, buf);
    387156        return buf;
    388157}
    389158
    390159/**
    391  * Reentrant variant of ctime().
     160 * Convers broken-down time to a string in format
     161 * "Sun Jan 1 00:00:00 1970\n". (Obsolete)
     162 * (non reentrant version)
     163 *
     164 * @param timeptr    Broken-down time structure.
     165 * @return           Pointer to a statically allocated buffer that stores
     166 *                   the result, NULL in case of error.
     167 */
     168char *posix_asctime(const struct tm *restrict timeptr)
     169{
     170        static char buf[ASCTIME_BUF_LEN];
     171
     172        return posix_asctime_r(timeptr, buf);
     173}
     174
     175/**
     176 * Converts the calendar time to a string in format
     177 * "Sun Jan 1 00:00:00 1970\n" (Obsolete)
    392178 *
    393179 * @param timer Time to convert.
    394180 * @param buf Buffer to store string to. Must be at least ASCTIME_BUF_LEN
    395181 *     bytes long.
    396  * @return Pointer to buf on success, NULL on falure.
     182 * @return Pointer to buf on success, NULL on failure.
    397183 */
    398184char *posix_ctime_r(const time_t *timer, char *buf)
    399185{
    400         struct tm loctime;
    401         if (posix_localtime_r(timer, &loctime) == NULL) {
     186        int r = localtime2str(*timer, buf);
     187        if (r != EOK) {
     188                errno = r;
    402189                return NULL;
    403190        }
    404         return posix_asctime_r(&loctime, buf);
     191
     192        return buf;
     193}
     194
     195/**
     196 * Converts the calendar time to a string in format
     197 * "Sun Jan 1 00:00:00 1970\n" (Obsolete)
     198 * (non reentrant version)
     199 *
     200 * @param timep    Time to convert.
     201 * @return         Pointer to a statically allocated buffer that stores
     202 *                 the result, NULL in case of error.
     203 */
     204char *posix_ctime(const time_t *timep)
     205{
     206        static char buf[ASCTIME_BUF_LEN];
     207
     208        return posix_ctime_r(timep, buf);
    405209}
    406210
  • uspace/lib/posix/time.h

    r9dec6d4 rf7ea5400  
    8787extern struct tm *posix_gmtime_r(const time_t *restrict timer,
    8888    struct tm *restrict result);
     89extern struct tm *posix_gmtime(const time_t *restrict timep);
    8990extern struct tm *posix_localtime_r(const time_t *restrict timer,
    9091    struct tm *restrict result);
     92extern struct tm *posix_localtime(const time_t *restrict timep);
    9193
    9294/* Formatting Calendar Time */
    9395extern char *posix_asctime_r(const struct tm *restrict timeptr,
    9496    char *restrict buf);
     97extern char *posix_asctime(const struct tm *restrict timeptr);
    9598extern char *posix_ctime_r(const time_t *timer, char *buf);
     99extern char *posix_ctime(const time_t *timer);
    96100
    97101/* Clocks */
     
    109113
    110114#ifndef LIBPOSIX_INTERNAL
    111         #define timespec posix_timespec
    112         #define itimerspec posix_itimerspec
    113         #define timer_t posix_timer_t
     115        #define timespec    posix_timespec
     116        #define itimerspec  posix_itimerspec
     117        #define timer_t     posix_timer_t
    114118
    115         #define daylight posix_daylight
    116         #define timezone posix_timezone
    117         #define tzname posix_tzname
    118         #define tzset posix_tzset
     119        #define daylight    posix_daylight
     120        #define timezone    posix_timezone
     121        #define tzname      posix_tzname
     122        #define tzset       posix_tzset
    119123
    120         #define gmtime_r posix_gmtime_r
     124        #define gmtime_r    posix_gmtime_r
     125        #define gmtime      posix_gmtime
    121126        #define localtime_r posix_localtime_r
     127        #define localtime   posix_localtime
    122128
    123         #define asctime_r posix_asctime_r
    124         #define ctime_r posix_ctime_r
     129        #define asctime_r   posix_asctime_r
     130        #define asctime     posix_asctime
     131        #define ctime_r     posix_ctime_r
     132        #define ctime       posix_ctime
    125133
    126134        #define clock_getres posix_clock_getres
Note: See TracChangeset for help on using the changeset viewer.