1 #include "q_string.h"
2
3 #include <assert.h>
4 #include <ctype.h>
5 #include <errno.h>
6 #include <math.h>
7 #include <stddef.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11
12 #include "q_color.h"
13
Q_isprint(int c)14 int Q_isprint( int c )
15 {
16 if ( c >= 0x20 && c <= 0x7E )
17 return ( 1 );
18 return ( 0 );
19 }
20
Q_isprintext(int c)21 int Q_isprintext( int c )
22 {
23 if ( c >= 0x20 && c <= 0x7E )
24 return (1);
25 if ( c >= 0x80 && c <= 0xFE )
26 return (1);
27 return (0);
28 }
29
Q_isgraph(int c)30 int Q_isgraph( int c )
31 {
32 if ( c >= 0x21 && c <= 0x7E )
33 return (1);
34 if ( c >= 0x80 && c <= 0xFE )
35 return (1);
36 return (0);
37 }
38
Q_islower(int c)39 int Q_islower( int c )
40 {
41 if (c >= 'a' && c <= 'z')
42 return ( 1 );
43 return ( 0 );
44 }
45
Q_isupper(int c)46 int Q_isupper( int c )
47 {
48 if (c >= 'A' && c <= 'Z')
49 return ( 1 );
50 return ( 0 );
51 }
52
Q_isalpha(int c)53 int Q_isalpha( int c )
54 {
55 if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
56 return ( 1 );
57 return ( 0 );
58 }
59
Q_isanumber(const char * s)60 qboolean Q_isanumber( const char *s )
61 {
62 char *p;
63 double ret;
64
65 if( *s == '\0' )
66 return qfalse;
67
68 ret = strtod( s, &p );
69
70 if ( ret == HUGE_VAL || errno == ERANGE )
71 return qfalse;
72
73 return (qboolean)(*p == '\0');
74 }
75
Q_isintegral(float f)76 qboolean Q_isintegral( float f )
77 {
78 return (qboolean)( (int)f == f );
79 }
80
Q_strrchr(const char * string,int c)81 char* Q_strrchr( const char* string, int c )
82 {
83 char cc = c;
84 char *s;
85 char *sp=(char *)0;
86
87 s = (char*)string;
88
89 while (*s)
90 {
91 if (*s == cc)
92 sp = s;
93 s++;
94 }
95 if (cc == 0)
96 sp = s;
97
98 return sp;
99 }
100
101 /*
102 =============
103 Q_strncpyz
104
105 Safe strncpy that ensures a trailing zero
106 =============
107 */
Q_strncpyz(char * dest,const char * src,int destsize)108 void Q_strncpyz( char *dest, const char *src, int destsize ) {
109 assert(src);
110 assert(dest);
111 assert(destsize);
112
113 strncpy( dest, src, destsize-1 );
114 dest[destsize-1] = 0;
115 }
116
Q_stricmpn(const char * s1,const char * s2,int n)117 int Q_stricmpn (const char *s1, const char *s2, int n) {
118 int c1, c2;
119
120 if ( s1 == NULL ) {
121 if ( s2 == NULL )
122 return 0;
123 else
124 return -1;
125 }
126 else if ( s2==NULL )
127 return 1;
128
129 do {
130 c1 = *s1++;
131 c2 = *s2++;
132
133 if (!n--) {
134 return 0; // strings are equal until end point
135 }
136
137 if (c1 != c2) {
138 if (c1 >= 'a' && c1 <= 'z') {
139 c1 -= ('a' - 'A');
140 }
141 if (c2 >= 'a' && c2 <= 'z') {
142 c2 -= ('a' - 'A');
143 }
144 if (c1 != c2) {
145 return c1 < c2 ? -1 : 1;
146 }
147 }
148 } while (c1);
149
150 return 0; // strings are equal
151 }
152
Q_stricmp(const char * s1,const char * s2)153 int Q_stricmp (const char *s1, const char *s2) {
154 return (s1 && s2) ? Q_stricmpn (s1, s2, 99999) : -1;
155 }
156
Q_strncmp(const char * s1,const char * s2,int n)157 int Q_strncmp (const char *s1, const char *s2, int n) {
158 int c1, c2;
159
160 do {
161 c1 = *s1++;
162 c2 = *s2++;
163
164 if (!n--) {
165 return 0; // strings are equal until end point
166 }
167
168 if (c1 != c2) {
169 return c1 < c2 ? -1 : 1;
170 }
171 } while (c1);
172
173 return 0; // strings are equal
174 }
175
Q_strlwr(char * s1)176 char *Q_strlwr( char *s1 ) {
177 char *s;
178
179 s = s1;
180 while ( *s ) {
181 *s = tolower(*s);
182 s++;
183 }
184 return s1;
185 }
186
Q_strupr(char * s1)187 char *Q_strupr( char *s1 ) {
188 char *s;
189
190 s = s1;
191 while ( *s ) {
192 *s = toupper(*s);
193 s++;
194 }
195 return s1;
196 }
197
198 // never goes past bounds or leaves without a terminating 0
Q_strcat(char * dest,int size,const char * src)199 void Q_strcat( char *dest, int size, const char *src ) {
200 int l1;
201
202 l1 = strlen( dest );
203 if ( l1 >= size ) {
204 //Com_Error( ERR_FATAL, "Q_strcat: already overflowed" );
205 return;
206 }
207 if ( strlen(src)+1 > (size_t)(size - l1))
208 { //do the error here instead of in Q_strncpyz to get a meaningful msg
209 //Com_Error(ERR_FATAL,"Q_strcat: cannot append \"%s\" to \"%s\"", src, dest);
210 return;
211 }
212 Q_strncpyz( dest + l1, src, size - l1 );
213 }
214
215 /*
216 * Find the first occurrence of find in s.
217 */
Q_stristr(const char * s,const char * find)218 const char *Q_stristr( const char *s, const char *find )
219 {
220 char c, sc;
221 size_t len;
222
223 if ((c = *find++) != 0)
224 {
225 if (c >= 'a' && c <= 'z')
226 {
227 c -= ('a' - 'A');
228 }
229 len = strlen(find);
230 do
231 {
232 do
233 {
234 if ((sc = *s++) == 0)
235 return NULL;
236 if (sc >= 'a' && sc <= 'z')
237 {
238 sc -= ('a' - 'A');
239 }
240 } while (sc != c);
241 } while (Q_stricmpn(s, find, len) != 0);
242 s--;
243 }
244 return s;
245 }
246
Q_PrintStrlen(const char * string)247 int Q_PrintStrlen( const char *string ) {
248 int len;
249 const char *p;
250
251 if( !string ) {
252 return 0;
253 }
254
255 len = 0;
256 p = string;
257 while( *p ) {
258 if( Q_IsColorString( p ) ) {
259 p += 2;
260 continue;
261 }
262 p++;
263 len++;
264 }
265
266 return len;
267 }
268
269
Q_CleanStr(char * string)270 char *Q_CleanStr( char *string ) {
271 char* d;
272 char* s;
273 int c;
274
275 s = string;
276 d = string;
277 while ((c = *s) != 0 ) {
278 if ( Q_IsColorString( s ) ) {
279 s++;
280 }
281 else if ( c >= 0x20 && c <= 0x7E ) {
282 *d++ = c;
283 }
284 s++;
285 }
286 *d = '\0';
287
288 return string;
289 }
290
291 /*
292 ==================
293 Q_StripColor
294
295 Strips coloured strings in-place using multiple passes: "fgs^^56fds" -> "fgs^6fds" -> "fgsfds"
296
297 This function modifies INPUT (is mutable)
298
299 (Also strips ^8 and ^9)
300 ==================
301 */
Q_StripColor(char * text)302 void Q_StripColor(char *text)
303 {
304 qboolean doPass = qtrue;
305 char *read;
306 char *write;
307
308 while ( doPass )
309 {
310 doPass = qfalse;
311 read = write = text;
312 while ( *read )
313 {
314 if ( Q_IsColorStringExt(read) )
315 {
316 doPass = qtrue;
317 read += 2;
318 }
319 else
320 {
321 // Avoid writing the same data over itself
322 if (write != read)
323 {
324 *write = *read;
325 }
326 write++;
327 read++;
328 }
329 }
330 if ( write < read )
331 {
332 // Add trailing NUL byte if string has shortened
333 *write = '\0';
334 }
335 }
336 }
337
338 /*
339 Q_strstrip
340
341 Description: Replace strip[x] in string with repl[x] or remove characters entirely
342 Mutates: string
343 Return: --
344
345 Examples: Q_strstrip( "Bo\nb is h\rairy!!", "\n\r!", "123" ); // "Bo1b is h2airy33"
346 Q_strstrip( "Bo\nb is h\rairy!!", "\n\r!", "12" ); // "Bo1b is h2airy"
347 Q_strstrip( "Bo\nb is h\rairy!!", "\n\r!", NULL ); // "Bob is hairy"
348 */
349
Q_strstrip(char * string,const char * strip,const char * repl)350 void Q_strstrip( char *string, const char *strip, const char *repl )
351 {
352 char *out=string, *p=string, c;
353 const char *s=strip;
354 int replaceLen = repl?strlen( repl ):0, offset=0;
355 qboolean recordChar = qtrue;
356
357 while ( (c = *p++) != '\0' )
358 {
359 recordChar = qtrue;
360 for ( s=strip; *s; s++ )
361 {
362 offset = s-strip;
363 if ( c == *s )
364 {
365 if ( !repl || offset >= replaceLen )
366 recordChar = qfalse;
367 else
368 c = repl[offset];
369 break;
370 }
371 }
372 if ( recordChar )
373 *out++ = c;
374 }
375 *out = '\0';
376 }
377
378 /*
379 Q_strchrs
380
381 Description: Find any characters in a string. Think of it as a shorthand strchr loop.
382 Mutates: --
383 Return: first instance of any characters found
384 otherwise NULL
385 */
386
Q_strchrs(const char * string,const char * search)387 const char *Q_strchrs( const char *string, const char *search )
388 {
389 const char *p = string, *s = search;
390
391 while ( *p != '\0' )
392 {
393 for ( s=search; *s; s++ )
394 {
395 if ( *p == *s )
396 return p;
397 }
398 p++;
399 }
400
401 return NULL;
402 }
403
404 #if defined(_MSC_VER)
405 /*
406 =============
407 Q_vsnprintf
408
409 Special wrapper function for Microsoft's broken _vsnprintf() function.
410 MinGW comes with its own snprintf() which is not broken.
411 =============
412 */
413
Q_vsnprintf(char * str,size_t size,const char * format,va_list ap)414 int Q_vsnprintf(char *str, size_t size, const char *format, va_list ap)
415 {
416 int retval;
417
418 retval = _vsnprintf(str, size, format, ap);
419
420 if(retval < 0 || retval == size)
421 {
422 // Microsoft doesn't adhere to the C99 standard of vsnprintf,
423 // which states that the return value must be the number of
424 // bytes written if the output string had sufficient length.
425 //
426 // Obviously we cannot determine that value from Microsoft's
427 // implementation, so we have no choice but to return size.
428
429 str[size - 1] = '\0';
430 return size;
431 }
432
433 return retval;
434 }
435 #endif