aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--LICENSE2
-rw-r--r--close_range.c19
-rw-r--r--config.mk4
-rw-r--r--libsimple.h35
-rw-r--r--libsimple/definitions.h134
-rw-r--r--libsimple/time.h39
-rw-r--r--man3/libsimple_close_range.35
-rw-r--r--memcasemem.c28
-rw-r--r--memmem.c34
9 files changed, 274 insertions, 26 deletions
diff --git a/LICENSE b/LICENSE
index be3bb97..99eb019 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
ISC License
-© 2017, 2018, 2021, 2022, 2023, 2024 Mattias Andrée <m@maandree.se>
+© 2017, 2018, 2021, 2022, 2023, 2024, 2025 Mattias Andrée <m@maandree.se>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
diff --git a/close_range.c b/close_range.c
index 540eba0..096aa56 100644
--- a/close_range.c
+++ b/close_range.c
@@ -73,7 +73,8 @@ libsimple_close_range(unsigned int first, unsigned int last, unsigned int *next)
{
int saved_errno;
- *next = first;
+ if (next)
+ *next = first;
if (first > last) {
errno = EINVAL;
@@ -103,10 +104,12 @@ libsimple_close_range(unsigned int first, unsigned int last, unsigned int *next)
qsort(fds, n, sizeof(*fds), uintpcmp);
for (i = 0; i < n; i++) {
if (close((int)fds[i]) && errno != EBADF) {
- if (i + 1 < n)
- *next = fds[i + 1];
- else
- *next = fds[i] + (fds[i] < LIBSIMPLE_CLOSE_RANGE_MAX);
+ if (next) {
+ if (i + 1 < n)
+ *next = fds[i + 1];
+ else
+ *next = fds[i] + (fds[i] < LIBSIMPLE_CLOSE_RANGE_MAX);
+ }
free(fds);
return -1;
}
@@ -118,13 +121,15 @@ libsimple_close_range(unsigned int first, unsigned int last, unsigned int *next)
fallback:
do {
if (close((int)first) && errno != EBADF) {
- *next = first + (first < LIBSIMPLE_CLOSE_RANGE_MAX);
+ if (next)
+ *next = first + (first < LIBSIMPLE_CLOSE_RANGE_MAX);
return -1;
}
} while (first++ < last);
out:
- *next = last + (last < LIBSIMPLE_CLOSE_RANGE_MAX);
+ if (next)
+ *next = last + (last < LIBSIMPLE_CLOSE_RANGE_MAX);
errno = saved_errno;
return 0;
}
diff --git a/config.mk b/config.mk
index c7eb5ca..85ba3e0 100644
--- a/config.mk
+++ b/config.mk
@@ -1,8 +1,8 @@
PREFIX = /usr
MANPREFIX = $(PREFIX)/share/man
-CC = cc
+CC = cc -std=c11
CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_GNU_SOURCE
-CFLAGS = -std=c11 -Wall -Wextra -O2
+CFLAGS = -Wall -Wextra -O2
LDFLAGS = -s -lm
diff --git a/libsimple.h b/libsimple.h
index ba01ab5..6e5f170 100644
--- a/libsimple.h
+++ b/libsimple.h
@@ -125,6 +125,40 @@
#endif
+/* TODO doc, man, since 1.8, check which are supported by clang */
+#if defined(__GNUC__) && !defined(__clang__)
+# define LIBSIMPLE_PURE __attribute__((pure))
+# define LIBSIMPLE_CONST __attribute__((const))
+# define LIBSIMPLE_NONNULL_RETURN __attribute__((returns_nonnull))
+# define LIBSIMPLE_USE_RETURN __attribute__((warn_unused_result))
+# define LIBSIMPLE_NONNULL_ARGS(...) __attribute__((nonnull__(__VA_ARGS__)))
+# define LIBSIMPLE_NO_NULL_ARGS __attribute__((nonnull))
+# define LIBSIMPLE_RETURNS_TWICE __attribute__((returns_twice))
+# define LIBSIMPLE_UNREACHABLE __builtin_unreachable()
+# define LIBSIMPLE_EXPECT(V, LIKELY) __builtin_expect((V), (LIKELY))
+# define LIBSIMPLE_ALIGNED(P) __builtin_assume_aligned((P), sizeof(*(P)))
+# define LIBSIMPLE_ALIGNED_TO(P, A) __builtin_assume_aligned((P), (A))
+# define LIBSIMPLE_MISALIGNED(P, OFF) __builtin_assume_aligned((P), sizeof(*(P)), 0)
+# define LIBSIMPLE_MISALIGNED_FROM(P, A, OFF) __builtin_assume_aligned((P), (A), 0)
+#else
+# define LIBSIMPLE_PURE
+# define LIBSIMPLE_CONST
+# define LIBSIMPLE_NONNULL_RETURN
+# define LIBSIMPLE_USE_RETURN
+# define LIBSIMPLE_NONNULL_ARGS(...)
+# define LIBSIMPLE_NO_NULL_ARGS
+# define LIBSIMPLE_RETURNS_TWICE
+# define LIBSIMPLE_UNREACHABLE abort()
+# define LIBSIMPLE_EXPECT(V, LIKELY) (V)
+# define LIBSIMPLE_ALIGNED(P) (P)
+# define LIBSIMPLE_ALIGNED_TO(P, A) (P)
+# define LIBSIMPLE_MISALIGNED(P, OFF) (P)
+# define LIBSIMPLE_MISALIGNED_FROM(P, A, OFF) (P)
+#endif
+#define LIBSIMPLE_LIKELY(V) LIBSIMPLE_EXPECT(!!(V), 1)
+#define LIBSIMPLE_UNLIKELY(V) LIBSIMPLE_EXPECT(!!(V), 0)
+
+
#include "libsimple/overflow.h"
#include "libsimple/printf.h"
#include "libsimple/definitions.h"
@@ -211,6 +245,7 @@ libsimple_close(int *fdp__)
* @throws Any error for close(3) except EBADF
*
* @since 1.6
+ * @since 1.8 `next` can be `NULL`
*/
int libsimple_close_range(unsigned int first, unsigned int last, unsigned int *next);
#define LIBSIMPLE_CLOSE_RANGE_MAX (~0U)
diff --git a/libsimple/definitions.h b/libsimple/definitions.h
index 6fbc17f..1e39867 100644
--- a/libsimple/definitions.h
+++ b/libsimple/definitions.h
@@ -218,13 +218,117 @@
*
* This macro does not support the wide-character strings
*
- * @param STR:const char [] The string, must be a literal
- * @return :size_t The value of `strlen(STR)` as a constant expression
+ * @param STR:string literal The string (must be a literal)
+ * @return :size_t The value of `strlen(STR)` as a constant expression
*
* @since 1.0
*/
#ifndef STRLEN
-# define STRLEN(STR) (sizeof(STR) - 1)
+# define STRLEN(STR) (sizeof(STR) - 1U)
+#endif
+
+
+/**
+ * Get the length of a string, stored in as a
+ * character array, that might not be NUL-termianted
+ *
+ * Note that since arrays are passed as pointers
+ * in function arguments, function parameters
+ * declared as arrays are actually pointers and
+ * cannot be used with this macro
+ *
+ * Using this macro when `S` is a pointer,
+ * will cause the returned length to be truncated
+ * to at most `sizeof(void *)`
+ *
+ * @param S:char[] The string to get the legnth of
+ * @return The length of `S`
+ *
+ * @since 1.8
+ */
+#ifndef BUFSTRLEN
+# define BUFSTRLEN(S) (strnlen((S), sizeof(S))) /* TODO man */
+#endif
+
+
+/**
+ * This macro doesn't really do anything, but
+ * it can be used to mark that a poorly named
+ * constant is the length of a string including
+ * the NUL byte
+ *
+ * @param X:size_t Any value
+ * @return :size_t `X` as is
+ *
+ * @since 1.8
+ */
+#ifndef ISSTRSIZE
+# define ISSTRSIZE(X) (X) /* TODO man */
+#endif
+
+
+/**
+ * Macro that can be used to mark that a value
+ * is the length of a string excluding the NUL
+ * byte, but adds one to convert it to the
+ * length of the string inlcuding the NUL byte
+ *
+ * @param X:size_t String length excluding NUL byte
+ * @return :size_t String length including NUL byte
+ *
+ * @since 1.8
+ */
+#ifndef TOSTRSIZE
+# define TOSTRSIZE(X) ((X) + 1U) /* TODO man */
+#endif
+
+
+/**
+ * This macro doesn't really do anything, but
+ * it can be used to mark that a poorly named
+ * constant is the length of a string excluding
+ * the NUL byte
+ *
+ * @param X:size_t Any value
+ * @return :size_t `X` as is
+ *
+ * @since 1.8
+ */
+#ifndef ISSTRLEN
+# define ISSTRLEN(X) (X) /* TODO man */
+#endif
+
+
+/**
+ * Macro that can be used to mark that a value
+ * is the length of a string including the NUL
+ * byte, but substracts one to convert it to the
+ * length of the string exlcuding the NUL byte
+ *
+ * @param X:size_t String length including NUL byte
+ * @return :size_t String length excluding NUL byte
+ *
+ * @since 1.8
+ */
+#ifndef TOSTRLEN
+# define TOSTRLEN(X) ((X) - 1U) /* TODO man */
+#endif
+
+
+/**
+ * Limit a value to an inclusive range
+ *
+ * @param MINIMUM The minimum allowed value
+ * @param X The value to limit
+ * @param MAXIMUM The maximum allowed value
+ * @return `X` except no less than `MINIMUM` and no greater than `MAXIMUM`
+ *
+ * `MAXIMUM` must be at least `MINIMUM`
+ *
+ * @since 1.8
+ */
+#ifndef LIMITRANGE
+# define LIMITRANGE(MINIMUM, X, MAXIMUM) (MIN(MAX((MINIMUM), (X)), (MAXIMUM))) /* TODO man */
#endif
@@ -247,7 +351,7 @@
* @since 1.0
*/
#ifndef INTSTRLEN
-# define INTSTRLEN(TYPE) ((sizeof(TYPE) == 1 ? 3 : 5 * (sizeof(TYPE) / 2)) + ((TYPE)-1 < 0))
+# define INTSTRLEN(TYPE) ((CHAR_BIT * sizeof(TYPE) <= 8 ? 3 : 5 * (CHAR_BIT * sizeof(TYPE) / 16)) + ((TYPE)-1 < 0))
#endif
@@ -260,7 +364,7 @@
* @since 1.0
*/
#ifndef TYPE_MAX
-# define TYPE_MAX(TYPE) ((TYPE)(((1ULL << (8 * sizeof(TYPE) - 1)) - 1) << ((TYPE)-1 > 0) | 1))
+# define TYPE_MAX(TYPE) ((TYPE)(((1ULL << (CHAR_BIT * sizeof(TYPE) - 1)) - 1) << ((TYPE)-1 > 0) | 1))
#endif
@@ -273,7 +377,25 @@
* @since 1.0
*/
#ifndef TYPE_MIN
-# define TYPE_MIN(TYPE) ((TYPE)((TYPE)-1 > 0 ? 0 : (TYPE)~0 < (TYPE)-1 ? (TYPE)~0 : (TYPE)(1ULL << (8 * sizeof(TYPE) - 1))))
+# define TYPE_MIN(TYPE) ((TYPE)((TYPE)-1 > 0 ? 0 : (TYPE)~0 < (TYPE)-1 ? (TYPE)~0 : (TYPE)(1ULL << (CHAR_BIT * sizeof(TYPE) - 1))))
+#endif
+
+
+/* TODO man, doc, since 1.8 */
+#define LIBSIMPLE_0_TO_7 "01234567"
+#define LIBSIMPLE_0_TO_9 "0123456789"
+#define LIBSIMPLE_a_TO_f "abcdef"
+#define LIBSIMPLE_A_TO_F "ABCDEF"
+#define LIBSIMPLE_a_TO_z "abcdefghijklmnopqrstuvwxyz"
+#define LIBSIMPLE_A_TO_Z "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+#define LIBSIMPLE_0_TO_f LIBSIMPLE_0_TO_9 LIBSIMPLE_a_TO_f
+#define LIBSIMPLE_0_TO_F LIBSIMPLE_0_TO_9 LIBSIMPLE_A_TO_F
+
+
+/* TODO man, doc, since 1.8 */
+#define LIBSIMPLE_SIZEOF_MEMBER(STRUCT, MEMBER) (sizeof(((STRUCT *)NULL)->MEMBER))
+#ifndef sizeof_member
+#define sizeof_member(STRUCT, MEMBER) LIBSIMPLE_SIZEOF_MEMBER(STRUCT, MEMBER)
#endif
diff --git a/libsimple/time.h b/libsimple/time.h
index b873635..5317cfc 100644
--- a/libsimple/time.h
+++ b/libsimple/time.h
@@ -1,6 +1,45 @@
/* See LICENSE file for copyright and license details. */
+/* TODO man, doc (since 1.8) */
+#define LIBSIMPLE_NANOSECONDS_PER_NANOSECOND UINT64_C(1)
+#define LIBSIMPLE_NANOSECONDS_PER_MICROSECOND UINT64_C(1000)
+#define LIBSIMPLE_NANOSECONDS_PER_MILLISECOND (LIBSIMPLE_NANOSECONDS_PER_MICROSECOND * UINT64_C(1000))
+#define LIBSIMPLE_NANOSECONDS_PER_SECOND (LIBSIMPLE_NANOSECONDS_PER_MILLISECOND * UINT64_C(1000))
+#define LIBSIMPLE_NANOSECONDS_PER_MINUTE (LIBSIMPLE_NANOSECONDS_PER_SECOND * UINT64_C(60))
+#define LIBSIMPLE_NANOSECONDS_PER_HOUR (LIBSIMPLE_NANOSECONDS_PER_MINUTE * UINT64_C(60))
+#define LIBSIMPLE_NANOSECONDS_PER_DAY (LIBSIMPLE_NANOSECONDS_PER_HOUR * UINT64_C(24))
+#define LIBSIMPLE_NANOSECONDS_PER_WEEK (LIBSIMPLE_NANOSECONDS_PER_DAY * UINT64_C(7))
+#define LIBSIMPLE_MICROSECONDS_PER_MICROSECOND UINT64_C(1)
+#define LIBSIMPLE_MICROSECONDS_PER_MILLISECOND UINT64_C(1000)
+#define LIBSIMPLE_MICROSECONDS_PER_SECOND (LIBSIMPLE_MICROSECONDS_PER_MICROSECOND * UINT64_C(1000))
+#define LIBSIMPLE_MICROSECONDS_PER_MINUTE (LIBSIMPLE_MICROSECONDS_PER_SECOND * UINT64_C(60))
+#define LIBSIMPLE_MICROSECONDS_PER_HOUR (LIBSIMPLE_MICROSECONDS_PER_MINUTE * UINT64_C(60))
+#define LIBSIMPLE_MICROSECONDS_PER_DAY (LIBSIMPLE_MICROSECOND_PER_HOUR * UINT64_C(24))
+#define LIBSIMPLE_MICROSECONDS_PER_WEEK (LIBSIMPLE_MICROSECOND_PER_DAY * UINT64_C(7))
+#define LIBSIMPLE_MILLISECONDS_PER_MILLISECONDS UINT64_C(1)
+#define LIBSIMPLE_MILLISECONDS_PER_SECOND UINT64_C(1000)
+#define LIBSIMPLE_MILLISECONDS_PER_MINUTE (LIBSIMPLE_MILLISECONDS_PER_SECOND * UINT64_C(60))
+#define LIBSIMPLE_MILLISECONDS_PER_HOUR (LIBSIMPLE_MILLISECONDS_PER_MINUTE * UINT64_C(60))
+#define LIBSIMPLE_MILLISECONDS_PER_DAY (LIBSIMPLE_MILLISECONDS_PER_HOUR * UINT64_C(24))
+#define LIBSIMPLE_MILLISECONDS_PER_WEEK (LIBSIMPLE_MILLISECONDS_PER_DAY * UINT64_C(7))
+#define LIBSIMPLE_SECONDS_PER_SECOND UINT64_C(1)
+#define LIBSIMPLE_SECONDS_PER_MINUTE UINT64_C(60)
+#define LIBSIMPLE_SECONDS_PER_HOUR (LIBSIMPLE_SECONDS_PER_MINUTE * UINT64_C(60))
+#define LIBSIMPLE_SECONDS_PER_DAY (LIBSIMPLE_SECONDS_PER_HOUR * UINT64_C(24))
+#define LIBSIMPLE_SECONDS_PER_WEEK (LIBSIMPLE_SECONDS_PER_DAY * UINT64_C(7))
+#define LIBSIMPLE_MINUTES_PER_MINUTE UINT64_C(1)
+#define LIBSIMPLE_MINUTES_PER_HOUR UINT64_C(60)
+#define LIBSIMPLE_MINUTES_PER_DAY (LIBSIMPLE_MINUTES_PER_HOUR * UINT64_C(24))
+#define LIBSIMPLE_MINUTES_PER_WEEK (LIBSIMPLE_MINUTES_PER_DAY * UINT64_C(7))
+#define LIBSIMPLE_HOURS_PER_HOUR UINT64_C(1)
+#define LIBSIMPLE_HOURS_PER_DAY UINT64_C(24)
+#define LIBSIMPLE_HOURS_PER_WEEK (LIBSIMPLE_HOURS_PER_DAY * UINT64_C(7))
+#define LIBSIMPLE_DAYS_PER_DAY UINT64_C(1)
+#define LIBSIMPLE_DAYS_PER_WEEK UINT64_C(7)
+#define LIBSIMPLE_WEEKS_PER_WEEK UINT64_C(1)
+
+
/**
* Calculates the sum of two `struct timespec`s
*
diff --git a/man3/libsimple_close_range.3 b/man3/libsimple_close_range.3
index 76094d0..a1b172c 100644
--- a/man3/libsimple_close_range.3
+++ b/man3/libsimple_close_range.3
@@ -69,7 +69,10 @@ None.
libsimple 1.6
.SH BUGS
-None.
+.I next
+could not be
+.I NULL
+before version 1.8 of libsimple.
.SH SEE ALSO
.BR close_range (2),
diff --git a/memcasemem.c b/memcasemem.c
index b3ea476..625861a 100644
--- a/memcasemem.c
+++ b/memcasemem.c
@@ -8,7 +8,8 @@ libsimple_memcasemem(const void *hay_, size_t hayn, const void *sub_, size_t sub
{
const char *hay = hay_;
const char *sub = sub_;
- const char *end;
+ size_t *next, i, j;
+
if (!subn)
return REMOVE_CONST(hay, char *);
@@ -17,9 +18,30 @@ libsimple_memcasemem(const void *hay_, size_t hayn, const void *sub_, size_t sub
if (subn == 1)
return libsimple_memcasechr(hay, *sub, hayn);
- for (end = &hay[hayn - subn + 1]; hay != end; hay++)
- if (tolower(*hay) == tolower(*sub) && !libsimple_memcasecmp(hay, sub, subn))
+ /* TODO segment search if pattern is too large */
+ next = alloca((subn + 1U) * sizeof(*next));
+ i = 0, j = SIZE_MAX;
+ goto beginning;
+ for (; i < subn; i++, j++) {
+ if (tolower(sub[i]) == tolower(sub[j])) {
+ next[i] = next[j];
+ } else {
+ beginning:
+ next[i] = j;
+ while (j != SIZE_MAX && tolower(sub[i]) != tolower(sub[j]))
+ j = next[j];
+ }
+ }
+
+ for (i = j = 0; i < hayn;) {
+ while (j != SIZE_MAX && tolower(sub[j]) != tolower(hay[i]))
+ j = next[j];
+ i++;
+ if (++j == subn) {
+ hay = &hay[i - j];
return REMOVE_CONST(hay, char *);
+ }
+ }
return NULL;
}
diff --git a/memmem.c b/memmem.c
index 847c4f0..739f7e0 100644
--- a/memmem.c
+++ b/memmem.c
@@ -6,19 +6,41 @@
void *
libsimple_memmem(const void *hay_, size_t hayn, const void *sub_, size_t subn)
{
- const char *hay = hay_, *end;
- const char *sub = sub_;
+ const unsigned char *hay = hay_;
+ const unsigned char *sub = sub_;
+ size_t *next, i, j;
if (!subn)
- return REMOVE_CONST(hay, char *);
+ return REMOVE_CONST(hay, unsigned char *);
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 REMOVE_CONST(hay, char *);
+ /* TODO segment search if pattern is too large */
+ next = alloca((subn + 1U) * sizeof(*next));
+ i = 0, j = SIZE_MAX;
+ goto beginning;
+ for (; i < subn; i++, j++) {
+ if (sub[i] == sub[j]) {
+ next[i] = next[j];
+ } else {
+ beginning:
+ next[i] = j;
+ while (j != SIZE_MAX && sub[i] != sub[j])
+ j = next[j];
+ }
+ }
+
+ for (i = j = 0; i < hayn;) {
+ while (j != SIZE_MAX && sub[j] != hay[i])
+ j = next[j];
+ i++;
+ if (++j == subn) {
+ hay = &hay[i - j];
+ return REMOVE_CONST(hay, unsigned char *);
+ }
+ }
return NULL;
}