aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile62
-rw-r--r--allocn.c38
-rw-r--r--asprintf.c14
-rw-r--r--difftimespec.c50
-rw-r--r--difftimeval.c16
-rw-r--r--doubletotimespec.c22
-rw-r--r--doubletotimeval.c22
-rw-r--r--encalloc.c17
-rw-r--r--enmalloc.c17
-rw-r--r--enmemdup.c17
-rw-r--r--enrealloc.c17
-rw-r--r--enstrdup.c17
-rw-r--r--enstrndup.c17
-rw-r--r--envmalloczn.c17
-rw-r--r--envputenvf.c15
-rw-r--r--envreallocn.c17
-rw-r--r--isutf8.c70
-rw-r--r--libsimple.c1072
-rw-r--r--libsimple.h5
-rw-r--r--memdup.c12
-rw-r--r--memends.c15
-rw-r--r--memmem.c23
-rw-r--r--memrchr.c12
-rw-r--r--memstarts.c14
-rw-r--r--multimespec.c65
-rw-r--r--multimeval.c15
-rw-r--r--rawmemchr.c11
-rw-r--r--rawmemrchr.c11
-rw-r--r--recvfd.c40
-rw-r--r--recvfrom_timestamped.c57
-rw-r--r--sendfd.c31
-rw-r--r--strcasestr.c17
-rw-r--r--strchrnul.c11
-rw-r--r--strends.c9
-rw-r--r--strndup.c18
-rw-r--r--strstarts.c10
-rw-r--r--strtotimespec.c144
-rw-r--r--strtotimeval.c13
-rw-r--r--sumtimespec.c50
-rw-r--r--sumtimeval.c16
-rw-r--r--timespec2timeval.c23
-rw-r--r--timespectostr.c39
-rw-r--r--timevaltostr.c39
-rw-r--r--vasprintf.c26
-rw-r--r--vputenvf.c23
-rw-r--r--vweprintf.c56
46 files changed, 1242 insertions, 1080 deletions
diff --git a/Makefile b/Makefile
index 35e122e..bdaeb44 100644
--- a/Makefile
+++ b/Makefile
@@ -1,10 +1,66 @@
.POSIX:
+CFLAGS = -std=c99 -Wall -Wextra -O2 $(CPPFLAGS)
+CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700
+LDFLAGS = -s
+
+OBJ =\
+ allocn.o\
+ asprintf.o\
+ difftimespec.o\
+ difftimeval.o\
+ doubletotimespec.o\
+ doubletotimeval.o\
+ encalloc.o\
+ enmalloc.o\
+ enmemdup.o\
+ enrealloc.o\
+ enstrdup.o\
+ enstrndup.o\
+ envmalloczn.o\
+ envputenvf.o\
+ envreallocn.o\
+ isutf8.o\
+ memdup.o\
+ memends.o\
+ memmem.o\
+ memrchr.o\
+ memstarts.o\
+ multimespec.o\
+ multimeval.o\
+ rawmemchr.o\
+ rawmemrchr.o\
+ rawmemrchr.o\
+ recvfd.o\
+ recvfrom_timestamped.o\
+ sendfd.o\
+ strcasestr.o\
+ strchrnul.o\
+ strends.o\
+ strndup.o\
+ strstarts.o\
+ strtotimespec.o\
+ strtotimeval.o\
+ sumtimespec.o\
+ sumtimeval.o\
+ timespec2timeval.o\
+ timespectostr.o\
+ timevaltostr.o\
+ vasprintf.o\
+ vputenvf.o\
+ vweprintf.o\
+ libsimple.o
+
all: libsimple.a
-libsimple.o: libsimple.h
-libsimple.a: libsimple.o
+$(OBJ): libsimple.h
+
+libsimple.a: $(OBJ)
+ $(AR) rc $@ $?
+ $(AR) -s $@
clean:
- -rm -r -- libsimple.o libsimple.a libsimple.so libsimple.so.*
+ -rm -r -- *.o libsimple.a libsimple.so libsimple.so.*
+
+.SUFFIXES: .c.o
.PHONY: all clean
diff --git a/allocn.c b/allocn.c
new file mode 100644
index 0000000..168e54c
--- /dev/null
+++ b/allocn.c
@@ -0,0 +1,38 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+
+
+static inline size_t
+alloc_size_product(size_t n, va_list ap)
+{
+ size_t prod = n;
+ if (!n) {
+ errno = EINVAL;
+ return 0;
+ }
+ for (;;) {
+ n = va_arg(ap, size_t);
+ if (!n)
+ break;
+ if (n >= SIZE_MAX / prod) {
+ errno = ENOMEM;
+ return 0;
+ }
+ prod *= n;
+ }
+ return prod;
+}
+
+void *
+libsimple_vmalloczn(int clear, size_t n, va_list ap)
+{
+ n = alloc_size_product(n, ap);
+ return !n ? NULL : clear ? calloc(1, n) : malloc(n);
+}
+
+void *
+libsimple_vreallocn(void *ptr, size_t n, va_list ap)
+{
+ n = alloc_size_product(n, ap);
+ return !n ? NULL : realloc(ptr, n);
+}
diff --git a/asprintf.c b/asprintf.c
new file mode 100644
index 0000000..7f565a3
--- /dev/null
+++ b/asprintf.c
@@ -0,0 +1,14 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+
+
+int
+libsimple_asprintf(char **strp, const char *fmt, ...)
+{
+ va_list ap;
+ int r;
+ va_start(ap, fmt);
+ r = libsimple_vasprintf(strp, fmt, ap);
+ va_end(ap);
+ return r;
+}
diff --git a/difftimespec.c b/difftimespec.c
new file mode 100644
index 0000000..4ea74a8
--- /dev/null
+++ b/difftimespec.c
@@ -0,0 +1,50 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+
+
+int
+libsimple_difftimespec(struct timespec *diff, const struct timespec *minuend, const struct timespec *subtrahend)
+{
+ long int ns = minuend->tv_nsec - subtrahend->tv_nsec;
+ time_t s;
+ int ret = 0;
+
+ s = minuend->tv_sec - subtrahend->tv_sec;
+ if ((minuend->tv_sec <= 0) != (subtrahend->tv_sec <= 0)) {
+ if (minuend->tv_sec < 0 && minuend->tv_sec < TIME_MIN + subtrahend->tv_sec) {
+ s = TIME_MIN;
+ ns = 0;
+ errno = ERANGE;
+ ret = -1;
+ } else if (minuend->tv_sec >= 0 && minuend->tv_sec > TIME_MAX + subtrahend->tv_sec) {
+ s = TIME_MAX;
+ ns = 999999999L;
+ errno = ERANGE;
+ ret = -1;
+ }
+ }
+
+ if (ns < 0) {
+ if (s == TIME_MIN) {
+ ns = 0L;
+ errno = ERANGE;
+ ret = -1;
+ } else {
+ s -= 1;
+ ns += 1000000000L;
+ }
+ } else if (ns >= 1000000000L) {
+ if (s == TIME_MAX) {
+ ns = 999999999L;
+ errno = ERANGE;
+ ret = -1;
+ } else {
+ s += 1;
+ ns -= 1000000000L;
+ }
+ }
+
+ diff->tv_sec = s;
+ diff->tv_nsec = ns;
+ return ret;
+}
diff --git a/difftimeval.c b/difftimeval.c
new file mode 100644
index 0000000..b4c3451
--- /dev/null
+++ b/difftimeval.c
@@ -0,0 +1,16 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+
+
+int
+libsimple_difftimeval(struct timeval *diff, const struct timeval *minuend, const struct timeval *subtrahend)
+{
+ struct timespec a, b, d;
+ int r;
+ libsimple_timeval2timespec(&a, minuend);
+ libsimple_timeval2timespec(&b, subtrahend);
+ r = libsimple_difftimespec(&d, &a, &b);
+ if (r && errno != ERANGE)
+ return r;
+ return r | libsimple_timespec2timeval(diff, &d);
+}
diff --git a/doubletotimespec.c b/doubletotimespec.c
new file mode 100644
index 0000000..8b2cccd
--- /dev/null
+++ b/doubletotimespec.c
@@ -0,0 +1,22 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+
+
+void
+libsimple_doubletotimespec(struct timespec *ts, double d)
+{
+ double ns = (long long int)d;
+ long int nsi;
+ ns = d - ns;
+ ns *= (double)1000000000L;
+ nsi = (long int)ns;
+ if (2 * (ns - (double)nsi) >= 1) {
+ nsi += 1;
+ if (nsi == 1000000000L) {
+ nsi = 0;
+ d += 1;
+ }
+ }
+ ts->tv_sec = (time_t)d;
+ ts->tv_nsec = nsi;
+}
diff --git a/doubletotimeval.c b/doubletotimeval.c
new file mode 100644
index 0000000..c9c1b61
--- /dev/null
+++ b/doubletotimeval.c
@@ -0,0 +1,22 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+
+
+void
+libsimple_doubletotimeval(struct timeval *tv, double d)
+{
+ double ns = (long long int)d;
+ long int nsi;
+ ns = d - ns;
+ ns *= (double)1000000L;
+ nsi = (long int)ns;
+ if (2 * (ns - (double)nsi) >= 1) {
+ nsi += 1;
+ if (nsi == 1000000L) {
+ nsi = 0;
+ d += 1;
+ }
+ }
+ tv->tv_sec = (time_t)d;
+ tv->tv_usec = nsi;
+}
diff --git a/encalloc.c b/encalloc.c
new file mode 100644
index 0000000..fea9c7e
--- /dev/null
+++ b/encalloc.c
@@ -0,0 +1,17 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+
+
+extern char *argv0;
+
+
+void *
+encalloc(int status, size_t n, size_t m)
+{
+ void *ret = calloc(n, m);
+ if (!ret) {
+ fprintf(stderr, "%s: calloc: %s\n", argv0, strerror(errno));
+ exit(status);
+ }
+ return ret;
+}
diff --git a/enmalloc.c b/enmalloc.c
new file mode 100644
index 0000000..570f0a6
--- /dev/null
+++ b/enmalloc.c
@@ -0,0 +1,17 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+
+
+extern char *argv0;
+
+
+void *
+enmalloc(int status, size_t n)
+{
+ void *ret = malloc(n);
+ if (!ret) {
+ fprintf(stderr, "%s: malloc: %s\n", argv0, strerror(errno));
+ exit(status);
+ }
+ return ret;
+}
diff --git a/enmemdup.c b/enmemdup.c
new file mode 100644
index 0000000..c2c89d9
--- /dev/null
+++ b/enmemdup.c
@@ -0,0 +1,17 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+
+
+extern char *argv0;
+
+
+void *
+enmemdup(int status, const void *s, size_t n)
+{
+ void *ret = memdup(s, n);
+ if (!ret) {
+ fprintf(stderr, "%s: memdup: %s\n", argv0, strerror(errno));
+ exit(status);
+ }
+ return ret;
+}
diff --git a/enrealloc.c b/enrealloc.c
new file mode 100644
index 0000000..565eb0a
--- /dev/null
+++ b/enrealloc.c
@@ -0,0 +1,17 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+
+
+extern char *argv0;
+
+
+void *
+enrealloc(int status, void *ptr, size_t n)
+{
+ char *ret = realloc(ptr, n);
+ if (!ret) {
+ fprintf(stderr, "%s: realloc: %s\n", argv0, strerror(errno));
+ exit(status);
+ }
+ return ret;
+}
diff --git a/enstrdup.c b/enstrdup.c
new file mode 100644
index 0000000..da008ce
--- /dev/null
+++ b/enstrdup.c
@@ -0,0 +1,17 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+
+
+extern char *argv0;
+
+
+char *
+enstrdup(int status, const char *s)
+{
+ char *ret = strdup(s);
+ if (!ret) {
+ fprintf(stderr, "%s: strdup: %s\n", argv0, strerror(errno));
+ exit(status);
+ }
+ return ret;
+}
diff --git a/enstrndup.c b/enstrndup.c
new file mode 100644
index 0000000..58fd74e
--- /dev/null
+++ b/enstrndup.c
@@ -0,0 +1,17 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+
+
+extern char *argv0;
+
+
+char *
+enstrndup(int status, const char *s, size_t n)
+{
+ void *ret = strndup(s, n);
+ if (!ret) {
+ fprintf(stderr, "%s: strndup: %s\n", argv0, strerror(errno));
+ exit(status);
+ }
+ return ret;
+}
diff --git a/envmalloczn.c b/envmalloczn.c
new file mode 100644
index 0000000..27c6c0b
--- /dev/null
+++ b/envmalloczn.c
@@ -0,0 +1,17 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+
+
+extern char *argv0;
+
+
+void *
+libsimple_envmalloczn(int status, int clear, size_t n, va_list ap)
+{
+ void *ret = libsimple_vmalloczn(clear, n, ap);
+ if (!ret) {
+ fprintf(stderr, "%s: %s: %s\n", argv0, clear ? "calloc" : "malloc", strerror(errno));
+ exit(status);
+ }
+ return ret;
+}
diff --git a/envputenvf.c b/envputenvf.c
new file mode 100644
index 0000000..1b463ce
--- /dev/null
+++ b/envputenvf.c
@@ -0,0 +1,15 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+
+
+extern char *argv0;
+
+
+void
+envputenvf(int status, const char *fmt, va_list ap)
+{
+ if (vputenvf(fmt, ap)) {
+ fprintf(stderr, "%s: putenvf: %s\n", argv0, strerror(errno));
+ exit(status);
+ }
+}
diff --git a/envreallocn.c b/envreallocn.c
new file mode 100644
index 0000000..25a5e33
--- /dev/null
+++ b/envreallocn.c
@@ -0,0 +1,17 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+
+
+extern char *argv0;
+
+
+void *
+libsimple_envreallocn(int status, void *ptr, size_t n, va_list ap)
+{
+ void *ret = libsimple_vreallocn(ptr, n, ap);
+ if (!ret) {
+ fprintf(stderr, "%s: realloc: %s\n", argv0, strerror(errno));
+ exit(status);
+ }
+ return ret;
+}
diff --git a/isutf8.c b/isutf8.c
new file mode 100644
index 0000000..5f63a49
--- /dev/null
+++ b/isutf8.c
@@ -0,0 +1,70 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+
+
+int
+libsimple_isutf8(const char *string, int allow_modified_nul)
+{
+ static long BYTES_TO_MIN_BITS[] = {0, 0, 8, 12, 17, 22, 37};
+ static long BYTES_TO_MAX_BITS[] = {0, 7, 11, 16, 21, 26, 31};
+ long int bytes = 0, read_bytes = 0, bits = 0, c, character;
+
+ /* min bits max bits
+ 0....... 0 7
+ 110..... 10...... 8 11
+ 1110.... 10...... 10...... 12 16
+ 11110... 10...... 10...... 10...... 17 21
+ 111110.. 10...... 10...... 10...... 10...... 22 26
+ 1111110. 10...... 10...... 10...... 10...... 10...... 27 31
+ */
+
+ while ((c = (long int)(*string++))) {
+ if (!read_bytes) {
+ /* First byte of the character. */
+
+ if (!(c & 0x80))
+ /* Single-byte character. */
+ continue;
+
+ if ((c & 0xC0) == 0x80)
+ /* Single-byte character marked as multibyte, or
+ a non-first byte in a multibyte character. */
+ return -1;
+
+ /* Multibyte character. */
+ while ((c & 0x80))
+ bytes++, c <<= 1;
+ read_bytes = 1;
+ character = c & 0x7F;
+ if (bytes > 6)
+ /* 31-bit characters can be encoded with 6-bytes,
+ and UTF-8 does not cover higher code points. */
+ return -1;
+ } else {
+ /* Not first byte of the character. */
+
+ if ((c & 0xC0) != 0x80)
+ /* Beginning of new character before a
+ multibyte character has ended. */
+ return -1;
+
+ character = (character << 6) | (c & 0x7F);
+
+ if (++read_bytes < bytes)
+ /* Not at last byte yet. */
+ continue;
+
+ /* Check that the character is not unnecessarily long. */
+ while (character)
+ character >>= 1, bits++;
+ bits = (!bits && bytes == 2 && allow_modified_nul) ? 8 : bits;
+ if (bits < BYTES_TO_MIN_BITS[bytes] || BYTES_TO_MAX_BITS[bytes] < bits)
+ return -1;
+
+ read_bytes = bytes = bits = 0;
+ }
+ }
+
+ /* Make sure we did not stop at the middle of a multibyte character. */
+ return !read_bytes;
+}
diff --git a/libsimple.c b/libsimple.c
index ac7432a..7ada6af 100644
--- a/libsimple.c
+++ b/libsimple.c
@@ -1,1077 +1,5 @@
/* See LICENSE file for copyright and license details. */
#include "libsimple.h"
-#include <ifaddrs.h>
-
-
-extern char *argv0;
int libsimple_default_failure_exit = 1;
-
-
-void *
-libsimple_rawmemchr(const void *s_, int c)
-{
- char *s = *(char **)(void *)&s_;
- while ((int)*s++ != c);
- return &s[-1];
-}
-
-
-void *
-libsimple_memrchr(const void *s_, int c, size_t n_)
-{
- char *s = *(char **)(void *)&s_;
- ssize_t n = n_;
- while (n-- && (int)s[n] != c);
- return n < 0 ? NULL : &s[n];
-}
-
-
-void *
-libsimple_rawmemrchr(const void *s_, int c, size_t n)
-{
- char *s = *(char **)(void *)&s_;
- while ((int)s[--n] != c);
- return &s[n];
-}
-
-
-char *
-libsimple_strchrnul(const char *s_, int c)
-{
- char *s = *(char **)(void *)&s_;
- for (; *s && (int)*s != c; s++)
- return s;
-}
-
-
-void *
-libsimple_memdup(const void *s, size_t n)
-{
- void *ret = malloc(n);
- if (!ret)
- return NULL;
- return memcpy(ret, s, n);
-}
-
-
-char *
-libsimple_strndup(const char *s, size_t n)
-{
- void *ret;
- if (n == SIZE_MAX) {
- errno = ENOMEM;
- return NULL;
- }
- if (!(ret = malloc(n + 1)))
- return NULL;
- memcpy(ret, s, n);
- ((char *)ret)[n] = '\0';
- return ret;
-}
-
-
-int
-libsimple_isutf8(const char *string, int allow_modified_nul)
-{
- static long BYTES_TO_MIN_BITS[] = {0, 0, 8, 12, 17, 22, 37};
- static long BYTES_TO_MAX_BITS[] = {0, 7, 11, 16, 21, 26, 31};
- long int bytes = 0, read_bytes = 0, bits = 0, c, character;
-
- /* min bits max bits
- 0....... 0 7
- 110..... 10...... 8 11
- 1110.... 10...... 10...... 12 16
- 11110... 10...... 10...... 10...... 17 21
- 111110.. 10...... 10...... 10...... 10...... 22 26
- 1111110. 10...... 10...... 10...... 10...... 10...... 27 31
- */
-
- while ((c = (long int)(*string++))) {
- if (!read_bytes) {
- /* First byte of the character. */
-
- if (!(c & 0x80))
- /* Single-byte character. */
- continue;
-
- if ((c & 0xC0) == 0x80)
- /* Single-byte character marked as multibyte, or
- a non-first byte in a multibyte character. */
- return -1;
-
- /* Multibyte character. */
- while ((c & 0x80))
- bytes++, c <<= 1;
- read_bytes = 1;
- character = c & 0x7F;
- if (bytes > 6)
- /* 31-bit characters can be encoded with 6-bytes,
- and UTF-8 does not cover higher code points. */
- return -1;
- } else {
- /* Not first byte of the character. */
-
- if ((c & 0xC0) != 0x80)
- /* Beginning of new character before a
- multibyte character has ended. */
- return -1;
-
- character = (character << 6) | (c & 0x7F);
-
- if (++read_bytes < bytes)
- /* Not at last byte yet. */
- continue;
-
- /* Check that the character is not unnecessarily long. */
- while (character)
- character >>= 1, bits++;
- bits = (!bits && bytes == 2 && allow_modified_nul) ? 8 : bits;
- if (bits < BYTES_TO_MIN_BITS[bytes] || BYTES_TO_MAX_BITS[bytes] < bits)
- return -1;
-
- read_bytes = bytes = bits = 0;
- }
- }
-
- /* Make sure we did not stop at the middle of a multibyte character. */
- return !read_bytes;
-}
-
-
-int
-libsimple_asprintf(char **strp, const char *fmt, ...)
-{
- va_list ap;
- int r;
- va_start(ap, fmt);
- r = libsimple_vasprintf(strp, fmt, ap);
- va_end(ap);
- return r;
-}
-
-
-int
-libsimple_vasprintf(char **strp, const char *fmt, va_list ap)
-{
- FILE *fp;
- size_t siz = 0;
- int ret;
- *strp = NULL;
- fp = open_memstream(strp, &siz);
- if (!fp)
- goto fail;
- ret = vfprintf(fp, fmt, ap);
- if (ret < 0)
- goto fail;
- if (fputc(0, fp))
- goto fail;
- fclose(fp);
- return ret;
-fail:
- free(*strp);
- *strp = NULL;
- return -1;
-}
-
-
-void *
-libsimple_memmem(const void *hay_, size_t hayn, const void *sub_, size_t subn)
-{
- char *hay = *(char **)(void *)&hay_, *end;
- const char *sub = sub_;
-
- if (!subn)
- return hay;
- if (hayn < subn)
- return NULL;
- if (subn == 1)
- return memchr(hay, *sub, hayn);
-
- for (end = &hay[hayn - subn + 1]; hay != end; hay++)
- if (*hay == *sub && !memcmp(hay, sub, subn))
- return hay;
-
- return NULL;
-}
-
-
-char *
-libsimple_strcasestr(const char *h_, const char *n)
-{
- char *h = *(char **)(void *)&h_;
- size_t hn = strlen(h);
- size_t nn = strlen(n);
- if (hn < nn)
- return NULL;
- for (hn -= nn; hn--; h++)
- if (!strcasecmp(h, n))
- return h;
- return NULL;
-}
-
-
-int
-libsimple_memstarts(const void *s_, size_t n, const void *t_, size_t m)
-{
- const char *s = s_, *t = t_;
- size_t i = 0;
- if (n < m)
- return 0;
- while (i < m && s[i] == t[i]) i++;
- return i == m;
-}
-
-
-int
-libsimple_memends(const void *s_, size_t n, const void *t_, size_t m)
-{
- const char *s = s_, *t = t_;
- if (n < m)
- return 0;
- while (n--, m--)
- if (s[n] != t[m])
- return 0;
- return 1;
-}
-
-
-int
-libsimple_strstarts(const char *s, const char *t)
-{
- for (; *t && *s == *t; s++, t++);
- return !*t;
-}
-
-
-int
-libsimple_strends(const char *s, const char *t)
-{
- return memends(s, strlen(s), t, strlen(t));
-}
-
-
-static inline size_t
-alloc_size_product(size_t n, va_list ap)
-{
- size_t prod = n;
- if (!n) {
- errno = EINVAL;
- return 0;
- }
- for (;;) {
- n = va_arg(ap, size_t);
- if (!n)
- break;
- if (n >= SIZE_MAX / prod) {
- errno = ENOMEM;
- return 0;
- }
- prod *= n;
- }
- return prod;
-}
-
-void *
-libsimple_vmalloczn(int clear, size_t n, va_list ap)
-{
- n = alloc_size_product(n, ap);
- return !n ? NULL : clear ? calloc(1, n) : malloc(n);
-}
-
-void *
-libsimple_vreallocn(void *ptr, size_t n, va_list ap)
-{
- n = alloc_size_product(n, ap);
- return !n ? NULL : realloc(ptr, n);
-}
-
-
-void *
-enmalloc(int status, size_t n)
-{
- void *ret = malloc(n);
- if (!ret) {
- fprintf(stderr, "%s: malloc: %s\n", argv0, strerror(errno));
- exit(status);
- }
- return ret;
-}
-
-
-void *
-encalloc(int status, size_t n, size_t m)
-{
- void *ret = calloc(n, m);
- if (!ret) {
- fprintf(stderr, "%s: calloc: %s\n", argv0, strerror(errno));
- exit(status);
- }
- return ret;
-}
-
-
-void *
-enrealloc(int status, void *ptr, size_t n)
-{
- char *ret = realloc(ptr, n);
- if (!ret) {
- fprintf(stderr, "%s: realloc: %s\n", argv0, strerror(errno));
- exit(status);
- }
- return ret;
-}
-
-
-char *
-enstrdup(int status, const char *s)
-{
- char *ret = strdup(s);
- if (!ret) {
- fprintf(stderr, "%s: strdup: %s\n", argv0, strerror(errno));
- exit(status);
- }
- return ret;
-}
-
-
-char *
-enstrndup(int status, const char *s, size_t n)
-{
- void *ret = strndup(s, n);
- if (!ret) {
- fprintf(stderr, "%s: strndup: %s\n", argv0, strerror(errno));
- exit(status);
- }
- return ret;
-}
-
-
-void *
-enmemdup(int status, const void *s, size_t n)
-{
- void *ret = memdup(s, n);
- if (!ret) {
- fprintf(stderr, "%s: memdup: %s\n", argv0, strerror(errno));
- exit(status);
- }
- return ret;
-}
-
-
-void *
-libsimple_envmalloczn(int status, int clear, size_t n, va_list ap)
-{
- void *ret = libsimple_vmalloczn(clear, n, ap);
- if (!ret) {
- fprintf(stderr, "%s: %s: %s\n", argv0, clear ? "calloc" : "malloc", strerror(errno));
- exit(status);
- }
- return ret;
-}
-
-
-void *
-libsimple_envreallocn(int status, void *ptr, size_t n, va_list ap)
-{
- void *ret = libsimple_vreallocn(ptr, n, ap);
- if (!ret) {
- fprintf(stderr, "%s: realloc: %s\n", argv0, strerror(errno));
- exit(status);
- }
- return ret;
-}
-
-
-int
-vputenvf(const char *fmt, va_list ap)
-{
- va_list ap2;
- int n;
- char *s;
- va_copy(ap2, ap);
- n = vsnprintf(NULL, 0, fmt, ap2);
- va_end(ap2);
- if (n < 0)
- return -1;
- if ((size_t)n == SIZE_MAX) {
- errno = ENOMEM;
- return -1;
- }
- s = alloca((size_t)n + 1);
- vsprintf(s, fmt, ap);
- return putenv(s);
-}
-
-
-void
-envputenvf(int status, const char *fmt, va_list ap)
-{
- if (vputenvf(fmt, ap)) {
- fprintf(stderr, "%s: putenvf: %s\n", argv0, strerror(errno));
- exit(status);
- }
-}
-
-
-void
-vweprintf(const char *fmt, va_list ap)
-{
- int saved_errno = errno, r;
- const char *end = strchr(fmt, '\0');
- const char *prefix1 = argv0;
- const char *prefix2 = ": ";
- const char *suffix1 = "";
- const char *suffix2 = "";
- const char *suffix3 = "";
- char *message = NULL;
- va_list ap1;
- va_list ap2;
-
- if (!argv0 || !strncmp(fmt, "usage: ", strlen("usage: ")))
- prefix1 = prefix2 = "";
-
- va_copy(ap1, ap);
- va_copy(ap2, ap);
- r = vsnprintf(NULL, 0, fmt, ap1);
- if (0 <= r && (size_t)r < SIZE_MAX) {
- message = alloca((size_t)r + 1);
- vsprintf(message, fmt, ap2);
- }
- va_end(ap2);
- va_end(ap1);
-
- if (!*fmt) {
- suffix1 = strerror(saved_errno);
- suffix2 = "\n";
- } else if (end[-1] == ':') {
- suffix1 = " ";
- suffix2 = strerror(saved_errno);
- suffix3 = "\n";
- } else if (end[-1] != '\n') {
- suffix1 = "\n";
- }
-
- if (message) {
- /* This is to avoid mangling when multiple processes are writting. */
- fprintf(stderr, "%s%s%s%s%s%s", prefix1, prefix2, message, suffix1, suffix2, suffix3);
- } else {
- fprintf(stderr, "%s%s", prefix1, prefix2);
- vfprintf(stderr, fmt, ap);
- fprintf(stderr, "%s%s%s", suffix1, suffix2, suffix3);
- }
-
- errno = saved_errno;
-}
-
-
-
-int
-libsimple_sendfd(int sock, int fd)
-{
- char buf[1];
- struct iovec iov;
- struct msghdr msg;
- struct cmsghdr *cmsg;
- char cms[CMSG_SPACE(sizeof(fd))];
-
- buf[0] = 0;
- iov.iov_base = buf;
- iov.iov_len = 1;
-
- memset(&msg, 0, sizeof(msg));
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
- msg.msg_control = (caddr_t)cms;
- msg.msg_controllen = CMSG_LEN(sizeof(fd));
-
- cmsg = CMSG_FIRSTHDR(&msg);
- cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
- cmsg->cmsg_level = SOL_SOCKET;
- cmsg->cmsg_type = SCM_RIGHTS;
- memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd));
-
- return -(sendmsg(sock, &msg, 0) != (ssize_t)iov.iov_len);
-}
-
-
-int
-libsimple_recvfd(int sock)
-{
- int fd;
- char buf[1];
- struct iovec iov;
- struct msghdr msg;
- struct cmsghdr *cmsg;
- char cms[CMSG_SPACE(sizeof(fd))];
-
- iov.iov_base = buf;
- iov.iov_len = 1;
-
- memset(&msg, 0, sizeof(msg));
- msg.msg_name = NULL;
- msg.msg_namelen = 0;
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
-
- msg.msg_control = (caddr_t)cms;
- msg.msg_controllen = sizeof(cms);
-
- switch (recvmsg(sock, &msg, 0)) {
- case -1:
- return -1;
- case 0:
- errno = ECONNRESET;
- return -1;
- default:
- break;
- }
-
- cmsg = CMSG_FIRSTHDR(&msg);
- memcpy(&fd, CMSG_DATA(cmsg), sizeof(fd));
- return fd;
-}
-
-
-ssize_t
-libsimple_recvfrom_timestamped(int fd, void *restrict buf, size_t n, int flags, struct sockaddr *restrict addr,
- socklen_t addrlen, struct timespec *restrict ts)
-{
- struct iovec iov;
- struct msghdr msg;
- struct cmsghdr *cmsg;
- char cms[CMSG_SPACE(sizeof(*ts))];
- size_t r;
-
- iov.iov_base = buf;
- iov.iov_len = n;
-
- memset(&msg, 0, sizeof(msg));
- msg.msg_name = addr;
- msg.msg_namelen = addrlen;
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
-
- msg.msg_control = (caddr_t)cms;
- msg.msg_controllen = sizeof(cms);
-
- switch ((r = recvmsg(fd, &msg, flags))) {
- case -1:
- return -1;
- case 0:
- errno = ECONNRESET;
- return -1;
- default:
- break;
- }
-
- if (!ts)
- return r;
-
- cmsg = CMSG_FIRSTHDR(&msg);
- if (cmsg &&
- cmsg->cmsg_level == SOL_SOCKET &&
- cmsg->cmsg_type == SCM_TIMESTAMPNS &&
- cmsg->cmsg_len == CMSG_LEN(sizeof(*ts))) {
- memcpy(ts, CMSG_DATA(cmsg), sizeof(*ts));
- } else if (cmsg &&
- cmsg->cmsg_level == SOL_SOCKET &&
- cmsg->cmsg_type == SCM_TIMESTAMP &&
- cmsg->cmsg_len == CMSG_LEN(sizeof(*ts))) {
- memcpy(ts, CMSG_DATA(cmsg), sizeof(*ts));
- ts->tv_nsec *= 1000;
- } else {
- memset(ts, 0, sizeof(*ts));
- }
-
- return r;
-}
-
-
-int
-libsimple_sumtimespec(struct timespec *sum, const struct timespec *augend, const struct timespec *addend)
-{
- long int ns = augend->tv_nsec + addend->tv_nsec;
- time_t s;
- int ret = 0;
-
- s = augend->tv_sec + addend->tv_sec;
- if ((augend->tv_sec < 0) == (addend->tv_sec < 0)) {
- if (augend->tv_sec >= 0 && augend->tv_sec > TIME_MAX - addend->tv_sec) {
- s = TIME_MAX;
- ns = 999999999L;
- errno = ERANGE;
- ret = -1;
- } else if (augend->tv_sec < 0 && augend->tv_sec + addend->tv_sec < TIME_MIN) {
- s = TIME_MIN;
- ns = 0;
- errno = ERANGE;
- ret = -1;
- }
- }
-
- if (ns < 0) {
- if (s == TIME_MIN) {
- ns = 0L;
- errno = ERANGE;
- ret = -1;
- } else {
- s -= 1;
- ns += 1000000000L;
- }
- } else if (ns >= 1000000000L) {
- if (s == TIME_MAX) {
- ns = 999999999L;
- errno = ERANGE;
- ret = -1;
- } else {
- s += 1;
- ns -= 1000000000L;
- }
- }
-
- sum->tv_sec = s;
- sum->tv_nsec = ns;
- return ret;
-}
-
-
-int
-libsimple_difftimespec(struct timespec *diff, const struct timespec *minuend, const struct timespec *subtrahend)
-{
- long int ns = minuend->tv_nsec - subtrahend->tv_nsec;
- time_t s;
- int ret = 0;
-
- s = minuend->tv_sec - subtrahend->tv_sec;
- if ((minuend->tv_sec <= 0) != (subtrahend->tv_sec <= 0)) {
- if (minuend->tv_sec < 0 && minuend->tv_sec < TIME_MIN + subtrahend->tv_sec) {
- s = TIME_MIN;
- ns = 0;
- errno = ERANGE;
- ret = -1;
- } else if (minuend->tv_sec >= 0 && minuend->tv_sec > TIME_MAX + subtrahend->tv_sec) {
- s = TIME_MAX;
- ns = 999999999L;
- errno = ERANGE;
- ret = -1;
- }
- }
-
- if (ns < 0) {
- if (s == TIME_MIN) {
- ns = 0L;
- errno = ERANGE;
- ret = -1;
- } else {
- s -= 1;
- ns += 1000000000L;
- }
- } else if (ns >= 1000000000L) {
- if (s == TIME_MAX) {
- ns = 999999999L;
- errno = ERANGE;
- ret = -1;
- } else {
- s += 1;
- ns -= 1000000000L;
- }
- }
-
- diff->tv_sec = s;
- diff->tv_nsec = ns;
- return ret;
-}
-
-
-int
-libsimple_multimespec(struct timespec *prod, const struct timespec *multiplicand, int multiplier)
-{
- time_t s = multiplicand->tv_sec;
- long long int ns = (long long int)(multiplicand->tv_nsec);
- long long int xs;
- int neg = (s < 0) ^ (multiplier < 0);
-
- if (multiplier == 0 || multiplier == 1) {
- prod->tv_sec = multiplier * multiplicand->tv_sec;
- prod->tv_nsec = multiplier * multiplicand->tv_nsec;
- return 0;
- }
-
- if (s < 0) {
- if (TIME_MIN != -TIME_MAX && s == TIME_MIN)
- goto overflow;
- s = -s;
- if (ns)
- ns = 1000000000L - ns;
- }
- if (multiplier < 0)
- multiplier = -multiplier;
-
- ns *= multiplier;
- xs /= 1000000000L;
- ns %= 1000000000L;
-
- if (s > TIME_MAX / multiplier)
- goto overflow;
- s *= multiplier;
-
- if (s > TIME_MAX - (time_t)xs)
- goto overflow;
- s += (time_t)xs;
-
- if (neg) {
- s = -s;
- if (ns) {
- if (s == TIME_MIN)
- goto overflow;
- ns = 1000000000L - ns;
- s -= 1;
- }
- }
-
- prod->tv_sec = s;
- prod->tv_nsec = ns;
- return 0;
-
-overflow:
- if (neg) {
- prod->tv_sec = TIME_MIN;
- prod->tv_nsec = 0;
- } else {
- prod->tv_sec = TIME_MAX;
- prod->tv_nsec = 999999999L;
- }
- errno = ERANGE;
- return -1;
-}
-
-
-int
-libsimple_sumtimeval(struct timeval *sum, const struct timeval *augend, const struct timeval *addend)
-{
- struct timespec a, b, s;
- int r;
- libsimple_timeval2timespec(&a, augend);
- libsimple_timeval2timespec(&b, addend);
- r = libsimple_sumtimespec(&s, &a, &b);
- if (r && errno != ERANGE)
- return r;
- return r | libsimple_timespec2timeval(sum, &s);
-}
-
-
-int
-libsimple_difftimeval(struct timeval *diff, const struct timeval *minuend, const struct timeval *subtrahend)
-{
- struct timespec a, b, d;
- int r;
- libsimple_timeval2timespec(&a, minuend);
- libsimple_timeval2timespec(&b, subtrahend);
- r = libsimple_difftimespec(&d, &a, &b);
- if (r && errno != ERANGE)
- return r;
- return r | libsimple_timespec2timeval(diff, &d);
-}
-
-
-int
-libsimple_multimeval(struct timeval *prod, const struct timeval *multiplicand, int multiplier)
-{
- struct timespec a, p;
- int r;
- libsimple_timeval2timespec(&a, multiplicand);
- r = libsimple_multimespec(&p, &a, multiplier);
- if (r && errno != ERANGE)
- return r;
- return r | libsimple_timespec2timeval(prod, &p);
-}
-
-
-int
-libsimple_timespec2timeval(struct timeval *restrict tv, const struct timespec *restrict ts)
-{
- tv->tv_sec = ts->tv_sec;
- tv->tv_usec = ts->tv_nsec / 1000L;
- if ((ts->tv_nsec % 1000L) >= 500L) {
- if (++(tv->tv_usec) == 1000000L) {
- tv->tv_usec = 0;
- if (tv->tv_sec == TIME_MAX) {
- tv->tv_usec = 999999L;
- errno = EOVERFLOW;
- return -1;
- } else {
- tv->tv_sec += 1;
- }
- }
- }
- return 0;
-}
-
-
-int
-libsimple_strtotimespec(struct timespec *restrict ts, const char *restrict s, char **restrict end)
-{
- int neg = 0, bracket = 0;
- time_t sec = 0;
- long int nsec = 0;
- long int mul = 100000000L;
- const char *p;
-
- if (end)
- *end = (void *)s;
-
- while (isspace(*s))
- s++;
-
- if (!isdigit(s) && *s != '+' && *s != '-' && *s != '.') {
- errno = EINVAL;
- return -1;
- }
-
- if (*s == '-') {
- neg = 1;
- s++;
- } else if (*s == '+') {
- s++;
- }
-
- if (*s == '.') {
- if (s[1] == '.' || s[1] == '(') {
- if (!isdigit(s[2])) {
- errno = EINVAL;
- return -1;
- }
- } else if (!isdigit(s[1])) {
- errno = EINVAL;
- return -1;
- }
- }
-
- for (; isdigit(*s); s++) {
- if (sec < TIME_MIN / 10)
- goto overflow;
- sec *= 10;
- if (sec < TIME_MIN + (*s & 15))
- goto overflow;
- sec -= *s & 15;
- }
-
- if (!neg) {
- if (TIME_MIN != -TIME_MAX && sec == TIME_MIN)
- goto overflow;
- sec = -sec;
- }
-
- if (*s != '.') {
- ts->tv_sec = sec;
- ts->tv_nsec = 0;
- if (end)
- *end = (void *)s;
- return 0;
- }
-
- for (s++; mul && isdigit(*s); s++) {
- nsec += (*s & 15) * mul;
- mul /= 10;
- }
-
- if (*s == '.' || *s == '(') {
- bracket = *s++ == '(';
- p = s;
- if (!isdigit(*s)) {
- errno = EINVAL;
- return -1;
- }
- for (p = s; isdigit(*p); p++);
- if (bracket) {
- if (*p == ')') {
- p++;
- } else {
- errno = EINVAL;
- return -1;
- }
- }
- if (end)
- *end = (void *)p;
- p = s;
- while (mul) {
- for (s = p; mul && isdigit(*s); s++) {
- nsec += (*s & 15) * mul;
- mul /= 10;
- }
- }
- if (!isdigit(*s))
- s = p;
- if (*s >= '5') {
- nsec += 1;
- if (nsec == 1000000000L) {
- if (sec == TIME_MAX)
- goto overflow;
- sec += 1;
- nsec = 0;
- }
- }
- } else {
- if (isdigit(*s)) {
- if (*s >= '5') {
- nsec += 1;
- if (nsec == 1000000000L) {
- if (sec == TIME_MAX)
- goto overflow;
- sec += 1;
- nsec = 0;
- }
- }
- while (isdigit(*s))
- s++;
- }
- if (end)
- *end = (void *)s;
- }
-
- if (neg && nsec) {
- if (sec == TIME_MIN)
- goto overflow;
- nsec = 1000000000L - nsec;
- sec -= 1;
- }
-
- return 0;
-overflow:
- if (neg) {
- ts->tv_sec = TIME_MIN;
- ts->tv_nsec = 0;
- } else {
- ts->tv_sec = TIME_MAX;
- ts->tv_nsec = 999999999L;
- }
- errno = ERANGE;
- return -1;
-}
-
-
-int
-libsimple_strtotimeval(struct timeval *restrict tv, const char *restrict s, char **restrict end)
-{
- struct timespec ts;
- int r = libsimple_strtotimespec(&ts, s, end);
- if (r && errno != ERANGE)
- return r;
- return r | libsimple_timespec2timeval(tv, &ts);
-}
-
-
-char *
-libsimple_timespectostr(char *restrict buf, const struct timespec *restrict ts)
-{
- time_t s = ts->tv_sec;
- long int ns = ts->tv_nsec;
- char sign[2] = "+";
-
- if (!s) {
- buf = malloc(INTSTRLEN(time_t) + sizeof("-.999999999"));
- if (!buf)
- return NULL;
- }
-
- if (ts->tv_nsec < 0 || ts->tv_nsec >= 1000000000L) {
- errno = EINVAL;
- return NULL;
- }
-
- if (s == TIME_MIN && !ns) {
- sprintf(buf, "%lli.000000000", (long long int)s);
- return buf;
- }
-
- if (s < 0) {
- s = -s;
- *sign == '-';
- if (ns) {
- s -= 1;
- ns = 1000000000L - ns;
- }
- }
-
- sprintf(buf, "%s%lli.%09li", sign, (long long int)s, ns);
- return buf;
-}
-
-
-char *
-libsimple_timevaltostr(char *restrict buf, const struct timeval *restrict tv)
-{
- time_t s = tv->tv_sec;
- long int us = tv->tv_usec;
- char sign[2] = "+";
-
- if (!s) {
- buf = malloc(INTSTRLEN(time_t) + sizeof("-.999999"));
- if (!buf)
- return NULL;
- }
-
- if (tv->tv_usec < 0 || tv->tv_usec >= 1000000L) {
- errno = EINVAL;
- return NULL;
- }
-
- if (s == TIME_MIN && !us) {
- sprintf(buf, "%lli.000000", (long long int)s);
- return buf;
- }
-
- if (s < 0) {
- s = -s;
- *sign == '-';
- if (us) {
- s -= 1;
- us = 1000000L - us;
- }
- }
-
- sprintf(buf, "%s%lli.%06li", sign, (long long int)s, us);
- return buf;
-}
-
-
-void
-libsimple_doubletotimespec(struct timespec *ts, double d)
-{
- double ns = (long long int)d;
- long int nsi;
- ns = d - ns;
- ns *= (double)1000000000L;
- nsi = (long int)ns;
- if (2 * (ns - (double)nsi) >= 1) {
- nsi += 1;
- if (nsi == 1000000000L) {
- nsi == 0;
- d += 1;
- }
- }
- ts->tv_sec = (time_t)d;
- ts->tv_nsec = nsi;
-}
-
-
-void
-libsimple_doubletotimeval(struct timeval *tv, double d)
-{
- double ns = (long long int)d;
- long int nsi;
- ns = d - ns;
- ns *= (double)1000000L;
- nsi = (long int)ns;
- if (2 * (ns - (double)nsi) >= 1) {
- nsi += 1;
- if (nsi == 1000000L) {
- nsi == 0;
- d += 1;
- }
- }
- tv->tv_sec = (time_t)d;
- tv->tv_usec = nsi;
-}
diff --git a/libsimple.h b/libsimple.h
index 893ba72..019d261 100644
--- a/libsimple.h
+++ b/libsimple.h
@@ -499,17 +499,12 @@ extern int libsimple_default_failure_exit;
#endif
-#define LIBSIMPLE_INTERFACE 0x0001
-#define LIBSIMPLE_NO_HOSTNAME 0x0002
-
-
#define FREE(PTR) (free(PTR), (PTR) = NULL, 0)
#define CLOSE(FD) ((FD) >= 0 ? (close(FD), (FD) = -1, 0) : 0)
-
_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __warn_unused_result__)))
void *libsimple_rawmemchr(const void *, int);
#ifndef rawmemchr
diff --git a/memdup.c b/memdup.c
new file mode 100644
index 0000000..f3997a6
--- /dev/null
+++ b/memdup.c
@@ -0,0 +1,12 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+
+
+void *
+libsimple_memdup(const void *s, size_t n)
+{
+ void *ret = malloc(n);
+ if (!ret)
+ return NULL;
+ return memcpy(ret, s, n);
+}
diff --git a/memends.c b/memends.c
new file mode 100644
index 0000000..1dde636
--- /dev/null
+++ b/memends.c
@@ -0,0 +1,15 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+
+
+int
+libsimple_memends(const void *s_, size_t n, const void *t_, size_t m)
+{
+ const char *s = s_, *t = t_;
+ if (n < m)
+ return 0;
+ while (n--, m--)
+ if (s[n] != t[m])
+ return 0;
+ return 1;
+}
diff --git a/memmem.c b/memmem.c
new file mode 100644
index 0000000..c7e331a
--- /dev/null
+++ b/memmem.c
@@ -0,0 +1,23 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+
+
+void *
+libsimple_memmem(const void *hay_, size_t hayn, const void *sub_, size_t subn)
+{
+ char *hay = (void *)hay_, *end;
+ const char *sub = sub_;
+
+ if (!subn)
+ return hay;
+ if (hayn < subn)
+ return NULL;
+ if (subn == 1)
+ return memchr(hay, *sub, hayn);
+
+ for (end = &hay[hayn - subn + 1]; hay != end; hay++)
+ if (*hay == *sub && !memcmp(hay, sub, subn))
+ return hay;
+
+ return NULL;
+}
diff --git a/memrchr.c b/memrchr.c
new file mode 100644
index 0000000..6beec6d
--- /dev/null
+++ b/memrchr.c
@@ -0,0 +1,12 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+
+
+void *
+libsimple_memrchr(const void *s_, int c, size_t n_)
+{
+ char *s = *(char **)(void *)&s_;
+ ssize_t n = n_;
+ while (n-- && (int)s[n] != c);
+ return n < 0 ? NULL : &s[n];
+}
diff --git a/memstarts.c b/memstarts.c
new file mode 100644
index 0000000..1dd1e6a
--- /dev/null
+++ b/memstarts.c
@@ -0,0 +1,14 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+
+
+int
+libsimple_memstarts(const void *s_, size_t n, const void *t_, size_t m)
+{
+ const char *s = s_, *t = t_;
+ size_t i = 0;
+ if (n < m)
+ return 0;
+ while (i < m && s[i] == t[i]) i++;
+ return i == m;
+}
diff --git a/multimespec.c b/multimespec.c
new file mode 100644
index 0000000..2e1c2a9
--- /dev/null
+++ b/multimespec.c
@@ -0,0 +1,65 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+
+
+int
+libsimple_multimespec(struct timespec *prod, const struct timespec *multiplicand, int multiplier)
+{
+ time_t s = multiplicand->tv_sec;
+ long long int ns = (long long int)(multiplicand->tv_nsec);
+ long long int xs;
+ int neg = (s < 0) ^ (multiplier < 0);
+
+ if (multiplier == 0 || multiplier == 1) {
+ prod->tv_sec = multiplier * multiplicand->tv_sec;
+ prod->tv_nsec = multiplier * multiplicand->tv_nsec;
+ return 0;
+ }
+
+ if (s < 0) {
+ if (TIME_MIN != -TIME_MAX && s == TIME_MIN)
+ goto overflow;
+ s = -s;
+ if (ns)
+ ns = 1000000000L - ns;
+ }
+ if (multiplier < 0)
+ multiplier = -multiplier;
+
+ ns *= multiplier;
+ xs = ns / 1000000000L;
+ ns %= 1000000000L;
+
+ if (s > TIME_MAX / multiplier)
+ goto overflow;
+ s *= multiplier;
+
+ if (s > TIME_MAX - (time_t)xs)
+ goto overflow;
+ s += (time_t)xs;
+
+ if (neg) {
+ s = -s;
+ if (ns) {
+ if (s == TIME_MIN)
+ goto overflow;
+ ns = 1000000000L - ns;
+ s -= 1;
+ }
+ }
+
+ prod->tv_sec = s;
+ prod->tv_nsec = ns;
+ return 0;
+
+overflow:
+ if (neg) {
+ prod->tv_sec = TIME_MIN;
+ prod->tv_nsec = 0;
+ } else {
+ prod->tv_sec = TIME_MAX;
+ prod->tv_nsec = 999999999L;
+ }
+ errno = ERANGE;
+ return -1;
+}
diff --git a/multimeval.c b/multimeval.c
new file mode 100644
index 0000000..10b8be9
--- /dev/null
+++ b/multimeval.c
@@ -0,0 +1,15 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+
+
+int
+libsimple_multimeval(struct timeval *prod, const struct timeval *multiplicand, int multiplier)
+{
+ struct timespec a, p;
+ int r;
+ libsimple_timeval2timespec(&a, multiplicand);
+ r = libsimple_multimespec(&p, &a, multiplier);
+ if (r && errno != ERANGE)
+ return r;
+ return r | libsimple_timespec2timeval(prod, &p);
+}
diff --git a/rawmemchr.c b/rawmemchr.c
new file mode 100644
index 0000000..6dd8496
--- /dev/null
+++ b/rawmemchr.c
@@ -0,0 +1,11 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+
+
+void *
+libsimple_rawmemchr(const void *s_, int c)
+{
+ char *s = *(char **)(void *)&s_;
+ while ((int)*s++ != c);
+ return &s[-1];
+}
diff --git a/rawmemrchr.c b/rawmemrchr.c
new file mode 100644
index 0000000..5ce374d
--- /dev/null
+++ b/rawmemrchr.c
@@ -0,0 +1,11 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+
+
+void *
+libsimple_rawmemrchr(const void *s_, int c, size_t n)
+{
+ char *s = *(char **)(void *)&s_;
+ while ((int)s[--n] != c);
+ return &s[n];
+}
diff --git a/recvfd.c b/recvfd.c
new file mode 100644
index 0000000..34919d4
--- /dev/null
+++ b/recvfd.c
@@ -0,0 +1,40 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+
+
+int
+libsimple_recvfd(int sock)
+{
+ int fd;
+ char buf[1];
+ struct iovec iov;
+ struct msghdr msg;
+ struct cmsghdr *cmsg;
+ char cms[CMSG_SPACE(sizeof(fd))];
+
+ iov.iov_base = buf;
+ iov.iov_len = 1;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+
+ msg.msg_control = (caddr_t)cms;
+ msg.msg_controllen = sizeof(cms);
+
+ switch (recvmsg(sock, &msg, 0)) {
+ case -1:
+ return -1;
+ case 0:
+ errno = ECONNRESET;
+ return -1;
+ default:
+ break;
+ }
+
+ cmsg = CMSG_FIRSTHDR(&msg);
+ memcpy(&fd, CMSG_DATA(cmsg), sizeof(fd));
+ return fd;
+}
diff --git a/recvfrom_timestamped.c b/recvfrom_timestamped.c
new file mode 100644
index 0000000..6dd43b0
--- /dev/null
+++ b/recvfrom_timestamped.c
@@ -0,0 +1,57 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+
+
+ssize_t
+libsimple_recvfrom_timestamped(int fd, void *restrict buf, size_t n, int flags, struct sockaddr *restrict addr,
+ socklen_t addrlen, struct timespec *restrict ts)
+{
+ struct iovec iov;
+ struct msghdr msg;
+ struct cmsghdr *cmsg;
+ char cms[CMSG_SPACE(sizeof(*ts))];
+ size_t r;
+
+ iov.iov_base = buf;
+ iov.iov_len = n;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_name = addr;
+ msg.msg_namelen = addrlen;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+
+ msg.msg_control = (caddr_t)cms;
+ msg.msg_controllen = sizeof(cms);
+
+ switch ((r = recvmsg(fd, &msg, flags))) {
+ case -1:
+ return -1;
+ case 0:
+ errno = ECONNRESET;
+ return -1;
+ default:
+ break;
+ }
+
+ if (!ts)
+ return r;
+
+ cmsg = CMSG_FIRSTHDR(&msg);
+ if (cmsg &&
+ cmsg->cmsg_level == SOL_SOCKET &&
+ cmsg->cmsg_type == SCM_TIMESTAMPNS &&
+ cmsg->cmsg_len == CMSG_LEN(sizeof(*ts))) {
+ memcpy(ts, CMSG_DATA(cmsg), sizeof(*ts));
+ } else if (cmsg &&
+ cmsg->cmsg_level == SOL_SOCKET &&
+ cmsg->cmsg_type == SCM_TIMESTAMP &&
+ cmsg->cmsg_len == CMSG_LEN(sizeof(*ts))) {
+ memcpy(ts, CMSG_DATA(cmsg), sizeof(*ts));
+ ts->tv_nsec *= 1000;
+ } else {
+ memset(ts, 0, sizeof(*ts));
+ }
+
+ return r;
+}
diff --git a/sendfd.c b/sendfd.c
new file mode 100644
index 0000000..ca26265
--- /dev/null
+++ b/sendfd.c
@@ -0,0 +1,31 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+
+
+int
+libsimple_sendfd(int sock, int fd)
+{
+ char buf[1];
+ struct iovec iov;
+ struct msghdr msg;
+ struct cmsghdr *cmsg;
+ char cms[CMSG_SPACE(sizeof(fd))];
+
+ buf[0] = 0;
+ iov.iov_base = buf;
+ iov.iov_len = 1;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = (caddr_t)cms;
+ msg.msg_controllen = CMSG_LEN(sizeof(fd));
+
+ cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd));
+
+ return -(sendmsg(sock, &msg, 0) != (ssize_t)iov.iov_len);
+}
diff --git a/strcasestr.c b/strcasestr.c
new file mode 100644
index 0000000..62bcfdb
--- /dev/null
+++ b/strcasestr.c
@@ -0,0 +1,17 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+
+
+char *
+libsimple_strcasestr(const char *h_, const char *n)
+{
+ char *h = *(char **)(void *)&h_;
+ size_t hn = strlen(h);
+ size_t nn = strlen(n);
+ if (hn < nn)
+ return NULL;
+ for (hn -= nn; hn--; h++)
+ if (!strcasecmp(h, n))
+ return h;
+ return NULL;
+}
diff --git a/strchrnul.c b/strchrnul.c
new file mode 100644
index 0000000..e76978f
--- /dev/null
+++ b/strchrnul.c
@@ -0,0 +1,11 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+
+
+char *
+libsimple_strchrnul(const char *s_, int c)
+{
+ char *s = *(char **)(void *)&s_;
+ for (; *s && (int)*s != c; s++);
+ return s;
+}
diff --git a/strends.c b/strends.c
new file mode 100644
index 0000000..7be8714
--- /dev/null
+++ b/strends.c
@@ -0,0 +1,9 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+
+
+int
+libsimple_strends(const char *s, const char *t)
+{
+ return memends(s, strlen(s), t, strlen(t));
+}
diff --git a/strndup.c b/strndup.c
new file mode 100644
index 0000000..12c8006
--- /dev/null
+++ b/strndup.c
@@ -0,0 +1,18 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+
+
+char *
+libsimple_strndup(const char *s, size_t n)
+{
+ void *ret;
+ if (n == SIZE_MAX) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ if (!(ret = malloc(n + 1)))
+ return NULL;
+ memcpy(ret, s, n);
+ ((char *)ret)[n] = '\0';
+ return ret;
+}
diff --git a/strstarts.c b/strstarts.c
new file mode 100644
index 0000000..ca44e52
--- /dev/null
+++ b/strstarts.c
@@ -0,0 +1,10 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+
+
+int
+libsimple_strstarts(const char *s, const char *t)
+{
+ for (; *t && *s == *t; s++, t++);
+ return !*t;
+}
diff --git a/strtotimespec.c b/strtotimespec.c
new file mode 100644
index 0000000..b8a7489
--- /dev/null
+++ b/strtotimespec.c
@@ -0,0 +1,144 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+
+
+int
+libsimple_strtotimespec(struct timespec *restrict ts, const char *restrict s, char **restrict end)
+{
+ int neg = 0, bracket = 0;
+ time_t sec = 0;
+ long int nsec = 0;
+ long int mul = 100000000L;
+ const char *p;
+
+ if (end)
+ *end = (void *)s;
+
+ while (isspace(*s))
+ s++;
+
+ if (!isdigit(s) && *s != '+' && *s != '-' && *s != '.') {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (*s == '-') {
+ neg = 1;
+ s++;
+ } else if (*s == '+') {
+ s++;
+ }
+
+ if (*s == '.') {
+ if (s[1] == '.' || s[1] == '(') {
+ if (!isdigit(s[2])) {
+ errno = EINVAL;
+ return -1;
+ }
+ } else if (!isdigit(s[1])) {
+ errno = EINVAL;
+ return -1;
+ }
+ }
+
+ for (; isdigit(*s); s++) {
+ if (sec < TIME_MIN / 10)
+ goto overflow;
+ sec *= 10;
+ if (sec < TIME_MIN + (*s & 15))
+ goto overflow;
+ sec -= *s & 15;
+ }
+
+ if (!neg) {
+ if (TIME_MIN != -TIME_MAX && sec == TIME_MIN)
+ goto overflow;
+ sec = -sec;
+ }
+
+ if (*s != '.') {
+ ts->tv_sec = sec;
+ ts->tv_nsec = 0;
+ if (end)
+ *end = (void *)s;
+ return 0;
+ }
+
+ for (s++; mul && isdigit(*s); s++) {
+ nsec += (*s & 15) * mul;
+ mul /= 10;
+ }
+
+ if (*s == '.' || *s == '(') {
+ bracket = *s++ == '(';
+ p = s;
+ if (!isdigit(*s)) {
+ errno = EINVAL;
+ return -1;
+ }
+ for (p = s; isdigit(*p); p++);
+ if (bracket) {
+ if (*p == ')') {
+ p++;
+ } else {
+ errno = EINVAL;
+ return -1;
+ }
+ }
+ if (end)
+ *end = (void *)p;
+ p = s;
+ while (mul) {
+ for (s = p; mul && isdigit(*s); s++) {
+ nsec += (*s & 15) * mul;
+ mul /= 10;
+ }
+ }
+ if (!isdigit(*s))
+ s = p;
+ if (*s >= '5') {
+ nsec += 1;
+ if (nsec == 1000000000L) {
+ if (sec == TIME_MAX)
+ goto overflow;
+ sec += 1;
+ nsec = 0;
+ }
+ }
+ } else {
+ if (isdigit(*s)) {
+ if (*s >= '5') {
+ nsec += 1;
+ if (nsec == 1000000000L) {
+ if (sec == TIME_MAX)
+ goto overflow;
+ sec += 1;
+ nsec = 0;
+ }
+ }
+ while (isdigit(*s))
+ s++;
+ }
+ if (end)
+ *end = (void *)s;
+ }
+
+ if (neg && nsec) {
+ if (sec == TIME_MIN)
+ goto overflow;
+ nsec = 1000000000L - nsec;
+ sec -= 1;
+ }
+
+ return 0;
+overflow:
+ if (neg) {
+ ts->tv_sec = TIME_MIN;
+ ts->tv_nsec = 0;
+ } else {
+ ts->tv_sec = TIME_MAX;
+ ts->tv_nsec = 999999999L;
+ }
+ errno = ERANGE;
+ return -1;
+}
diff --git a/strtotimeval.c b/strtotimeval.c
new file mode 100644
index 0000000..e210e87
--- /dev/null
+++ b/strtotimeval.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+
+
+int
+libsimple_strtotimeval(struct timeval *restrict tv, const char *restrict s, char **restrict end)
+{
+ struct timespec ts;
+ int r = libsimple_strtotimespec(&ts, s, end);
+ if (r && errno != ERANGE)
+ return r;
+ return r | libsimple_timespec2timeval(tv, &ts);
+}
diff --git a/sumtimespec.c b/sumtimespec.c
new file mode 100644
index 0000000..11c5903
--- /dev/null
+++ b/sumtimespec.c
@@ -0,0 +1,50 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+
+
+int
+libsimple_sumtimespec(struct timespec *sum, const struct timespec *augend, const struct timespec *addend)
+{
+ long int ns = augend->tv_nsec + addend->tv_nsec;
+ time_t s;
+ int ret = 0;
+
+ s = augend->tv_sec + addend->tv_sec;
+ if ((augend->tv_sec < 0) == (addend->tv_sec < 0)) {
+ if (augend->tv_sec >= 0 && augend->tv_sec > TIME_MAX - addend->tv_sec) {
+ s = TIME_MAX;
+ ns = 999999999L;
+ errno = ERANGE;
+ ret = -1;
+ } else if (augend->tv_sec < 0 && augend->tv_sec + addend->tv_sec < TIME_MIN) {
+ s = TIME_MIN;
+ ns = 0;
+ errno = ERANGE;
+ ret = -1;
+ }
+ }
+
+ if (ns < 0) {
+ if (s == TIME_MIN) {
+ ns = 0L;
+ errno = ERANGE;
+ ret = -1;
+ } else {
+ s -= 1;
+ ns += 1000000000L;
+ }
+ } else if (ns >= 1000000000L) {
+ if (s == TIME_MAX) {
+ ns = 999999999L;
+ errno = ERANGE;
+ ret = -1;
+ } else {
+ s += 1;
+ ns -= 1000000000L;
+ }
+ }
+
+ sum->tv_sec = s;
+ sum->tv_nsec = ns;
+ return ret;
+}
diff --git a/sumtimeval.c b/sumtimeval.c
new file mode 100644
index 0000000..04746aa
--- /dev/null
+++ b/sumtimeval.c
@@ -0,0 +1,16 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+
+
+int
+libsimple_sumtimeval(struct timeval *sum, const struct timeval *augend, const struct timeval *addend)
+{
+ struct timespec a, b, s;
+ int r;
+ libsimple_timeval2timespec(&a, augend);
+ libsimple_timeval2timespec(&b, addend);
+ r = libsimple_sumtimespec(&s, &a, &b);
+ if (r && errno != ERANGE)
+ return r;
+ return r | libsimple_timespec2timeval(sum, &s);
+}
diff --git a/timespec2timeval.c b/timespec2timeval.c
new file mode 100644
index 0000000..c4069ff
--- /dev/null
+++ b/timespec2timeval.c
@@ -0,0 +1,23 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+
+
+int
+libsimple_timespec2timeval(struct timeval *restrict tv, const struct timespec *restrict ts)
+{
+ tv->tv_sec = ts->tv_sec;
+ tv->tv_usec = ts->tv_nsec / 1000L;
+ if ((ts->tv_nsec % 1000L) >= 500L) {
+ if (++(tv->tv_usec) == 1000000L) {
+ tv->tv_usec = 0;
+ if (tv->tv_sec == TIME_MAX) {
+ tv->tv_usec = 999999L;
+ errno = EOVERFLOW;
+ return -1;
+ } else {
+ tv->tv_sec += 1;
+ }
+ }
+ }
+ return 0;
+}
diff --git a/timespectostr.c b/timespectostr.c
new file mode 100644
index 0000000..2e7dd7a
--- /dev/null
+++ b/timespectostr.c
@@ -0,0 +1,39 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+
+
+char *
+libsimple_timespectostr(char *restrict buf, const struct timespec *restrict ts)
+{
+ time_t s = ts->tv_sec;
+ long int ns = ts->tv_nsec;
+ char sign[2] = "+";
+
+ if (!s) {
+ buf = malloc(INTSTRLEN(time_t) + sizeof("-.999999999"));
+ if (!buf)
+ return NULL;
+ }
+
+ if (ts->tv_nsec < 0 || ts->tv_nsec >= 1000000000L) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ if (s == TIME_MIN && !ns) {
+ sprintf(buf, "%lli.000000000", (long long int)s);
+ return buf;
+ }
+
+ if (s < 0) {
+ s = -s;
+ *sign = '-';
+ if (ns) {
+ s -= 1;
+ ns = 1000000000L - ns;
+ }
+ }
+
+ sprintf(buf, "%s%lli.%09li", sign, (long long int)s, ns);
+ return buf;
+}
diff --git a/timevaltostr.c b/timevaltostr.c
new file mode 100644
index 0000000..d8610b3
--- /dev/null
+++ b/timevaltostr.c
@@ -0,0 +1,39 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+
+
+char *
+libsimple_timevaltostr(char *restrict buf, const struct timeval *restrict tv)
+{
+ time_t s = tv->tv_sec;
+ long int us = tv->tv_usec;
+ char sign[2] = "+";
+
+ if (!s) {
+ buf = malloc(INTSTRLEN(time_t) + sizeof("-.999999"));
+ if (!buf)
+ return NULL;
+ }
+
+ if (tv->tv_usec < 0 || tv->tv_usec >= 1000000L) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ if (s == TIME_MIN && !us) {
+ sprintf(buf, "%lli.000000", (long long int)s);
+ return buf;
+ }
+
+ if (s < 0) {
+ s = -s;
+ *sign = '-';
+ if (us) {
+ s -= 1;
+ us = 1000000L - us;
+ }
+ }
+
+ sprintf(buf, "%s%lli.%06li", sign, (long long int)s, us);
+ return buf;
+}
diff --git a/vasprintf.c b/vasprintf.c
new file mode 100644
index 0000000..59fb190
--- /dev/null
+++ b/vasprintf.c
@@ -0,0 +1,26 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+
+
+int
+libsimple_vasprintf(char **strp, const char *fmt, va_list ap)
+{
+ FILE *fp;
+ size_t siz = 0;
+ int ret;
+ *strp = NULL;
+ fp = open_memstream(strp, &siz);
+ if (!fp)
+ goto fail;
+ ret = vfprintf(fp, fmt, ap);
+ if (ret < 0)
+ goto fail;
+ if (fputc(0, fp))
+ goto fail;
+ fclose(fp);
+ return ret;
+fail:
+ free(*strp);
+ *strp = NULL;
+ return -1;
+}
diff --git a/vputenvf.c b/vputenvf.c
new file mode 100644
index 0000000..a197fb5
--- /dev/null
+++ b/vputenvf.c
@@ -0,0 +1,23 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+
+
+int
+vputenvf(const char *fmt, va_list ap)
+{
+ va_list ap2;
+ int n;
+ char *s;
+ va_copy(ap2, ap);
+ n = vsnprintf(NULL, 0, fmt, ap2);
+ va_end(ap2);
+ if (n < 0)
+ return -1;
+ if ((size_t)n == SIZE_MAX) {
+ errno = ENOMEM;
+ return -1;
+ }
+ s = alloca((size_t)n + 1);
+ vsprintf(s, fmt, ap);
+ return putenv(s);
+}
diff --git a/vweprintf.c b/vweprintf.c
new file mode 100644
index 0000000..605f1c2
--- /dev/null
+++ b/vweprintf.c
@@ -0,0 +1,56 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+
+
+extern char *argv0;
+
+
+void
+vweprintf(const char *fmt, va_list ap)
+{
+ int saved_errno = errno, r;
+ const char *end = strchr(fmt, '\0');
+ const char *prefix1 = argv0;
+ const char *prefix2 = ": ";
+ const char *suffix1 = "";
+ const char *suffix2 = "";
+ const char *suffix3 = "";
+ char *message = NULL;
+ va_list ap1;
+ va_list ap2;
+
+ if (!argv0 || !strncmp(fmt, "usage: ", strlen("usage: ")))
+ prefix1 = prefix2 = "";
+
+ va_copy(ap1, ap);
+ va_copy(ap2, ap);
+ r = vsnprintf(NULL, 0, fmt, ap1);
+ if (0 <= r && (size_t)r < SIZE_MAX) {
+ message = alloca((size_t)r + 1);
+ vsprintf(message, fmt, ap2);
+ }
+ va_end(ap2);
+ va_end(ap1);
+
+ if (!*fmt) {
+ suffix1 = strerror(saved_errno);
+ suffix2 = "\n";
+ } else if (end[-1] == ':') {
+ suffix1 = " ";
+ suffix2 = strerror(saved_errno);
+ suffix3 = "\n";
+ } else if (end[-1] != '\n') {
+ suffix1 = "\n";
+ }
+
+ if (message) {
+ /* This is to avoid mangling when multiple processes are writting. */
+ fprintf(stderr, "%s%s%s%s%s%s", prefix1, prefix2, message, suffix1, suffix2, suffix3);
+ } else {
+ fprintf(stderr, "%s%s", prefix1, prefix2);
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "%s%s%s", suffix1, suffix2, suffix3);
+ }
+
+ errno = saved_errno;
+}