From 10ed4484b3d4bafd7a7aa287097fd612f7b9034a Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Fri, 1 Dec 2006 23:40:30 +0100 Subject: [PATCH] string documentation. Signed-off-by: Pierre Habouzit --- apidoc/doxygen.cfg.in | 11 +-- lib-lib/str.c | 66 ++++++++++++------ lib-lib/str.h | 159 +++++++++++++++++++++++++++++++++++++++--- muttlib.c | 4 +- 4 files changed, 203 insertions(+), 37 deletions(-) diff --git a/apidoc/doxygen.cfg.in b/apidoc/doxygen.cfg.in index 9c328db..708849e 100644 --- a/apidoc/doxygen.cfg.in +++ b/apidoc/doxygen.cfg.in @@ -574,13 +574,13 @@ STRIP_CODE_COMMENTS = YES # then for each documented function all documented # functions referencing it will be listed. -REFERENCED_BY_RELATION = YES +REFERENCED_BY_RELATION = NO # If the REFERENCES_RELATION tag is set to YES (the default) # then for each documented function all documented entities # called/used by that function will be listed. -REFERENCES_RELATION = YES +REFERENCES_RELATION = NO # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen @@ -709,7 +709,7 @@ TOC_EXPAND = NO # top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. -DISABLE_INDEX = YES +DISABLE_INDEX = NO # This tag can be used to set the number of enum values (range [1..20]) # that doxygen will group on one line in the generated HTML documentation. @@ -1006,14 +1006,15 @@ INCLUDE_FILE_PATTERNS = # undefined via #undef or recursively expanded use the := operator # instead of the = operator. -PREDEFINED = _DOXYGEN_SKIP_ME +PREDEFINED = __doxygen_skip__ \ + __attribute__(x)= # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition. -EXPAND_AS_DEFINED = +EXPAND_AS_DEFINED = __attribute__(x) # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all function-like macros that are alone diff --git a/lib-lib/str.c b/lib-lib/str.c index ab603da..39e6a90 100644 --- a/lib-lib/str.c +++ b/lib-lib/str.c @@ -27,7 +27,7 @@ #include "lib-lib.h" -#ifndef _DOXYGEN_SKIP_ME +#ifndef __doxygen_skip__ #define XX 255 unsigned char const __m_strdigits[128] = { XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, @@ -80,7 +80,7 @@ char const __m_b36chars_upper[36] = { /** \brief safe strcpy. * * Copies at most n-1 characters from \c src into \c dst, always - * adding a final \c '\\0' in \c dst. + * adding a final \c \\0 in \c dst. * * \param[in] dst destination buffer. * \param[in] n size of the buffer. Negative sizes are allowed. @@ -102,6 +102,18 @@ ssize_t m_strcpy(char *dst, ssize_t n, const char *src) return len; } +/** \brief safe limited strcpy. + * + * Copies at most min(n-1, \c l) characters from \c src into \c dst, + * always adding a final \c \\0 in \c dst. + * + * \param[in] dst destination buffer. + * \param[in] n size of the buffer. Negative sizes are allowed. + * \param[in] src source string. + * \param[in] l maximum number of chars to copy. + * + * \return minimum of \c src \e length and \c l. + */ ssize_t m_strncpy(char *dst, ssize_t n, const char *src, ssize_t l) { ssize_t len = MIN(m_strlen(src), l); @@ -158,39 +170,51 @@ const char *m_stristrn(const char *haystack, const char *needle, ssize_t nlen) } } +/** \brief \c NULL resistant strcasecmp. + * \param[in] a the first string. + * \param[in] b the second string. + * \return strcasecmp(a, b), and treats \c NULL strings like \c "" + * ones, as if we were in the C locale. + */ int ascii_strcasecmp(const char *a, const char *b) { - int i; - if (a == b) return 0; - if (a == NULL && b) - return -1; - if (b == NULL && a) - return 1; - - for (; *a || *b; a++, b++) { - if ((i = ascii_tolower(*a) - ascii_tolower(*b))) + if (!a) + a = ""; + if (!b) + b = ""; + + while (*a || *b) { + int i; + if ((i = ascii_tolower(*a++) - ascii_tolower(*b++))) return i; } return 0; } -int ascii_strncasecmp (const char *a, const char *b, ssize_t n) +/** \brief \c NULL resistant strncasecmp. + * \param[in] a the first string. + * \param[in] b the second string. + * \param[in] n the number of maximum chars to compare. + * \return strncasecmp(a, b), and treats \c NULL strings like \c "" + * ones, as if we were in the C locale. + */ +int ascii_strncasecmp(const char *a, const char *b, ssize_t n) { - int i, j; - if (a == b) return 0; - if (a == NULL && b) - return -1; - if (b == NULL && a) - return 1; - - for (j = 0; (*a || *b) && j < n; a++, b++, j++) { - if ((i = ascii_tolower(*a) - ascii_tolower(*b))) + if (!a) + a = ""; + if (!b) + b = ""; + + while ((*a || *b) && n >= 0) { + int i; + if ((i = ascii_tolower(*a++) - ascii_tolower(*b++))) return i; + n--; } return 0; diff --git a/lib-lib/str.h b/lib-lib/str.h index 8c793fb..3133585 100644 --- a/lib-lib/str.h +++ b/lib-lib/str.h @@ -33,16 +33,20 @@ * strings. * * The strong point that have to be followed are: - * - strings are always \c '\\0' terminated, meaning that we don't have + * - strings are always \c \\0 terminated, meaning that we don't have * stupid semantics à la strncpy. * - function try to always work on buffers with its size (including the - * ending \c '\\0') to prevent buffer overflows. + * ending \c \\0) to prevent buffer overflows. * - string and buffers sizes are \c ssize_t, negative values are allowed and * supported. * - functions use a à la sprintf semantics (for those that produce strings) * meaning that they all return the len that could have fit in the buffer * if it would have been big enough. We never try to reallocate the * buffers, it's up to the caller if it's needed. + * + * Many of the function do no difference between \c NULL and \c "" and will + * behave the same when you pass either the former or the latter (m_strlen(), + * m_strcpy(), ... to cite a few). */ /*@{*/ @@ -55,9 +59,10 @@ #define LONG_STRING 1024 /**< \brief Long buffers */ #define STRING 256 /**< \brief Usual buffers */ -#define NONULL(x) (x ? x : "") /**< \brief replace \c NULL strings - with emtpy strings */ -#define ISSPACE(c) isspace((unsigned char)c) /**< \brief safe isspace */ +/** \brief replace \c NULL strings with emtpy strings */ +#define NONULL(x) (x ? x : "") +/** \brief safe isspace */ +#define ISSPACE(c) isspace((unsigned char)c) /** \brief Convert ascii digits into ints. * @@ -66,7 +71,7 @@ * * Translating a digit \c c into its numerical value in base \c x is just doing: * \code - * return (c & ~127) && __m_strdigits[c] < x ? __m_strdigits[c] : -1; + * return !(c & ~127) && __m_strdigits[c] < x ? __m_strdigits[c] : -1; * \endcode */ extern unsigned char const __m_strdigits[128]; @@ -89,19 +94,41 @@ extern char const __m_b36chars_upper[36]; /* conversions */ /****************************************************************************/ +/** \brief Converts an hexadecimal digit into an int. + * \param[in] c the hexadecimal char + * \return + * - 0–15 if c is a valid hexadecimal digit, + * - -1 on error. + */ static inline int hexval(int c) { return !(c & ~127) && __m_strdigits[c] < 16 ? __m_strdigits[c] : -1; } +/** \brief Converts a base64 digit into an int. + * \param[in] c the base64 char + * \return + * - 0–15 if c is a valid base64 digit, + * - -1 on error. + */ static inline int base64val(int c) { return (c & ~127) ? -1 : __m_b64digits[c]; } -static inline void m_strtolower(char *p) { +/** \brief Converts a string to lowercase. + * \param[in] p the string, shall not be \c NULL. + * \return a pointer to the terminating \c \\0. + */ +__attribute__((nonnull(1))) +static inline char *m_strtolower(char *p) { for (; *p; p++) *p = tolower((unsigned char)*p); + return p; } +/** \brief Converts a lower case ascii char to upper case. + * \param[in] c the character. + * \return the upper case character. + */ static inline int ascii_toupper(int c) { if ('a' <= c && c <= 'z') return c & ~32; @@ -109,6 +136,10 @@ static inline int ascii_toupper(int c) { return c; } +/** \brief Converts a upper case ascii char to lower case. + * \param[in] c the character. + * \return the lower case character. + */ static inline int ascii_tolower(int c) { if ('A' <= c && c <= 'Z') return c | 32; @@ -120,35 +151,89 @@ static inline int ascii_tolower(int c) { /* length related */ /****************************************************************************/ +/** \brief Short hand to test if a string is empty or not. + * \param[in] s the string. + * \return \c true iff s is an empty string. + */ static inline int m_strisempty(const char *s) { return !s || !*s; } +/** \brief \c NULL resistant strlen. + * + * Unlinke it's libc sibling, m_strlen returns a ssize_t, and supports its + * argument beeing NULL. + * + * \param[in] s the string. + * \return the string length (or 0 if \c s is \c NULL). + */ static inline ssize_t m_strlen(const char *s) { return s ? strlen(s) : 0; } +/** \brief \c NULL resistant strnlen. + * + * Unlinke it's GNU libc sibling, m_strnlen returns a ssize_t, and supports + * its argument beeing NULL. + * + * The m_strnlen() function returns the number of characters in the string + * pointed to by \c s, not including the terminating \c \\0 character, but at + * most \c n. In doing this, m_strnlen() looks only at the first \c n + * characters at \c s and never beyond \c s+n. + * + * \param[in] s the string. + * \param[in] n the maximum length to return. + * \return \c m_strlen(s) if less than \c n, else \c n. + */ static inline ssize_t m_strnlen(const char *s, ssize_t n) { - const char *p = memchr(s, '\0', n); - return p ? p - s : n; + if (s) { + const char *p = memchr(s, '\0', n); + return p ? p - s : n; + } + return 0; } /****************************************************************************/ /* comparisons */ /****************************************************************************/ +/** \brief \c NULL resistant strcmp. + * \param[in] a the first string. + * \param[in] b the second string. + * \return strcmp(a, b), and treats \c NULL strings like \c "" ones. + */ static inline int m_strcmp(const char *a, const char *b) { return strcmp(NONULL(a), NONULL(b)); } +/** \brief \c NULL resistant strcasecmp. + * \param[in] a the first string. + * \param[in] b the second string. + * \return strcasecmp(a, b), and treats \c NULL strings like \c "" + * ones. + */ static inline int m_strcasecmp(const char *a, const char *b) { return strcasecmp(NONULL(a), NONULL(b)); } +/** \brief \c NULL resistant strncmp. + * \param[in] a the first string. + * \param[in] b the second string. + * \param[in] n the number of maximum chars to compare. + * \return strncmp(a, b, n), and treats \c NULL strings like \c "" + * ones. + */ static inline int m_strncmp(const char *a, const char *b, ssize_t n) { return strncmp(NONULL(a), NONULL(b), n); } +/** \brief \c NULL resistant strncasecmp. + * \param[in] a the first string. + * \param[in] b the second string. + * \param[in] n the number of maximum chars to compare. + * \return strcasecmp(a, b, n), and treats \c NULL strings like \c "" + * ones. + */ static inline int m_strncasecmp(const char *a, const char *b, ssize_t n) { return strncasecmp(NONULL(a), NONULL(b), n); } @@ -160,20 +245,54 @@ int ascii_strncasecmp(const char *a, const char *b, ssize_t n); /* making copies */ /****************************************************************************/ +/** \brief \c NULL resistant strdup. + * + * the m_strdup() function returns a pointer to a new string, which is a + * duplicate of \c s. Memory should be freed using p_delete(). + * + * \warning when s is \c "", it returns NULL ! + * + * \param[in] s the string to duplicate. + * \return a pointer to the duplicated string. + */ static inline char *m_strdup(const char *s) { ssize_t len = m_strlen(s); return len ? p_dup(s, len + 1) : NULL; } +/** \brief Duplicate substrings. + * \deprecated API IS NOT GOOD, I WILL DEPRECATE IT IN A NEAR FUTURE. + */ static inline char *m_substrdup(const char *s, const char *end) { return p_dupstr(s, end ? end - s : m_strlen(s)); } +/** \brief Replace an allocated string with another. + * + * Replace the string pointed by \c *p with a copy of the string \c s. + * \c *p must point to a buffer allocated with p_new() or one of its alias. + * + * \param[in,out] p a pointer on a string (char **) + * \param[in] s the string to copy into p. + * \return a pointer on the duplicated string (aka \c *p). + */ +__attribute__((nonnull(1))) static inline char *m_strreplace(char **p, const char *s) { p_delete(p); return (*p = m_strdup(s)); } +/** \brief Puts a char in a string buffer. + * + * Puts a char at position 0 of a string buffer of size \c n. + * Then \c \\0 terminate the buffer. + * + * \param[in] dst pointer to the buffer. + * \param[in] n size of that buffer (negative values allowed). + * \param[in] c the character to append. + * \return always return 1. + */ +__attribute__((nonnull(1))) static inline ssize_t m_strputc(char *dst, ssize_t n, int c) { if (n > 1) { dst[0] = c; @@ -188,11 +307,33 @@ ssize_t m_strcpy(char *dst, ssize_t n, const char *src) ssize_t m_strncpy(char *dst, ssize_t n, const char *src, ssize_t l) __attribute__((nonnull(1))); +/** \brief safe strcat. + * + * The m_strcat() function appends the string \c src at the end of the buffer + * \c dst if space is available. + * + * \param[in] dst destination buffer. + * \param[in] n size of the buffer, Negative sizes are allowed. + * \param[in] src the string to append. + * \return m_strlen(dst) + m_strlen(src) + */ static inline ssize_t m_strcat(char *dst, ssize_t n, const char *src) { ssize_t dlen = m_strnlen(dst, n - 1); return dlen + m_strcpy(dst + dlen, n - dlen, src); } +/** \brief safe strncat. + * + * The m_strncat() function appends at most \c n chars from the string \c src + * at the end of the buffer \c dst if space is available. + * + * \param[in] dst destination buffer. + * \param[in] n size of the buffer, Negative sizes are allowed. + * \param[in] src the string to append. + * \param[in] l maximum number of chars of src to consider. + * \return the smallest value between m_strlen(dst) + m_strlen(src) + * and m_strlen(dst) + l + */ static inline ssize_t m_strncat(char *dst, ssize_t n, const char *src, ssize_t l) { ssize_t dlen = m_strnlen(dst, n - 1); diff --git a/muttlib.c b/muttlib.c index 1f8ab30..590b53a 100644 --- a/muttlib.c +++ b/muttlib.c @@ -750,7 +750,7 @@ int mutt_extract_token(BUFFER *dest, BUFFER *tok, int flags) if (!*tok->dptr) return -1; /* premature end of token */ mutt_buffer_addch(dest, - (ascii_toupper(*tok->dptr) - 'A' + 1) & 0x7f); + (toupper((unsigned char)*tok->dptr) - 'A' + 1) & 0x7f); tok->dptr++; break; case 'r': @@ -792,7 +792,7 @@ int mutt_extract_token(BUFFER *dest, BUFFER *tok, int flags) mutt_buffer_addch(dest, '\033'); } else if (isalpha((unsigned char)ch)) { - mutt_buffer_addch(dest, ascii_toupper(ch) - 'A' + 1); + mutt_buffer_addch(dest, toupper((unsigned char)ch) - 'A' + 1); } else { mutt_buffer_addch(dest, '^'); mutt_buffer_addch(dest, ch); -- 2.20.1