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 "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"
#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 character 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))
> ---
>
> 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>
>
> 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(-)
>
> 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++) == NULL)
> + if (strchr(CTYPE_HEX_C, *s++) == NULL)
This is certainly useful!
> return 0;
>
> 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 = 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 = '\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:
> }
>
>
> -static const char safe_chars[] =
> "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+@{}._-:%";
> +static const char safe_chars[] = CTYPE_PFCHAR_C "+@{}:%";
LGTM. Are those extra safe chars specified by any standard, or is it
just of this project?
>
> 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++;
>
> +/*
> + * 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 portable
> + // filename character 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=423>
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)
> }
>
> static const char *VALID_MECHANISM_CHARACTERS =
> - "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_";
> + CTYPE_UPPER_C CTYPE_DIGIT_C "-_";
LGTM.
Have a lovely day!
Alex
>
> /* This logic is derived from the libgsasl suggest code */
> static int mechlist_contains(const char *uc_mech, const char *uc_mechlist)
> 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 char
> *f, int add_outer)
> mutt_buffer_addch(d, '\'');
> }
>
> -static const char safe_chars[] =
> "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+@{}._-:%";
> +static const char safe_chars[] = CTYPE_PFCHAR_C "+@{}:%";
>
> 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[] = "0123456789ABCDEF";
> + static const char hex[] = CTYPE_UHEX_C;
> char *s0 = s;
>
> memcpy(s, "=?", 2), s += 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)
>
> static void url_pct_encode(char *dst, size_t l, const char *src)
> {
> - static const char *alph = "0123456789ABCDEF";
> + static const char *alph = CTYPE_UHEX_C;
>
> *dst = 0;
> l--;
> --
> 2.55.0
>
--
<https://www.alejandro-colomar.es>
signature.asc
Description: PGP signature
