pfix-srsd: add a -I option
[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 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.                                               */
30 /*                                                                            */
31 /*   Copyright (c) 2006-2008 the Authors                                      */
32 /*   see AUTHORS and source files for details                                 */
33 /******************************************************************************/
34
35 /*
36  * Copyright © 2006 Pierre Habouzit
37  */
38
39 #ifndef PFIXTOOLS_STR_H
40 #define PFIXTOOLS_STR_H
41
42 #include "mem.h"
43
44 /** \defgroup mutt_strings Madmutt string API
45  *
46  * This module contains the prefered string API to be used in Madmutt.
47  *
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
50  * strings.
51  *
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
58  *    supported.
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.
63  *
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).
67  */
68 /*@{*/
69
70 /** \brief Convert ascii digits into ints.
71  *
72  * Convert ascii digits into its integer value in base 36.
73  * Non convertible values are converted to 255.
74  *
75  * Translating a digit \c c into its numerical value in base \c x is just doing:
76  * \code
77  *   return !(c & ~127) && __m_strdigits[c] < x ? __m_strdigits[c] : -1;
78  * \endcode
79  */
80 extern unsigned char const __m_strdigits[128];
81 /** \brief Convert an ascii base64 digit into ints.
82  *
83  * Convert an a char base64 digit into its int value.
84  * Used by base64val(). Unlike #__m_strdigits, the invalid values are set to
85  * -1 instead of 255.
86  */
87 extern signed char const __m_b64digits[128];
88
89 /** \brief Convert ints from 0&ndash;64 into the corresponding base64 digit. */
90 extern char const __m_b64chars[64];
91 /** \brief Convert ints from 0&ndash;36 into a base36 lowercase digit. */
92 extern char const __m_b36chars_lower[36];
93 /** \brief Convert ints from 0&ndash;36 into a base36 uppercase digit. */
94 extern char const __m_b36chars_upper[36];
95
96 /****************************************************************************/
97 /* conversions                                                              */
98 /****************************************************************************/
99
100 /** \brief Converts an octal digit into an int.
101  * \param[in]  c    the octal char
102  * \return
103  *   - 0&ndash;7 if c is a valid octal digit,
104  *   - -1 on error.
105  */
106 static inline int octval(int c) {
107     return !(c & ~127) && __m_strdigits[c] < 7 ? __m_strdigits[c] : -1;
108 }
109
110 /** \brief Converts an hexadecimal digit into an int.
111  * \param[in]  c    the hexadecimal char
112  * \return
113  *   - 0&ndash;15 if c is a valid hexadecimal digit,
114  *   - -1 on error.
115  */
116 static inline int hexval(int c) {
117     return !(c & ~127) && __m_strdigits[c] < 16 ? __m_strdigits[c] : -1;
118 }
119
120 /** \brief Converts a base64 digit into an int.
121  * \param[in]  c    the base64 char
122  * \return
123  *   - 0&ndash;15 if c is a valid base64 digit,
124  *   - -1 on error.
125  */
126 static inline int base64val(int c) {
127     return (c & ~127) ? -1 : __m_b64digits[c];
128 }
129
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.
133  */
134 __attribute__((nonnull(1)))
135 static inline char *m_strtolower(char *p) {
136     for (; *p; p++)
137         *p = tolower((unsigned char)*p);
138     return p;
139 }
140
141 /** \brief Converts a lower case ascii char to upper case.
142  * \param[in]  c    the character.
143  * \return the upper case character.
144  */
145 static inline int ascii_toupper(int c) {
146     if ('a' <= c && c <= 'z')
147         return c & ~32;
148
149     return c;
150 }
151
152 /** \brief Converts a upper case ascii char to lower case.
153  * \param[in]  c    the character.
154  * \return the lower case character.
155  */
156 static inline int ascii_tolower(int c) {
157     if ('A' <= c && c <= 'Z')
158         return c | 32;
159
160     return c;
161 }
162
163 /****************************************************************************/
164 /* length related                                                           */
165 /****************************************************************************/
166
167 /** \brief \c NULL resistant strlen.
168  *
169  * Unlinke it's libc sibling, m_strlen returns a ssize_t, and supports its
170  * argument beeing NULL.
171  *
172  * \param[in]  s    the string.
173  * \return the string length (or 0 if \c s is \c NULL).
174  */
175 static inline ssize_t m_strlen(const char *s) {
176     return s ? strlen(s) : 0;
177 }
178
179 /** \brief \c NULL resistant strnlen.
180  *
181  * Unlinke it's GNU libc sibling, m_strnlen returns a ssize_t, and supports
182  * its argument beeing NULL.
183  *
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.
188  *
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.
192  */
193 static inline ssize_t m_strnlen(const char *s, ssize_t n) {
194     if (s) {
195         const char *p = memchr(s, '\0', n);
196         return p ? p - s : n;
197     }
198     return 0;
199 }
200
201 /****************************************************************************/
202 /* comparisons                                                              */
203 /****************************************************************************/
204
205 int ascii_strcasecmp(const char *a, const char *b);
206 int ascii_strncasecmp(const char *a, const char *b, ssize_t n);
207
208 /****************************************************************************/
209 /* making copies                                                            */
210 /****************************************************************************/
211
212 /** \brief \c NULL resistant strdup.
213  *
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().
216  *
217  * \warning when s is \c "", it returns NULL !
218  *
219  * \param[in]  s    the string to duplicate.
220  * \return a pointer to the duplicated string.
221  */
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;
225 }
226
227 /** \brief Duplicate substrings.
228  * \deprecated API IS NOT GOOD, I WILL DEPRECATE IT IN A NEAR FUTURE.
229  */
230 static inline char *m_substrdup(const char *s, const char *end) {
231     return p_dupstr(s, end ? end - s : m_strlen(s));
232 }
233
234 /** \brief Replace an allocated string with another.
235  *
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.
238  *
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).
242  */
243 __attribute__((nonnull(1)))
244 static inline char *m_strreplace(char **p, const char *s) {
245     p_delete(p);
246     return (*p = m_strdup(s));
247 }
248
249 /** \brief Puts a char in a string buffer.
250  *
251  * Puts a char at position 0 of a string buffer of size \c n.
252  * Then \c \\0 terminate the buffer.
253  *
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.
258  */
259 __attribute__((nonnull(1)))
260 static inline ssize_t m_strputc(char *dst, ssize_t n, int c) {
261     if (n > 1) {
262         dst[0] = c;
263         dst[1] = '\0';
264     }
265     return 1;
266 }
267
268 /** \brief Sets a portion of a string to a defined character, à la memset.
269  *
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).
275  */
276 __attribute__((nonnull(1)))
277 static inline ssize_t m_strpad(char *dst, ssize_t n, int c, ssize_t len)
278 {
279     ssize_t dlen = MIN(n - 1, len);
280     if (dlen > 0) {
281         memset(dst, c, dlen);
282         dst[dlen] = '\0';
283     }
284     return MAX(0, len);
285 }
286
287 ssize_t m_strcpy(char *dst, ssize_t n, const char *src)
288     __attribute__((nonnull(1)));
289
290 ssize_t m_strncpy(char *dst, ssize_t n, const char *src, ssize_t l)
291     __attribute__((nonnull(1)));
292
293 /** \brief safe strcat.
294  *
295  * The m_strcat() function appends the string \c src at the end of the buffer
296  * \c dst if space is available.
297  *
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>
302  */
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);
306 }
307
308 /** \brief safe strncat.
309  *
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.
312  *
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>
319  */
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);
324 }
325
326 /****************************************************************************/
327 /* parsing related                                                          */
328 /****************************************************************************/
329
330 __attribute__((nonnull(1)))
331 static inline const char *m_strchrnul(const char *s, int c) {
332     while (*s && *s != c)
333         s++;
334     return s;
335 }
336
337 __attribute__((nonnull(1)))
338 static inline const char *m_strnextsp(const char *s) {
339     while (*s && !isspace((unsigned char)*s))
340         s++;
341     return s;
342 }
343
344 __attribute__((nonnull(1)))
345 static inline char *m_vstrnextsp(char *s) {
346     while (*s && !isspace((unsigned char)*s))
347         s++;
348     return s;
349 }
350
351
352 __attribute__((nonnull(1)))
353 static inline const char *skipspaces(const char *s) {
354     while (isspace((unsigned char)*s))
355         s++;
356     return s;
357 }
358 __attribute__((nonnull(1)))
359 static inline char *vskipspaces(const char *s) {
360     return (char *)skipspaces(s);
361 }
362
363 char *m_strrtrim(char *s);
364
365 /****************************************************************************/
366 /* search                                                                   */
367 /****************************************************************************/
368
369 const char *
370 m_stristrn(const char *haystack, const char *needle, ssize_t nlen);
371
372 static inline const char *
373 m_stristr(const char *haystack, const char *needle) {
374     return m_stristrn(haystack, needle, m_strlen(needle));
375 }
376
377 /****************************************************************************/
378 /* static strings                                                           */
379 /****************************************************************************/
380
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
383  * useless strlen.
384  */
385 typedef struct static_str_t {
386     const char *str;
387     ssize_t    len;
388 } static_str_t;
389
390 /*@}*/
391 #endif /* PFIXTOOLS_STR_H */