1 /******************************************************************************/
2 /* pfixtools: a collection of postfix related tools */
4 /* ________________________________________________________________________ */
6 /* Redistribution and use in source and binary forms, with or without */
7 /* modification, are permitted provided that the following conditions */
10 /* 1. Redistributions of source code must retain the above copyright */
11 /* notice, this list of conditions and the following disclaimer. */
12 /* 2. Redistributions in binary form must reproduce the above copyright */
13 /* notice, this list of conditions and the following disclaimer in the */
14 /* documentation and/or other materials provided with the distribution. */
15 /* 3. The names of its contributors may not be used to endorse or promote */
16 /* products derived from this software without specific prior written */
19 /* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS */
20 /* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED */
21 /* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE */
22 /* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY */
23 /* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL */
24 /* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS */
25 /* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) */
26 /* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, */
27 /* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN */
28 /* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE */
29 /* POSSIBILITY OF SUCH DAMAGE. */
31 /* Copyright (c) 2006-2008 the Authors */
32 /* see AUTHORS and source files for details */
33 /******************************************************************************/
36 * Copyright © 2006 Pierre Habouzit
39 #ifndef PFIXTOOLS_STR_H
40 #define PFIXTOOLS_STR_H
44 /** \defgroup mutt_strings Madmutt string API
46 * This module contains the prefered string API to be used in Madmutt.
48 * Those function reimplement many usual calls (strlen, strcpy, strcat, …)
49 * It's intended to provide a uniform and consistent API to deal with usual C
52 * The strong point that have to be followed are:
53 * - strings are always \c \\0 terminated, meaning that we don't have
54 * stupid semantics à la strncpy.
55 * - function try to always work on buffers with its size (including the
56 * ending \c \\0) to prevent buffer overflows.
57 * - string and buffers sizes are \c ssize_t, negative values are allowed and
59 * - functions use a à la sprintf semantics (for those that produce strings)
60 * meaning that they all return the len that could have fit in the buffer
61 * if it would have been big enough. We never try to reallocate the
62 * buffers, it's up to the caller if it's needed.
64 * Many of the function do no difference between \c NULL and \c "" and will
65 * behave the same when you pass either the former or the latter (m_strlen(),
66 * m_strcpy(), ... to cite a few).
70 /** \brief Convert ascii digits into ints.
72 * Convert ascii digits into its integer value in base 36.
73 * Non convertible values are converted to 255.
75 * Translating a digit \c c into its numerical value in base \c x is just doing:
77 * return !(c & ~127) && __m_strdigits[c] < x ? __m_strdigits[c] : -1;
80 extern unsigned char const __m_strdigits[128];
81 /** \brief Convert an ascii base64 digit into ints.
83 * Convert an a char base64 digit into its int value.
84 * Used by base64val(). Unlike #__m_strdigits, the invalid values are set to
87 extern signed char const __m_b64digits[128];
89 /** \brief Convert ints from 0–64 into the corresponding base64 digit. */
90 extern char const __m_b64chars[64];
91 /** \brief Convert ints from 0–36 into a base36 lowercase digit. */
92 extern char const __m_b36chars_lower[36];
93 /** \brief Convert ints from 0–36 into a base36 uppercase digit. */
94 extern char const __m_b36chars_upper[36];
96 /****************************************************************************/
98 /****************************************************************************/
100 /** \brief Converts an octal digit into an int.
101 * \param[in] c the octal char
103 * - 0–7 if c is a valid octal digit,
106 static inline int octval(int c) {
107 return !(c & ~127) && __m_strdigits[c] < 7 ? __m_strdigits[c] : -1;
110 /** \brief Converts an hexadecimal digit into an int.
111 * \param[in] c the hexadecimal char
113 * - 0–15 if c is a valid hexadecimal digit,
116 static inline int hexval(int c) {
117 return !(c & ~127) && __m_strdigits[c] < 16 ? __m_strdigits[c] : -1;
120 /** \brief Converts a base64 digit into an int.
121 * \param[in] c the base64 char
123 * - 0–15 if c is a valid base64 digit,
126 static inline int base64val(int c) {
127 return (c & ~127) ? -1 : __m_b64digits[c];
130 /** \brief Converts a string to lowercase.
131 * \param[in] p the string, shall not be \c NULL.
132 * \return a pointer to the terminating \c \\0.
134 __attribute__((nonnull(1)))
135 static inline char *m_strtolower(char *p) {
137 *p = tolower((unsigned char)*p);
141 /** \brief Converts a lower case ascii char to upper case.
142 * \param[in] c the character.
143 * \return the upper case character.
145 static inline int ascii_toupper(int c) {
146 if ('a' <= c && c <= 'z')
152 /** \brief Converts a upper case ascii char to lower case.
153 * \param[in] c the character.
154 * \return the lower case character.
156 static inline int ascii_tolower(int c) {
157 if ('A' <= c && c <= 'Z')
163 /****************************************************************************/
165 /****************************************************************************/
167 /** \brief \c NULL resistant strlen.
169 * Unlinke it's libc sibling, m_strlen returns a ssize_t, and supports its
170 * argument beeing NULL.
172 * \param[in] s the string.
173 * \return the string length (or 0 if \c s is \c NULL).
175 static inline ssize_t m_strlen(const char *s) {
176 return s ? strlen(s) : 0;
179 /** \brief \c NULL resistant strnlen.
181 * Unlinke it's GNU libc sibling, m_strnlen returns a ssize_t, and supports
182 * its argument beeing NULL.
184 * The m_strnlen() function returns the number of characters in the string
185 * pointed to by \c s, not including the terminating \c \\0 character, but at
186 * most \c n. In doing this, m_strnlen() looks only at the first \c n
187 * characters at \c s and never beyond \c s+n.
189 * \param[in] s the string.
190 * \param[in] n the maximum length to return.
191 * \return \c m_strlen(s) if less than \c n, else \c n.
193 static inline ssize_t m_strnlen(const char *s, ssize_t n) {
195 const char *p = memchr(s, '\0', n);
196 return p ? p - s : n;
201 /****************************************************************************/
203 /****************************************************************************/
205 int ascii_strcasecmp(const char *a, const char *b);
206 int ascii_strncasecmp(const char *a, const char *b, ssize_t n);
208 /****************************************************************************/
210 /****************************************************************************/
212 /** \brief \c NULL resistant strdup.
214 * the m_strdup() function returns a pointer to a new string, which is a
215 * duplicate of \c s. Memory should be freed using p_delete().
217 * \warning when s is \c "", it returns NULL !
219 * \param[in] s the string to duplicate.
220 * \return a pointer to the duplicated string.
222 static inline char *m_strdup(const char *s) {
223 ssize_t len = m_strlen(s);
224 return len ? p_dup(s, len + 1) : NULL;
227 /** \brief Duplicate substrings.
228 * \deprecated API IS NOT GOOD, I WILL DEPRECATE IT IN A NEAR FUTURE.
230 static inline char *m_substrdup(const char *s, const char *end) {
231 return p_dupstr(s, end ? end - s : m_strlen(s));
234 /** \brief Replace an allocated string with another.
236 * Replace the string pointed by \c *p with a copy of the string \c s.
237 * \c *p must point to a buffer allocated with p_new() or one of its alias.
239 * \param[in,out] p a pointer on a string (<tt>char **</tt>)
240 * \param[in] s the string to copy into p.
241 * \return a pointer on the duplicated string (aka \c *p).
243 __attribute__((nonnull(1)))
244 static inline char *m_strreplace(char **p, const char *s) {
246 return (*p = m_strdup(s));
249 /** \brief Puts a char in a string buffer.
251 * Puts a char at position 0 of a string buffer of size \c n.
252 * Then \c \\0 terminate the buffer.
254 * \param[in] dst pointer to the buffer.
255 * \param[in] n size of that buffer (negative values allowed).
256 * \param[in] c the character to append.
257 * \return always return 1.
259 __attribute__((nonnull(1)))
260 static inline ssize_t m_strputc(char *dst, ssize_t n, int c) {
268 /** \brief Sets a portion of a string to a defined character, à la memset.
270 * \param[in] dst pointer to the buffer.
271 * \param[in] n size of that buffer, (negative values allowed).
272 * \param[in] c the char to use in the padding.
273 * \param[in] len length of the padding.
274 * \return MAX(0, len).
276 __attribute__((nonnull(1)))
277 static inline ssize_t m_strpad(char *dst, ssize_t n, int c, ssize_t len)
279 ssize_t dlen = MIN(n - 1, len);
281 memset(dst, c, dlen);
287 ssize_t m_strcpy(char *dst, ssize_t n, const char *src)
288 __attribute__((nonnull(1)));
290 ssize_t m_strncpy(char *dst, ssize_t n, const char *src, ssize_t l)
291 __attribute__((nonnull(1)));
293 /** \brief safe strcat.
295 * The m_strcat() function appends the string \c src at the end of the buffer
296 * \c dst if space is available.
298 * \param[in] dst destination buffer.
299 * \param[in] n size of the buffer, Negative sizes are allowed.
300 * \param[in] src the string to append.
301 * \return <tt>m_strlen(dst) + m_strlen(src)</tt>
303 static inline ssize_t m_strcat(char *dst, ssize_t n, const char *src) {
304 ssize_t dlen = m_strnlen(dst, n - 1);
305 return dlen + m_strcpy(dst + dlen, n - dlen, src);
308 /** \brief safe strncat.
310 * The m_strncat() function appends at most \c n chars from the string \c src
311 * at the end of the buffer \c dst if space is available.
313 * \param[in] dst destination buffer.
314 * \param[in] n size of the buffer, Negative sizes are allowed.
315 * \param[in] src the string to append.
316 * \param[in] l maximum number of chars of src to consider.
317 * \return the smallest value between <tt>m_strlen(dst) + m_strlen(src)</tt>
318 * and <tt>m_strlen(dst) + l</tt>
320 static inline ssize_t
321 m_strncat(char *dst, ssize_t n, const char *src, ssize_t l) {
322 ssize_t dlen = m_strnlen(dst, n - 1);
323 return dlen + m_strncpy(dst + dlen, n - dlen, src, l);
326 /****************************************************************************/
327 /* parsing related */
328 /****************************************************************************/
330 __attribute__((nonnull(1)))
331 static inline const char *m_strchrnul(const char *s, int c) {
332 while (*s && *s != c)
337 __attribute__((nonnull(1)))
338 static inline const char *m_strnextsp(const char *s) {
339 while (*s && !isspace((unsigned char)*s))
344 __attribute__((nonnull(1)))
345 static inline char *m_vstrnextsp(char *s) {
346 while (*s && !isspace((unsigned char)*s))
352 __attribute__((nonnull(1)))
353 static inline const char *skipspaces(const char *s) {
354 while (isspace((unsigned char)*s))
358 __attribute__((nonnull(1)))
359 static inline char *vskipspaces(const char *s) {
360 return (char *)skipspaces(s);
363 char *m_strrtrim(char *s);
365 /****************************************************************************/
367 /****************************************************************************/
370 m_stristrn(const char *haystack, const char *needle, ssize_t nlen);
372 static inline const char *
373 m_stristr(const char *haystack, const char *needle) {
374 return m_stristrn(haystack, needle, m_strlen(needle));
377 /****************************************************************************/
379 /****************************************************************************/
381 /** Store a pointer to a string with a pre-computed length.
382 * This intends to store pointers to a part of a longer string and to avoid
385 typedef struct static_str_t {
391 #endif /* PFIXTOOLS_STR_H */