commit d8f11964ad3523f4510fc77a36befc6e4626bd81
parent 91007a9244e60b1c2690a60ac3d0b7eaecd94266
Author: Roberto Vargas <roberto.vargas@arm.com>
Date: Thu, 25 Oct 2018 15:17:44 +0100
[libc] Synchronize with scc libc
Diffstat:
37 files changed, 1061 insertions(+), 0 deletions(-)
diff --git a/include/bits/amd64/arch/time.h b/include/bits/amd64/arch/time.h
@@ -0,0 +1,8 @@
+#ifndef _SIZET
+typedef unsigned long size_t;
+#define _SIZET
+#endif
+
+#define _MAXYEAR 9999
+
+typedef long int time_t;
diff --git a/include/bits/arm64/arch/time.h b/include/bits/arm64/arch/time.h
@@ -0,0 +1,8 @@
+#ifndef _SIZET
+typedef unsigned long size_t;
+#define _SIZET
+#endif
+
+#define _MAXYEAR 9999
+
+typedef long int time_t;
diff --git a/include/locale.h b/include/locale.h
@@ -0,0 +1,39 @@
+#ifndef _LOCALE_H
+#define _LOCALE_H
+
+#ifndef NULL
+#define NULL ((void *) 0)
+#endif
+
+#define LC_ALL 0
+#define LC_COLLATE 1
+#define LC_CTYPE 2
+#define LC_MONETARY 3
+#define LC_NUMERIC 4
+#define LC_TIME 5
+
+struct lconv {
+ char *decimal_point;
+ char *thousands_sep;
+ char *grouping;
+ char *mon_decimal_point;
+ char *mon_thousands_sep;
+ char *mon_grouping;
+ char *positive_sign;
+ char *negative_sign;
+ char *currency_symbol;
+ char *int_curr_symbol;
+ char frac_digits;
+ char p_cs_precedes;
+ char n_cs_precedes;
+ char p_sep_by_space;
+ char n_sep_by_space;
+ char p_sign_posn;
+ char n_sign_posn;
+ char int_frac_digits;
+};
+
+extern char *setlocale(int category, const char *locale);
+extern struct lconv *localeconv(void);
+
+#endif
diff --git a/include/time.h b/include/time.h
@@ -0,0 +1,43 @@
+#ifndef _TIME_H
+#define _TIME_H
+
+#include <arch/time.h>
+
+#ifndef NULL
+#define NULL ((void *) 0)
+#endif
+
+#define CLOCKS_PER_SEC 1000000
+
+typedef long int clock_t;
+
+struct tm {
+ int tm_sec;
+ int tm_min;
+ int tm_hour;
+ int tm_mday;
+ int tm_mon;
+ int tm_year;
+ int tm_wday;
+ int tm_yday;
+ int tm_isdst;
+
+ /* fields used internally */
+
+ char *tm_zone;
+ long tm_gmtoff;
+};
+
+extern clock_t clock(void);
+extern double difftime(time_t time1, time_t time0);
+extern time_t mktime(struct tm *timeptr);
+extern time_t time(time_t *timer);
+extern char *asctime(const struct tm *timeptr);
+extern char *ctime(const time_t *timer);
+extern struct tm *gmtime(const time_t *timer);
+extern struct tm *localtime(const time_t *timer);
+extern size_t strftime(char * restrict s, size_t maxsize,
+ const char * restrict format,
+ const struct tm * restrict timeptr);
+
+#endif
diff --git a/src/libc/Makefile b/src/libc/Makefile
@@ -82,6 +82,37 @@ COBJ = __assert.o \
vfprintf.o \
vsnprintf.o \
vsprintf.o \
+ __abs.o\
+ __labs.o\
+ __llabs.o\
+ _daysyear.o\
+ abs.o\
+ asctime.o\
+ atoi.o\
+ atol.o\
+ atoll.o\
+ bsearch.o\
+ ctime.o\
+ fgetc.o\
+ fgets.o\
+ freopen.o\
+ getc.o\
+ getchar.o\
+ gets.o\
+ gmtime.o\
+ labs.o\
+ llabs.o\
+ localeconv.o\
+ localtime.o\
+ mktime.o\
+ perror.o\
+ qsort.o\
+ realloc.o\
+ rewind.o\
+ setlocale.o\
+ strftime.o\
+ tmpnam.o\
+ tolower.o\
OBJS = $(COBJ) $(SYSOBJ)
TARGET = $(PROJECTDIR)/lib/libc.a
diff --git a/src/libc/__abs.c b/src/libc/__abs.c
@@ -0,0 +1,4 @@
+#define __USE_MACROS
+#include <stdlib.h>
+
+int __abs;
diff --git a/src/libc/__labs.c b/src/libc/__labs.c
@@ -0,0 +1,4 @@
+#define __USE_MACROS
+#include <stdlib.h>
+
+long __labs;
diff --git a/src/libc/__llabs.c b/src/libc/__llabs.c
@@ -0,0 +1,4 @@
+#define __USE_MACROS
+#include <stdlib.h>
+
+long long __llabs;
diff --git a/src/libc/_daysyear.c b/src/libc/_daysyear.c
@@ -0,0 +1,30 @@
+#include <time.h>
+#include "libc.h"
+
+int _daysmon[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+
+int
+_daysyear(int year)
+{
+ if (year%4 != 0)
+ return 365;
+ if (year%100 == 0 && year%400 != 0)
+ return 365;
+ return 366;
+}
+
+/*
+ * Happy New Year!!!!
+ */
+int
+_newyear(int year)
+{
+ int day;
+
+ year += 1900 - 1;
+ day = 1 + year + year/4;
+ day -= year/100;
+ day += year/400;
+
+ return day % 7;
+}
diff --git a/src/libc/abs.c b/src/libc/abs.c
@@ -0,0 +1,8 @@
+#include <stdlib.h>
+#undef abs
+
+int
+abs(int n)
+{
+ return (n < 0) ? -n : n;
+}
diff --git a/src/libc/asctime.c b/src/libc/asctime.c
@@ -0,0 +1,12 @@
+#include <time.h>
+#undef asctime
+
+#include <stdio.h> // TODO: remove me!
+char *
+asctime(const struct tm *tm)
+{
+ static char buf[30];
+
+ strftime(buf, sizeof(buf), "%c\n", tm);
+ return buf;
+}
diff --git a/src/libc/atoi.c b/src/libc/atoi.c
@@ -0,0 +1,25 @@
+#include <ctype.h>
+#include <stdlib.h>
+#undef atoi
+
+int
+atoi(const char *s)
+{
+ int n, sign = -1;
+
+ while (isspace(*s))
+ ++s;
+
+ switch (*s) {
+ case '-':
+ sign = 1;
+ case '+':
+ ++s;
+ }
+
+ /* Compute n as a negative number to avoid overflow on INT_MIN */
+ for (n = 0; isdigit(*s); ++s)
+ n = 10*n - (*s - '0');
+
+ return sign * n;
+}
diff --git a/src/libc/atol.c b/src/libc/atol.c
@@ -0,0 +1,26 @@
+#include <ctype.h>
+#include <stdlib.h>
+#undef atol
+
+long
+atol(const char *s)
+{
+ int sign = -1;
+ long n;
+
+ while (isspace(*s))
+ ++s;
+
+ switch (*s) {
+ case '-':
+ sign = 1;
+ case '+':
+ ++s;
+ }
+
+ /* Compute n as a negative number to avoid overflow on LONG_MIN */
+ for (n = 0; isdigit(*s); ++s)
+ n = 10*n - (*s - '0');
+
+ return sign * n;
+}
diff --git a/src/libc/atoll.c b/src/libc/atoll.c
@@ -0,0 +1,26 @@
+#include <ctype.h>
+#include <stdlib.h>
+#undef atoll
+
+long long
+atoll(const char *s)
+{
+ int sign = -1;
+ long long n;
+
+ while (isspace(*s))
+ ++s;
+
+ switch (*s) {
+ case '-':
+ sign = 1;
+ case '+':
+ ++s;
+ }
+
+ /* Compute n as a negative number to avoid overflow on LLONG_MIN */
+ for (n = 0; isdigit(*s); ++s)
+ n = 10*n - (*s - '0');
+
+ return sign * n;
+}
diff --git a/src/libc/bsearch.c b/src/libc/bsearch.c
@@ -0,0 +1,26 @@
+#include <stdlib.h>
+
+void *
+bsearch(const void *key, const void *ary, size_t n, size_t size,
+ int (*cmp)(const void *, const void *))
+{
+ int t;
+ size_t mid, low, high;
+ char *cur, *base = ary;
+
+ low = 0;
+ high = n - 1;
+ while (low <= high) {
+ mid = low + (high - low) / 2;
+ cur = base + mid*size;
+
+ if ((t = (*cmp)(key, cur)) == 0)
+ return cur;
+ else if (t > 0)
+ low = mid + 1;
+ else
+ high = mid - 1;
+ }
+
+ return NULL;
+}
diff --git a/src/libc/ctime.c b/src/libc/ctime.c
@@ -0,0 +1,8 @@
+#include <time.h>
+#undef ctime
+
+char *
+ctime(const time_t *t)
+{
+ return asctime(localtime(t));
+}
diff --git a/src/libc/difftime.c b/src/libc/difftime.c
@@ -0,0 +1,8 @@
+#include <time.h>
+#undef difftime
+
+double
+difftime(time_t t1, time_t t2)
+{
+ return (double) (t1 - t2);
+}
diff --git a/src/libc/fgetc.c b/src/libc/fgetc.c
@@ -0,0 +1,8 @@
+#include <stdio.h>
+#undef fgetc
+
+int
+fgetc(FILE *fp)
+{
+ return getc(fp);
+}
diff --git a/src/libc/fgets.c b/src/libc/fgets.c
@@ -0,0 +1,19 @@
+#include <stdio.h>
+#undef fgets
+
+char *
+fgets(char *s, int n, FILE *fp)
+{
+ int ch;
+ char *t = s;
+
+ while (--n > 0 && (ch = getc(fp)) != EOF) {
+ if ((*t++ = ch) == '\n')
+ break;
+ }
+ if (ch == EOF && s == t)
+ return NULL;
+ *t = '\0';
+
+ return s;
+}
diff --git a/src/libc/freopen.c b/src/libc/freopen.c
@@ -0,0 +1,14 @@
+#include <stdio.h>
+
+#include "syscall.h"
+#include "libc.h"
+#undef freopen
+
+FILE *
+freopen(const char * restrict name, const char * restrict mode,
+ FILE * restrict fp)
+{
+ if (fclose(fp) == EOF)
+ return NULL;
+ return _fpopen(name, mode, fp);
+}
diff --git a/src/libc/getc.c b/src/libc/getc.c
@@ -0,0 +1,8 @@
+#include <stdio.h>
+#undef getc
+
+int
+getc(FILE *fp)
+{
+ return (fp->rp >= fp->wp) ? __getc(fp) : *fp->rp++;
+}
diff --git a/src/libc/getchar.c b/src/libc/getchar.c
@@ -0,0 +1,8 @@
+#include <stdio.h>
+#undef getchar
+
+int
+getchar(void)
+{
+ return getc(stdin);
+}
diff --git a/src/libc/gets.c b/src/libc/gets.c
@@ -0,0 +1,17 @@
+#include <stdio.h>
+#undef gets
+
+char *
+gets(char *s)
+{
+ int ch;
+ char *t = s;
+
+ while ((ch = getc(stdin)) != EOF && ch != '\n')
+ *t++ = ch;
+ if (ch == EOF && s == t)
+ return NULL;
+ *t = '\0';
+
+ return s;
+}
diff --git a/src/libc/gmtime.c b/src/libc/gmtime.c
@@ -0,0 +1,35 @@
+#include <time.h>
+#include "libc.h"
+#undef gmtime
+
+struct tm *
+gmtime(const time_t *t)
+{
+ static struct tm tm;
+ time_t sec, min, hour, year, day;
+ int i;
+
+ tm.tm_sec = *t % SECDAY;
+ tm.tm_min = tm.tm_sec / 60;
+ tm.tm_sec %= 60;
+ tm.tm_hour = tm.tm_min / 60;
+ tm.tm_min %= 60;
+ day = *t / SECDAY;
+
+ tm.tm_wday = (day + THU) % 7; /* 1/1/1970 was Thursday */
+
+ for (i = EPOCH; day >= _daysyear(i); ++i)
+ day -= _daysyear(i);
+ tm.tm_year = i - 1900;
+ tm.tm_yday = day;
+
+ _daysmon[FEB] = FEBDAYS(tm.tm_year);
+ for (i = JAN; day > _daysmon[i]; i++)
+ day -= _daysmon[i];
+ tm.tm_mon = i;
+ tm.tm_mday = day + 1;
+
+ tm.tm_isdst = 0;
+
+ return &tm;
+}
diff --git a/src/libc/labs.c b/src/libc/labs.c
@@ -0,0 +1,8 @@
+#include <stdlib.h>
+#undef labs
+
+long
+labs(long n)
+{
+ return (n < 0) ? -n : n;
+}
diff --git a/src/libc/llabs.c b/src/libc/llabs.c
@@ -0,0 +1,8 @@
+#include <stdlib.h>
+#undef llabs
+
+long long
+llabs(long long n)
+{
+ return (n < 0) ? -n : n;
+}
diff --git a/src/libc/localeconv.c b/src/libc/localeconv.c
@@ -0,0 +1,29 @@
+#include <locale.h>
+#include <limits.h>
+#undef localeconv
+
+struct lconv *
+localeconv(void)
+{
+ static struct lconv lc = {
+ .decimal_point = ".",
+ .thousands_sep = "",
+ .grouping = "",
+ .mon_decimal_point = "",
+ .mon_thousands_sep = "",
+ .mon_grouping = "",
+ .positive_sign = "",
+ .negative_sign = "",
+ .currency_symbol = "",
+ .int_curr_symbol = "",
+ .frac_digits = CHAR_MAX,
+ .p_cs_precedes = CHAR_MAX,
+ .n_cs_precedes = CHAR_MAX,
+ .p_sep_by_space = CHAR_MAX,
+ .p_sign_posn = CHAR_MAX,
+ .n_sep_by_space = CHAR_MAX,
+ .n_sign_posn = CHAR_MAX,
+ .int_frac_digits = CHAR_MAX,
+ };
+ return &lc;
+}
diff --git a/src/libc/localtime.c b/src/libc/localtime.c
@@ -0,0 +1,21 @@
+#include <time.h>
+#include "libc.h"
+#undef localtime
+
+struct tm *
+localtime(const time_t *timep)
+{
+ struct tzone *tz;
+ struct tm *tm;
+ time_t t = *timep;
+
+ t += tz->gmtoff * 60;
+ t += tz->isdst * 60;
+ tm = gmtime(&t);
+ tz = _tzone(tm);
+ tm->tm_zone = tz->name;
+ tm->tm_isdst = tz->isdst;
+ tm->tm_gmtoff = tz->gmtoff;
+
+ return tm;
+}
diff --git a/src/libc/mktime.c b/src/libc/mktime.c
@@ -0,0 +1,112 @@
+#include <limits.h>
+#include <time.h>
+#include "libc.h"
+#undef mktime
+
+static int
+norm(int *val, int *next, int qty)
+{
+ int v = *val, n = *next, d;
+
+ if (v < 0) {
+ d = -v / qty + 1;
+ v += d * qty;
+ if (n > INT_MAX - d)
+ return 0;
+ n += d;
+ }
+ if (v >= qty) {
+ d = v / qty;
+ v -= d * qty;
+ if (n < INT_MIN + d)
+ return 0;
+ n -= d;
+ }
+
+ *val = v;
+ *next = n;
+ return 1;
+}
+
+static int
+normalize(struct tm *tm)
+{
+ int mon, day, year;
+ struct tm aux = *tm;
+
+ if (!norm(&tm->tm_sec, &tm->tm_min, 60) ||
+ !norm(&tm->tm_min, &tm->tm_hour, 60) ||
+ !norm(&tm->tm_hour, &tm->tm_mday, 24) ||
+ !norm(&tm->tm_mon, &tm->tm_year, 12)) {
+ return 0;
+ }
+
+ day = tm->tm_mday;
+ year = EPOCH + tm->tm_year;
+ _daysmon[FEB] = FEBDAYS(year);
+
+ for (mon = tm->tm_mon; day < 1; --mon) {
+ day += _daysmon[mon];
+ if (mon == JAN) {
+ if (year == EPOCH)
+ return -1;
+ year--;
+ _daysmon[FEB] = FEBDAYS(year);
+ mon = DEC+1;
+ }
+ }
+
+ for (; day > _daysmon[mon]; ++mon) {
+ day -= _daysmon[mon];
+ if (mon == DEC) {
+ if (year == _MAXYEAR)
+ return -1;
+ year++;
+ _daysmon[FEB] = FEBDAYS(year);
+ mon = JAN-1;
+ }
+ }
+
+ tm->tm_mon = mon;
+ tm->tm_year = year - EPOCH;
+ tm->tm_mday = day;
+ tm->tm_wday = (_newyear(tm->tm_year) + tm->tm_yday) % 7;
+
+ return 1;
+}
+
+time_t
+mktime(struct tm *tm)
+{
+ int i, year, dst;
+ time_t t;
+ struct tm *aux;
+
+ if (!normalize(tm))
+ return -1;
+
+ t = 0;
+ year = tm->tm_year + 1900;
+ for (i = EPOCH; i < year; i++)
+ t += _daysyear(i) * SECDAY;
+
+ for (i = 0; i < tm->tm_mon; i++)
+ t += _daysmon[i] * SECDAY;
+
+ t += tm->tm_sec;
+ t += tm->tm_min * SECMIN;
+ t += tm->tm_hour * SECHOUR;
+ t += (tm->tm_mday-1) * SECDAY;
+
+ aux = localtime(&t);
+
+ dst = 0;
+ if (tm->tm_isdst == 0 && aux->tm_isdst == 1)
+ dst = -SECHOUR;
+ else if (tm->tm_isdst == 1 && aux->tm_isdst == 0)
+ dst = +SECHOUR;
+
+ t += aux->tm_gmtoff + dst;
+
+ return t;
+}
diff --git a/src/libc/perror.c b/src/libc/perror.c
@@ -0,0 +1,16 @@
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#undef perror
+
+void
+perror(const char *msg)
+{
+ if (msg && *msg) {
+ fputs(msg, stderr);
+ putc(':', stderr);
+ putc(' ', stderr);
+ }
+ fputs(strerror(errno), stderr);
+ putc('\n', stderr);
+}
diff --git a/src/libc/qsort.c b/src/libc/qsort.c
@@ -0,0 +1,68 @@
+#include <stdlib.h>
+#include <string.h>
+#undef qsort
+
+/*
+ * This implementation of qsort is based in the paper
+ * "Engineering a Sort Function", by Jon L.Bentley and M. Douglas McIlroy.
+ * A lot of different optimizations were removed to make the code simpler.
+ */
+
+struct qsort {
+ size_t es;
+ int (*cmp)(const void *, const void *);
+};
+
+static void
+swap(char *i, char *j, size_t n)
+{
+ do {
+ char c = *i;
+ *i++ = *j;
+ *j++ = c;
+ } while (--n > 0);
+}
+
+static void
+xqsort(char *a, size_t n, struct qsort *qs)
+{
+ size_t j, es = qs->es;
+ char *pi, *pj, *pn;
+
+ if (n <= 1)
+ return;
+
+ pi = a;
+ pn = pj = a + n*es;
+
+ swap(a, a + n/2 * es, es);
+ for (;;) {
+ do {
+ pi += es;
+ } while (pi < pn && qs->cmp(pi, a) < 0);
+
+ do {
+ pj -= es;
+ } while (pj > a && qs->cmp(pj, a) > 0);
+
+ if (pj < pi)
+ break;
+ swap(pi, pj, es);
+ }
+ swap(a, pj, es);
+
+ j = (pj - a) / es;
+ xqsort(a, j, qs);
+ xqsort(a + (j+1)*es, n-j-1, qs);
+}
+
+void
+qsort(void *base, size_t nmemb, size_t size,
+ int (*f)(const void *, const void *))
+{
+ struct qsort qs;
+
+ qs.cmp = f;
+ qs.es = size;
+ xqsort(base, nmemb, &qs);
+}
diff --git a/src/libc/realloc.c b/src/libc/realloc.c
@@ -0,0 +1,68 @@
+#include <stdlib.h>
+#include <string.h>
+
+#include "malloc.h"
+#undef realloc
+
+void *
+realloc(void *ptr, size_t nbytes)
+{
+ Header *oh, *prev, *next, *new;
+ size_t nunits, avail, onbytes, n;
+
+ if (!nbytes)
+ return NULL;
+
+ if (!ptr)
+ return malloc(nbytes);
+
+ nunits = (nbytes + sizeof(Header) - 1) / sizeof(Header) + 1;
+ oh = (Header*)ptr - 1;
+
+ if (oh->h.size == nunits)
+ return ptr;
+
+ new = oh + nunits;
+
+ if (nunits < oh->h.size - 1) {
+ new->h.size = oh->h.size - nunits;
+ oh->h.size = nunits;
+ free(new + 1);
+ return oh;
+ }
+
+ prev = _prevchunk(oh);
+
+ if (oh + oh->h.size == prev->h.next) {
+ /*
+ * if there is free space adjacent
+ * to the current memory
+ */
+ next = prev->h.next;
+ avail = oh->h.size + next->h.size;
+
+ if (avail == nunits) {
+ oh->h.size = nunits;
+ prev->h.next = next->h.next;
+ return oh;
+ }
+
+ if (avail > nunits) {
+ oh->h.size = nunits;
+ prev->h.next = new;
+ new->h.next = next;
+ new->h.size = avail - nunits;
+ return oh;
+ }
+ }
+
+ onbytes = (oh->h.size - 1) * sizeof(Header);
+ if ((new = malloc(nbytes)) == NULL)
+ return NULL;
+
+ n = (onbytes > nbytes) ? nbytes : onbytes;
+ memcpy(new, ptr, n);
+ free(ptr);
+
+ return new;
+}
diff --git a/src/libc/rewind.c b/src/libc/rewind.c
@@ -0,0 +1,10 @@
+#include <stdio.h>
+#undef rewind
+
+void
+rewind(FILE *fp)
+{
+ fp->flags &= ~_IOERR;
+ fseek(fp, 0, SEEK_SET);
+ clearerr(fp);
+}
diff --git a/src/libc/setlocale.c b/src/libc/setlocale.c
@@ -0,0 +1,16 @@
+#include <locale.h>
+#include <stddef.h>
+#undef setlocale
+
+char *
+setlocale(int category, const char *locale)
+{
+ if (category > LC_TIME || category < LC_ALL)
+ return NULL;
+ if (!locale ||
+ locale[0] == '\0' ||
+ locale[0] == 'C' && locale[1] == '\0') {
+ return "C";
+ }
+ return NULL;
+}
diff --git a/src/libc/strftime.c b/src/libc/strftime.c
@@ -0,0 +1,246 @@
+#include <time.h>
+#include <string.h>
+#include "libc.h"
+#undef strftime
+
+static char *days[] = {
+ "Sunday", "Monday", "Tuesday", "Wednesday",
+ "Thursday", "Friday", "Saturday",
+};
+
+static char *months[] = {
+ "January", "February", "March", "April",
+ "May", "June", "July", "August",
+ "September", "October", "November", "December"
+};
+
+static char *am_pm[] = {"AM", "PM"};
+
+static size_t
+sval(char *s, size_t siz, char **strs, int abrev, int idx, int max)
+{
+ char *str;
+ size_t len;
+
+ if (idx < 0 && idx >= max)
+ goto wrong;
+
+ str = strs[idx];
+ len = (!abrev) ? strlen(str) : 3;
+ if (len > siz)
+ goto wrong;
+
+ memcpy(s, str, len);
+ return len;
+
+wrong:
+ *s = '?';
+ return 1;
+}
+
+static size_t
+dval(char *s, size_t siz, int prec, int fill, int val)
+{
+ char *t;
+ int n;
+ static char digits[] = "0123456789";
+
+ if (prec > siz || val < 0) {
+ *s = '?';
+ return 1;
+ }
+
+ n = prec;
+ do {
+ s[--n] = digits[val % 10];
+ val /= 10;
+ } while (n > 0 && val > 0);
+
+ while (n > 0)
+ s[--n] = fill;
+
+ return prec;
+}
+
+static size_t
+timezone(char *s, size_t prec, const struct tm * restrict tm)
+{
+ long off = tm->tm_gmtoff;
+
+ if (prec < 5) {
+ *s = '?';
+ return 1;
+ }
+
+ if (off >= 0) {
+ *s++ = '+';
+ } else {
+ *s++ = '-';
+ off = -off;
+ }
+
+ dval(s, 2, 2, '0', off / 3600);
+ dval(s, 2, 2, '0', (off % 3600) / 60);
+
+ return 5;
+}
+
+size_t
+strftime(char * restrict s, size_t siz,
+ const char * restrict fmt,
+ const struct tm * restrict tm)
+{
+ int ch, abrev, val, fill, width;
+ size_t n, inc;
+ char *tfmt;
+
+ for (n = siz-1; (ch = *fmt++) && n > 0; s += inc, n -= inc) {
+ if (ch != '%') {
+ *s = ch;
+ inc = 1;
+ continue;
+ }
+
+ abrev = 0;
+ fill = '0';
+ width = 2;
+
+ switch (*fmt++) {
+ case 'Z':
+ if (!tm->tm_zone)
+ break;
+ inc = sval(s, n, &tm->tm_zone, 0, 0, 1);
+ break;
+ case 'a':
+ abrev = 1;
+ case 'A':
+ inc = sval(s, n, days, abrev, tm->tm_wday, 7);
+ break;
+ case 'h':
+ case 'b':
+ abrev = 1;
+ case 'B':
+ inc = sval(s, n, months, abrev, tm->tm_mon, 12);
+ break;
+ case 'p':
+ inc = sval(s, n, am_pm, 0, tm->tm_hour > 12, 2);
+ break;
+ case 'c':
+ tfmt = "%a %b %e %T %Y";
+ goto recursive;
+ case 'D':
+ tfmt = "%m/%d/%y";
+ goto recursive;
+ case 'F':
+ tfmt = "%Y-%m-%d";
+ goto recursive;
+ case 'R':
+ tfmt = "%H:%M";
+ goto recursive;
+ case 'X':
+ case 'T':
+ tfmt = "%H:%M:%S";
+ goto recursive;
+ case 'r':
+ tfmt = "%I:%M:%S %p";
+ goto recursive;
+ case 'x':
+ tfmt = "%m/%d/%y";
+ goto recursive;
+ recursive:
+ inc = strftime(s, n+1, tfmt, tm) - 1;
+ break;
+ case 'n':
+ val = '\n';
+ goto character;
+ case 't':
+ val = '\t';
+ goto character;
+ case '%':
+ val = '%';
+ character:
+ *s = val;
+ inc = 1;
+ break;
+ case 'e':
+ fill = ' ';
+ val = tm->tm_mday;
+ goto number;
+ case 'd':
+ val = tm->tm_mday;
+ goto number;
+ case 'V':
+ case 'g':
+ case 'G':
+ /* TODO */
+ break;
+ case 'C':
+ val = tm->tm_year / 100;
+ goto number;
+ case 'H':
+ val = tm->tm_hour;
+ goto number;
+ case 'I':
+ val = tm->tm_hour;
+ if (val == 0)
+ val = 12;
+ if (val > 12)
+ val -= 12;
+ goto number;
+ case 'j':
+ width = 3;
+ val = tm->tm_yday+1;
+ goto number;
+ case 'm':
+ val = tm->tm_mon+1;
+ goto number;
+ case 'M':
+ val = tm->tm_min;
+ goto number;
+ case 'S':
+ val = tm->tm_sec;
+ goto number;
+ case 'u':
+ width = 1;
+ val = tm->tm_wday+1;
+ goto number;
+ case 'U':
+ val = tm->tm_yday / 7;
+ if (_newyear(tm->tm_year) == SAT)
+ val++;
+ goto number;
+ case 'W':
+ val = tm->tm_yday / 7;
+ if (_newyear(tm->tm_year) == MON)
+ val++;
+ goto number;
+ case 'w':
+ width = 1;
+ val = tm->tm_wday;
+ goto number;
+ case 'y':
+ val = tm->tm_year%100;
+ goto number;
+ case 'Y':
+ width = 4;
+ val = 1900 + tm->tm_year;
+ number:
+ inc = dval(s, n, width, fill, val);
+ break;
+ case 'z':
+ inc = timezone(s, n, tm);
+ break;
+ case 'E':
+ case 'O':
+ if (*fmt != '\0')
+ fmt += 2;;
+ case '\0':
+ inc = 0;
+ --fmt;
+ break;
+ }
+ }
+ *s = '\0';
+
+ return siz - n;
+}
diff --git a/src/libc/tmpnam.c b/src/libc/tmpnam.c
@@ -0,0 +1,31 @@
+#include <stdio.h>
+#include <string.h>
+#include "syscall.h"
+#undef tmpnam
+
+char *
+tmpnam(char *s)
+{
+ static char *tmpl, buf[L_tmpnam];
+ char *p;
+
+ if (*buf == '\0') {
+ for (tmpl = buf, p = _TMPNAME; *tmpl++ = *p++; )
+ ;
+ for (p = tmpl; p < &buf[L_tmpnam-1]; ++p)
+ *p = '0';
+ *p = '\0';
+ }
+ for (;;) {
+ for (p = tmpl; *p && *p != '9'; ++p)
+ ;
+ if (*p == '\0')
+ return NULL;
+ ++*p;
+ if (_access(buf, 0) != 0)
+ break;
+ }
+ if (s)
+ strcpy(s, buf);
+ return buf;
+}
diff --git a/src/libc/tolower.c b/src/libc/tolower.c
@@ -0,0 +1,9 @@
+#define __USE_MACROS
+#include <ctype.h>
+#undef tolower
+
+int
+tolower(int c)
+{
+ return (isupper(c)) ? c | 0x20 : c;
+}