Merge pull request #110 from tesselode/fixes
[wdl/wdl-ol.git] / WDL / wdlcstring.h
blob60c8ebccfc558b38c082f4a0530c111e04b7f4d9
1 /*
2 WDL - wdlcstring.h
3 Copyright (C) 2005 and later, Cockos Incorporated
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
24 C string manipulation utilities -- [v]snprintf for Win32, also snprintf_append, lstrcatn, etc
26 #ifndef _WDL_CSTRING_H_
27 #define _WDL_CSTRING_H_
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <ctype.h>
33 #include "wdltypes.h"
35 #ifdef _WDL_CSTRING_IMPL_ONLY_
36 #ifdef _WDL_CSTRING_IF_ONLY_
37 #undef _WDL_CSTRING_IF_ONLY_
38 #endif
39 #define _WDL_CSTRING_PREFIX
40 #else
41 #define _WDL_CSTRING_PREFIX static WDL_STATICFUNC_UNUSED
42 #endif
46 #if defined(_WIN32) && defined(_MSC_VER)
47 // provide snprintf()/vsnprintf() for win32 -- note that these have no way of knowing
48 // what the amount written was, code should(must) be written to not depend on this.
49 #ifdef snprintf
50 #undef snprintf
51 #endif
52 #define snprintf WDL_snprintf
54 #ifdef vsnprintf
55 #undef vsnprintf
56 #endif
57 #define vsnprintf WDL_vsnprintf
59 #endif // win32 snprintf/vsnprintf
61 // use wdlcstring.h's lstrcpyn_safe rather than the real lstrcpyn.
62 #ifdef _WIN32
63 #ifdef lstrcpyn
64 #undef lstrcpyn
65 #endif
66 #define lstrcpyn lstrcpyn_safe
67 #endif
69 #ifdef __cplusplus
70 extern "C" {
71 #endif
73 #ifdef _WDL_CSTRING_IF_ONLY_
75 void lstrcpyn_safe(char *o, const char *in, int count);
76 void lstrcatn(char *o, const char *in, int count);
77 void WDL_VARARG_WARN(printf,3,4) snprintf_append(char *o, int count, const char *format, ...);
78 void vsnprintf_append(char *o, int count, const char *format, va_list va);
80 const char *WDL_get_filepart(const char *str); // returns whole string if no dir chars
81 const char *WDL_get_fileext(const char *str); // returns ".ext" or end of string "" if no extension
82 char *WDL_remove_fileext(char *str); // returns pointer to "ext" if ".ext" was removed (zero-d dot), or NULL
83 char WDL_remove_filepart(char *str); // returns dir character that was zeroed, or 0 if new string is empty
84 int WDL_remove_trailing_dirchars(char *str); // returns trailing dirchar count removed, will not convert "/" into ""
85 size_t WDL_remove_trailing_crlf(char *str); // returns new length
88 #if defined(_WIN32) && defined(_MSC_VER)
89 void WDL_vsnprintf(char *o, size_t count, const char *format, va_list args);
90 void WDL_VARARG_WARN(printf,3,4) WDL_snprintf(char *o, size_t count, const char *format, ...);
91 #endif
93 int WDL_strcmp_logical(const char *s1, const char *s2, int case_sensitive);
94 #else
97 #if defined(_WIN32) && defined(_MSC_VER)
99 _WDL_CSTRING_PREFIX void WDL_vsnprintf(char *o, size_t count, const char *format, va_list args)
101 if (count>0)
103 int rv;
104 o[0]=0;
105 rv=_vsnprintf(o,count,format,args); // returns -1 if over, and does not null terminate, ugh
106 if (rv < 0 || rv>=(int)count-1) o[count-1]=0;
109 _WDL_CSTRING_PREFIX void WDL_VARARG_WARN(printf,3,4) WDL_snprintf(char *o, size_t count, const char *format, ...)
111 if (count>0)
113 int rv;
114 va_list va;
115 va_start(va,format);
116 o[0]=0;
117 rv=_vsnprintf(o,count,format,va); // returns -1 if over, and does not null terminate, ugh
118 va_end(va);
120 if (rv < 0 || rv>=(int)count-1) o[count-1]=0;
123 #endif
125 _WDL_CSTRING_PREFIX void lstrcpyn_safe(char *o, const char *in, int count)
127 if (count>0)
129 while (--count>0 && *in) *o++ = *in++;
130 *o=0;
134 _WDL_CSTRING_PREFIX void lstrcatn(char *o, const char *in, int count)
136 if (count>0)
138 while (*o) { if (--count < 1) return; o++; }
139 while (--count>0 && *in) *o++ = *in++;
140 *o=0;
144 _WDL_CSTRING_PREFIX const char *WDL_get_filepart(const char *str) // returns whole string if no dir chars
146 const char *p = str;
147 while (*p) p++;
148 while (p >= str && !WDL_IS_DIRCHAR(*p)) --p;
149 return p + 1;
151 _WDL_CSTRING_PREFIX const char *WDL_get_fileext(const char *str) // returns ".ext" or end of string "" if no extension
153 const char *p=str, *ep;
154 while (*p) p++;
155 ep = p;
156 while (p >= str && !WDL_IS_DIRCHAR(*p))
158 if (*p == '.') return p;
159 --p;
161 return ep;
164 _WDL_CSTRING_PREFIX char *WDL_remove_fileext(char *str) // returns pointer to "ext" if ".ext" was removed (zero-d dot), or NULL
166 char *p=str;
167 while (*p) p++;
168 while (p >= str && !WDL_IS_DIRCHAR(*p))
170 if (*p == '.')
172 *p = 0;
173 return p+1;
175 --p;
177 return NULL;
180 _WDL_CSTRING_PREFIX char WDL_remove_filepart(char *str) // returns dir character that was zeroed, or 0 if new string is empty
182 char *p=str;
183 while (*p) p++;
184 while (p >= str)
186 char c = *p;
187 if (WDL_IS_DIRCHAR(c))
189 *p = 0;
190 return c;
192 --p;
194 str[0] = 0;
195 return 0;
198 _WDL_CSTRING_PREFIX int WDL_remove_trailing_dirchars(char *str) // returns trailing dirchar count removed
200 int cnt = 0;
201 char *p=str;
202 while (*p) p++;
203 while (p > str+1 && WDL_IS_DIRCHAR(p[-1]))
205 cnt++;
206 p--;
208 *p = 0;
209 return cnt;
212 _WDL_CSTRING_PREFIX size_t WDL_remove_trailing_crlf(char *str) // returns new length
214 char *p=str;
215 while (*p) p++;
216 while (p > str && (p[-1] == '\r' || p[-1] == '\n')) p--;
217 *p = 0;
218 return p-str;
221 _WDL_CSTRING_PREFIX void WDL_VARARG_WARN(printf,3,4) snprintf_append(char *o, int count, const char *format, ...)
223 if (count>0)
225 va_list va;
226 while (*o) { if (--count < 1) return; o++; }
227 va_start(va,format);
228 vsnprintf(o,count,format,va);
229 va_end(va);
233 _WDL_CSTRING_PREFIX void vsnprintf_append(char *o, int count, const char *format, va_list va)
235 if (count>0)
237 while (*o) { if (--count < 1) return; o++; }
238 vsnprintf(o,count,format,va);
242 _WDL_CSTRING_PREFIX int WDL_strcmp_logical(const char *s1, const char *s2, int case_sensitive)
244 // also exists as WDL_LogicalSortStringKeyedArray::_cmpstr()
246 char lastNonZeroChar=0;
247 // last matching character, updated if not 0. this allows us to track whether
248 // we are inside of a number with the same leading digits
250 for (;;)
252 char c1=*s1++, c2=*s2++;
253 if (!c1) return c1-c2;
255 if (c1!=c2)
257 if (c1 >= '0' && c1 <= '9' && c2 >= '0' && c2 <= '9')
259 int lzdiff=0, cnt=0;
260 if (lastNonZeroChar < '1' || lastNonZeroChar > '9')
262 while (c1 == '0') { c1=*s1++; lzdiff--; }
263 while (c2 == '0') { c2=*s2++; lzdiff++; } // lzdiff = lz2-lz1, more leading 0s = earlier in list
266 for (;;)
268 if (c1 >= '0' && c1 <= '9')
270 if (c2 < '0' || c2 > '9') return 1;
272 c1=s1[cnt];
273 c2=s2[cnt++];
275 else
277 if (c2 >= '0' && c2 <= '9') return -1;
278 break;
282 s1--;
283 s2--;
285 while (cnt--)
287 const int d = *s1++ - *s2++;
288 if (d) return d;
291 if (lzdiff) return lzdiff;
293 else
295 if (!case_sensitive)
297 if (c1>='a' && c1<='z') c1+='A'-'a';
298 if (c2>='a' && c2<='z') c2+='A'-'a';
300 if (c1 != c2) return c1-c2;
303 else if (c1 != '0') lastNonZeroChar=c1;
307 #endif
310 #ifdef __cplusplus
312 #endif
314 #undef _WDL_CSTRING_PREFIX
316 #endif