summary refs log tree commit diff
path: root/compat.c
diff options
context:
space:
mode:
Diffstat (limited to 'compat.c')
-rw-r--r--compat.c330
1 files changed, 330 insertions, 0 deletions
diff --git a/compat.c b/compat.c
new file mode 100644
index 0000000..b578962
--- /dev/null
+++ b/compat.c
@@ -0,0 +1,330 @@
+#define COMPAT_C_IMPL
+#include "compat.h"
+
+#ifndef __OpenBSD__
+
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <unistd.h>
+
+#ifndef program_invocation_short_name
+extern char *__progname;
+#define program_invocation_short_name (__progname ? __progname : "ftp")
+#endif
+
+long long
+strtonum(const char *numstr, long long minval, long long maxval,
+    const char **errstrp)
+{
+	long long ll = 0;
+	int error = 0;
+	char *ep;
+	struct errval {
+		const char *errstr;
+		int err;
+	} ev[4] = {
+		{ NULL, 0 },
+		{ "too large", ERANGE },
+		{ "too small", ERANGE },
+		{ "invalid", EINVAL },
+	};
+
+	ev[0].err = errno;
+	errno = 0;
+	if (minval > maxval) {
+		error = 3;
+		ev[error].err = EINVAL;
+		ev[error].errstr = "invalid";
+	} else {
+		ll = strtoll(numstr, &ep, 10);
+		if (numstr == ep || *ep != '\0')
+			error = 3;
+		else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval)
+			error = 1;
+		else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval)
+			error = 2;
+	}
+	if (errstrp != NULL)
+		*errstrp = ev[error].errstr;
+	errno = ev[error].err;
+	if (error)
+		ll = 0;
+
+	return (ll);
+}
+
+size_t
+strlcpy(char *dst, const char *src, size_t siz)
+{
+	char *d = dst;
+	const char *s = src;
+	size_t n = siz;
+
+	if (n != 0) {
+		while (--n != 0) {
+			if ((*d++ = *s++) == '\0')
+				break;
+		}
+	}
+
+	if (n == 0) {
+		if (siz != 0)
+			*d = '\0';
+		while (*s++)
+			;
+	}
+
+	return(s - src - 1);
+}
+
+void
+err(int eval, const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	if (fmt != NULL) {
+		fprintf(stderr, "%s: ", program_invocation_short_name);
+		vfprintf(stderr, fmt, ap);
+		va_end(ap);
+		if (errno != 0)
+			fprintf(stderr, ": %s", strerror(errno));
+		fprintf(stderr, "\n");
+	} else {
+		if (errno != 0)
+			fprintf(stderr, "%s: %s\n", program_invocation_short_name,
+			    strerror(errno));
+		va_end(ap);
+	}
+	exit(eval);
+}
+
+void
+errx(int eval, const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	fprintf(stderr, "%s: ", program_invocation_short_name);
+	vfprintf(stderr, fmt, ap);
+	va_end(ap);
+	fprintf(stderr, "\n");
+	exit(eval);
+}
+
+void
+warn(const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	if (fmt != NULL) {
+		fprintf(stderr, "%s: ", program_invocation_short_name);
+		vfprintf(stderr, fmt, ap);
+		va_end(ap);
+		if (errno != 0)
+			fprintf(stderr, ": %s", strerror(errno));
+		fprintf(stderr, "\n");
+	} else {
+		if (errno != 0)
+			fprintf(stderr, "%s: %s\n", program_invocation_short_name,
+			    strerror(errno));
+		va_end(ap);
+	}
+	errno = 0;
+}
+
+void
+warnx(const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	fprintf(stderr, "%s: ", program_invocation_short_name);
+	vfprintf(stderr, fmt, ap);
+	va_end(ap);
+	fprintf(stderr, "\n");
+}
+
+#if defined(__linux__) && !defined(HAVE_FUNOPEN)
+#define _GNU_SOURCE
+#include <stdio.h>
+
+struct funopen_cookie {
+	const void *cookie;
+	int (*readfn)(void *, char *, int);
+	int (*writefn)(void *, const char *, int);
+	fpos_t (*seekfn)(void *, fpos_t, int);
+	int (*closefn)(void *);
+};
+
+static ssize_t
+funopen_read(void *cookie, char *buf, size_t size)
+{
+	struct funopen_cookie *c = cookie;
+	if (c->readfn)
+		return c->readfn((void *)c->cookie, buf, (int)size);
+	return -1;
+}
+
+static ssize_t
+funopen_write(void *cookie, const char *buf, size_t size)
+{
+	struct funopen_cookie *c = cookie;
+	if (c->writefn)
+		return c->writefn((void *)c->cookie, buf, (int)size);
+	return -1;
+}
+
+static int
+funopen_seek(void *cookie, off64_t *offset, int whence)
+{
+	struct funopen_cookie *c = cookie;
+	fpos_t pos = (fpos_t)*offset;
+	int ret;
+	if (c->seekfn) {
+		ret = c->seekfn((void *)c->cookie, pos, whence);
+		if (ret == 0)
+			*offset = (off64_t)pos;
+		return ret;
+	}
+	return -1;
+}
+
+static int
+funopen_close(void *cookie)
+{
+	struct funopen_cookie *c = cookie;
+	if (c->closefn)
+		return c->closefn((void *)c->cookie);
+	free(c);
+	return 0;
+}
+
+FILE *
+funopen(const void *cookie, 
+    int (*readfn)(void *, char *, int),
+    int (*writefn)(void *, const char *, int),
+    fpos_t (*seekfn)(void *, fpos_t, int),
+    int (*closefn)(void *))
+{
+	struct funopen_cookie *c = malloc(sizeof(*c));
+	if (c == NULL)
+		return NULL;
+	c->cookie = cookie;
+	c->readfn = readfn;
+	c->writefn = writefn;
+	c->seekfn = seekfn;
+	c->closefn = closefn;
+
+	cookie_io_functions_t funcs = {
+		.read = funopen_read,
+		.write = funopen_write,
+		.seek = funopen_seek,
+		.close = funopen_close
+	};
+
+	return fopencookie(c, "r+", funcs);
+}
+#endif
+
+#if defined(__APPLE__)
+#include <vis.h>
+
+int
+strnvis_openbsd(char *dst, const char *src, size_t dlen, int flags)
+{
+	return strnvis(dst, dlen, src, flags);
+}
+#endif
+
+#ifndef __OpenBSD__
+#include <sys/types.h>
+#ifndef u_char
+#define u_char unsigned char
+#endif
+
+static const char Base64[] =
+	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+static const char Pad64 = '=';
+
+int
+b64_ntop(u_char const *src, size_t srclength, char *target, size_t targsize)
+{
+	size_t datalength = 0;
+	u_char input[3];
+	u_char output[4];
+	u_int i;
+
+	while (2 < srclength) {
+		input[0] = *src++;
+		input[1] = *src++;
+		input[2] = *src++;
+		srclength -= 3;
+
+		output[0] = input[0] >> 2;
+		output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
+		output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
+		output[3] = input[2] & 0x3f;
+
+		if (datalength + 4 > targsize)
+			return (-1);
+		target[datalength++] = Base64[output[0]];
+		target[datalength++] = Base64[output[1]];
+		target[datalength++] = Base64[output[2]];
+		target[datalength++] = Base64[output[3]];
+	}
+
+	if (srclength != 0) {
+		input[0] = input[1] = input[2] = '\0';
+		for (i = 0; i < srclength; i++)
+			input[i] = *src++;
+
+		output[0] = input[0] >> 2;
+		output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
+		output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
+
+		if (datalength + 4 > targsize)
+			return (-1);
+		target[datalength++] = Base64[output[0]];
+		target[datalength++] = Base64[output[1]];
+		if (srclength == 1)
+			target[datalength++] = Pad64;
+		else
+			target[datalength++] = Base64[output[2]];
+		target[datalength++] = Pad64;
+	}
+	if (datalength >= targsize)
+		return (-1);
+	target[datalength] = '\0';
+	return (datalength);
+}
+#endif
+
+#if !defined(__OpenBSD__)
+#include <poll.h>
+#include <signal.h>
+
+int
+ppoll(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout_ts,
+    const sigset_t *sigmask)
+{
+	int timeout_ms;
+
+	(void)sigmask; /* Ignoring signal mask for simplicity */
+
+	if (timeout_ts == NULL) {
+		timeout_ms = -1;
+	} else {
+		/* Convert timespec to milliseconds */
+		timeout_ms = timeout_ts->tv_sec * 1000 + timeout_ts->tv_nsec / 1000000;
+	}
+
+	return poll(fds, nfds, timeout_ms);
+}
+#endif
+
+#endif
\ No newline at end of file