Re: [PATCH v2 1/2] Add CTYPE defines for various sets of characters.
Alejandro Colomar via Mutt-dev <[email protected]> Tue, 4 Aug 2026 13:50:16 +0200
| Newsgroups | gmane.mail.mutt.devel |
|---|---|
| Message-ID | <anHJtLAKsiqIbWbF@devuan> |
--b6zvpv5kpg5tbwuo Content-Type: text/plain; protected-headers=v1; charset=utf-8 Content-Disposition: inline Content-Transfer-Encoding: quoted-printable From: Alejandro Colomar <[email protected]> To: [email protected] Subject: Re: [PATCH v2 1/2] Add CTYPE defines for various sets of characters. Message-ID: <anHJtLAKsiqIbWbF@devuan> References: <[email protected]> <[email protected]> MIME-Version: 1.0 In-Reply-To: <[email protected]> Hi Kevin, > Date: 2026-08-04 13:18:19+0800 > From: "Kevin J. McCarthy" <[email protected]> > > Thanks to Alejandro Colomar for this suggestion, and I used his > examples directly for LOWER_C to PFCHAR_C. The HEX additions are > mine, so you can blame those on me. ;-) :-) Actually, since there's the standard [:xdigit:] and isxdigit(3), I'd call it (and actually called it in shadow-utils) CTYPE_XDIGIT_C: #define CTYPE_XDIGIT_C CTYPE_DIGIT_C "abcdefABCDEF" Here's the full set of APIs I have (they may inspire you to add a few more similar ones): #define CTYPE_CNTRL_C \ "\x7F" \ "\x1F\x1E\x1D\x1C\x1B\x1A\x19\x18\x17\x16\x15\x14\x13\x12\x11\x10" \ "\x0F\x0E\x0D\x0C\x0B\x0A\x09\x08\x07\x06\x05\x04\x03\x02\x01" /*NUL*/ #define CTYPE_LOWER_C "abcdefghijklmnopqrstuvwxyz" #define CTYPE_UPPER_C "ABCDEFGHIJKLMNOPQRSTUVWXYZ" #define CTYPE_DIGIT_C "0123456789" #define CTYPE_PUNCT_C "!\"#$%&'()*+,-./:;<=3D>?@[\\]^_`{|}~" #define CTYPE_BLANK_C " \t" #define CTYPE_SPACE_C CTYPE_BLANK_C "\n\v\f\r" #define CTYPE_ALPHA_C CTYPE_LOWER_C CTYPE_UPPER_C #define CTYPE_ALNUM_C CTYPE_ALPHA_C CTYPE_DIGIT_C #define CTYPE_GRAPH_C CTYPE_ALNUM_C CTYPE_PUNCT_C #define CTYPE_PRINT_C CTYPE_GRAPH_C " " #define CTYPE_XDIGIT_C CTYPE_DIGIT_C "abcdefABCDEF" #define CTYPE_ASCII_C CTYPE_PRINT_C CTYPE_CNTRL_C /*NUL*/ #define CTYPE_PFCHAR_C CTYPE_ALNUM_C "._-" // portable filename c= haracter set #define CTYPE_LDH_RFC1035_C CTYPE_ALNUM_C "-" // letter, digit, hyphen // isascii_c - is [:ascii:] C-locale #define isascii_c(c) (!!strchr(CTYPE_ASCII_C, c)) #define iscntrl_c(c) (!!strchr(CTYPE_CNTRL_C, c)) #define islower_c(c) (!streq(strchrnul(CTYPE_LOWER_C, c), "")) #define isupper_c(c) (!streq(strchrnul(CTYPE_UPPER_C, c), "")) #define isdigit_c(c) (!streq(strchrnul(CTYPE_DIGIT_C, c), "")) #define ispunct_c(c) (!streq(strchrnul(CTYPE_PUNCT_C, c), "")) #define isblank_c(c) (!streq(strchrnul(CTYPE_BLANK_C, c), "")) #define isspace_c(c) (!streq(strchrnul(CTYPE_SPACE_C, c), "")) #define isalpha_c(c) (!streq(strchrnul(CTYPE_ALPHA_C, c), "")) #define isalnum_c(c) (!streq(strchrnul(CTYPE_ALNUM_C, c), "")) #define isgraph_c(c) (!streq(strchrnul(CTYPE_GRAPH_C, c), "")) #define isprint_c(c) (!streq(strchrnul(CTYPE_PRINT_C, c), "")) #define isxdigit_c(c) (!streq(strchrnul(CTYPE_XDIGIT_C, c), "")) #define ispfchar_c(c) (!streq(strchrnul(CTYPE_PFCHAR_C, c), "")) #define isldh_rfc1035_c(c) (!streq(strchrnul(CTYPE_LDH_RFC1035_C, c), = "")) // strisascii_c - string is [:ascii:] C-locale #define strisdigit_c(s) streq(stpspn(s, CTYPE_DIGIT_C), "") #define strisprint_c(s) streq(stpspn(s, CTYPE_PRINT_C), "") #define strispfchar_c(s) streq(stpspn(s, CTYPE_PFCHAR_C), "") #define strisldh_rfc1035_c(s) streq(stpspn(s, CTYPE_LDH_RFC1035_C), "") // strchriscntrl_c - string character is [:cntrl:] C-locale #define strchriscntrl_c(s) (!!strpbrk(s, CTYPE_CNTRL_C)) > --- >=20 > Please let me know what you think. Does it help readability for the > cases where we use the CTYPE along with extra characters? > e.g. imap/command.c, lib.c, muttlib.c below. Yup, IMO. Where thr RFCs use a name for that, I'd give them a new name (see for example, CTYPE_LDH_RFC1035_C above, which corresponds to RFC1035's <ldh-str>), but where there's not a standard-ish name, I guess direct use like this is fine. <https://www.rfc-editor.org/info/rfc1035/#section-2.3.1> >=20 > crypt.c | 2 +- > imap/command.c | 2 +- > lib.c | 2 +- > lib.h | 13 +++++++++++++ > mutt_sasl_gnu.c | 2 +- > muttlib.c | 2 +- > rfc2047.c | 2 +- > url.c | 2 +- > 8 files changed, 20 insertions(+), 7 deletions(-) >=20 > diff --git a/crypt.c b/crypt.c > index e4c8051d..d141ac6f 100644 > --- a/crypt.c > +++ b/crypt.c > @@ -1295,7 +1295,7 @@ short crypt_is_numerical_keyid(const char *s) > if (strlen(s) % 8) > return 0; > while (*s) > - if (strchr("0123456789ABCDEFabcdef", *s++) =3D=3D NULL) > + if (strchr(CTYPE_HEX_C, *s++) =3D=3D NULL) This is certainly useful! > return 0; > =20 > return 1; > diff --git a/imap/command.c b/imap/command.c > index 63dedf6c..94c98883 100644 > --- a/imap/command.c > +++ b/imap/command.c > @@ -701,7 +701,7 @@ static void cmd_parse_vanished(IMAP_DATA *idata, char= *s) > end_of_seqset =3D s; > while (*end_of_seqset) > { > - if (!strchr("0123456789:,", *end_of_seqset)) > + if (!strchr(CTYPE_DIGIT_C ":,", *end_of_seqset)) I wonder if this character set has any name in RFC 7162. I can't find it, though. The only reference to DIGIT seems to be in mod-sequence-value. > *end_of_seqset =3D '\0'; > else > end_of_seqset++; > diff --git a/lib.c b/lib.c > index 9776fcdb..fdecda25 100644 > --- a/lib.c > +++ b/lib.c > @@ -573,7 +573,7 @@ success: > } > =20 > =20 > -static const char safe_chars[] =3D "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghij= klmnopqrstuvwxyz0123456789+@{}._-:%"; > +static const char safe_chars[] =3D CTYPE_PFCHAR_C "+@{}:%"; LGTM. Are those extra safe chars specified by any standard, or is it just of this project? > =20 > void mutt_sanitize_filename(char *f, int flags) > { > diff --git a/lib.h b/lib.h > index 25875656..b622e9c0 100644 > --- a/lib.h > +++ b/lib.h > @@ -147,6 +147,19 @@ static inline char *skip_email_wsp(const char *s) > on some systems */ > #define SKIP_LOCALE_WS(c) while (*(c) && IS_LOCALE_WS(*(c))) c++; > =20 > +/* > + * Various useful sets of characters > + */ > +#define CTYPE_LOWER_C "abcdefghijklmnopqrstuvwxyz" > +#define CTYPE_UPPER_C "ABCDEFGHIJKLMNOPQRSTUVWXYZ" > +#define CTYPE_DIGIT_C "0123456789" > +#define CTYPE_ALPHA_C CTYPE_LOWER_C CTYPE_UPPER_C > +#define CTYPE_ALNUM_C CTYPE_ALPHA_C CTYPE_DIGIT_C > +#define CTYPE_PFCHAR_C CTYPE_ALNUM_C "._-" // POSIX.1-2008 port= able > + // filename characte= r set Actually, that was already true as of POSIX.1-2001 (Issue 6); the first modern-day POSIX, where POSIX and SUS (the Single UNIX Specification) were unified I suspect this was already true way earlier, since I see a reference to the 'portable filename character set' in XPG Issue 4 (v2) (from which modern-day POSIX derives). <https://pubs.opengroup.org/onlinepubs/009656499/toc.pdf#page=3D423> I don't see the the definition of the p.f.c.s. in that document, because it was in a separate volume, and I can't find it. It's also difficult to find older standards, unless you know where they are. :) > +#define CTYPE_UHEX_C CTYPE_DIGIT_C "ABCDEF" // uppercase hex Hmmm, I'd maybe call this UXDIGIT? (Considering that the below would be XDIGIT, per the usual standards.) > +#define CTYPE_HEX_C CTYPE_UHEX_C "abcdef" > + > /* > * These functions aren't defined in lib.c, but > * they are used there. > diff --git a/mutt_sasl_gnu.c b/mutt_sasl_gnu.c > index 9a7a4b87..2bd5afbf 100644 > --- a/mutt_sasl_gnu.c > +++ b/mutt_sasl_gnu.c > @@ -66,7 +66,7 @@ void mutt_gsasl_done(void) > } > =20 > static const char *VALID_MECHANISM_CHARACTERS =3D > - "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"; > + CTYPE_UPPER_C CTYPE_DIGIT_C "-_"; LGTM. Have a lovely day! Alex > =20 > /* This logic is derived from the libgsasl suggest code */ > static int mechlist_contains(const char *uc_mech, const char *uc_mechlis= t) > diff --git a/muttlib.c b/muttlib.c > index d24a37f0..ee29cc17 100644 > --- a/muttlib.c > +++ b/muttlib.c > @@ -1178,7 +1178,7 @@ void _mutt_buffer_quote_filename(BUFFER *d, const c= har *f, int add_outer) > mutt_buffer_addch(d, '\''); > } > =20 > -static const char safe_chars[] =3D "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghij= klmnopqrstuvwxyz0123456789+@{}._-:%"; > +static const char safe_chars[] =3D CTYPE_PFCHAR_C "+@{}:%"; > =20 > void mutt_buffer_sanitize_filename(BUFFER *d, const char *f, int flags) > { > diff --git a/rfc2047.c b/rfc2047.c > index 2bdd8553..1bacb54f 100644 > --- a/rfc2047.c > +++ b/rfc2047.c > @@ -257,7 +257,7 @@ static size_t b_encoder(char *s, ICONV_CONST char *d,= size_t dlen, > static size_t q_encoder(char *s, ICONV_CONST char *d, size_t dlen, > const char *tocode) > { > - static const char hex[] =3D "0123456789ABCDEF"; > + static const char hex[] =3D CTYPE_UHEX_C; > char *s0 =3D s; > =20 > memcpy(s, "=3D?", 2), s +=3D 2; > diff --git a/url.c b/url.c > index 02dbf34c..176877cd 100644 > --- a/url.c > +++ b/url.c > @@ -193,7 +193,7 @@ int url_parse_ciss(ciss_url_t *ciss, char *src) > =20 > static void url_pct_encode(char *dst, size_t l, const char *src) > { > - static const char *alph =3D "0123456789ABCDEF"; > + static const char *alph =3D CTYPE_UHEX_C; > =20 > *dst =3D 0; > l--; > --=20 > 2.55.0 >=20 --=20 <https://www.alejandro-colomar.es> --b6zvpv5kpg5tbwuo Content-Type: application/pgp-signature; name="signature.asc" -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEES7Jt9u9GbmlWADAi64mZXMKQwqkFAmpx0fIACgkQ64mZXMKQ wqlPZA/8DF1wZPbxxXkzWAIiLoA1yNLBwrb+YUFJGRNowLfgqB2bVrgnPbsfXP0U WBgt55ZKuAe0nCEr9cGQZN6G7GteSqBHqghfSzgd3zPmkGJfnfbQbyzS5dCB5iGI jj6WdlDDE+ZRXGiHX33KeMictMKuXpgYwd+EuENlnwWRyggIC9KxKRIcnOkpaQ/V WYTFEFrUoCzQJAsOMD3BqndHKToCJCPgCSFVL/NdmlXxspu0q2P2Rd6cOrmejjHq S8HC2Bs2o/crRUp1zHV3wbRC1Pt37ax9fUrDnkMhPeqf1sbQZaHjj0S1ni65AT2f +vr9CHBEYJk5wvAKcFWl+gzuEgTINi5TMtsxF6c9qVLuhQSsc8WQsBfbRXWDlGoo tqYSboRa/X7MUvtXdbUu+nTyQRXn9XtJ7riNJx9zyACsUwcCjUeT1rCRivB3uiOE zMIalUrB/41oBsts1GfozemZj01gIxe+Lv52qgBV0KI4eOtmL3X673zPvNeLQeEm IeIIvm8I4JGBPKB1ONX9jluYfcT32iRmveFC/yNkuHn+kTOsFHoSdu5b8hUEYG7y 9nk2Q1Ld+5q723tjqxAspTL0Tyvqy90A+k8aOZSWbDzK8VnY8utXUHRSUdOW+oB4 W+WngQlSwy9QoVUHAPbLmGX8qk5j5n65CCnrcKWEgCTgAtDcrKg= =2MkP -----END PGP SIGNATURE----- --b6zvpv5kpg5tbwuo--