aboutsummaryrefslogtreecommitdiff
path: root/src/libc/newlib
diff options
context:
space:
mode:
authorXavier Del Campo Romero <xavi92@disroot.org>2025-07-07 13:22:53 +0200
committerXavier Del Campo Romero <xavi92@disroot.org>2025-11-11 00:08:15 +0100
commit7861a52adf92a083bb2aed4c35f98d8035dce032 (patch)
tree28cd3c40e4c878f730f5df3c1d93bdf91af490c3 /src/libc/newlib
parent7fc48e9216ff809da5f8055a50b0be17628ef1df (diff)
downloadwnix-7861a52adf92a083bb2aed4c35f98d8035dce032.tar.gz
Setup project skeleton
Diffstat (limited to 'src/libc/newlib')
-rw-r--r--src/libc/newlib/CMakeLists.txt18
-rw-r--r--src/libc/newlib/private_include/sys/_tz_structs.h30
-rw-r--r--src/libc/newlib/src/CMakeLists.txt18
-rw-r--r--src/libc/newlib/src/stdlib/CMakeLists.txt19
-rw-r--r--src/libc/newlib/src/stdlib/div.c121
-rw-r--r--src/libc/newlib/src/time/CMakeLists.txt25
-rw-r--r--src/libc/newlib/src/time/gettzinfo.c15
-rw-r--r--src/libc/newlib/src/time/local.h38
-rw-r--r--src/libc/newlib/src/time/mktime.c288
-rw-r--r--src/libc/newlib/src/time/month_lengths.c14
-rw-r--r--src/libc/newlib/src/time/tzcalc_limits.c76
-rw-r--r--src/libc/newlib/src/time/tzvars.c9
12 files changed, 671 insertions, 0 deletions
diff --git a/src/libc/newlib/CMakeLists.txt b/src/libc/newlib/CMakeLists.txt
new file mode 100644
index 0000000..aedf961
--- /dev/null
+++ b/src/libc/newlib/CMakeLists.txt
@@ -0,0 +1,18 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_subdirectory(src)
+target_include_directories(c PRIVATE private_include)
diff --git a/src/libc/newlib/private_include/sys/_tz_structs.h b/src/libc/newlib/private_include/sys/_tz_structs.h
new file mode 100644
index 0000000..f20aacb
--- /dev/null
+++ b/src/libc/newlib/private_include/sys/_tz_structs.h
@@ -0,0 +1,30 @@
+#ifndef _SYS__TZ_STRUCTS_H_
+#define _SYS__TZ_STRUCTS_H_
+
+#include <time.h>
+
+typedef struct __tzrule_struct
+{
+ char ch;
+ int m; /* Month of year if ch=M */
+ int n; /* Week of month if ch=M */
+ int d; /* Day of week if ch=M, day of year if ch=J or ch=D */
+ int s; /* Time of day in seconds */
+ time_t change;
+ long offset; /* Match type of _timezone. */
+} __tzrule_type;
+
+typedef struct __tzinfo_struct
+{
+ int __tznorth;
+ int __tzyear;
+ __tzrule_type __tzrule[2];
+} __tzinfo_type;
+
+__tzinfo_type *__gettzinfo (void);
+
+extern char *_tzname[2];
+extern int _daylight;
+extern long _timezone;
+
+#endif /* _SYS__TZ_STRUCTS_H_ */
diff --git a/src/libc/newlib/src/CMakeLists.txt b/src/libc/newlib/src/CMakeLists.txt
new file mode 100644
index 0000000..f2f8ba4
--- /dev/null
+++ b/src/libc/newlib/src/CMakeLists.txt
@@ -0,0 +1,18 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_subdirectory(stdlib)
+add_subdirectory(time)
diff --git a/src/libc/newlib/src/stdlib/CMakeLists.txt b/src/libc/newlib/src/stdlib/CMakeLists.txt
new file mode 100644
index 0000000..ab499b9
--- /dev/null
+++ b/src/libc/newlib/src/stdlib/CMakeLists.txt
@@ -0,0 +1,19 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(c PRIVATE
+ div.c
+)
diff --git a/src/libc/newlib/src/stdlib/div.c b/src/libc/newlib/src/stdlib/div.c
new file mode 100644
index 0000000..2a19cae
--- /dev/null
+++ b/src/libc/newlib/src/stdlib/div.c
@@ -0,0 +1,121 @@
+/*
+FUNCTION
+<<div>>---divide two integers
+
+INDEX
+ div
+
+SYNOPSIS
+ #include <stdlib.h>
+ div_t div(int <[n]>, int <[d]>);
+
+DESCRIPTION
+Divide
+@tex
+$n/d$,
+@end tex
+@ifnottex
+<[n]>/<[d]>,
+@end ifnottex
+returning quotient and remainder as two integers in a structure <<div_t>>.
+
+RETURNS
+The result is represented with the structure
+
+. typedef struct
+. {
+. int quot;
+. int rem;
+. } div_t;
+
+where the <<quot>> field represents the quotient, and <<rem>> the
+remainder. For nonzero <[d]>, if `<<<[r]> = div(<[n]>,<[d]>);>>' then
+<[n]> equals `<<<[r]>.rem + <[d]>*<[r]>.quot>>'.
+
+To divide <<long>> rather than <<int>> values, use the similar
+function <<ldiv>>.
+
+PORTABILITY
+<<div>> is ANSI.
+
+No supporting OS subroutines are required.
+*/
+
+/*
+ * Copyright (c) 1990 Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdlib.h> /* div_t */
+
+div_t
+div (int num,
+ int denom)
+{
+ div_t r;
+
+ r.quot = num / denom;
+ r.rem = num % denom;
+ /*
+ * The ANSI standard says that |r.quot| <= |n/d|, where
+ * n/d is to be computed in infinite precision. In other
+ * words, we should always truncate the quotient towards
+ * 0, never -infinity or +infinity.
+ *
+ * Machine division and remainer may work either way when
+ * one or both of n or d is negative. If only one is
+ * negative and r.quot has been truncated towards -inf,
+ * r.rem will have the same sign as denom and the opposite
+ * sign of num; if both are negative and r.quot has been
+ * truncated towards -inf, r.rem will be positive (will
+ * have the opposite sign of num). These are considered
+ * `wrong'.
+ *
+ * If both are num and denom are positive, r will always
+ * be positive.
+ *
+ * This all boils down to:
+ * if num >= 0, but r.rem < 0, we got the wrong answer.
+ * In that case, to get the right answer, add 1 to r.quot and
+ * subtract denom from r.rem.
+ * if num < 0, but r.rem > 0, we also have the wrong answer.
+ * In this case, to get the right answer, subtract 1 from r.quot and
+ * add denom to r.rem.
+ */
+ if (num >= 0 && r.rem < 0) {
+ ++r.quot;
+ r.rem -= denom;
+ }
+ else if (num < 0 && r.rem > 0) {
+ --r.quot;
+ r.rem += denom;
+ }
+ return (r);
+}
diff --git a/src/libc/newlib/src/time/CMakeLists.txt b/src/libc/newlib/src/time/CMakeLists.txt
new file mode 100644
index 0000000..ea7167f
--- /dev/null
+++ b/src/libc/newlib/src/time/CMakeLists.txt
@@ -0,0 +1,25 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(c PRIVATE
+ gettzinfo.c
+ month_lengths.c
+ mktime.c
+ tzvars.c
+ tzcalc_limits.c
+)
+
+target_compile_definitions(c PRIVATE __SINGLE_THREAD__)
diff --git a/src/libc/newlib/src/time/gettzinfo.c b/src/libc/newlib/src/time/gettzinfo.c
new file mode 100644
index 0000000..c28e72f
--- /dev/null
+++ b/src/libc/newlib/src/time/gettzinfo.c
@@ -0,0 +1,15 @@
+#include <sys/types.h>
+#include "local.h"
+
+/* Shared timezone information for libc/time functions. */
+static __tzinfo_type tzinfo = {1, 0,
+ { {'J', 0, 0, 0, 0, (time_t)0, 0L },
+ {'J', 0, 0, 0, 0, (time_t)0, 0L }
+ }
+};
+
+__tzinfo_type *
+__gettzinfo (void)
+{
+ return &tzinfo;
+}
diff --git a/src/libc/newlib/src/time/local.h b/src/libc/newlib/src/time/local.h
new file mode 100644
index 0000000..41940c0
--- /dev/null
+++ b/src/libc/newlib/src/time/local.h
@@ -0,0 +1,38 @@
+/* local header used by libc/time routines */
+#include <time.h>
+#include <sys/_tz_structs.h>
+
+#define SECSPERMIN 60L
+#define MINSPERHOUR 60L
+#define HOURSPERDAY 24L
+#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR)
+#define SECSPERDAY (SECSPERHOUR * HOURSPERDAY)
+#define DAYSPERWEEK 7
+#define MONSPERYEAR 12
+
+#define YEAR_BASE 1900
+#define EPOCH_YEAR 1970
+#define EPOCH_WDAY 4
+#define EPOCH_YEARS_SINCE_LEAP 2
+#define EPOCH_YEARS_SINCE_CENTURY 70
+#define EPOCH_YEARS_SINCE_LEAP_CENTURY 370
+
+#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0)
+
+int __tzcalc_limits (int __year);
+
+extern const int __month_lengths[2][MONSPERYEAR];
+
+void _tzset_unlocked (void);
+
+/* locks for multi-threading */
+#ifdef __SINGLE_THREAD__
+#define TZ_LOCK
+#define TZ_UNLOCK
+#else
+#define TZ_LOCK __tz_lock()
+#define TZ_UNLOCK __tz_unlock()
+#endif
+
+void __tz_lock (void);
+void __tz_unlock (void);
diff --git a/src/libc/newlib/src/time/mktime.c b/src/libc/newlib/src/time/mktime.c
new file mode 100644
index 0000000..4ca1493
--- /dev/null
+++ b/src/libc/newlib/src/time/mktime.c
@@ -0,0 +1,288 @@
+/*
+ * mktime.c
+ * Original Author: G. Haley
+ *
+ * Converts the broken-down time, expressed as local time, in the structure
+ * pointed to by tim_p into a calendar time value. The original values of the
+ * tm_wday and tm_yday fields of the structure are ignored, and the original
+ * values of the other fields have no restrictions. On successful completion
+ * the fields of the structure are set to represent the specified calendar
+ * time. Returns the specified calendar time. If the calendar time can not be
+ * represented, returns the value (time_t) -1.
+ *
+ * Modifications: Fixed tm_isdst usage - 27 August 2008 Craig Howland.
+ */
+
+/*
+FUNCTION
+<<mktime>>---convert time to arithmetic representation
+
+INDEX
+ mktime
+
+SYNOPSIS
+ #include <time.h>
+ time_t mktime(struct tm *<[timp]>);
+
+DESCRIPTION
+<<mktime>> assumes the time at <[timp]> is a local time, and converts
+its representation from the traditional representation defined by
+<<struct tm>> into a representation suitable for arithmetic.
+
+<<localtime>> is the inverse of <<mktime>>.
+
+RETURNS
+If the contents of the structure at <[timp]> do not form a valid
+calendar time representation, the result is <<-1>>. Otherwise, the
+result is the time, converted to a <<time_t>> value.
+
+PORTABILITY
+ANSI C requires <<mktime>>.
+
+<<mktime>> requires no supporting OS subroutines.
+*/
+
+#include "local.h"
+#include <stdlib.h>
+#include <sys/_tz_structs.h>
+#include <time.h>
+
+#define TZ_LOCK
+#define TZ_UNLOCK
+#define _tzset_unlocked()
+#define YEAR_BASE 1900
+
+#define _SEC_IN_MINUTE 60L
+#define _SEC_IN_HOUR 3600L
+#define _SEC_IN_DAY 86400L
+
+static const int DAYS_IN_MONTH[12] =
+{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+
+#define _DAYS_IN_MONTH(x) ((x == 1) ? days_in_feb : DAYS_IN_MONTH[x])
+
+static const int _DAYS_BEFORE_MONTH[12] =
+{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
+
+#define _ISLEAP(y) (((y) % 4) == 0 && (((y) % 100) != 0 || (((y)+1900) % 400) == 0))
+#define _DAYS_IN_YEAR(year) (_ISLEAP(year) ? 366 : 365)
+
+static void
+validate_structure (struct tm *tim_p)
+{
+ div_t res;
+ int days_in_feb = 28;
+
+ /* calculate time & date to account for out of range values */
+ if (tim_p->tm_sec < 0 || tim_p->tm_sec > 59)
+ {
+ res = div (tim_p->tm_sec, 60);
+ tim_p->tm_min += res.quot;
+ if ((tim_p->tm_sec = res.rem) < 0)
+ {
+ tim_p->tm_sec += 60;
+ --tim_p->tm_min;
+ }
+ }
+
+ if (tim_p->tm_min < 0 || tim_p->tm_min > 59)
+ {
+ res = div (tim_p->tm_min, 60);
+ tim_p->tm_hour += res.quot;
+ if ((tim_p->tm_min = res.rem) < 0)
+ {
+ tim_p->tm_min += 60;
+ --tim_p->tm_hour;
+ }
+ }
+
+ if (tim_p->tm_hour < 0 || tim_p->tm_hour > 23)
+ {
+ res = div (tim_p->tm_hour, 24);
+ tim_p->tm_mday += res.quot;
+ if ((tim_p->tm_hour = res.rem) < 0)
+ {
+ tim_p->tm_hour += 24;
+ --tim_p->tm_mday;
+ }
+ }
+
+ if (tim_p->tm_mon < 0 || tim_p->tm_mon > 11)
+ {
+ res = div (tim_p->tm_mon, 12);
+ tim_p->tm_year += res.quot;
+ if ((tim_p->tm_mon = res.rem) < 0)
+ {
+ tim_p->tm_mon += 12;
+ --tim_p->tm_year;
+ }
+ }
+
+ if (_DAYS_IN_YEAR (tim_p->tm_year) == 366)
+ days_in_feb = 29;
+
+ if (tim_p->tm_mday <= 0)
+ {
+ while (tim_p->tm_mday <= 0)
+ {
+ if (--tim_p->tm_mon == -1)
+ {
+ tim_p->tm_year--;
+ tim_p->tm_mon = 11;
+ days_in_feb =
+ ((_DAYS_IN_YEAR (tim_p->tm_year) == 366) ?
+ 29 : 28);
+ }
+ tim_p->tm_mday += _DAYS_IN_MONTH (tim_p->tm_mon);
+ }
+ }
+ else
+ {
+ while (tim_p->tm_mday > _DAYS_IN_MONTH (tim_p->tm_mon))
+ {
+ tim_p->tm_mday -= _DAYS_IN_MONTH (tim_p->tm_mon);
+ if (++tim_p->tm_mon == 12)
+ {
+ tim_p->tm_year++;
+ tim_p->tm_mon = 0;
+ days_in_feb =
+ ((_DAYS_IN_YEAR (tim_p->tm_year) == 366) ?
+ 29 : 28);
+ }
+ }
+ }
+}
+
+time_t
+mktime (struct tm *tim_p)
+{
+ time_t tim = 0;
+ long days = 0;
+ int year, isdst=0;
+ __tzinfo_type *tz = __gettzinfo ();
+
+ /* validate structure */
+ validate_structure (tim_p);
+
+ /* compute hours, minutes, seconds */
+ tim += tim_p->tm_sec + (tim_p->tm_min * _SEC_IN_MINUTE) +
+ (tim_p->tm_hour * _SEC_IN_HOUR);
+
+ /* compute days in year */
+ days += tim_p->tm_mday - 1;
+ days += _DAYS_BEFORE_MONTH[tim_p->tm_mon];
+ if (tim_p->tm_mon > 1 && _DAYS_IN_YEAR (tim_p->tm_year) == 366)
+ days++;
+
+ /* compute day of the year */
+ tim_p->tm_yday = days;
+
+ if (tim_p->tm_year > 10000 || tim_p->tm_year < -10000)
+ return (time_t) -1;
+
+ /* compute days in other years */
+ if ((year = tim_p->tm_year) > 70)
+ {
+ for (year = 70; year < tim_p->tm_year; year++)
+ days += _DAYS_IN_YEAR (year);
+ }
+ else if (year < 70)
+ {
+ for (year = 69; year > tim_p->tm_year; year--)
+ days -= _DAYS_IN_YEAR (year);
+ days -= _DAYS_IN_YEAR (year);
+ }
+
+ /* compute total seconds */
+ tim += (time_t)days * _SEC_IN_DAY;
+
+ TZ_LOCK;
+
+ _tzset_unlocked ();
+
+ if (_daylight)
+ {
+ int tm_isdst;
+ int y = tim_p->tm_year + YEAR_BASE;
+ /* Convert user positive into 1 */
+ tm_isdst = tim_p->tm_isdst > 0 ? 1 : tim_p->tm_isdst;
+ isdst = tm_isdst;
+
+ if (y == tz->__tzyear || __tzcalc_limits (y))
+ {
+ /* calculate start of dst in dst local time and
+ start of std in both std local time and dst local time */
+ time_t startdst_dst = tz->__tzrule[0].change
+ - (time_t) tz->__tzrule[1].offset;
+ time_t startstd_dst = tz->__tzrule[1].change
+ - (time_t) tz->__tzrule[1].offset;
+ time_t startstd_std = tz->__tzrule[1].change
+ - (time_t) tz->__tzrule[0].offset;
+ /* if the time is in the overlap between dst and std local times */
+ if (tim >= startstd_std && tim < startstd_dst)
+ ; /* we let user decide or leave as -1 */
+ else
+ {
+ isdst = (tz->__tznorth
+ ? (tim >= startdst_dst && tim < startstd_std)
+ : (tim >= startdst_dst || tim < startstd_std));
+ /* if user committed and was wrong, perform correction, but not
+ * if the user has given a negative value (which
+ * asks mktime() to determine if DST is in effect or not) */
+ if (tm_isdst >= 0 && (isdst ^ tm_isdst) == 1)
+ {
+ /* we either subtract or add the difference between
+ time zone offsets, depending on which way the user got it
+ wrong. The diff is typically one hour, or 3600 seconds,
+ and should fit in a 16-bit int, even though offset
+ is a long to accomodate 12 hours. */
+ int diff = (int) (tz->__tzrule[0].offset
+ - tz->__tzrule[1].offset);
+ if (!isdst)
+ diff = -diff;
+ tim_p->tm_sec += diff;
+ tim += diff; /* we also need to correct our current time calculation */
+ int mday = tim_p->tm_mday;
+ validate_structure (tim_p);
+ mday = tim_p->tm_mday - mday;
+ /* roll over occurred */
+ if (mday) {
+ /* compensate for month roll overs */
+ if (mday > 1)
+ mday = -1;
+ else if (mday < -1)
+ mday = 1;
+ /* update days for wday calculation */
+ days += mday;
+ /* handle yday */
+ if ((tim_p->tm_yday += mday) < 0) {
+ --year;
+ tim_p->tm_yday = _DAYS_IN_YEAR(year) - 1;
+ } else {
+ mday = _DAYS_IN_YEAR(year);
+ if (tim_p->tm_yday > (mday - 1))
+ tim_p->tm_yday -= mday;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* add appropriate offset to put time in gmt format */
+ if (isdst == 1)
+ tim += (time_t) tz->__tzrule[1].offset;
+ else /* otherwise assume std time */
+ tim += (time_t) tz->__tzrule[0].offset;
+
+ TZ_UNLOCK;
+
+ /* reset isdst flag to what we have calculated */
+ tim_p->tm_isdst = isdst;
+
+ /* compute day of the week */
+ if ((tim_p->tm_wday = (days + 4) % 7) < 0)
+ tim_p->tm_wday += 7;
+
+ return tim;
+}
diff --git a/src/libc/newlib/src/time/month_lengths.c b/src/libc/newlib/src/time/month_lengths.c
new file mode 100644
index 0000000..03fac2f
--- /dev/null
+++ b/src/libc/newlib/src/time/month_lengths.c
@@ -0,0 +1,14 @@
+/*
+ * month_lengths.c
+ *
+ * Array __month_lengths[] is (indirectly) needed by tzset(), mktime(),
+ * gmtime() and localtime(). To break any dependencies, this array is moved to
+ * separate source file.
+ */
+
+#include "local.h"
+
+const int __month_lengths[2][MONSPERYEAR] = {
+ {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
+ {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
+} ;
diff --git a/src/libc/newlib/src/time/tzcalc_limits.c b/src/libc/newlib/src/time/tzcalc_limits.c
new file mode 100644
index 0000000..00044a5
--- /dev/null
+++ b/src/libc/newlib/src/time/tzcalc_limits.c
@@ -0,0 +1,76 @@
+/*
+ * tzcalc_limits.c
+ * Original Author: Adapted from tzcode maintained by Arthur David Olson.
+ * Modifications:
+ * - Changed to mktm_r and added __tzcalc_limits - 04/10/02, Jeff Johnston
+ * - Fixed bug in mday computations - 08/12/04, Alex Mogilnikov <alx@intellectronika.ru>
+ * - Fixed bug in __tzcalc_limits - 08/12/04, Alex Mogilnikov <alx@intellectronika.ru>
+ * - Moved __tzcalc_limits() to separate file - 05/09/14, Freddie Chopin <freddie_chopin@op.pl>
+ */
+
+#include "local.h"
+
+int
+__tzcalc_limits (int year)
+{
+ int days, year_days, years;
+ int i, j;
+ __tzinfo_type *const tz = __gettzinfo ();
+
+ if (year < EPOCH_YEAR)
+ return 0;
+
+ tz->__tzyear = year;
+
+ years = (year - EPOCH_YEAR);
+
+ year_days = years * 365 +
+ (years - 1 + EPOCH_YEARS_SINCE_LEAP) / 4 -
+ (years - 1 + EPOCH_YEARS_SINCE_CENTURY) / 100 +
+ (years - 1 + EPOCH_YEARS_SINCE_LEAP_CENTURY) / 400;
+
+ for (i = 0; i < 2; ++i)
+ {
+ if (tz->__tzrule[i].ch == 'J')
+ {
+ /* The Julian day n (1 <= n <= 365). */
+ days = year_days + tz->__tzrule[i].d +
+ (isleap(year) && tz->__tzrule[i].d >= 60);
+ /* Convert to yday */
+ --days;
+ }
+ else if (tz->__tzrule[i].ch == 'D')
+ days = year_days + tz->__tzrule[i].d;
+ else
+ {
+ const int yleap = isleap(year);
+ int m_day, m_wday, wday_diff;
+ const int *const ip = __month_lengths[yleap];
+
+ days = year_days;
+
+ for (j = 1; j < tz->__tzrule[i].m; ++j)
+ days += ip[j-1];
+
+ m_wday = (EPOCH_WDAY + days) % DAYSPERWEEK;
+
+ wday_diff = tz->__tzrule[i].d - m_wday;
+ if (wday_diff < 0)
+ wday_diff += DAYSPERWEEK;
+ m_day = (tz->__tzrule[i].n - 1) * DAYSPERWEEK + wday_diff;
+
+ while (m_day >= ip[j-1])
+ m_day -= DAYSPERWEEK;
+
+ days += m_day;
+ }
+
+ /* store the change-over time in GMT form by adding offset */
+ tz->__tzrule[i].change = (time_t) days * SECSPERDAY +
+ tz->__tzrule[i].s + tz->__tzrule[i].offset;
+ }
+
+ tz->__tznorth = (tz->__tzrule[0].change < tz->__tzrule[1].change);
+
+ return 1;
+}
diff --git a/src/libc/newlib/src/time/tzvars.c b/src/libc/newlib/src/time/tzvars.c
new file mode 100644
index 0000000..aabf3c4
--- /dev/null
+++ b/src/libc/newlib/src/time/tzvars.c
@@ -0,0 +1,9 @@
+#include <time.h>
+#include <sys/_tz_structs.h>
+
+/* Global timezone variables. */
+
+/* Default timezone to GMT */
+char *_tzname[2] = {"GMT", "GMT"};
+int _daylight = 0;
+long _timezone = 0;