Files
2018-10-09 01:42:28 -04:00

272 lines
7.4 KiB
C

#include "string.h"
#include "stdio.h"
#include <limits.h>
// FIXME
#include "../kernel/kmalloc.h"
#define _ALIGN (sizeof(size_t))
#define _ONES ((size_t) - 1 / UCHAR_MAX)
#define _HIGHS (_ONES * (UCHAR_MAX / 2 + 1))
#define _HASZERO(x) (((x) - _ONES) & ~(x) & _HIGHS)
#define _SS (sizeof(size_t))
// One measly byte at a time...
void *memcpy(void *restrict destination, const void *restrict source, size_t num) {
char *s1 = (char *) destination;
const char *s2 = (const char *) source;
while (num--) {
*s1++ = *s2++;
}
return destination;
}
void *memmove(void *destination, const void *source, size_t num) {
char *dest = (char *) destination;
const char *src = (const char *) source;
if (dest <= src) {
while (num--) *dest++ = *src++;
} else {
src += num;
dest += num;
while (num--) *--dest = *--src;
}
return destination;
}
void *memset(void *const ptr, const int value, size_t num) {
const unsigned char b = (unsigned char) value;
unsigned char *p = (unsigned char *) ptr;
while (num--) {
*p++ = b;
}
return ptr;
}
int memcmp(const void *const s1, const void *const s2, size_t n) {
const unsigned char *p1 = s1;
const unsigned char *p2 = s2;
while (n--) {
const int r = *p1++ - *p2++;
if (r) return r;
}
return 0;
}
__attribute__((no_sanitize("alignment")))
void *memchr(const void *src, int c, size_t n) {
const unsigned char *s = src;
c = (unsigned char) c;
#ifdef __GNUC__
for (; ((uintptr_t) s & _ALIGN) && n && *s != c; s++, n--);
if (n && *s != c) {
typedef size_t __attribute__((__may_alias__)) word;
const word *w;
size_t k = _ONES * c;
for (w = (const void *) s; n >= _SS && !_HASZERO(*w ^ k); w++, n -= _SS);
s = (const void *) w;
}
#endif
for (; n && *s != c; s++, n--);
return n ? (void *) s : 0;
}
size_t strlen(const char *str) {
const char *a = str;
const size_t *w;
for (; (uintptr_t) str % _ALIGN; str++) if (!*str) return str - a;
for (w = (const void *) str; !_HASZERO(*w); w++);
for (str = (const void *) w; *str; str++);
return str - a;
}
size_t strnlen(const char *s, size_t n) {
const char *p = memchr(s, 0, n);
return p ? p - s : n;
}
int strcmp(const char *const str1, const char *const str2) {
const unsigned char *p1 = (unsigned char *) str1;
const unsigned char *p2 = (unsigned char *) str2;
while (*p1 != '\0' && *p1 == *p2) {
p1++, p2++;
}
return *p1 - *p2;
}
int strncmp(const char *str1, const char *str2, size_t num) {
while (*str1 && num && (*str1 == *str2)) {
++str1;
++str2;
--num;
}
return num == 0 ? 0 : *(unsigned char *) str1 - *(unsigned char *) str2;
}
char *strcpy(char *destination, const char *source) {
char *rc = destination;
while ((*destination++ = *source++));
return rc;
}
char *strncpy(char *restrict s1, const char *restrict s2, size_t n) {
char *rc = s1;
while ((n > 0) && (*s1++ = *s2++)) --n;
while (n-- > 1) *s1++ = '\0';
return rc;
}
char *strdup(const char *str) {
size_t len = strlen(str) + 1;
char *new = kmalloc(len);
if (new == NULL) return NULL;
return memcpy(new, str, len);
}
__attribute__((no_sanitize("alignment")))
char *__strchrnul(const char *s, int c) {
c = (unsigned char) c;
if (!c) return (char *) s + strlen(s);
#ifdef __GNUC__
typedef size_t __attribute__((__may_alias__)) word;
const word *w;
for (; (uintptr_t) s % _ALIGN; s++)
if (!*s || *(unsigned char *) s == c) return (char *) s;
size_t k = _ONES * c;
for (w = (void *) s; !_HASZERO(*w) && !_HASZERO(*w ^ k); w++);
s = (void *) w;
#endif
for (; *s && *(unsigned char *) s != c; s++);
return (char *) s;
}
char *strchr(const char *s, int c) {
char *r = __strchrnul(s, c);
return *(unsigned char *) r == (unsigned char) c ? r : 0;
}
size_t strlcpy(char *d, const char *s, size_t n) {
char *d0 = d;
size_t *wd;
if (!n--) goto finish;
#ifdef __GNUC__
typedef size_t __attribute__((__may_alias__)) word;
const word *ws;
if (((uintptr_t) s & _ALIGN) == ((uintptr_t) d & _ALIGN)) {
for (; ((uintptr_t) s & _ALIGN) && n && (*d = *s); n--, s++, d++);
if (n && *s) {
wd = (void *) d;
ws = (const void *) s;
for (; n >= sizeof(size_t) && !_HASZERO(*ws);
n -= sizeof(size_t), ws++, wd++)
*wd = *ws;
d = (void *) wd;
s = (const void *) ws;
}
}
#endif
for (; n && (*d = *s); n--, s++, d++);
*d = 0;
finish:
return d - d0 + strlen(s);
}
#define PATH_LOOKAHEAD(p, i, c) ((i < len) && (p[i] == c))
// FIXME insane crazy stupid code but it works, I guess
void path_append(char *dest, const char *path, const char *app, size_t len) {
size_t i = 0, out_idx = 0, dir_idx = 0;
// Skip existing path if necessary
if (app != NULL && app[0] == '/') goto append;
while (i < len && out_idx < len && path[i] != 0) {
if (path[i] == '/') {
if (PATH_LOOKAHEAD(path, i + 1, '.')) {
if (PATH_LOOKAHEAD(path, i + 2, '.')
&& (PATH_LOOKAHEAD(path, i + 3, '/')
|| PATH_LOOKAHEAD(path, i + 3, 0))) {
out_idx = dir_idx + 1;
i += 3;
while (PATH_LOOKAHEAD(path, i, '/')) i++;
continue;
} else if (PATH_LOOKAHEAD(path, i + 2, '/')
|| PATH_LOOKAHEAD(path, i + 2, 0)) {
i += 2;
continue;
}
} else if (PATH_LOOKAHEAD(path, i + 1, '/')) {
i++;
continue;
}
dir_idx = out_idx;
}
dest[out_idx] = path[i];
i++;
out_idx++;
}
i = 0;
if (app == NULL || app[0] == 0) goto close;
// Check for leading . or ..
if (app[i] == '.') {
if (PATH_LOOKAHEAD(app, i + 1, '/')) {
i += 2;
} else if (PATH_LOOKAHEAD(app, i + 1, 0)) {
goto close;
} else if (PATH_LOOKAHEAD(app, i + 1, '.')
&& (PATH_LOOKAHEAD(app, i + 2, '/')
|| PATH_LOOKAHEAD(app, i + 2, 0))) {
out_idx = dir_idx + 1;
i += 2;
}
}
if (out_idx && dest[out_idx - 1] != '/' && out_idx < len) dest[dir_idx = out_idx++] = '/'; // Add trailing slash
while (i < len && app[i] == '/') i++; // Skip leading slash(es)
append:
while (i < len && out_idx < len && app[i] != 0) {
if (app[i] == '/') {
if (PATH_LOOKAHEAD(app, i + 1, '.')) {
if (PATH_LOOKAHEAD(app, i + 2, '.')
&& (PATH_LOOKAHEAD(app, i + 3, '/')
|| PATH_LOOKAHEAD(app, i + 3, 0))) {
out_idx = dir_idx + 1;
i += 3;
while (PATH_LOOKAHEAD(app, i, '/')) i++;
continue;
} else if (PATH_LOOKAHEAD(app, i + 2, '/')
|| PATH_LOOKAHEAD(app, i + 2, 0)) {
i += 2;
continue;
}
} else if (PATH_LOOKAHEAD(app, i + 1, '/')) {
i++;
continue;
}
dir_idx = out_idx;
}
dest[out_idx] = app[i];
i++;
out_idx++;
}
close:
dest[out_idx] = 0;
}