initial commit
[profile/ivi/xterm.git] / xstrings.c
1 /* $XTermId: xstrings.c,v 1.37 2010/04/04 22:34:17 tom Exp $ */
2
3 /************************************************************
4
5 Copyright 2000-2009,2010 by Thomas E. Dickey
6
7                         All Rights Reserved
8
9 Permission is hereby granted, free of charge, to any person obtaining a
10 copy of this software and associated documentation files (the
11 "Software"), to deal in the Software without restriction, including
12 without limitation the rights to use, copy, modify, merge, publish,
13 distribute, sublicense, and/or sell copies of the Software, and to
14 permit persons to whom the Software is furnished to do so, subject to
15 the following conditions:
16
17 The above copyright notice and this permission notice shall be included
18 in all copies or substantial portions of the Software.
19
20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23 IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
24 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
25 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
26 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27
28 Except as contained in this notice, the name(s) of the above copyright
29 holders shall not be used in advertising or otherwise to promote the
30 sale, use or other dealings in this Software without prior written
31 authorization.
32
33 ********************************************************/
34
35 #include <xterm.h>
36
37 #include <sys/types.h>
38 #include <stdio.h>
39 #include <string.h>
40 #include <ctype.h>
41
42 #include <xstrings.h>
43
44 char *
45 x_basename(char *name)
46 {
47     char *cp;
48
49     cp = strrchr(name, '/');
50 #ifdef __UNIXOS2__
51     if (cp == 0)
52         cp = strrchr(name, '\\');
53 #endif
54     return (cp ? cp + 1 : name);
55 }
56
57 /*
58  * Decode a hexadecimal string, returning the decoded string.
59  * On return, 'next' points to the first character not part of the input.
60  * The caller must free the result.
61  */
62 char *
63 x_decode_hex(const char *source, const char **next)
64 {
65     char *result = 0;
66     int pass;
67     size_t j, k;
68
69     for (pass = 0; pass < 2; ++pass) {
70         for (j = k = 0; isxdigit(CharOf(source[j])); ++j) {
71             if ((pass != 0) && (j & 1) != 0) {
72                 result[k++] = (char) ((x_hex2int(source[j - 1]) << 4)
73                                       | x_hex2int(source[j]));
74             }
75         }
76         *next = (source + j);
77         if ((j & 1) == 0) {
78             if (pass) {
79                 result[k] = '\0';
80             } else {
81                 result = malloc(++j);
82                 if (result == 0)
83                     break;      /* not enough memory */
84             }
85         } else {
86             break;              /* must have an even number of digits */
87         }
88     }
89     return result;
90 }
91
92 /*
93  * Encode a string into hexadecimal, returning the encoded string.
94  * The caller must free the result.
95  */
96 char *
97 x_encode_hex(const char *source)
98 {
99     size_t need = (strlen(source) * 2) + 1;
100     char *result = malloc(need);
101
102     if (result != 0) {
103         unsigned j, k;
104         for (j = k = 0; source[j] != '\0'; ++j) {
105             sprintf(result + k, "%02X", CharOf(source[j]));
106             k += 2;
107         }
108     }
109     return result;
110 }
111
112 char *
113 x_getenv(const char *name)
114 {
115     return x_strdup(x_nonempty(getenv(name)));
116 }
117
118 /*
119  * Decode a single hex "nibble", returning the nibble as 0-15, or -1 on error.
120  */ int
121 x_hex2int(int c)
122 {
123     if (c >= '0' && c <= '9')
124         return c - '0';
125     if (c >= 'a' && c <= 'f')
126         return c - 'a' + 10;
127     if (c >= 'A' && c <= 'F')
128         return c - 'A' + 10;
129     return -1;
130 }
131
132 /*
133  * Check if the given string is nonnull/nonempty.  If so, return a pointer
134  * to the beginning of its content, otherwise return null.
135  */
136 String
137 x_nonempty(String s)
138 {
139     if (s != 0) {
140         if (*s == '\0') {
141             s = 0;
142         } else {
143             s = x_skip_blanks(s);
144             if (*s == '\0')
145                 s = 0;
146         }
147     }
148     return s;
149 }
150
151 String
152 x_skip_blanks(String s)
153 {
154     while (isspace(CharOf(*s)))
155         ++s;
156     return s;
157 }
158
159 String
160 x_skip_nonblanks(String s)
161 {
162     while (*s != '\0' && !isspace(CharOf(*s)))
163         ++s;
164     return s;
165 }
166
167 int
168 x_strcasecmp(const char *s1, const char *s2)
169 {
170     size_t len = strlen(s1);
171
172     if (len != strlen(s2))
173         return 1;
174
175     return x_strncasecmp(s1, s2, (unsigned) len);
176 }
177
178 int
179 x_strncasecmp(const char *s1, const char *s2, unsigned n)
180 {
181     while (n-- != 0) {
182         char c1 = x_toupper(*s1);
183         char c2 = x_toupper(*s2);
184         if (c1 != c2)
185             return 1;
186         if (c1 == 0)
187             break;
188         s1++, s2++;
189     }
190
191     return 0;
192 }
193
194 /*
195  * Allocates a copy of a string
196  */
197 char *
198 x_strdup(const char *s)
199 {
200     char *result = 0;
201
202     if (s != 0) {
203         char *t = CastMallocN(char, strlen(s));
204         if (t != 0) {
205             strcpy(t, s);
206         }
207         result = t;
208     }
209     return result;
210 }
211
212 /*
213  * Returns a pointer to the first occurrence of s2 in s1,
214  * or NULL if there are none.
215  */
216 char *
217 x_strindex(char *s1, const char *s2)
218 {
219     char *s3;
220     size_t s2len = strlen(s2);
221
222     while ((s3 = strchr(s1, *s2)) != NULL) {
223         if (strncmp(s3, s2, s2len) == 0)
224             return (s3);
225         s1 = ++s3;
226     }
227     return (NULL);
228 }
229
230 /*
231  * Trims leading/trailing spaces from a copy of the string.
232  */
233 char *
234 x_strtrim(const char *source)
235 {
236     char *result;
237     char *s;
238     char *d;
239
240     if (source != 0 && *source != '\0') {
241         char *t = x_strdup(source);
242         s = t;
243         d = s;
244         while (isspace(CharOf(*s)))
245             ++s;
246         while ((*d++ = *s++) != '\0') {
247             ;
248         }
249         if (*t != '\0') {
250             s = t + strlen(t);
251             while (s != t && isspace(CharOf(s[-1]))) {
252                 *--s = '\0';
253             }
254         }
255         result = t;
256     } else {
257         result = x_strdup("");
258     }
259     return result;
260 }
261
262 /*
263  * Avoid using system locale for upper/lowercase conversion, since there are
264  * a few locales where toupper(tolower(c)) != c.
265  */
266 char
267 x_toupper(int ch)
268 {
269     static char table[256];
270     char result = table[CharOf(ch)];
271
272     if (result == '\0') {
273         unsigned n;
274         const char *s = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
275
276         for (n = 0; n < sizeof(table); ++n) {
277             table[n] = (char) n;
278         }
279         for (n = 0; s[n] != '\0'; ++n) {
280             table[CharOf(s[n])] = s[n % 26];
281         }
282         result = table[CharOf(ch)];
283     }
284
285     return result;
286 }