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