pfix-srsd: add a -I option
[apps/pfixtools.git] / common / str.c
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 /** \addtogroup mutt_strings */
40 /*@{*/
41
42 /** \file str.c
43  * \brief Madmutt string API module implementation.
44  * \author Pierre Habouzit <madcoder@debian.org>
45  */
46
47 #include "str.h"
48
49 #ifndef __doxygen_skip__
50 #define XX 255
51 unsigned char const __m_strdigits[128] = {
52     XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX,
53     XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX,
54     XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX,
55      0,  1,  2,  3,  4,  5,  6,  7,  8,  9, XX, XX, XX, XX, XX, XX,
56     XX, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
57     25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, XX, XX, XX, XX, XX,
58     XX, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
59     25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, XX, XX, XX, XX, XX,
60 };
61 #undef XX
62
63 #define XX -1
64 signed char const __m_b64digits[128] = {
65     XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX,
66     XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX,
67     XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, 62, XX, XX, XX, 63,
68     52, 53, 54, 55, 56, 57, 58, 59, 60, 61, XX, XX, XX, XX, XX, XX,
69     XX,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
70     15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, XX, XX, XX, XX, XX,
71     XX, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
72     41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, XX, XX, XX, XX, XX
73 };
74 #undef XX
75
76 char const __m_b64chars[64] = {
77     'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
78     'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
79     'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
80     't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
81     '8', '9', '+', '/'
82 };
83
84 char const __m_b36chars_lower[36] = {
85     '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
86     'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
87     'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
88     'u', 'v', 'w', 'x', 'y', 'z'
89 };
90
91 char const __m_b36chars_upper[36] = {
92     '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
93     'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
94     'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
95     'U', 'V', 'W', 'X', 'Y', 'Z'
96 };
97 #endif
98
99 /** \brief safe strcpy.
100  *
101  * Copies at most <tt>n-1</tt> characters from \c src into \c dst, always
102  * adding a final \c \\0 in \c dst.
103  *
104  * \param[in]  dst      destination buffer.
105  * \param[in]  n        size of the buffer. Negative sizes are allowed.
106  * \param[in]  src      source string.
107  *
108  * \return \c src \e length. If this value is \>= \c n then the copy was
109  *         truncated.
110  */
111 ssize_t m_strcpy(char *dst, ssize_t n, const char *src)
112 {
113     ssize_t len = m_strlen(src);
114
115     if (n > 0) {
116         ssize_t dlen = MIN(n - 1, len);
117         memcpy(dst, src, dlen);
118         dst[dlen] = '\0';
119     }
120
121     return len;
122 }
123
124 /** \brief safe limited strcpy.
125  *
126  * Copies at most min(<tt>n-1</tt>, \c l) characters from \c src into \c dst,
127  * always adding a final \c \\0 in \c dst.
128  *
129  * \param[in]  dst      destination buffer.
130  * \param[in]  n        size of the buffer. Negative sizes are allowed.
131  * \param[in]  src      source string.
132  * \param[in]  l        maximum number of chars to copy.
133  *
134  * \return minimum of  \c src \e length and \c l.
135  */
136 ssize_t m_strncpy(char *dst, ssize_t n, const char *src, ssize_t l)
137 {
138     ssize_t len = m_strnlen(src, l);
139
140     if (n > 0) {
141         ssize_t dlen = MIN(n - 1, len);
142         memcpy(dst, src, dlen);
143         dst[dlen] = '\0';
144     }
145
146     return len;
147 }
148
149 char *m_strrtrim(char *s)
150 {
151     ssize_t len = m_strlen(s);
152
153     while (len > 1 && isspace((unsigned char)s[len - 1]))
154         s[--len] = '\0';
155
156     return s + len;
157 }
158
159 const char *m_stristrn(const char *haystack, const char *needle, ssize_t nlen)
160 {
161     int nc;
162
163     if (!nlen)
164         return haystack;
165
166     nc = tolower(*needle);
167     for (;;) {
168         int c = tolower(*haystack);
169
170         if (c != nc) {
171             if (c == '\0')
172                 return NULL;
173         } else {
174             ssize_t i;
175
176             /* compare the rest of needle */
177             for (i = 1;; i++) {
178                 if (i == nlen)
179                     return haystack;
180                 if (c == '\0')
181                     return NULL;
182                 c = tolower(haystack[i]);
183                 if (c != tolower(needle[i]))
184                     break;
185             }
186         }
187
188         haystack++;
189     }
190 }
191
192 /** \brief \c NULL resistant strcasecmp.
193  * \param[in]  a     the first string.
194  * \param[in]  b     the second string.
195  * \return <tt>strcasecmp(a, b)</tt>, and treats \c NULL strings like \c ""
196  *         ones, as if we were in the C locale.
197  */
198 int ascii_strcasecmp(const char *a, const char *b)
199 {
200     if (a == b)
201         return 0;
202     if (!a)
203         return -1;
204     if (!b)
205         return 1;
206
207     while (*a || *b) {
208         int i;
209         if ((i = ascii_tolower(*a++) - ascii_tolower(*b++)))
210             return i;
211     }
212
213     return 0;
214 }
215
216 /** \brief \c NULL resistant strncasecmp.
217  * \param[in]  a     the first string.
218  * \param[in]  b     the second string.
219  * \param[in]  n     the number of maximum chars to compare.
220  * \return <tt>strncasecmp(a, b)</tt>, and treats \c NULL strings like \c ""
221  *         ones, as if we were in the C locale.
222  */
223 int ascii_strncasecmp(const char *a, const char *b, ssize_t n)
224 {
225     if (a == b)
226         return 0;
227     if (!a)
228         return -1;
229     if (!b)
230         return 1;
231
232     while ((*a || *b) && n > 0) {
233         int i;
234         if ((i = ascii_tolower(*a++) - ascii_tolower(*b++)))
235             return i;
236         n--;
237     }
238
239     return 0;
240 }
241
242 /*@}*/