1 /* tmbstr.c -- Tidy string utility functions
2 
3   (c) 1998-2006 (W3C) MIT, ERCIM, Keio University
4   See tidy.h for the copyright notice.
5 
6   CVS Info :
7 
8     $Author: arnaud02 $
9     $Date: 2006/12/29 16:31:08 $
10     $Revision: 1.13 $
11 
12 */
13 
14 #include "forward.h"
15 #include "tmbstr.h"
16 #include "lexer.h"
17 
18 /* like strdup but using an allocator */
TY_(tmbstrdup)19 tmbstr TY_(tmbstrdup)( TidyAllocator *allocator, ctmbstr str )
20 {
21     tmbstr s = NULL;
22     if ( str )
23     {
24         uint len = TY_(tmbstrlen)( str );
25         tmbstr cp = s = (tmbstr) TidyAlloc( allocator, 1+len );
26         while ( 0 != (*cp++ = *str++) )
27             /**/;
28     }
29     return s;
30 }
31 
32 /* like strndup but using an allocator */
TY_(tmbstrndup)33 tmbstr TY_(tmbstrndup)( TidyAllocator *allocator, ctmbstr str, uint len )
34 {
35     tmbstr s = NULL;
36     if ( str && len > 0 )
37     {
38         tmbstr cp = s = (tmbstr) TidyAlloc( allocator, 1+len );
39         while ( len-- > 0 &&  (*cp++ = *str++) )
40           /**/;
41         *cp = 0;
42     }
43     return s;
44 }
45 
46 /* exactly same as strncpy */
TY_(tmbstrncpy)47 uint TY_(tmbstrncpy)( tmbstr s1, ctmbstr s2, uint size )
48 {
49     if ( s1 != NULL && s2 != NULL )
50     {
51         tmbstr cp = s1;
52         while ( *s2 && --size )  /* Predecrement: reserve byte */
53             *cp++ = *s2++;       /* for NULL terminator. */
54         *cp = 0;
55     }
56     return size;
57 }
58 
59 /* Allows expressions like:  cp += tmbstrcpy( cp, "joebob" );
60 */
TY_(tmbstrcpy)61 uint TY_(tmbstrcpy)( tmbstr s1, ctmbstr s2 )
62 {
63     uint ncpy = 0;
64     while (0 != (*s1++ = *s2++) )
65         ++ncpy;
66     return ncpy;
67 }
68 
69 /* Allows expressions like:  cp += tmbstrcat( cp, "joebob" );
70 */
TY_(tmbstrcat)71 uint TY_(tmbstrcat)( tmbstr s1, ctmbstr s2 )
72 {
73     uint ncpy = 0;
74     while ( *s1 )
75         ++s1;
76 
77     while (0 != (*s1++ = *s2++) )
78         ++ncpy;
79     return ncpy;
80 }
81 
82 /* exactly same as strcmp */
TY_(tmbstrcmp)83 int TY_(tmbstrcmp)( ctmbstr s1, ctmbstr s2 )
84 {
85     int c;
86     while ((c = *s1) == *s2)
87     {
88         if (c == '\0')
89             return 0;
90 
91         ++s1;
92         ++s2;
93     }
94 
95     return (*s1 > *s2 ? 1 : -1);
96 }
97 
98 /* returns byte count, not char count */
TY_(tmbstrlen)99 uint TY_(tmbstrlen)( ctmbstr str )
100 {
101     uint len = 0;
102     if ( str )
103     {
104         while ( *str++ )
105             ++len;
106     }
107     return len;
108 }
109 
110 /*
111  MS C 4.2 doesn't include strcasecmp.
112  Note that tolower and toupper won't
113  work on chars > 127.
114 
115  Neither does ToLower()!
116 */
TY_(tmbstrcasecmp)117 int TY_(tmbstrcasecmp)( ctmbstr s1, ctmbstr s2 )
118 {
119     uint c;
120 
121     while (c = (uint)(*s1), TY_(ToLower)(c) == TY_(ToLower)((uint)(*s2)))
122     {
123         if (c == '\0')
124             return 0;
125 
126         ++s1;
127         ++s2;
128     }
129 
130     return (*s1 > *s2 ? 1 : -1);
131 }
132 
TY_(tmbstrncmp)133 int TY_(tmbstrncmp)( ctmbstr s1, ctmbstr s2, uint n )
134 {
135     uint c;
136 
137     while ((c = (byte)*s1) == (byte)*s2)
138     {
139         if (c == '\0')
140             return 0;
141 
142         if (n == 0)
143             return 0;
144 
145         ++s1;
146         ++s2;
147         --n;
148     }
149 
150     if (n == 0)
151         return 0;
152 
153     return (*s1 > *s2 ? 1 : -1);
154 }
155 
TY_(tmbstrncasecmp)156 int TY_(tmbstrncasecmp)( ctmbstr s1, ctmbstr s2, uint n )
157 {
158     uint c;
159 
160     while (c = (uint)(*s1), TY_(ToLower)(c) == TY_(ToLower)((uint)(*s2)))
161     {
162         if (c == '\0')
163             return 0;
164 
165         if (n == 0)
166             return 0;
167 
168         ++s1;
169         ++s2;
170         --n;
171     }
172 
173     if (n == 0)
174         return 0;
175 
176     return (*s1 > *s2 ? 1 : -1);
177 }
178 
179 #if 0
180 /* return offset of cc from beginning of s1,
181 ** -1 if not found.
182 */
183 int TY_(tmbstrnchr)( ctmbstr s1, uint maxlen, tmbchar cc )
184 {
185     int i;
186     ctmbstr cp = s1;
187 
188     for ( i = 0; (uint)i < maxlen; ++i, ++cp )
189     {
190         if ( *cp == cc )
191             return i;
192     }
193 
194     return -1;
195 }
196 #endif
197 
TY_(tmbsubstrn)198 ctmbstr TY_(tmbsubstrn)( ctmbstr s1, uint len1, ctmbstr s2 )
199 {
200     uint len2 = TY_(tmbstrlen)(s2);
201     int ix, diff = len1 - len2;
202 
203     for ( ix = 0; ix <= diff; ++ix )
204     {
205         if ( TY_(tmbstrncmp)(s1+ix, s2, len2) == 0 )
206             return (ctmbstr) s1+ix;
207     }
208     return NULL;
209 }
210 
211 #if 0
212 ctmbstr TY_(tmbsubstrncase)( ctmbstr s1, uint len1, ctmbstr s2 )
213 {
214     uint len2 = TY_(tmbstrlen)(s2);
215     int ix, diff = len1 - len2;
216 
217     for ( ix = 0; ix <= diff; ++ix )
218     {
219         if ( TY_(tmbstrncasecmp)(s1+ix, s2, len2) == 0 )
220             return (ctmbstr) s1+ix;
221     }
222     return NULL;
223 }
224 #endif
225 
TY_(tmbsubstr)226 ctmbstr TY_(tmbsubstr)( ctmbstr s1, ctmbstr s2 )
227 {
228     uint len1 = TY_(tmbstrlen)(s1), len2 = TY_(tmbstrlen)(s2);
229     int ix, diff = len1 - len2;
230 
231     for ( ix = 0; ix <= diff; ++ix )
232     {
233         if ( TY_(tmbstrncasecmp)(s1+ix, s2, len2) == 0 )
234             return (ctmbstr) s1+ix;
235     }
236     return NULL;
237 }
238 
239 /* Transform ASCII chars in string to lower case */
TY_(tmbstrtolower)240 tmbstr TY_(tmbstrtolower)( tmbstr s )
241 {
242     tmbstr cp;
243     for ( cp=s; *cp; ++cp )
244         *cp = (tmbchar) TY_(ToLower)( *cp );
245     return s;
246 }
247 
248 /* Transform ASCII chars in string to upper case */
TY_(tmbstrtoupper)249 tmbstr TY_(tmbstrtoupper)(tmbstr s)
250 {
251     tmbstr cp;
252 
253     for (cp = s; *cp; ++cp)
254         *cp = (tmbchar)TY_(ToUpper)(*cp);
255 
256     return s;
257 }
258 
259 #if 0
260 Bool TY_(tmbsamefile)( ctmbstr filename1, ctmbstr filename2 )
261 {
262 #if FILENAMES_CASE_SENSITIVE
263     return ( TY_(tmbstrcmp)( filename1, filename2 ) == 0 );
264 #else
265     return ( TY_(tmbstrcasecmp)( filename1, filename2 ) == 0 );
266 #endif
267 }
268 #endif
269 
TY_(tmbvsnprintf)270 int TY_(tmbvsnprintf)(tmbstr buffer, size_t count, ctmbstr format, va_list args)
271 {
272     int retval;
273 #if HAS_VSNPRINTF
274     retval = vsnprintf(buffer, count - 1, format, args);
275     /* todo: conditionally null-terminate the string? */
276     buffer[count - 1] = 0;
277 #else
278     retval = vsprintf(buffer, format, args);
279 #endif /* HAS_VSNPRINTF */
280     return retval;
281 }
282 
TY_(tmbsnprintf)283 int TY_(tmbsnprintf)(tmbstr buffer, size_t count, ctmbstr format, ...)
284 {
285     int retval;
286     va_list args;
287     va_start(args, format);
288 #if HAS_VSNPRINTF
289     retval = vsnprintf(buffer, count - 1, format, args);
290     /* todo: conditionally null-terminate the string? */
291     buffer[count - 1] = 0;
292 #else
293     retval = vsprintf(buffer, format, args);
294 #endif /* HAS_VSNPRINTF */
295     va_end(args);
296     return retval;
297 }
298 
299 /*
300  * local variables:
301  * mode: c
302  * indent-tabs-mode: nil
303  * c-basic-offset: 4
304  * eval: (c-set-offset 'substatement-open 0)
305  * end:
306  */
307