diff options
Diffstat (limited to 'compat.c')
| -rw-r--r-- | compat.c | 330 |
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 |