Move some code.
[apps/pfixtools.git] / common / str.h
1 /******************************************************************************/
2 /*          pfixtools: a collection of postfix related tools                  */
3 /*          ~~~~~~~~~                                                         */
4 /*  ________________________________________________________________________  */
5 /*                                                                            */
6 /*  Redistribution and use in source and binary forms, with or without        */
7 /*  modification, are permitted provided that the following conditions        */
8 /*  are met:                                                                  */
9 /*                                                                            */
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     */
17 /*     permission.                                                            */
18 /*                                                                            */
19 /*  THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND   */
20 /*  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE     */
21 /*  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR        */
22 /*  PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS    */
23 /*  BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR    */
24 /*  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF      */
25 /*  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  */
26 /*  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN   */
27 /*  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)   */
28 /*  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF    */
29 /*  THE POSSIBILITY OF SUCH DAMAGE.                                           */
30 /******************************************************************************/
31
32 /*
33  * Copyright © 2006 Pierre Habouzit
34  */
35
36 #ifndef PFIXTOOLS_STR_H
37 #define PFIXTOOLS_STR_H
38
39 #include "mem.h"
40
41 /** \defgroup mutt_strings Madmutt string API
42  *
43  * This module contains the prefered string API to be used in Madmutt.
44  *
45  * Those function reimplement many usual calls (strlen, strcpy, strcat, …)
46  * It's intended to provide a uniform and consistent API to deal with usual C
47  * strings.
48  *
49  * The strong point that have to be followed are:
50  *  - strings are always \c \\0 terminated, meaning that we don't have
51  *    stupid semantics à la strncpy.
52  *  - function try to always work on buffers with its size (including the
53  *    ending \c \\0) to prevent buffer overflows.
54  *  - string and buffers sizes are \c ssize_t, negative values are allowed and
55  *    supported.
56  *  - functions use a à la sprintf semantics (for those that produce strings)
57  *    meaning that they all return the len that could have fit in the buffer
58  *    if it would have been big enough. We never try to reallocate the
59  *    buffers, it's up to the caller if it's needed.
60  *
61  * Many of the function do no difference between \c NULL and \c "" and will
62  * behave the same when you pass either the former or the latter (m_strlen(),
63  * m_strcpy(), ... to cite a few).
64  */
65 /*@{*/
66
67 /** \brief Convert ascii digits into ints.
68  *
69  * Convert ascii digits into its integer value in base 36.
70  * Non convertible values are converted to 255.
71  *
72  * Translating a digit \c c into its numerical value in base \c x is just doing:
73  * \code
74  *   return !(c & ~127) && __m_strdigits[c] < x ? __m_strdigits[c] : -1;
75  * \endcode
76  */
77 extern unsigned char const __m_strdigits[128];
78 /** \brief Convert an ascii base64 digit into ints.
79  *
80  * Convert an a char base64 digit into its int value.
81  * Used by base64val(). Unlike #__m_strdigits, the invalid values are set to
82  * -1 instead of 255.
83  */
84 extern signed char const __m_b64digits[128];
85
86 /** \brief Convert ints from 0&ndash;64 into the corresponding base64 digit. */
87 extern char const __m_b64chars[64];
88 /** \brief Convert ints from 0&ndash;36 into a base36 lowercase digit. */
89 extern char const __m_b36chars_lower[36];
90 /** \brief Convert ints from 0&ndash;36 into a base36 uppercase digit. */
91 extern char const __m_b36chars_upper[36];
92
93 /****************************************************************************/
94 /* conversions                                                              */
95 /****************************************************************************/
96
97 /** \brief Converts an octal digit into an int.
98  * \param[in]  c    the octal char
99  * \return
100  *   - 0&ndash;7 if c is a valid octal digit,
101  *   - -1 on error.
102  */
103 static inline int octval(int c) {
104     return !(c & ~127) && __m_strdigits[c] < 7 ? __m_strdigits[c] : -1;
105 }
106
107 /** \brief Converts an hexadecimal digit into an int.
108  * \param[in]  c    the hexadecimal char
109  * \return
110  *   - 0&ndash;15 if c is a valid hexadecimal digit,
111  *   - -1 on error.
112  */
113 static inline int hexval(int c) {
114     return !(c & ~127) && __m_strdigits[c] < 16 ? __m_strdigits[c] : -1;
115 }
116
117 /** \brief Converts a base64 digit into an int.
118  * \param[in]  c    the base64 char
119  * \return
120  *   - 0&ndash;15 if c is a valid base64 digit,
121  *   - -1 on error.
122  */
123 static inline int base64val(int c) {
124     return (c & ~127) ? -1 : __m_b64digits[c];
125 }
126
127 /** \brief Converts a string to lowercase.
128  * \param[in] p     the string, shall not be \c NULL.
129  * \return a pointer to the terminating \c \\0.
130  */
131 __attribute__((nonnull(1)))
132 static inline char *m_strtolower(char *p) {
133     for (; *p; p++)
134         *p = tolower((unsigned char)*p);
135     return p;
136 }
137
138 /** \brief Converts a lower case ascii char to upper case.
139  * \param[in]  c    the character.
140  * \return the upper case character.
141  */
142 static inline int ascii_toupper(int c) {
143     if ('a' <= c && c <= 'z')
144         return c & ~32;
145
146     return c;
147 }
148
149 /** \brief Converts a upper case ascii char to lower case.
150  * \param[in]  c    the character.
151  * \return the lower case character.
152  */
153 static inline int ascii_tolower(int c) {
154     if ('A' <= c && c <= 'Z')
155         return c | 32;
156
157     return c;
158 }
159
160 /****************************************************************************/
161 /* length related                                                           */
162 /****************************************************************************/
163
164 /** \brief \c NULL resistant strlen.
165  *
166  * Unlinke it's libc sibling, m_strlen returns a ssize_t, and supports its
167  * argument beeing NULL.
168  *
169  * \param[in]  s    the string.
170  * \return the string length (or 0 if \c s is \c NULL).
171  */
172 static inline ssize_t m_strlen(const char *s) {
173     return s ? strlen(s) : 0;
174 }
175
176 /** \brief \c NULL resistant strnlen.
177  *
178  * Unlinke it's GNU libc sibling, m_strnlen returns a ssize_t, and supports
179  * its argument beeing NULL.
180  *
181  * The m_strnlen() function returns the number of characters in the string
182  * pointed to by \c s, not including the terminating \c \\0 character, but at
183  * most \c n. In doing this, m_strnlen() looks only at the first \c n
184  * characters at \c s and never beyond \c s+n.
185  *
186  * \param[in]  s    the string.
187  * \param[in]  n    the maximum length to return.
188  * \return \c m_strlen(s) if less than \c n, else \c n.
189  */
190 static inline ssize_t m_strnlen(const char *s, ssize_t n) {
191     if (s) {
192         const char *p = memchr(s, '\0', n);
193         return p ? p - s : n;
194     }
195     return 0;
196 }
197
198 /****************************************************************************/
199 /* comparisons                                                              */
200 /****************************************************************************/
201
202 int ascii_strcasecmp(const char *a, const char *b);
203 int ascii_strncasecmp(const char *a, const char *b, ssize_t n);
204
205 /****************************************************************************/
206 /* making copies                                                            */
207 /****************************************************************************/
208
209 /** \brief \c NULL resistant strdup.
210  *
211  * the m_strdup() function returns a pointer to a new string, which is a
212  * duplicate of \c s. Memory should be freed using p_delete().
213  *
214  * \warning when s is \c "", it returns NULL !
215  *
216  * \param[in]  s    the string to duplicate.
217  * \return a pointer to the duplicated string.
218  */
219 static inline char *m_strdup(const char *s) {
220     ssize_t len = m_strlen(s);
221     return len ? p_dup(s, len + 1) : NULL;
222 }
223
224 /** \brief Duplicate substrings.
225  * \deprecated API IS NOT GOOD, I WILL DEPRECATE IT IN A NEAR FUTURE.
226  */
227 static inline char *m_substrdup(const char *s, const char *end) {
228     return p_dupstr(s, end ? end - s : m_strlen(s));
229 }
230
231 /** \brief Replace an allocated string with another.
232  *
233  * Replace the string pointed by \c *p with a copy of the string \c s.
234  * \c *p must point to a buffer allocated with p_new() or one of its alias.
235  *
236  * \param[in,out]  p    a pointer on a string (<tt>char **</tt>)
237  * \param[in]      s    the string to copy into p.
238  * \return a pointer on the duplicated string (aka \c *p).
239  */
240 __attribute__((nonnull(1)))
241 static inline char *m_strreplace(char **p, const char *s) {
242     p_delete(p);
243     return (*p = m_strdup(s));
244 }
245
246 /** \brief Puts a char in a string buffer.
247  *
248  * Puts a char at position 0 of a string buffer of size \c n.
249  * Then \c \\0 terminate the buffer.
250  *
251  * \param[in]  dst   pointer to the buffer.
252  * \param[in]  n     size of that buffer (negative values allowed).
253  * \param[in]  c     the character to append.
254  * \return always return 1.
255  */
256 __attribute__((nonnull(1)))
257 static inline ssize_t m_strputc(char *dst, ssize_t n, int c) {
258     if (n > 1) {
259         dst[0] = c;
260         dst[1] = '\0';
261     }
262     return 1;
263 }
264
265 /** \brief Sets a portion of a string to a defined character, à la memset.
266  *
267  * \param[in]  dst  pointer to the buffer.
268  * \param[in]  n    size of that buffer, (negative values allowed).
269  * \param[in]  c    the char to use in the padding.
270  * \param[in]  len  length of the padding.
271  * \return MAX(0, len).
272  */
273 __attribute__((nonnull(1)))
274 static inline ssize_t m_strpad(char *dst, ssize_t n, int c, ssize_t len)
275 {
276     ssize_t dlen = MIN(n - 1, len);
277     if (dlen > 0) {
278         memset(dst, c, dlen);
279         dst[dlen] = '\0';
280     }
281     return MAX(0, len);
282 }
283
284 ssize_t m_strcpy(char *dst, ssize_t n, const char *src)
285     __attribute__((nonnull(1)));
286
287 ssize_t m_strncpy(char *dst, ssize_t n, const char *src, ssize_t l)
288     __attribute__((nonnull(1)));
289
290 /** \brief safe strcat.
291  *
292  * The m_strcat() function appends the string \c src at the end of the buffer
293  * \c dst if space is available.
294  *
295  * \param[in]  dst   destination buffer.
296  * \param[in]  n     size of the buffer, Negative sizes are allowed.
297  * \param[in]  src   the string to append.
298  * \return <tt>m_strlen(dst) + m_strlen(src)</tt>
299  */
300 static inline ssize_t m_strcat(char *dst, ssize_t n, const char *src) {
301     ssize_t dlen = m_strnlen(dst, n - 1);
302     return dlen + m_strcpy(dst + dlen, n - dlen, src);
303 }
304
305 /** \brief safe strncat.
306  *
307  * The m_strncat() function appends at most \c n chars from the string \c src
308  * at the end of the buffer \c dst if space is available.
309  *
310  * \param[in]  dst   destination buffer.
311  * \param[in]  n     size of the buffer, Negative sizes are allowed.
312  * \param[in]  src   the string to append.
313  * \param[in]  l     maximum number of chars of src to consider.
314  * \return the smallest value between <tt>m_strlen(dst) + m_strlen(src)</tt>
315  *         and <tt>m_strlen(dst) + l</tt>
316  */
317 static inline ssize_t
318 m_strncat(char *dst, ssize_t n, const char *src, ssize_t l) {
319     ssize_t dlen = m_strnlen(dst, n - 1);
320     return dlen + m_strncpy(dst + dlen, n - dlen, src, l);
321 }
322
323 /****************************************************************************/
324 /* parsing related                                                          */
325 /****************************************************************************/
326
327 __attribute__((nonnull(1)))
328 static inline const char *m_strchrnul(const char *s, int c) {
329     while (*s && *s != c)
330         s++;
331     return s;
332 }
333
334 __attribute__((nonnull(1)))
335 static inline const char *m_strnextsp(const char *s) {
336     while (*s && !isspace((unsigned char)*s))
337         s++;
338     return s;
339 }
340
341 __attribute__((nonnull(1)))
342 static inline char *m_vstrnextsp(char *s) {
343     while (*s && !isspace((unsigned char)*s))
344         s++;
345     return s;
346 }
347
348
349 __attribute__((nonnull(1)))
350 static inline const char *skipspaces(const char *s) {
351     while (isspace((unsigned char)*s))
352         s++;
353     return s;
354 }
355 __attribute__((nonnull(1)))
356 static inline char *vskipspaces(const char *s) {
357     return (char *)skipspaces(s);
358 }
359
360 char *m_strrtrim(char *s);
361
362 /****************************************************************************/
363 /* search                                                                   */
364 /****************************************************************************/
365
366 const char *
367 m_stristrn(const char *haystack, const char *needle, ssize_t nlen);
368
369 static inline const char *
370 m_stristr(const char *haystack, const char *needle) {
371     return m_stristrn(haystack, needle, m_strlen(needle));
372 }
373
374 /*@}*/
375 #endif /* PFIXTOOLS_STR_H */