From fcc4316b28ecc353595ec3efd98b101494a0d2ae Mon Sep 17 00:00:00 2001
From: Thomas Voss <mail@thomasvoss.com>
Date: Tue, 16 Apr 2024 02:14:07 +0200
Subject: Add _attrs.h for function attributes

---
 gen/prop/bool-props      |   2 +-
 include/_attrs.h         |   5 +-
 include/errors.h         |  11 ++--
 include/optparse.h       |   3 +-
 include/unicode/prop.h   | 165 +++++++++++++++++++++++------------------------
 include/unicode/string.h |  16 +++--
 6 files changed, 103 insertions(+), 99 deletions(-)

diff --git a/gen/prop/bool-props b/gen/prop/bool-props
index bac9ac7..3d806b5 100755
--- a/gen/prop/bool-props
+++ b/gen/prop/bool-props
@@ -91,7 +91,7 @@ for prop in $props3; do gen $prop emoji-data & done
 for prop in $props4; do gen $prop DerivedNormalizationProps & done
 for prop in $props5; do gen $prop DerivedBinaryProperties & done
 
-printf '[[__mlib_uprop_attrs]] bool uprop_is_%s(rune);\n' \
+printf '[[_mlib_pure]] bool uprop_is_%s(rune);\n' \
 	$(printf '%s\n' $props1 $props2 $props3 $props4 $props5 | cut -d= -f1) \
 | gawk '
 	/PROP PREDICATES END/ { no = 0 }
diff --git a/include/_attrs.h b/include/_attrs.h
index 513a5c7..d3ab3e8 100644
--- a/include/_attrs.h
+++ b/include/_attrs.h
@@ -1,7 +1,8 @@
 #ifndef MLIB__ATTRS_H
 #define MLIB__ATTRS_H
 
-#define _mlib_pure __nodiscard__, __unsequenced__
-#define _mlib_inline gnu::__always_inline__, clang::__always_inline__
+#define _mlib_pure         __nodiscard__, __unsequenced__
+#define _mlib_inline       gnu::__always_inline__, clang::__always_inline__
+#define _mlib_printf(n, m) gnu::__format__(printf, n, m)
 
 #endif /* !MLIB__ATTRS_H */
diff --git a/include/errors.h b/include/errors.h
index 1e5d41f..1cd6b70 100644
--- a/include/errors.h
+++ b/include/errors.h
@@ -3,18 +3,19 @@
 
 #include <stdarg.h>
 
-[[gnu::__format__(printf, 1, 2)]] void warn(const char *, ...);
+#include "_attrs.h"
+
+[[_mlib_printf(1, 2)]] void warn(const char *, ...);
 void vwarn(const char *, va_list);
 
-[[__noreturn__, gnu::__format__(printf, 1, 2)]] void err(const char *, ...);
-[[__noreturn__, gnu::__format__(printf, 2, 3)]] void cerr(int, const char *,
-                                                          ...);
+[[__noreturn__, _mlib_printf(1, 2)]] void err(const char *, ...);
+[[__noreturn__, _mlib_printf(2, 3)]] void cerr(int, const char *, ...);
 
 extern const char *__mlib_errors_progname;
 
 void mlib_setprogname(const char *);
 
