diff options
| author | Kacper <kacper@mail.openlinux.dev> | 2025-12-07 20:10:31 +0100 |
|---|---|---|
| committer | Kacper <kacper@mail.openlinux.dev> | 2025-12-07 20:10:31 +0100 |
| commit | fc00c656c96528112d05cf0edf8631bd5eaea446 (patch) | |
| tree | a6e0e6c588191a8bd1c64afc3b7a258e3e66c236 /lib/libc/time | |
Add build system scaffolding and libc headers
Diffstat (limited to 'lib/libc/time')
| -rw-r--r-- | lib/libc/time/asctime.c | 19 | ||||
| -rw-r--r-- | lib/libc/time/clock.c | 16 | ||||
| -rw-r--r-- | lib/libc/time/clock_getcpuclockid.c | 18 | ||||
| -rw-r--r-- | lib/libc/time/clock_getres.c | 7 | ||||
| -rw-r--r-- | lib/libc/time/clock_nanosleep.c | 8 | ||||
| -rw-r--r-- | lib/libc/time/ctime.c | 6 | ||||
| -rw-r--r-- | lib/libc/time/difftime.c | 6 | ||||
| -rw-r--r-- | lib/libc/time/gmtime_r.c | 42 | ||||
| -rw-r--r-- | lib/libc/time/localtime.c | 7 | ||||
| -rw-r--r-- | lib/libc/time/localtime_r.c | 7 | ||||
| -rw-r--r-- | lib/libc/time/nanosleep.c | 7 | ||||
| -rw-r--r-- | lib/libc/time/strftime.c | 562 | ||||
| -rw-r--r-- | lib/libc/time/time.c | 20 | ||||
| -rw-r--r-- | lib/libc/time/tzset.c | 58 | ||||
| -rw-r--r-- | lib/libc/time/utimes.c | 25 |
15 files changed, 808 insertions, 0 deletions
diff --git a/lib/libc/time/asctime.c b/lib/libc/time/asctime.c new file mode 100644 index 00000000..54729a77 --- /dev/null +++ b/lib/libc/time/asctime.c @@ -0,0 +1,19 @@ +#include <time.h> +#include <stdio.h> + +char *asctime(const struct tm *timeptr) +{ + static char wday_name[7][3] = { "Sun", "Mon", "Tue", "Wed", + "Thu", "Fri", "Sat" }; + static char mon_name[12][3] = { "Jan", "Feb", "Mar", "Apr", + "May", "Jun", "Jul", "Aug", + "Sep", "Oct", "Nov", "Dec" }; + static char result[26]; + + snprintf(result, sizeof(result), "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n", + wday_name[timeptr->tm_wday], mon_name[timeptr->tm_mon], + timeptr->tm_mday, timeptr->tm_hour, timeptr->tm_min, + timeptr->tm_sec, 1900 + timeptr->tm_year); + + return result; +} diff --git a/lib/libc/time/clock.c b/lib/libc/time/clock.c new file mode 100644 index 00000000..ec2e6084 --- /dev/null +++ b/lib/libc/time/clock.c @@ -0,0 +1,16 @@ +#include <time.h> +#include <limits.h> + +clock_t clock(void) +{ + struct timespec ts; + + if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts)) + return -1; + + if (ts.tv_sec > LONG_MAX / 1000000 || + ts.tv_nsec / 1000 > LONG_MAX - 1000000 * ts.tv_sec) + return -1; + + return ts.tv_sec * 1000000 + ts.tv_nsec / 1000; +} diff --git a/lib/libc/time/clock_getcpuclockid.c b/lib/libc/time/clock_getcpuclockid.c new file mode 100644 index 00000000..5bb53221 --- /dev/null +++ b/lib/libc/time/clock_getcpuclockid.c @@ -0,0 +1,18 @@ +#include <time.h> +#include <syscall.h> + +int clock_getcpuclockid(pid_t pid, clockid_t *clock_id) +{ + int ret; + clockid_t id; + struct timespec ts; + + id = (-pid - 1) * 8U + 2; + ret = syscall(clock_getres, id, &ts); + + if (ret >= 0) { + *clock_id = id; + } + + return ret; +} diff --git a/lib/libc/time/clock_getres.c b/lib/libc/time/clock_getres.c new file mode 100644 index 00000000..5af37e8d --- /dev/null +++ b/lib/libc/time/clock_getres.c @@ -0,0 +1,7 @@ +#include <time.h> +#include <syscall.h> + +int clock_getres(clockid_t clock_id, struct timespec *res) +{ + return syscall(clock_getres, clock_id, res); +} diff --git a/lib/libc/time/clock_nanosleep.c b/lib/libc/time/clock_nanosleep.c new file mode 100644 index 00000000..63190d06 --- /dev/null +++ b/lib/libc/time/clock_nanosleep.c @@ -0,0 +1,8 @@ +#include <time.h> +#include <syscall.h> + +int clock_nanosleep(clockid_t clock_id, int flags, const struct timespec *rqtp, + struct timespec *rmtp) +{ + return __syscall(nanosleep, clock_id, flags, rqtp, rmtp) * -1; +} diff --git a/lib/libc/time/ctime.c b/lib/libc/time/ctime.c new file mode 100644 index 00000000..bddd30cf --- /dev/null +++ b/lib/libc/time/ctime.c @@ -0,0 +1,6 @@ +#include <time.h> + +char *ctime(const time_t *clock) +{ + return asctime(localtime(clock)); +} diff --git a/lib/libc/time/difftime.c b/lib/libc/time/difftime.c new file mode 100644 index 00000000..e7b567c1 --- /dev/null +++ b/lib/libc/time/difftime.c @@ -0,0 +1,6 @@ +#include <time.h> + +double difftime(time_t time1, time_t time0) +{ + return time1 - time0; +} diff --git a/lib/libc/time/gmtime_r.c b/lib/libc/time/gmtime_r.c new file mode 100644 index 00000000..8d441549 --- /dev/null +++ b/lib/libc/time/gmtime_r.c @@ -0,0 +1,42 @@ +#include <time.h> + +struct tm *gmtime_r(const time_t *timer, struct tm *result) +{ + time_t t = *timer; + int days, rem; + int year, month; + + rem = t % 86400; + days = t / 86400; + if (rem < 0) { + rem += 86400; + days--; + } + + result->tm_hour = rem / 3600; + rem %= 3600; + result->tm_min = rem / 60; + result->tm_sec = rem % 60; + result->tm_isdst = 0; + + result->tm_wday = (4 + days) % 7; + if (result->tm_wday < 0) + result->tm_wday += 7; + + long z = days + 719468; + long era = (z >= 0 ? z : z - 146096) / 146097; + long day_of_era = z - era * 146097; + long yoe = (day_of_era - day_of_era / 1460 + day_of_era / 36524 - + day_of_era / 146096) / + 365; + year = (int)(yoe + era * 400); + long doy = day_of_era - (365 * yoe + yoe / 4 - yoe / 100); + result->tm_yday = (int)doy; + + int mp = (5 * doy + 2) / 153; + result->tm_mday = (int)(doy - (153 * mp + 2) / 5 + 1); + result->tm_mon = (mp + 2) % 12; + result->tm_year = year - 1900 + (mp / 10); + + return result; +} diff --git a/lib/libc/time/localtime.c b/lib/libc/time/localtime.c new file mode 100644 index 00000000..44029920 --- /dev/null +++ b/lib/libc/time/localtime.c @@ -0,0 +1,7 @@ +#include <time.h> + +struct tm *localtime(const time_t *timer) +{ + static struct tm result; + return localtime_r(timer, &result); +} diff --git a/lib/libc/time/localtime_r.c b/lib/libc/time/localtime_r.c new file mode 100644 index 00000000..1fb620a4 --- /dev/null +++ b/lib/libc/time/localtime_r.c @@ -0,0 +1,7 @@ +#include <time.h> + +struct tm *localtime_r(const time_t *restrict timer, struct tm *restrict result) +{ + time_t local = *timer - timezone; + return gmtime_r(&local, result); +} diff --git a/lib/libc/time/nanosleep.c b/lib/libc/time/nanosleep.c new file mode 100644 index 00000000..f5c5f7c9 --- /dev/null +++ b/lib/libc/time/nanosleep.c @@ -0,0 +1,7 @@ +#include <time.h> +#include <syscall.h> + +int nanosleep(const struct timespec *rqtp, struct timespec *rmtp) +{ + return syscall(nanosleep, rqtp, rmtp); +} diff --git a/lib/libc/time/strftime.c b/lib/libc/time/strftime.c new file mode 100644 index 00000000..d359140b --- /dev/null +++ b/lib/libc/time/strftime.c @@ -0,0 +1,562 @@ +#include <time.h> +#include <libc.h> +#include <string.h> + +static size_t append_string(char *restrict *s, size_t *remaining, + const char *str) +{ + size_t len = strlen(str); + if (len >= *remaining) { + return 0; + } + strcpy(*s, str); + *s += len; + *remaining -= len; + return len; +} + +static size_t append_char(char *restrict *s, size_t *remaining, char c) +{ + if (*remaining <= 1) { + return 0; + } + **s = c; + (*s)++; + (*remaining)--; + return 1; +} + +static size_t format_int(char *restrict *s, size_t *remaining, int value, + int width, char pad, int show_sign) +{ + char buffer[32]; + char *ptr = buffer + sizeof(buffer) - 1; + *ptr = '\0'; + + int negative = 0; + if (value < 0) { + negative = 1; + value = -value; + } + + do { + *--ptr = '0' + (value % 10); + value /= 10; + } while (value > 0); + + if (negative) { + *--ptr = '-'; + } else if (show_sign && value >= 0) { + *--ptr = '+'; + } + + int len = (buffer + sizeof(buffer) - 1) - ptr; + + while (len < width) { + *--ptr = pad; + len++; + } + + return append_string(s, remaining, ptr); +} + +static const char *weekday_abbr[] = { "Sun", "Mon", "Tue", "Wed", + "Thu", "Fri", "Sat" }; +static const char *weekday_full[] = { "Sunday", "Monday", "Tuesday", + "Wednesday", "Thursday", "Friday", + "Saturday" }; + +static const char *month_abbr[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; +static const char *month_full[] = { "January", "February", "March", + "April", "May", "June", + "July", "August", "September", + "October", "November", "December" }; + +static int day_of_year(const struct tm *tm) +{ + static const int days_to_month[] = { 0, 31, 59, 90, 120, 151, + 181, 212, 243, 273, 304, 334 }; + int days = days_to_month[tm->tm_mon] + tm->tm_mday; + + if (tm->tm_mon > 1) { + int year = tm->tm_year + 1900; + if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) { + days++; + } + } + return days; +} + +static int iso_week_number(const struct tm *tm, int *week_year) +{ + int year = tm->tm_year + 1900; + int yday = tm->tm_yday + 1; + int wday; + + int jan4_wday = (4 + year + (year - 1) / 4 - (year - 1) / 100 + + (year - 1) / 400) % + 7; + if (jan4_wday == 0) + jan4_wday = 7; + + int week1_start = 4 - jan4_wday + 1; + + int week = (yday - week1_start + 7) / 7; + + if (week < 1) { + *week_year = year - 1; + + int prev_jan4_wday = (jan4_wday - 1 + 7) % 7; + if (prev_jan4_wday == 0) + prev_jan4_wday = 7; + int prev_week1_start = 4 - prev_jan4_wday + 1; + int prev_year_days = 365; + if (((year - 1) % 4 == 0 && (year - 1) % 100 != 0) || + ((year - 1) % 400 == 0)) { + prev_year_days = 366; + } + week = (prev_year_days - prev_week1_start + 8) / 7; + } else { + *week_year = year; + + int year_days = 365; + if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) { + year_days = 366; + } + if (week1_start + (week - 1) * 7 > year_days - 3) { + if (yday > year_days - (7 - jan4_wday)) { + *week_year = year + 1; + week = 1; + } + } + } + + return week; +} + +size_t strftime(char *restrict s, size_t maxsize, const char *restrict format, + const struct tm *restrict timeptr) +{ + if (maxsize == 0) + return 0; + + char *orig_s = s; + size_t remaining = maxsize - 1; + const char *ptr = format; + + while (*ptr && remaining > 0) { + if (*ptr != '%') { + if (!append_char(&s, &remaining, *ptr)) { + *orig_s = '\0'; + return 0; + } + ptr++; + continue; + } + + ptr++; + if (!*ptr) + break; + + char pad_char = ' '; + int show_sign = 0; + int min_width = 0; + + if (*ptr == '0') { + pad_char = '0'; + ptr++; + } else if (*ptr == '+') { + pad_char = '0'; + show_sign = 1; + ptr++; + } + + while (*ptr >= '0' && *ptr <= '9') { + min_width = min_width * 10 + (*ptr - '0'); + ptr++; + } + + if (*ptr == 'E' || *ptr == 'O') { + ptr++; + } + + switch (*ptr) { + case 'a': + if (!append_string(&s, &remaining, + weekday_abbr[timeptr->tm_wday])) { + *orig_s = '\0'; + return 0; + } + break; + case 'A': + if (!append_string(&s, &remaining, + weekday_full[timeptr->tm_wday])) { + *orig_s = '\0'; + return 0; + } + break; + case 'b': + case 'h': + if (!append_string(&s, &remaining, + month_abbr[timeptr->tm_mon])) { + *orig_s = '\0'; + return 0; + } + break; + case 'B': + if (!append_string(&s, &remaining, + month_full[timeptr->tm_mon])) { + *orig_s = '\0'; + return 0; + } + break; + case 'c': + if (!append_string(&s, &remaining, + weekday_abbr[timeptr->tm_wday]) || + !append_char(&s, &remaining, ' ') || + !append_string(&s, &remaining, + month_abbr[timeptr->tm_mon]) || + !append_char(&s, &remaining, ' ') || + !format_int(&s, &remaining, timeptr->tm_mday, 2, + ' ', 0) || + !append_char(&s, &remaining, ' ') || + !format_int(&s, &remaining, timeptr->tm_hour, 2, + '0', 0) || + !append_char(&s, &remaining, ':') || + !format_int(&s, &remaining, timeptr->tm_min, 2, '0', + 0) || + !append_char(&s, &remaining, ':') || + !format_int(&s, &remaining, timeptr->tm_sec, 2, '0', + 0) || + !append_char(&s, &remaining, ' ') || + !format_int(&s, &remaining, timeptr->tm_year + 1900, + 4, '0', 0)) { + *orig_s = '\0'; + return 0; + } + break; + case 'C': + if (!format_int(&s, &remaining, + (timeptr->tm_year + 1900) / 100, + min_width ? min_width : 2, pad_char, + show_sign)) { + *orig_s = '\0'; + return 0; + } + break; + case 'd': + if (!format_int(&s, &remaining, timeptr->tm_mday, 2, + '0', 0)) { + *orig_s = '\0'; + return 0; + } + break; + case 'D': + if (!format_int(&s, &remaining, timeptr->tm_mon + 1, 2, + '0', 0) || + !append_char(&s, &remaining, '/') || + !format_int(&s, &remaining, timeptr->tm_mday, 2, + '0', 0) || + !append_char(&s, &remaining, '/') || + !format_int(&s, &remaining, timeptr->tm_year % 100, + 2, '0', 0)) { + *orig_s = '\0'; + return 0; + } + break; + case 'e': + if (!format_int(&s, &remaining, timeptr->tm_mday, 2, + ' ', 0)) { + *orig_s = '\0'; + return 0; + } + break; + case 'F': { + int width = min_width ? min_width - 6 : 4; + if (width < 4) + width = 4; + if (!format_int(&s, &remaining, timeptr->tm_year + 1900, + width, pad_char, show_sign) || + !append_char(&s, &remaining, '-') || + !format_int(&s, &remaining, timeptr->tm_mon + 1, 2, + '0', 0) || + !append_char(&s, &remaining, '-') || + !format_int(&s, &remaining, timeptr->tm_mday, 2, + '0', 0)) { + *orig_s = '\0'; + return 0; + } + } break; + case 'g': { + int week_year; + iso_week_number(timeptr, &week_year); + if (!format_int(&s, &remaining, week_year % 100, 2, '0', + 0)) { + *orig_s = '\0'; + return 0; + } + } break; + case 'G': { + int week_year; + iso_week_number(timeptr, &week_year); + if (!format_int(&s, &remaining, week_year, + min_width ? min_width : 4, pad_char, + show_sign)) { + *orig_s = '\0'; + return 0; + } + } break; + case 'H': + if (!format_int(&s, &remaining, timeptr->tm_hour, 2, + '0', 0)) { + *orig_s = '\0'; + return 0; + } + break; + case 'I': { + int hour12 = timeptr->tm_hour % 12; + if (hour12 == 0) + hour12 = 12; + if (!format_int(&s, &remaining, hour12, 2, '0', 0)) { + *orig_s = '\0'; + return 0; + } + } break; + case 'j': + if (!format_int(&s, &remaining, timeptr->tm_yday + 1, 3, + '0', 0)) { + *orig_s = '\0'; + return 0; + } + break; + case 'm': + if (!format_int(&s, &remaining, timeptr->tm_mon + 1, 2, + '0', 0)) { + *orig_s = '\0'; + return 0; + } + break; + case 'M': + if (!format_int(&s, &remaining, timeptr->tm_min, 2, '0', + 0)) { + *orig_s = '\0'; + return 0; + } + break; + case 'n': + if (!append_char(&s, &remaining, '\n')) { + *orig_s = '\0'; + return 0; + } + break; + case 'p': + if (!append_string(&s, &remaining, + timeptr->tm_hour < 12 ? "AM" : + "PM")) { + *orig_s = '\0'; + return 0; + } + break; + case 'r': { + int hour12 = timeptr->tm_hour % 12; + if (hour12 == 0) + hour12 = 12; + if (!format_int(&s, &remaining, hour12, 2, '0', 0) || + !append_char(&s, &remaining, ':') || + !format_int(&s, &remaining, timeptr->tm_min, 2, '0', + 0) || + !append_char(&s, &remaining, ':') || + !format_int(&s, &remaining, timeptr->tm_sec, 2, '0', + 0) || + !append_char(&s, &remaining, ' ') || + !append_string(&s, &remaining, + timeptr->tm_hour < 12 ? "AM" : + "PM")) { + *orig_s = '\0'; + return 0; + } + } break; + case 'R': + if (!format_int(&s, &remaining, timeptr->tm_hour, 2, + '0', 0) || + !append_char(&s, &remaining, ':') || + !format_int(&s, &remaining, timeptr->tm_min, 2, '0', + 0)) { + *orig_s = '\0'; + return 0; + } + break; + case 's': + + if (!append_char(&s, &remaining, '0')) { + *orig_s = '\0'; + return 0; + } + break; + case 'S': + if (!format_int(&s, &remaining, timeptr->tm_sec, 2, '0', + 0)) { + *orig_s = '\0'; + return 0; + } + break; + case 't': + if (!append_char(&s, &remaining, '\t')) { + *orig_s = '\0'; + return 0; + } + break; + case 'T': + if (!format_int(&s, &remaining, timeptr->tm_hour, 2, + '0', 0) || + !append_char(&s, &remaining, ':') || + !format_int(&s, &remaining, timeptr->tm_min, 2, '0', + 0) || + !append_char(&s, &remaining, ':') || + !format_int(&s, &remaining, timeptr->tm_sec, 2, '0', + 0)) { + *orig_s = '\0'; + return 0; + } + break; + case 'u': { + int wday = timeptr->tm_wday; + if (wday == 0) + wday = 7; + if (!format_int(&s, &remaining, wday, 1, '0', 0)) { + *orig_s = '\0'; + return 0; + } + } break; + case 'U': { + int week = + (timeptr->tm_yday + 7 - timeptr->tm_wday) / 7; + if (!format_int(&s, &remaining, week, 2, '0', 0)) { + *orig_s = '\0'; + return 0; + } + } break; + case 'V': { + int week_year; + int week = iso_week_number(timeptr, &week_year); + if (!format_int(&s, &remaining, week, 2, '0', 0)) { + *orig_s = '\0'; + return 0; + } + } break; + case 'w': + if (!format_int(&s, &remaining, timeptr->tm_wday, 1, + '0', 0)) { + *orig_s = '\0'; + return 0; + } + break; + case 'W': { + int wday = timeptr->tm_wday; + if (wday == 0) + wday = 7; + int week = (timeptr->tm_yday + 7 - wday + 1) / 7; + if (!format_int(&s, &remaining, week, 2, '0', 0)) { + *orig_s = '\0'; + return 0; + } + } break; + case 'x': + if (!format_int(&s, &remaining, timeptr->tm_mon + 1, 2, + '0', 0) || + !append_char(&s, &remaining, '/') || + !format_int(&s, &remaining, timeptr->tm_mday, 2, + '0', 0) || + !append_char(&s, &remaining, '/') || + !format_int(&s, &remaining, timeptr->tm_year % 100, + 2, '0', 0)) { + *orig_s = '\0'; + return 0; + } + break; + case 'X': + if (!format_int(&s, &remaining, timeptr->tm_hour, 2, + '0', 0) || + !append_char(&s, &remaining, ':') || + !format_int(&s, &remaining, timeptr->tm_min, 2, '0', + 0) || + !append_char(&s, &remaining, ':') || + !format_int(&s, &remaining, timeptr->tm_sec, 2, '0', + 0)) { + *orig_s = '\0'; + return 0; + } + break; + case 'y': + if (!format_int(&s, &remaining, timeptr->tm_year % 100, + 2, '0', 0)) { + *orig_s = '\0'; + return 0; + } + break; + case 'Y': + if (!format_int(&s, &remaining, timeptr->tm_year + 1900, + min_width ? min_width : 4, pad_char, + show_sign)) { + *orig_s = '\0'; + return 0; + } + break; + case 'z': { + if (timeptr->tm_isdst < 0) { + break; + } + long offset = timeptr->tm_gmtoff; + char sign = '+'; + if (offset < 0) { + sign = '-'; + offset = -offset; + } + int hours = offset / 3600; + int minutes = (offset % 3600) / 60; + if (!append_char(&s, &remaining, sign) || + !format_int(&s, &remaining, hours, 2, '0', 0) || + !format_int(&s, &remaining, minutes, 2, '0', 0)) { + *orig_s = '\0'; + return 0; + } + } break; + case 'Z': + if (timeptr->tm_zone) { + if (!append_string(&s, &remaining, + timeptr->tm_zone)) { + *orig_s = '\0'; + return 0; + } + } + break; + case '%': + if (!append_char(&s, &remaining, '%')) { + *orig_s = '\0'; + return 0; + } + break; + default: + + if (!append_char(&s, &remaining, '%') || + !append_char(&s, &remaining, *ptr)) { + *orig_s = '\0'; + return 0; + } + break; + } + ptr++; + } + + *s = '\0'; + return s - orig_s; +} + +weak size_t strftime_l(char *restrict s, size_t maxsize, + const char *restrict format, + const struct tm *restrict timeptr, + locale_t unused locale) +{ + return strftime(s, maxsize, format, timeptr); +} diff --git a/lib/libc/time/time.c b/lib/libc/time/time.c new file mode 100644 index 00000000..134eed7b --- /dev/null +++ b/lib/libc/time/time.c @@ -0,0 +1,20 @@ +#include <time.h> +#include <asm/vdso.h> +#include <syscall.h> + +time_t time(time_t *tloc) +{ + struct timespec ts; + +#if defined(__x86_64__) + if (__vdso_time) + return __vdso_time(tloc); +#endif + + clock_gettime(CLOCK_REALTIME, &ts); + + if (tloc) + *tloc = ts.tv_sec; + + return ts.tv_sec; +} diff --git a/lib/libc/time/tzset.c b/lib/libc/time/tzset.c new file mode 100644 index 00000000..96f33702 --- /dev/null +++ b/lib/libc/time/tzset.c @@ -0,0 +1,58 @@ +#include <time.h> +#include <ctype.h> + +int daylight = 0; +long timezone = 0; +char *tzname[2] = { "UTC", "UTC" }; + +void tzset(void) +{ + const char *tz = NULL; // getenv("TZ"); + + if (tz == NULL || *tz == '\0') { + timezone = 0; + daylight = 0; + tzname[0] = tzname[1] = "UTC"; + return; + } + + const char *p = tz; + char sign = 0; + int hours = 0, mins = 0; + + static char stdname[8]; + int i = 0; + while (*p && !isdigit((unsigned char)*p) && *p != '+' && *p != '-' && + i < 7) { + stdname[i++] = *p++; + } + + stdname[i] = '\0'; + if (stdname[0]) + tzname[0] = stdname; + else + tzname[0] = "LCL"; + + if (*p == '+' || *p == '-') + sign = *p++; + + while (isdigit((unsigned char)*p)) + hours = hours * 10 + (*p++ - '0'); + + if (*p == ':') { + p++; + while (isdigit((unsigned char)*p)) + mins = mins * 10 + (*p++ - '0'); + } + + int total = hours * 3600 + mins * 60; + if (sign == '+') + timezone = -total; + else if (sign == '-') + timezone = total; + else + timezone = 0; + + daylight = 0; + tzname[1] = tzname[0]; +} diff --git a/lib/libc/time/utimes.c b/lib/libc/time/utimes.c new file mode 100644 index 00000000..d6448c76 --- /dev/null +++ b/lib/libc/time/utimes.c @@ -0,0 +1,25 @@ +#include <fcntl.h> +#include <errno.h> +#include <stddef.h> +#include <sys/stat.h> +#include <sys/time.h> + +int utimes(const char *path, const struct timeval times[2]) +{ + struct timespec ts[2]; + + if (times) { + if (times[0].tv_usec >= 1000000ULL || + times[1].tv_usec >= 1000000ULL) { + errno = EINVAL; + return -1; + } + + ts[0].tv_sec = times[0].tv_sec; + ts[0].tv_nsec = times[0].tv_usec * 1000; + ts[1].tv_sec = times[1].tv_sec; + ts[1].tv_nsec = times[1].tv_usec * 1000; + } + + return utimensat(AT_FDCWD, path, times ? ts : NULL, 0); +} |
