diff options
| -rw-r--r-- | LICENSE | 2 | ||||
| -rw-r--r-- | close_range.c | 19 | ||||
| -rw-r--r-- | config.mk | 4 | ||||
| -rw-r--r-- | libsimple.h | 35 | ||||
| -rw-r--r-- | libsimple/definitions.h | 134 | ||||
| -rw-r--r-- | libsimple/time.h | 39 | ||||
| -rw-r--r-- | man3/libsimple_close_range.3 | 5 | ||||
| -rw-r--r-- | memcasemem.c | 28 | ||||
| -rw-r--r-- | memmem.c | 34 |
9 files changed, 274 insertions, 26 deletions
@@ -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; } @@ -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; } @@ -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; } |