-[[gnu::__always_inline__]]
+[[_mlib_inline]]
 static inline const char *
 mlib_progname(void)
 {
diff --git a/include/optparse.h b/include/optparse.h
index 62358df..9fce9e7 100644
--- a/include/optparse.h
+++ b/include/optparse.h
@@ -6,6 +6,7 @@
 #include "__charN_t.h"
 #include "__rune.h"
 #include "__u8view.h"
+#include "_attrs.h"
 
 struct optparse {
 	bool _b;
@@ -32,7 +33,7 @@ struct op_option {
 [[__nodiscard__]] rune optparse(struct optparse *, const struct op_option *,
                                 size_t);
 
-[[gnu::__always_inline__]]
+[[_mlib_inline]]
 static inline struct optparse
 mkoptparser(char **argv)
 {
diff --git a/include/unicode/prop.h b/include/unicode/prop.h
index c22fb33..485a0cb 100644
--- a/include/unicode/prop.h
+++ b/include/unicode/prop.h
@@ -6,8 +6,7 @@
 
 #include "__rune.h"
 #include "__u8view.h"
-
-#define __mlib_uprop_attrs __nodiscard__, __unsequenced__
+#include "_attrs.h"
 
 struct rview {
 	const rune *p;
@@ -73,14 +72,14 @@ enum uprop_age : uint_least16_t {
 	AGE_V15_1 = (15 << 8) | 1,
 };
 
-[[__mlib_uprop_attrs, gnu::__always_inline__]]
+[[_mlib_pure, _mlib_inline]]
 static inline int
 uprop_age_major(enum uprop_age a)
 {
 	return a >> 8;
 }
 
-[[__mlib_uprop_attrs, gnu::__always_inline__]]
+[[_mlib_pure, _mlib_inline]]
 static inline int
 uprop_age_minor(enum uprop_age a)
 {
@@ -753,90 +752,90 @@ enum uprop_sc {
 };
 
 /* Not a Unicode property; but a nice-to-have */
-[[__mlib_uprop_attrs]] struct u8view uprop_blkname(enum uprop_blk);
+[[_mlib_pure]] struct u8view uprop_blkname(enum uprop_blk);
 
-[[__mlib_uprop_attrs]] double uprop_get_nv(rune);
-[[__mlib_uprop_attrs]] enum uprop_age uprop_get_age(rune);
-[[__mlib_uprop_attrs]] enum uprop_bc uprop_get_bc(rune);
-[[__mlib_uprop_attrs]] enum uprop_blk uprop_get_blk(rune);
-[[__mlib_uprop_attrs]] enum uprop_bpt uprop_get_bpt(rune);
-[[__mlib_uprop_attrs]] enum uprop_dt uprop_get_dt(rune);
-[[__mlib_uprop_attrs]] enum uprop_ea uprop_get_ea(rune);
-[[__mlib_uprop_attrs]] enum uprop_gc uprop_get_gc(rune);
-[[__mlib_uprop_attrs]] enum uprop_lb uprop_get_lb(rune);
-[[__mlib_uprop_attrs]] enum uprop_nt uprop_get_nt(rune);
-[[__mlib_uprop_attrs]] enum uprop_sc uprop_get_sc(rune);
-[[__mlib_uprop_attrs]] rune uprop_get_bmg(rune);
-[[__mlib_uprop_attrs]] rune uprop_get_bpb(rune);
-[[__mlib_uprop_attrs]] rune uprop_get_scf(rune, bool);
-[[__mlib_uprop_attrs]] rune uprop_get_slc(rune);
-[[__mlib_uprop_attrs]] rune uprop_get_stc(rune);
-[[__mlib_uprop_attrs]] rune uprop_get_suc(rune);
-[[__mlib_uprop_attrs]] struct rview uprop_get_cf(rune, bool);
-[[__mlib_uprop_attrs]] struct rview uprop_get_lc(rune, struct lcctx);
-[[__mlib_uprop_attrs]] struct rview uprop_get_tc(rune, struct tcctx);
-[[__mlib_uprop_attrs]] struct rview uprop_get_uc(rune, struct ucctx);
-[[__mlib_uprop_attrs]] struct u8view uprop_get_na1(rune);
-[[__mlib_uprop_attrs]] struct u8view uprop_get_na(rune);
+[[_mlib_pure]] double uprop_get_nv(rune);
+[[_mlib_pure]] enum uprop_age uprop_get_age(rune);
+[[_mlib_pure]] enum uprop_bc uprop_get_bc(rune);
+[[_mlib_pure]] enum uprop_blk uprop_get_blk(rune);
+[[_mlib_pure]] enum uprop_bpt uprop_get_bpt(rune);
+[[_mlib_pure]] enum uprop_dt uprop_get_dt(rune);
+[[_mlib_pure]] enum uprop_ea uprop_get_ea(rune);
+[[_mlib_pure]] enum uprop_gc uprop_get_gc(rune);
+[[_mlib_pure]] enum uprop_lb uprop_get_lb(rune);
+[[_mlib_pure]] enum uprop_nt uprop_get_nt(rune);
+[[_mlib_pure]] enum uprop_sc uprop_get_sc(rune);
+[[_mlib_pure]] rune uprop_get_bmg(rune);
+[[_mlib_pure]] rune uprop_get_bpb(rune);
+[[_mlib_pure]] rune uprop_get_scf(rune, bool);
+[[_mlib_pure]] rune uprop_get_slc(rune);
+[[_mlib_pure]] rune uprop_get_stc(rune);
+[[_mlib_pure]] rune uprop_get_suc(rune);
+[[_mlib_pure]] struct rview uprop_get_cf(rune, bool);
+[[_mlib_pure]] struct rview uprop_get_lc(rune, struct lcctx);
+[[_mlib_pure]] struct rview uprop_get_tc(rune, struct tcctx);
+[[_mlib_pure]] struct rview uprop_get_uc(rune, struct ucctx);
+[[_mlib_pure]] struct u8view uprop_get_na1(rune);
+[[_mlib_pure]] struct u8view uprop_get_na(rune);
 
 /* PROP PREDICATES START */
-[[__mlib_uprop_attrs]] bool uprop_is_ahex(rune);
-[[__mlib_uprop_attrs]] bool uprop_is_alpha(rune);
-[[__mlib_uprop_attrs]] bool uprop_is_bidi_c(rune);
-[[__mlib_uprop_attrs]] bool uprop_is_bidi_m(rune);
-[[__mlib_uprop_attrs]] bool uprop_is_cased(rune);
-[[__mlib_uprop_attrs]] bool uprop_is_ci(rune);
-[[__mlib_uprop_attrs]] bool uprop_is_cwcf(rune);
-[[__mlib_uprop_attrs]] bool uprop_is_cwcm(rune);
-[[__mlib_uprop_attrs]] bool uprop_is_cwkcf(rune);
-[[__mlib_uprop_attrs]] bool uprop_is_cwl(rune);
-[[__mlib_uprop_attrs]] bool uprop_is_cwt(rune);
-[[__mlib_uprop_attrs]] bool uprop_is_cwu(rune);
-[[__mlib_uprop_attrs]] bool uprop_is_dash(rune);
-[[__mlib_uprop_attrs]] bool uprop_is_dep(rune);
-[[__mlib_uprop_attrs]] bool uprop_is_di(rune);
-[[__mlib_uprop_attrs]] bool uprop_is_dia(rune);
-[[__mlib_uprop_attrs]] bool uprop_is_ebase(rune);
-[[__mlib_uprop_attrs]] bool uprop_is_ecomp(rune);
-[[__mlib_uprop_attrs]] bool uprop_is_emod(rune);
-[[__mlib_uprop_attrs]] bool uprop_is_emoji(rune);
-[[__mlib_uprop_attrs]] bool uprop_is_epres(rune);
-[[__mlib_uprop_attrs]] bool uprop_is_ext(rune);
-[[__mlib_uprop_attrs]] bool uprop_is_extpic(rune);
-[[__mlib_uprop_attrs]] bool uprop_is_gr_base(rune);
-[[__mlib_uprop_attrs]] bool uprop_is_gr_ext(rune);
-[[__mlib_uprop_attrs]] bool uprop_is_hex(rune);
-[[__mlib_uprop_attrs]] bool uprop_is_id_compat_math_continue(rune);
-[[__mlib_uprop_attrs]] bool uprop_is_id_compat_math_start(rune);
-[[__mlib_uprop_attrs]] bool uprop_is_idc(rune);
-[[__mlib_uprop_attrs]] bool uprop_is_ideo(rune);
-[[__mlib_uprop_attrs]] bool uprop_is_ids(rune);
-[[__mlib_uprop_attrs]] bool uprop_is_idsb(rune);
-[[__mlib_uprop_attrs]] bool uprop_is_incb(rune);
-[[__mlib_uprop_attrs]] bool uprop_is_loe(rune);
-[[__mlib_uprop_attrs]] bool uprop_is_lower(rune);
-[[__mlib_uprop_attrs]] bool uprop_is_math(rune);
-[[__mlib_uprop_attrs]] bool uprop_is_pat_syn(rune);
-[[__mlib_uprop_attrs]] bool uprop_is_pat_ws(rune);
-[[__mlib_uprop_attrs]] bool uprop_is_pcm(rune);
-[[__mlib_uprop_attrs]] bool uprop_is_qmark(rune);
-[[__mlib_uprop_attrs]] bool uprop_is_radical(rune);
-[[__mlib_uprop_attrs]] bool uprop_is_sd(rune);
-[[__mlib_uprop_attrs]] bool uprop_is_sterm(rune);
-[[__mlib_uprop_attrs]] bool uprop_is_term(rune);
-[[__mlib_uprop_attrs]] bool uprop_is_uideo(rune);
-[[__mlib_uprop_attrs]] bool uprop_is_upper(rune);
-[[__mlib_uprop_attrs]] bool uprop_is_vs(rune);
-[[__mlib_uprop_attrs]] bool uprop_is_wspace(rune);
-[[__mlib_uprop_attrs]] bool uprop_is_xidc(rune);
-[[__mlib_uprop_attrs]] bool uprop_is_xids(rune);
+[[_mlib_pure]] bool uprop_is_ahex(rune);
+[[_mlib_pure]] bool uprop_is_alpha(rune);
+[[_mlib_pure]] bool uprop_is_bidi_c(rune);
+[[_mlib_pure]] bool uprop_is_bidi_m(rune);
+[[_mlib_pure]] bool uprop_is_cased(rune);
+[[_mlib_pure]] bool uprop_is_ci(rune);
+[[_mlib_pure]] bool uprop_is_cwcf(rune);
+[[_mlib_pure]] bool uprop_is_cwcm(rune);
+[[_mlib_pure]] bool uprop_is_cwkcf(rune);
+[[_mlib_pure]] bool uprop_is_cwl(rune);
+[[_mlib_pure]] bool uprop_is_cwt(rune);
+[[_mlib_pure]] bool uprop_is_cwu(rune);
+[[_mlib_pure]] bool uprop_is_dash(rune);
+[[_mlib_pure]] bool uprop_is_dep(rune);
+[[_mlib_pure]] bool uprop_is_di(rune);
+[[_mlib_pure]] bool uprop_is_dia(rune);
+[[_mlib_pure]] bool uprop_is_ebase(rune);
+[[_mlib_pure]] bool uprop_is_ecomp(rune);
+[[_mlib_pure]] bool uprop_is_emod(rune);
+[[_mlib_pure]] bool uprop_is_emoji(rune);
+[[_mlib_pure]] bool uprop_is_epres(rune);
+[[_mlib_pure]] bool uprop_is_ext(rune);
+[[_mlib_pure]] bool uprop_is_extpic(rune);
+[[_mlib_pure]] bool uprop_is_gr_base(rune);
+[[_mlib_pure]] bool uprop_is_gr_ext(rune);
+[[_mlib_pure]] bool uprop_is_hex(rune);
+[[_mlib_pure]] bool uprop_is_id_compat_math_continue(rune);
+[[_mlib_pure]] bool uprop_is_id_compat_math_start(rune);
+[[_mlib_pure]] bool uprop_is_idc(rune);
+[[_mlib_pure]] bool uprop_is_ideo(rune);
+[[_mlib_pure]] bool uprop_is_ids(rune);
+[[_mlib_pure]] bool uprop_is_idsb(rune);
+[[_mlib_pure]] bool uprop_is_incb(rune);
+[[_mlib_pure]] bool uprop_is_loe(rune);
+[[_mlib_pure]] bool uprop_is_lower(rune);
+[[_mlib_pure]] bool uprop_is_math(rune);
+[[_mlib_pure]] bool uprop_is_pat_syn(rune);
+[[_mlib_pure]] bool uprop_is_pat_ws(rune);
+[[_mlib_pure]] bool uprop_is_pcm(rune);
+[[_mlib_pure]] bool uprop_is_qmark(rune);
+[[_mlib_pure]] bool uprop_is_radical(rune);
+[[_mlib_pure]] bool uprop_is_sd(rune);
+[[_mlib_pure]] bool uprop_is_sterm(rune);
+[[_mlib_pure]] bool uprop_is_term(rune);
+[[_mlib_pure]] bool uprop_is_uideo(rune);
+[[_mlib_pure]] bool uprop_is_upper(rune);
+[[_mlib_pure]] bool uprop_is_vs(rune);
+[[_mlib_pure]] bool uprop_is_wspace(rune);
+[[_mlib_pure]] bool uprop_is_xidc(rune);
+[[_mlib_pure]] bool uprop_is_xids(rune);
 /* PROP PREDICATES END */
 
 /* Manually implemented predicates */
-[[__mlib_uprop_attrs]] bool uprop_is_idst(rune);
-[[__mlib_uprop_attrs]] bool uprop_is_idsu(rune);
-[[__mlib_uprop_attrs]] bool uprop_is_join_c(rune);
-[[__mlib_uprop_attrs]] bool uprop_is_nchar(rune);
-[[__mlib_uprop_attrs]] bool uprop_is_ri(rune);
+[[_mlib_pure]] bool uprop_is_idst(rune);
+[[_mlib_pure]] bool uprop_is_idsu(rune);
+[[_mlib_pure]] bool uprop_is_join_c(rune);
+[[_mlib_pure]] bool uprop_is_nchar(rune);
+[[_mlib_pure]] bool uprop_is_ri(rune);
 
 #endif /* !MLIB_UNICODE_PROP_H */
diff --git a/include/unicode/string.h b/include/unicode/string.h
index d80f04c..3a8c77a 100644
--- a/include/unicode/string.h
+++ b/include/unicode/string.h
@@ -17,14 +17,16 @@ enum [[clang::__flag_enum__]] caseflags {
 
 /* clang-format on */
 
-size_t u8glen(const char8_t *, size_t);
+[[__nodiscard__]] size_t u8glen(const char8_t *, size_t);
 size_t u8gnext(struct u8view *, const char8_t **, size_t *);
 
-size_t u8casefold(char8_t *restrict, size_t, const char8_t *, size_t,
-                  enum caseflags);
-size_t u8lower(char8_t *restrict, size_t, const char8_t *, size_t,
-               enum caseflags);
-size_t u8upper(char8_t *restrict, size_t, const char8_t *, size_t,
-               enum caseflags);
+#define _mlib_warn_trunc __nodiscard__("don’t forget to check for truncation")
+
+[[_mlib_warn_trunc]] size_t u8casefold(char8_t *restrict, size_t,
+                                       const char8_t *, size_t, enum caseflags);
+[[_mlib_warn_trunc]] size_t u8lower(char8_t *restrict, size_t, const char8_t *,
+                                    size_t, enum caseflags);
+[[_mlib_warn_trunc]] size_t u8upper(char8_t *restrict, size_t, const char8_t *,
+                                    size_t, enum caseflags);
 
 #endif /* !MLIB_UNICODE_STRING_H */
-- 
cgit v1.2.3