+ssize_t m_strwidth(const char *s);
+
+/****************************************************************************/
+/* comparisons */
+/****************************************************************************/
+
+/** \brief Tells whether s begins with p.
+ *
+ * \param[in] s the input string
+ * \param[in] p the prefix
+ * \param[out] pp position in s
+ *
+ * \return 1 if a match is found, 0 otherwise.
+ */
+static inline int m_strstart(const char *s, const char *p, const char **pp)
+{
+ if (!s)
+ return 0;
+
+ while (*p) {
+ if (ascii_tolower(*s++) != ascii_tolower(*p++))
+ return 0;
+ }
+ if (pp)
+ *pp = s;
+ return 1;
+}
+
+/** \brief Tells whether s begins with p, case insensitive.
+ *
+ * \param[in] s the input string
+ * \param[in] p the prefix
+ * \param[out] pp position in s
+ *
+ * \return 1 if a match is found, 0 otherwise.
+ */
+static inline int m_strcasestart(const char *s, const char *p, const char **pp)
+{
+ if (!s)
+ return 0;
+
+ while (*p) {
+ if (*s++ != *p++)
+ return 0;
+ }
+ if (pp)
+ *pp = s;
+ return 1;
+}
+
+/** \brief \c NULL resistant strcmp.
+ * \param[in] a the first string.
+ * \param[in] b the second string.
+ * \return <tt>strcmp(a, b)</tt>, 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 <tt>strcasecmp(a, b)</tt>, 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 <tt>strncmp(a, b, n)</tt>, 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 <tt>strcasecmp(a, b, n)</tt>, 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);
+}
+
+int ascii_strcasecmp(const char *a, const char *b);
+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.
+ */