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