mirror of
https://github.com/DrBeef/JKXR.git
synced 2024-12-01 00:21:47 +00:00
435 lines
6.8 KiB
C
435 lines
6.8 KiB
C
|
#include "q_string.h"
|
||
|
|
||
|
#include <assert.h>
|
||
|
#include <ctype.h>
|
||
|
#include <errno.h>
|
||
|
#include <math.h>
|
||
|
#include <stddef.h>
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
|
||
|
#include "q_color.h"
|
||
|
|
||
|
int Q_isprint( int c )
|
||
|
{
|
||
|
if ( c >= 0x20 && c <= 0x7E )
|
||
|
return ( 1 );
|
||
|
return ( 0 );
|
||
|
}
|
||
|
|
||
|
int Q_isprintext( int c )
|
||
|
{
|
||
|
if ( c >= 0x20 && c <= 0x7E )
|
||
|
return (1);
|
||
|
if ( c >= 0x80 && c <= 0xFE )
|
||
|
return (1);
|
||
|
return (0);
|
||
|
}
|
||
|
|
||
|
int Q_isgraph( int c )
|
||
|
{
|
||
|
if ( c >= 0x21 && c <= 0x7E )
|
||
|
return (1);
|
||
|
if ( c >= 0x80 && c <= 0xFE )
|
||
|
return (1);
|
||
|
return (0);
|
||
|
}
|
||
|
|
||
|
int Q_islower( int c )
|
||
|
{
|
||
|
if (c >= 'a' && c <= 'z')
|
||
|
return ( 1 );
|
||
|
return ( 0 );
|
||
|
}
|
||
|
|
||
|
int Q_isupper( int c )
|
||
|
{
|
||
|
if (c >= 'A' && c <= 'Z')
|
||
|
return ( 1 );
|
||
|
return ( 0 );
|
||
|
}
|
||
|
|
||
|
int Q_isalpha( int c )
|
||
|
{
|
||
|
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
|
||
|
return ( 1 );
|
||
|
return ( 0 );
|
||
|
}
|
||
|
|
||
|
qboolean Q_isanumber( const char *s )
|
||
|
{
|
||
|
char *p;
|
||
|
double ret;
|
||
|
|
||
|
if( *s == '\0' )
|
||
|
return qfalse;
|
||
|
|
||
|
ret = strtod( s, &p );
|
||
|
|
||
|
if ( ret == HUGE_VAL || errno == ERANGE )
|
||
|
return qfalse;
|
||
|
|
||
|
return (qboolean)(*p == '\0');
|
||
|
}
|
||
|
|
||
|
qboolean Q_isintegral( float f )
|
||
|
{
|
||
|
return (qboolean)( (int)f == f );
|
||
|
}
|
||
|
|
||
|
char* Q_strrchr( const char* string, int c )
|
||
|
{
|
||
|
char cc = c;
|
||
|
char *s;
|
||
|
char *sp=(char *)0;
|
||
|
|
||
|
s = (char*)string;
|
||
|
|
||
|
while (*s)
|
||
|
{
|
||
|
if (*s == cc)
|
||
|
sp = s;
|
||
|
s++;
|
||
|
}
|
||
|
if (cc == 0)
|
||
|
sp = s;
|
||
|
|
||
|
return sp;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
=============
|
||
|
Q_strncpyz
|
||
|
|
||
|
Safe strncpy that ensures a trailing zero
|
||
|
=============
|
||
|
*/
|
||
|
void Q_strncpyz( char *dest, const char *src, int destsize ) {
|
||
|
assert(src);
|
||
|
assert(dest);
|
||
|
assert(destsize);
|
||
|
|
||
|
strncpy( dest, src, destsize-1 );
|
||
|
dest[destsize-1] = 0;
|
||
|
}
|
||
|
|
||
|
int Q_stricmpn (const char *s1, const char *s2, int n) {
|
||
|
int c1, c2;
|
||
|
|
||
|
if ( s1 == NULL ) {
|
||
|
if ( s2 == NULL )
|
||
|
return 0;
|
||
|
else
|
||
|
return -1;
|
||
|
}
|
||
|
else if ( s2==NULL )
|
||
|
return 1;
|
||
|
|
||
|
do {
|
||
|
c1 = *s1++;
|
||
|
c2 = *s2++;
|
||
|
|
||
|
if (!n--) {
|
||
|
return 0; // strings are equal until end point
|
||
|
}
|
||
|
|
||
|
if (c1 != c2) {
|
||
|
if (c1 >= 'a' && c1 <= 'z') {
|
||
|
c1 -= ('a' - 'A');
|
||
|
}
|
||
|
if (c2 >= 'a' && c2 <= 'z') {
|
||
|
c2 -= ('a' - 'A');
|
||
|
}
|
||
|
if (c1 != c2) {
|
||
|
return c1 < c2 ? -1 : 1;
|
||
|
}
|
||
|
}
|
||
|
} while (c1);
|
||
|
|
||
|
return 0; // strings are equal
|
||
|
}
|
||
|
|
||
|
int Q_stricmp (const char *s1, const char *s2) {
|
||
|
return (s1 && s2) ? Q_stricmpn (s1, s2, 99999) : -1;
|
||
|
}
|
||
|
|
||
|
int Q_strncmp (const char *s1, const char *s2, int n) {
|
||
|
int c1, c2;
|
||
|
|
||
|
do {
|
||
|
c1 = *s1++;
|
||
|
c2 = *s2++;
|
||
|
|
||
|
if (!n--) {
|
||
|
return 0; // strings are equal until end point
|
||
|
}
|
||
|
|
||
|
if (c1 != c2) {
|
||
|
return c1 < c2 ? -1 : 1;
|
||
|
}
|
||
|
} while (c1);
|
||
|
|
||
|
return 0; // strings are equal
|
||
|
}
|
||
|
|
||
|
char *Q_strlwr( char *s1 ) {
|
||
|
char *s;
|
||
|
|
||
|
s = s1;
|
||
|
while ( *s ) {
|
||
|
*s = tolower(*s);
|
||
|
s++;
|
||
|
}
|
||
|
return s1;
|
||
|
}
|
||
|
|
||
|
char *Q_strupr( char *s1 ) {
|
||
|
char *s;
|
||
|
|
||
|
s = s1;
|
||
|
while ( *s ) {
|
||
|
*s = toupper(*s);
|
||
|
s++;
|
||
|
}
|
||
|
return s1;
|
||
|
}
|
||
|
|
||
|
// never goes past bounds or leaves without a terminating 0
|
||
|
void Q_strcat( char *dest, int size, const char *src ) {
|
||
|
int l1;
|
||
|
|
||
|
l1 = strlen( dest );
|
||
|
if ( l1 >= size ) {
|
||
|
//Com_Error( ERR_FATAL, "Q_strcat: already overflowed" );
|
||
|
return;
|
||
|
}
|
||
|
if ( strlen(src)+1 > (size_t)(size - l1))
|
||
|
{ //do the error here instead of in Q_strncpyz to get a meaningful msg
|
||
|
//Com_Error(ERR_FATAL,"Q_strcat: cannot append \"%s\" to \"%s\"", src, dest);
|
||
|
return;
|
||
|
}
|
||
|
Q_strncpyz( dest + l1, src, size - l1 );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Find the first occurrence of find in s.
|
||
|
*/
|
||
|
const char *Q_stristr( const char *s, const char *find )
|
||
|
{
|
||
|
char c, sc;
|
||
|
size_t len;
|
||
|
|
||
|
if ((c = *find++) != 0)
|
||
|
{
|
||
|
if (c >= 'a' && c <= 'z')
|
||
|
{
|
||
|
c -= ('a' - 'A');
|
||
|
}
|
||
|
len = strlen(find);
|
||
|
do
|
||
|
{
|
||
|
do
|
||
|
{
|
||
|
if ((sc = *s++) == 0)
|
||
|
return NULL;
|
||
|
if (sc >= 'a' && sc <= 'z')
|
||
|
{
|
||
|
sc -= ('a' - 'A');
|
||
|
}
|
||
|
} while (sc != c);
|
||
|
} while (Q_stricmpn(s, find, len) != 0);
|
||
|
s--;
|
||
|
}
|
||
|
return s;
|
||
|
}
|
||
|
|
||
|
int Q_PrintStrlen( const char *string ) {
|
||
|
int len;
|
||
|
const char *p;
|
||
|
|
||
|
if( !string ) {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
len = 0;
|
||
|
p = string;
|
||
|
while( *p ) {
|
||
|
if( Q_IsColorString( p ) ) {
|
||
|
p += 2;
|
||
|
continue;
|
||
|
}
|
||
|
p++;
|
||
|
len++;
|
||
|
}
|
||
|
|
||
|
return len;
|
||
|
}
|
||
|
|
||
|
|
||
|
char *Q_CleanStr( char *string ) {
|
||
|
char* d;
|
||
|
char* s;
|
||
|
int c;
|
||
|
|
||
|
s = string;
|
||
|
d = string;
|
||
|
while ((c = *s) != 0 ) {
|
||
|
if ( Q_IsColorString( s ) ) {
|
||
|
s++;
|
||
|
}
|
||
|
else if ( c >= 0x20 && c <= 0x7E ) {
|
||
|
*d++ = c;
|
||
|
}
|
||
|
s++;
|
||
|
}
|
||
|
*d = '\0';
|
||
|
|
||
|
return string;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
==================
|
||
|
Q_StripColor
|
||
|
|
||
|
Strips coloured strings in-place using multiple passes: "fgs^^56fds" -> "fgs^6fds" -> "fgsfds"
|
||
|
|
||
|
This function modifies INPUT (is mutable)
|
||
|
|
||
|
(Also strips ^8 and ^9)
|
||
|
==================
|
||
|
*/
|
||
|
void Q_StripColor(char *text)
|
||
|
{
|
||
|
qboolean doPass = qtrue;
|
||
|
char *read;
|
||
|
char *write;
|
||
|
|
||
|
while ( doPass )
|
||
|
{
|
||
|
doPass = qfalse;
|
||
|
read = write = text;
|
||
|
while ( *read )
|
||
|
{
|
||
|
if ( Q_IsColorStringExt(read) )
|
||
|
{
|
||
|
doPass = qtrue;
|
||
|
read += 2;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Avoid writing the same data over itself
|
||
|
if (write != read)
|
||
|
{
|
||
|
*write = *read;
|
||
|
}
|
||
|
write++;
|
||
|
read++;
|
||
|
}
|
||
|
}
|
||
|
if ( write < read )
|
||
|
{
|
||
|
// Add trailing NUL byte if string has shortened
|
||
|
*write = '\0';
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
Q_strstrip
|
||
|
|
||
|
Description: Replace strip[x] in string with repl[x] or remove characters entirely
|
||
|
Mutates: string
|
||
|
Return: --
|
||
|
|
||
|
Examples: Q_strstrip( "Bo\nb is h\rairy!!", "\n\r!", "123" ); // "Bo1b is h2airy33"
|
||
|
Q_strstrip( "Bo\nb is h\rairy!!", "\n\r!", "12" ); // "Bo1b is h2airy"
|
||
|
Q_strstrip( "Bo\nb is h\rairy!!", "\n\r!", NULL ); // "Bob is hairy"
|
||
|
*/
|
||
|
|
||
|
void Q_strstrip( char *string, const char *strip, const char *repl )
|
||
|
{
|
||
|
char *out=string, *p=string, c;
|
||
|
const char *s=strip;
|
||
|
int replaceLen = repl?strlen( repl ):0, offset=0;
|
||
|
qboolean recordChar = qtrue;
|
||
|
|
||
|
while ( (c = *p++) != '\0' )
|
||
|
{
|
||
|
recordChar = qtrue;
|
||
|
for ( s=strip; *s; s++ )
|
||
|
{
|
||
|
offset = s-strip;
|
||
|
if ( c == *s )
|
||
|
{
|
||
|
if ( !repl || offset >= replaceLen )
|
||
|
recordChar = qfalse;
|
||
|
else
|
||
|
c = repl[offset];
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if ( recordChar )
|
||
|
*out++ = c;
|
||
|
}
|
||
|
*out = '\0';
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
Q_strchrs
|
||
|
|
||
|
Description: Find any characters in a string. Think of it as a shorthand strchr loop.
|
||
|
Mutates: --
|
||
|
Return: first instance of any characters found
|
||
|
otherwise NULL
|
||
|
*/
|
||
|
|
||
|
const char *Q_strchrs( const char *string, const char *search )
|
||
|
{
|
||
|
const char *p = string, *s = search;
|
||
|
|
||
|
while ( *p != '\0' )
|
||
|
{
|
||
|
for ( s=search; *s; s++ )
|
||
|
{
|
||
|
if ( *p == *s )
|
||
|
return p;
|
||
|
}
|
||
|
p++;
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
#if defined(_MSC_VER)
|
||
|
/*
|
||
|
=============
|
||
|
Q_vsnprintf
|
||
|
|
||
|
Special wrapper function for Microsoft's broken _vsnprintf() function.
|
||
|
MinGW comes with its own snprintf() which is not broken.
|
||
|
=============
|
||
|
*/
|
||
|
|
||
|
int Q_vsnprintf(char *str, size_t size, const char *format, va_list ap)
|
||
|
{
|
||
|
int retval;
|
||
|
|
||
|
retval = _vsnprintf(str, size, format, ap);
|
||
|
|
||
|
if(retval < 0 || retval == size)
|
||
|
{
|
||
|
// Microsoft doesn't adhere to the C99 standard of vsnprintf,
|
||
|
// which states that the return value must be the number of
|
||
|
// bytes written if the output string had sufficient length.
|
||
|
//
|
||
|
// Obviously we cannot determine that value from Microsoft's
|
||
|
// implementation, so we have no choice but to return size.
|
||
|
|
||
|
str[size - 1] = '\0';
|
||
|
return size;
|
||
|
}
|
||
|
|
||
|
return retval;
|
||
|
}
|
||
|
#endif
|